Files
bitvid/tests/services/link-preview-service.test.mjs
T
google-labs-jules[bot]andPR0M3TH3AN 415465d067 Fix LinkPreviewService test timeout and assertion failure
Wraps the `respects TTL` test body in a `try...finally` block to ensure `expiredService.db` is closed even if assertions fail, preventing `fake-indexeddb` from hanging during cleanup.
Adds a small delay to the same test to ensure time advances beyond the 0ms TTL (caused by negative TTL clamping), fixing a flaky assertion failure.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-01-27 18:36:32 +00:00

124 lines
3.9 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { LinkPreviewService } from "../../js/services/linkPreviewService.js";
import { indexedDB, IDBKeyRange } from "fake-indexeddb";
import { JSDOM } from "jsdom";
// Polyfill IndexedDB
globalThis.indexedDB = indexedDB;
globalThis.IDBKeyRange = IDBKeyRange;
// Polyfill DOMParser
const dom = new JSDOM();
globalThis.DOMParser = dom.window.DOMParser;
globalThis.URL = URL;
test("LinkPreviewService", async (t) => {
const originalFetch = globalThis.fetch;
let service;
t.beforeEach(() => {
service = new LinkPreviewService({ ttlMs: 1000 });
});
t.afterEach(async () => {
globalThis.fetch = originalFetch;
if (service && service.db) {
service.db.close();
service.db = null;
}
// Yield to allow connection close events to propagate
await new Promise((resolve) => setImmediate(resolve));
await new Promise((resolve, reject) => {
const request = indexedDB.deleteDatabase("bitvid-link-previews");
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
request.onblocked = () => {
// Log warning if blocked, though strictly closing connections should prevent this
console.warn("[LinkPreviewService Test] Database deletion blocked");
};
});
});
await t.test("initializes IndexedDB", async () => {
const db = await service.init();
assert.ok(db);
assert.equal(db.objectStoreNames.contains("previews"), true);
});
await t.test("fetches and caches preview", async () => {
// Mock fetch
const htmlContent = `
<html>
<head>
<meta property="og:title" content="Test Title" />
<meta property="og:description" content="Test Description" />
<meta property="og:image" content="https://example.com/image.png" />
<meta property="og:site_name" content="Test Site" />
</head>
</html>
`;
globalThis.fetch = async (url) => {
if (url === "https://example.com") {
return {
ok: true,
text: async () => htmlContent,
};
}
throw new Error("Network error");
};
const preview = await service.getPreview("https://example.com");
assert.ok(preview);
assert.equal(preview.title, "Test Title");
assert.equal(preview.description, "Test Description");
assert.equal(preview.image, "https://example.com/image.png");
assert.equal(preview.siteName, "Test Site");
// Verify cache
const cached = await service.getCachedPreview("https://example.com");
assert.deepEqual(cached, preview);
});
await t.test("returns null on fetch failure", async () => {
globalThis.fetch = async () => {
throw new Error("Network failure");
};
const preview = await service.getPreview("https://fail.com");
assert.equal(preview, null);
});
await t.test("respects TTL", async () => {
// Set a preview that is expired
const expiredService = new LinkPreviewService({ ttlMs: -1000 });
try {
// Initialize DB first to ensure we write to the same place
await expiredService.init();
await expiredService.setCachedPreview("https://expired.com", { title: "Expired" });
// Ensure time advances since TTL is clamped to 0
await new Promise((r) => setTimeout(r, 10));
const cached = await expiredService.getCachedPreview("https://expired.com");
assert.equal(cached, null);
} finally {
if (expiredService.db) {
expiredService.db.close();
expiredService.db = null;
}
}
});
await t.test("deletePreview removes from cache", async () => {
await service.setCachedPreview("https://delete.com", { title: "Delete Me" });
await service.deletePreview("https://delete.com");
const cached = await service.getCachedPreview("https://delete.com");
assert.equal(cached, null);
});
});