60 lines
3.7 KiB
JavaScript
60 lines
3.7 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
test("history connects without a helper, opens a tab, and retains failures before download starts", async () => {
|
|
const url = "https://www.youtube.com/watch?v=jNQXAC9IVRw";
|
|
const storage = { jobs: {
|
|
saved: { id: "saved", title: "Сохранённое видео", kind: "download", status: "complete", result: { path: "D:/Videos/saved.mp4" }, createdAt: 1 },
|
|
interrupted: { id: "interrupted", status: "running", createdAt: 2 },
|
|
} };
|
|
const listeners = {}, tabs = [], nativeRequests = [];
|
|
const noEvent = { addListener() {} };
|
|
const runtime = { id: "history-test", getManifest: () => ({ version: "1.4.5" }), getURL: file => `chrome-extension://history-test/${file}`,
|
|
onConnect: { addListener: listener => { listeners.connect = listener; } }, onMessage: noEvent,
|
|
connectNative() {
|
|
let receive;
|
|
return { onMessage: { addListener: listener => { receive = listener; } }, onDisconnect: noEvent, disconnect() {},
|
|
postMessage(message) {
|
|
nativeRequests.push(message);
|
|
queueMicrotask(() => receive({ id: message.id, ok: message.action !== "inspect", result: message.action === "hello" ? { version: "1.3.2" } : { alive: true }, error: "Видео недоступно" }));
|
|
} };
|
|
} };
|
|
globalThis.chrome = { runtime, storage: { local: { get: async () => structuredClone(storage), set: async data => Object.assign(storage, structuredClone(data)) } },
|
|
tabs: { create: async tab => { tabs.push(tab); }, sendMessage: async () => {} },
|
|
notifications: { clear: async () => {}, create: async () => {}, update: async () => true, onButtonClicked: noEvent },
|
|
permissions: { contains: async () => false },
|
|
action: { onClicked: noEvent, setBadgeText() {}, setBadgeBackgroundColor() {} },
|
|
};
|
|
await import("../extension/background.js?history-test");
|
|
const attach = file => {
|
|
let send;
|
|
const events = [], pending = new Map();
|
|
listeners.connect({ name: "ytdl-ui", sender: { id: runtime.id, url: runtime.getURL(file) }, onDisconnect: noEvent,
|
|
onMessage: { addListener: listener => { send = listener; } },
|
|
postMessage(message) {
|
|
if (message.id) { pending.get(message.id)?.(message); pending.delete(message.id); }
|
|
else events.push(message);
|
|
} });
|
|
return { connected: () => Boolean(send), events, call: (action, payload = {}) => new Promise(resolve => {
|
|
const id = crypto.randomUUID(); pending.set(id, resolve); send({ id, action, payload });
|
|
}) };
|
|
};
|
|
const history = attach("history.html?theme=dark"), menu = attach("downloader.html?embedded=1");
|
|
assert.ok(history.connected());
|
|
assert.ok(!attach("history.html.evil").connected());
|
|
assert.ok(!attach("content.js").connected());
|
|
const state = (await history.call("state")).result;
|
|
assert.equal(state.jobs.length, 2);
|
|
assert.equal(state.jobs.find(job => job.id === "interrupted").status, "error");
|
|
assert.equal(nativeRequests.length, 0, "Viewing history must not launch or query the helper");
|
|
assert.deepEqual((await menu.call("open_history", { theme: "dark" })).result, { opened: true });
|
|
assert.deepEqual(tabs, [{ url: runtime.getURL("history.html?theme=dark") }]);
|
|
const inspection = await menu.call("inspect", { url });
|
|
assert.equal(inspection.ok, false);
|
|
assert.equal(inspection.error, "Видео недоступно");
|
|
const failure = Object.values(storage.jobs).find(job => job.kind === "inspection");
|
|
assert.equal(failure.error, "Видео недоступно"); assert.equal(failure.url, url);
|
|
assert.ok(history.events.some(message => message.job?.id === failure.id), "Already open history receives failures immediately");
|
|
assert.ok(!JSON.stringify(storage).includes("browserCookies"));
|
|
});
|