Files
YouTubeDL/tests/history.test.mjs
T
DepressedCat 5f2aad00f4
Check extension and helper / check (push) Canceled after 0s
Publish YouTubeDL 1.4.5 and website on Gitea
2026-10-10 23:53:17 +03:00

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"));
});