mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
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]>
124 lines
3.9 KiB
JavaScript
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);
|
|
});
|
|
});
|