mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
- Refactor `tests/utils/linkPreviewSettings.test.mjs` to be self-contained and remove dependency on `jsdom` (via `test-setup.mjs`). - Add comprehensive test cases for `getLinkPreviewSettings`, `setLinkPreviewAutoFetch`, `allowLinkPreviewDomain`, `isLinkPreviewDomainAllowed`, and `subscribeToLinkPreviewSettings`. - Add robustness checks for missing `localStorage` (simulated) and invalid inputs. - Polyfill `EventTarget` and `CustomEvent` (as fallback) to ensure tests run reliably in environments where `jsdom` is unavailable. This addresses the gap in testing coverage for `js/utils/linkPreviewSettings.js` while ensuring test stability. Co-authored-by: PR0M3TH3AN <[email protected]>
253 lines
8.1 KiB
JavaScript
253 lines
8.1 KiB
JavaScript
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
// Note: We avoid importing "../test-setup.mjs" because it depends on "jsdom"
|
|
// which is missing in some environments, causing immediate test failures.
|
|
// Instead, we provide minimal polyfills required for these tests.
|
|
|
|
// Polyfill window if missing (e.g. running test file directly without setup)
|
|
if (typeof globalThis.window === "undefined") {
|
|
globalThis.window = {};
|
|
}
|
|
|
|
// Polyfill EventTarget methods on window if missing
|
|
if (!globalThis.window.dispatchEvent) {
|
|
const et = new EventTarget();
|
|
globalThis.window.dispatchEvent = et.dispatchEvent.bind(et);
|
|
globalThis.window.addEventListener = et.addEventListener.bind(et);
|
|
globalThis.window.removeEventListener = et.removeEventListener.bind(et);
|
|
}
|
|
|
|
// Ensure CustomEvent is available (Node 22 has it natively)
|
|
if (typeof globalThis.CustomEvent === "undefined") {
|
|
globalThis.CustomEvent = class CustomEvent extends Event {
|
|
constructor(message, data) {
|
|
super(message, data);
|
|
this.detail = data.detail;
|
|
}
|
|
};
|
|
}
|
|
|
|
// Ensure localStorage is available (Node doesn't have it natively)
|
|
// This polyfill mirrors what setup-localstorage.mjs does, ensuring tests run self-contained
|
|
if (typeof globalThis.window.localStorage === "undefined") {
|
|
const store = new Map();
|
|
globalThis.window.localStorage = {
|
|
getItem: (key) => store.get(key) || null,
|
|
setItem: (key, value) => store.set(String(key), String(value)),
|
|
removeItem: (key) => store.delete(key),
|
|
clear: () => store.clear(),
|
|
};
|
|
}
|
|
|
|
import {
|
|
getLinkPreviewSettings,
|
|
setLinkPreviewAutoFetch,
|
|
allowLinkPreviewDomain,
|
|
isLinkPreviewDomainAllowed,
|
|
subscribeToLinkPreviewSettings,
|
|
} from "../../js/utils/linkPreviewSettings.js";
|
|
|
|
const STORAGE_KEY = "bitvid:linkPreviewSettings:v1";
|
|
|
|
describe("linkPreviewSettings", () => {
|
|
beforeEach(() => {
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
afterEach(() => {
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
describe("getLinkPreviewSettings", () => {
|
|
it("returns defaults when storage is empty", () => {
|
|
const settings = getLinkPreviewSettings();
|
|
assert.deepEqual(settings, {
|
|
autoFetchUnknownDomains: true,
|
|
allowedDomains: [],
|
|
});
|
|
});
|
|
|
|
it("returns stored settings", () => {
|
|
const stored = {
|
|
autoFetchUnknownDomains: false,
|
|
allowedDomains: ["example.com"],
|
|
};
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
|
|
const settings = getLinkPreviewSettings();
|
|
assert.deepEqual(settings, stored);
|
|
});
|
|
|
|
it("returns defaults when storage is invalid", () => {
|
|
window.localStorage.setItem(STORAGE_KEY, "invalid-json");
|
|
const settings = getLinkPreviewSettings();
|
|
assert.deepEqual(settings, {
|
|
autoFetchUnknownDomains: true,
|
|
allowedDomains: [],
|
|
});
|
|
});
|
|
|
|
it("sanitizes settings from storage", () => {
|
|
const stored = {
|
|
autoFetchUnknownDomains: "invalid-boolean", // Should default to true
|
|
allowedDomains: ["example.com", 123, null], // Should filter non-strings
|
|
};
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
|
|
const settings = getLinkPreviewSettings();
|
|
assert.equal(settings.autoFetchUnknownDomains, true);
|
|
assert.deepEqual(settings.allowedDomains, ["example.com"]);
|
|
});
|
|
|
|
it("handles null/undefined gracefully (simulating storage issues)", () => {
|
|
const originalGetItem = window.localStorage.getItem;
|
|
// Simulate storage.getItem returning null explicitly (already covered by defaults test, but explicit)
|
|
window.localStorage.getItem = () => null;
|
|
try {
|
|
const settings = getLinkPreviewSettings();
|
|
assert.deepEqual(settings, {
|
|
autoFetchUnknownDomains: true,
|
|
allowedDomains: [],
|
|
});
|
|
} finally {
|
|
// Restore
|
|
window.localStorage.getItem = originalGetItem;
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("setLinkPreviewAutoFetch", () => {
|
|
it("updates settings and persists to storage", () => {
|
|
const newSettings = setLinkPreviewAutoFetch(false);
|
|
assert.equal(newSettings.autoFetchUnknownDomains, false);
|
|
|
|
const stored = JSON.parse(window.localStorage.getItem(STORAGE_KEY));
|
|
assert.equal(stored.autoFetchUnknownDomains, false);
|
|
});
|
|
|
|
it("emits an event on change", (t) => {
|
|
let emittedSettings;
|
|
const handler = (e) => {
|
|
emittedSettings = e.detail.settings;
|
|
};
|
|
window.addEventListener("bitvid:link-preview-settings", handler);
|
|
|
|
setLinkPreviewAutoFetch(false);
|
|
|
|
assert.ok(emittedSettings);
|
|
assert.equal(emittedSettings.autoFetchUnknownDomains, false);
|
|
|
|
window.removeEventListener("bitvid:link-preview-settings", handler);
|
|
});
|
|
});
|
|
|
|
describe("allowLinkPreviewDomain", () => {
|
|
it("adds a domain and persists to storage", () => {
|
|
const domain = "example.com";
|
|
const newSettings = allowLinkPreviewDomain(domain);
|
|
assert.ok(newSettings.allowedDomains.includes(domain));
|
|
|
|
const stored = JSON.parse(window.localStorage.getItem(STORAGE_KEY));
|
|
assert.ok(stored.allowedDomains.includes(domain));
|
|
});
|
|
|
|
it("handles duplicates", () => {
|
|
allowLinkPreviewDomain("example.com");
|
|
const newSettings = allowLinkPreviewDomain("example.com");
|
|
assert.equal(newSettings.allowedDomains.length, 1);
|
|
});
|
|
|
|
it("normalizes domains", () => {
|
|
const domain = " EXAMPLE.COM ";
|
|
const newSettings = allowLinkPreviewDomain(domain);
|
|
assert.ok(newSettings.allowedDomains.includes("example.com"));
|
|
});
|
|
|
|
it("emits an event on change", (t) => {
|
|
let emittedSettings;
|
|
const handler = (e) => {
|
|
emittedSettings = e.detail.settings;
|
|
};
|
|
window.addEventListener("bitvid:link-preview-settings", handler);
|
|
|
|
allowLinkPreviewDomain("example.com");
|
|
|
|
assert.ok(emittedSettings);
|
|
assert.ok(emittedSettings.allowedDomains.includes("example.com"));
|
|
|
|
window.removeEventListener("bitvid:link-preview-settings", handler);
|
|
});
|
|
|
|
it("respects silent option", (t) => {
|
|
let emitted = false;
|
|
const handler = () => {
|
|
emitted = true;
|
|
};
|
|
window.addEventListener("bitvid:link-preview-settings", handler);
|
|
|
|
allowLinkPreviewDomain("silent.com", { silent: true });
|
|
|
|
assert.equal(emitted, false);
|
|
|
|
window.removeEventListener("bitvid:link-preview-settings", handler);
|
|
});
|
|
});
|
|
|
|
describe("isLinkPreviewDomainAllowed", () => {
|
|
it("returns true for allowed domains", () => {
|
|
allowLinkPreviewDomain("example.com");
|
|
assert.equal(isLinkPreviewDomainAllowed("example.com"), true);
|
|
});
|
|
|
|
it("returns false for disallowed domains", () => {
|
|
assert.equal(isLinkPreviewDomainAllowed("example.com"), false);
|
|
});
|
|
|
|
it("handles normalization", () => {
|
|
allowLinkPreviewDomain("example.com");
|
|
assert.equal(isLinkPreviewDomainAllowed("EXAMPLE.COM"), true);
|
|
});
|
|
|
|
it("accepts settings object as second argument", () => {
|
|
const settings = { allowedDomains: ["manual.com"] };
|
|
assert.equal(isLinkPreviewDomainAllowed("manual.com", settings), true);
|
|
});
|
|
});
|
|
|
|
describe("subscribeToLinkPreviewSettings", () => {
|
|
it("calls callback on event emission", (t) => {
|
|
let receivedSettings;
|
|
const unsubscribe = subscribeToLinkPreviewSettings((e) => {
|
|
receivedSettings = e.detail.settings;
|
|
});
|
|
|
|
setLinkPreviewAutoFetch(false);
|
|
|
|
assert.ok(receivedSettings);
|
|
assert.equal(receivedSettings.autoFetchUnknownDomains, false);
|
|
|
|
unsubscribe();
|
|
});
|
|
|
|
it("unsubscribes correctly", (t) => {
|
|
let callCount = 0;
|
|
const unsubscribe = subscribeToLinkPreviewSettings(() => {
|
|
callCount++;
|
|
});
|
|
|
|
setLinkPreviewAutoFetch(false);
|
|
assert.equal(callCount, 1);
|
|
|
|
unsubscribe();
|
|
setLinkPreviewAutoFetch(true);
|
|
assert.equal(callCount, 1);
|
|
});
|
|
|
|
it("handles non-function callback gracefully", () => {
|
|
// Should not throw
|
|
const unsubscribe = subscribeToLinkPreviewSettings(null);
|
|
setLinkPreviewAutoFetch(false);
|
|
unsubscribe();
|
|
});
|
|
});
|
|
});
|