Something went wrong. Try again.
Something went wrong. Try again.
6.6 kB · 118 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119import { afterEach, beforeEach, describe, expect, it } from "vitest";import { JSDOM } from "jsdom";import { createWorker } from "../../extension/worker/worker";import { MemoryArchiveStore } from "../../extension/worker/archiveStore";import { handlePanelRequest } from "../../extension/worker/panelApi";import { mountPopup } from "../../extension/worker/popup";import { generateSigningKey } from "../../tools/bundleSign";import { startFakeCentral } from "../helpers/fakeCentral";
/** * #62: the popup and its message check on top of the real worker, against a central service that answers over HTTP (a fake one here; the real one is in the integration * tier). The worker is already enrolled by hand, as a test device is. Every control sends one request, and what the worker holds afterwards is what the popup shows. */
const ORIGIN = "http://127.0.0.1:4780";let key: Awaited<ReturnType<typeof generateSigningKey>>;let central: Awaited<ReturnType<typeof startFakeCentral>>;beforeEach(async () => { key = await generateSigningKey(); central = await startFakeCentral({ privateKey: key.privateKey });});afterEach(() => central.close());
async function enrolledPerson(open = false) { const stored = new Map<string, unknown>(); const worker = createWorker({ fetch: globalThis.fetch, storage: { get: async (k) => stored.get(k), set: async (k, v) => void stored.set(k, v) }, idb: undefined as never, store: new MemoryArchiveStore(), runJob: async () => { throw new Error("no job runs here"); }, deviceOrigins: open ? ["*"] : [ORIGIN], chrome: "155.0.0.0", pinnedKey: key.publicKey, pinnedDispatchKey: key.publicKey, now: () => Date.now(), setTimer: (fn, ms) => setTimeout(fn, ms), clearTimer: (h) => clearTimeout(h as number), requestTimeoutMs: 5000, }); await worker.configure({ central: central.url, token: central.token, deviceId: central.deviceId, accounts: { "test-qian": "qian.test" } }); const dom = new JSDOM('<!doctype html><body><div id="app"></div></body>'); const doc = dom.window.document; const $ = <T extends Element = HTMLElement>(sel: string) => doc.querySelector(sel) as T; const settle = async () => { for (let i = 0; i < 12; i++) await new Promise<void>((r) => setTimeout(r, 15)); }; const fire = (sel: string, type: string) => $(sel).dispatchEvent(new dom.window.Event(type, { bubbles: true })); await mountPopup(doc, (method, ...args) => handlePanelRequest(worker, central.url, { method, args })); return { worker, doc, $, settle, fire, text: () => doc.body.textContent ?? "" };}
describe("the popup over the real worker", () => { it("shows the device and its profile, and its controls start off", async () => { const p = await enrolledPerson(); expect(p.text()).toContain(central.deviceId); expect(p.text()).toContain("test-qian: qian.test"); for (const id of ["#paused", "#posting", "#spending"]) expect((p.$(id) as HTMLInputElement).checked).toBe(false); expect(p.$("#origins").textContent).toContain(ORIGIN); }); it("posting and spending are separate, and each stays as the person left it", async () => { const p = await enrolledPerson(); (p.$("#spending") as HTMLInputElement).checked = true; p.fire("#spending", "change"); await p.settle(); expect(await p.worker.status()).toMatchObject({ allowSpending: true, allowPosting: false }); expect((p.$("#spending") as HTMLInputElement).checked).toBe(true); expect((p.$("#posting") as HTMLInputElement).checked).toBe(false); }); it("approves a site only when the person ticks it and saves, and takes it back the same way", async () => { const p = await enrolledPerson(); expect(await p.worker.origins()).toEqual({ asked: [ORIGIN], approved: [] }); (p.$("#origins input[type=checkbox]") as HTMLInputElement).checked = true; p.fire("#saveOrigins", "click"); await p.settle(); expect(await p.worker.origins()).toEqual({ asked: [ORIGIN], approved: [ORIGIN] }); (p.$("#origins input[type=checkbox]") as HTMLInputElement).checked = false; p.fire("#saveOrigins", "click"); await p.settle(); expect(await p.worker.origins()).toEqual({ asked: [ORIGIN], approved: [] }); }); it("shows the worker's reason when a limit is refused", async () => { const p = await enrolledPerson(); (p.$("#postsPerDay") as HTMLInputElement).value = "0"; p.fire("#savePosts", "click"); await p.settle(); expect(p.$("#msg").textContent).toContain("whole number"); expect(await p.worker.status()).toMatchObject({ postsPerDay: 10 }); }); it("checks for work now and reports that there was none", async () => { const p = await enrolledPerson(); p.fire("#tick", "click"); await p.settle(); expect(p.$("#msg").textContent).toMatch(/idle|offline|error|refused|done/); });});
describe("the popup of an open device over the real worker", () => { it("has a box for the sites it will not test and none for approving sites", async () => { const p = await enrolledPerson(true); expect(p.$("#denied")).toBeTruthy(); expect(p.$("#origins")).toBeNull(); expect(await p.worker.status()).toMatchObject({ openMode: true, originsAsked: ["*"], deniedSites: [] }); }); it("keeps the sites the person writes, as hosts, and shows them back", async () => { const p = await enrolledPerson(true); (p.$("#denied") as HTMLTextAreaElement).value = "Bank.example\nhttps://mail.test:8443/inbox\n"; p.fire("#saveDenied", "click"); await p.settle(); expect(await p.worker.status()).toMatchObject({ deniedSites: ["bank.example", "mail.test"] }); expect((p.$("#denied") as HTMLTextAreaElement).value).toBe("bank.example\nmail.test"); expect(p.$("#msg").textContent).toBe("Saved."); }); it("shows why a line is not a site, and keeps the list it had", async () => { const p = await enrolledPerson(true); (p.$("#denied") as HTMLTextAreaElement).value = "bank.example"; p.fire("#saveDenied", "click"); await p.settle(); (p.$("#denied") as HTMLTextAreaElement).value = "bank.example\nnot a host!"; p.fire("#saveDenied", "click"); await p.settle(); expect(p.$("#msg").textContent).toContain("not a site"); expect(await p.worker.status()).toMatchObject({ deniedSites: ["bank.example"] }); }); it("cannot approve sites: there is nothing to approve", async () => { const p = await enrolledPerson(true); const r = await handlePanelRequest(p.worker, central.url, { method: "setApprovedOrigins", args: [[ORIGIN]] }); expect(r).toMatchObject({ ok: false, message: expect.stringContaining("nothing to approve") }); });});