import test from "node:test"; import assert from "node:assert/strict"; import { chooseFocus, advanceExample, initializeFocusScenes, } from "../src/scripts/scenes-focus.js"; test("focus has distinct meaningful task content for every supported selection", () => { const cards = ["all", "approvals", "connections", "agents"].map(chooseFocus); assert.equal(new Set(cards.map((card) => card.title)).size, 4); assert.ok(cards.every((card) => card.title && card.source && card.action)); }); test("unknown focus safely falls back to all tasks without modifying existing data", () => { const first = chooseFocus("all"); assert.deepEqual(chooseFocus("__proto__"), first); assert.notEqual(chooseFocus("all"), first); }); test("example explicitly cycles pending, reviewed, and a new pending example", () => { const first = advanceExample(0); assert.equal(first.step, 1); assert.equal(first.status, "Reviewed"); const second = advanceExample(first.step); assert.equal(second.step, 2); assert.equal(second.status, "Pending review"); assert.notEqual(second.title, first.title); assert.equal(advanceExample(3).step, 0); }); test("invalid update state recovers to first example", () => { assert.equal(advanceExample(NaN).step, 0); assert.equal(advanceExample(-2).step, 0); assert.equal(advanceExample("1").step, 0); }); function element(queries = {}) { return { dataset: {}, attributes: {}, textContent: "", firstChild: { textContent: "" }, events: {}, animations: [], querySelector(selector) { return queries[selector] ?? null; }, querySelectorAll(selector) { return queries[selector] ?? []; }, setAttribute(key, value) { this.attributes[key] = value; }, getAttribute(key) { return this.attributes[key]; }, addEventListener(key, callback) { this.events[key] = callback; }, removeEventListener(key) { delete this.events[key]; }, animate(frames, options) { this.animations.push({ frames, options }); return { cancel() {} }; }, getAnimations() { return [{ cancel() {} }]; }, }; } function illustrationFixture() { const choices = ["all", "approvals", "connections", "agents"].map((key) => { const button = element(); button.dataset.selChoice = key; button.attributes["aria-pressed"] = String(key === "approvals"); return button; }); const stageFields = Object.fromEntries( ["source", "label", "count", "title", "time", "action", "icon"].map( (field) => [`[data-sel-${field}]`, element()], ), ); const mainCard = element(); const stage = element({ ...stageFields, ".sel-main-card": mainCard }); const selector = element({ "[data-sel-choice]": choices, "#selector-stage": stage, }); const controlFields = Object.fromEntries( ["source", "status", "title", "outcome"].map((field) => [ `[data-control-${field}]`, element(), ]), ); const update = element(); const approvalCard = element(); const controlFrame = element(); const control = element({ ...controlFields, "[data-control-update]": update, "#control-example": controlFrame, ".control-approval-card": approvalCard, }); const document = { documentElement: { dataset: {} }, getElementById: (id) => ({ selector, control })[id], }; return { document, choices, stage, stageFields, mainCard, controlFrame, controlFields, update, approvalCard, }; } test("bound selection updates accessible state, task content, and only pointer motion", async () => { const fixture = illustrationFixture(); const originalDocument = globalThis.document; const originalMatch = globalThis.matchMedia; let reducedMotion = false; globalThis.document = fixture.document; globalThis.matchMedia = () => ({ get matches() { return reducedMotion; }, addEventListener() {}, removeEventListener() {}, }); try { const dispose = initializeFocusScenes(fixture.document, { matchMedia: globalThis.matchMedia, }); fixture.choices[2].events.click({ detail: 1 }); assert.equal(fixture.choices[2].attributes["aria-pressed"], "true"); assert.equal(fixture.choices[1].attributes["aria-pressed"], "false"); assert.equal( fixture.stageFields["[data-sel-title]"].textContent, "Reconnect to see recent transactions", ); assert.equal( fixture.stageFields["[data-sel-icon]"].attributes.href, "#i-sync", ); assert.equal(fixture.mainCard.animations.length, 1); fixture.choices[2].events.click({ detail: 1 }); assert.equal( fixture.mainCard.animations.length, 1, "selecting the same category does not replay motion", ); fixture.choices[3].events.click({ detail: 0 }); assert.equal(fixture.stage.dataset.focus, "agents"); assert.equal( fixture.mainCard.animations.length, 1, "keyboard activation settles immediately", ); fixture.document.documentElement.dataset.capture = "true"; fixture.choices[0].events.click({ detail: 1 }); assert.equal( fixture.mainCard.animations.length, 1, "capture mode suppresses motion", ); fixture.document.documentElement.dataset.capture = "false"; reducedMotion = true; fixture.choices[1].events.click({ detail: 1 }); assert.equal( fixture.mainCard.animations.length, 1, "reduced motion suppresses motion", ); fixture.update.events.click({ detail: 0 }); assert.equal(fixture.controlFrame.dataset.reviewState, "reviewed"); assert.equal( fixture.controlFields["[data-control-status]"].textContent, "Reviewed", ); assert.equal(fixture.update.firstChild.textContent, "Next"); fixture.update.events.click({ detail: 1 }); assert.equal(fixture.controlFrame.dataset.reviewState, "pending"); assert.equal( fixture.controlFields["[data-control-source]"].textContent, "Daily activity", ); assert.equal(fixture.approvalCard.animations.length, 0); reducedMotion = false; fixture.update.events.click({ detail: 1 }); assert.equal(fixture.approvalCard.animations.length, 1); fixture.update.events.click({ detail: 1 }); assert.equal( fixture.controlFields["[data-control-source]"].textContent, "Bank Recommendations", ); dispose(); assert.equal(fixture.update.events.click, undefined); assert.ok(fixture.choices.every((button) => !button.events.click)); } finally { globalThis.document = originalDocument; globalThis.matchMedia = originalMatch; } });