Files
stack/packages/webui/tests/w15-inbox-browser.test.mjs

72 lines
4.9 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { setup, oldId, currentId, requestId } from './helpers/w15-inbox.mjs';
for (const width of [1440, 390]) test(`decision evidence and two-step answer at ${width}px`, { timeout: 120000 }, async t => {
const s = await setup(t), { b, wait } = s;
const text = sel => b.evaluate(`document.querySelector(${JSON.stringify(sel)})?.textContent ?? ''`);
await s.page('/inbox', width);
await wait('document.querySelectorAll(".s1-decs > li").length === 2');
assert.match(await text('#b-for-you'), /Open decisions/);
const cards = await b.evaluate('[...document.querySelectorAll(".s1-decs > li")].map(e => e.textContent)');
assert.match(cards[0], /2026-11-03T22:17:22\.717Z.*\d+ d ago.*pm.*rcfdc22434131.*Not linked to a request/s);
assert.match(cards[1], /current-run/);
assert.doesNotMatch(cards[0], /current-run|b1869a13/);
assert.deepEqual(await b.evaluate('window.__request'), { id: requestId, currentWaitSubject: currentId });
assert.notEqual(currentId, requestId);
assert.equal(await b.evaluate('document.documentElement.scrollWidth <= innerWidth'), true);
await s.shot('open-decisions-old-and-current', width);
await s.page(`/inbox/${oldId}`, width);
await wait('document.querySelector("[data-decide=option-0]")');
assert.match(await text('#bus-view'), /rcfdc22434131/);
await s.shot('historic-decision-detail', width);
await b.evaluate('document.querySelector("[data-decide=option-0]").click()');
await wait('document.querySelector("[data-decide=confirm]")');
assert.match(await text('.s1-confirm'), /2026-11-03T22:17:22\.717Z.*rcfdc22434131.*Not linked to a request.*Affected object: unavailable.*Decision routed to: human.*Destination: unavailable.*keep.*Keep original/s);
assert.equal(await b.evaluate('window.__posts.length'), 1);
assert.equal(await b.evaluate('document.activeElement?.dataset.decide'), 'confirm');
await b.key('Tab', 'Tab');
assert.equal(await b.evaluate('document.activeElement?.dataset.decide'), 'cancel');
await b.key('Tab', 'Tab', 8);
assert.equal(await b.evaluate('document.activeElement?.dataset.decide'), 'confirm');
await b.key('Escape');
assert.equal(await b.evaluate('window.__posts.length'), 1);
await s.shot('historic-confirmation', width);
await b.evaluate('document.querySelector("[data-decide=confirm]").click()');
await wait('document.querySelector("#decide-status")?.textContent.startsWith("Recorded")');
assert.match(await text('#decide-section'), /Recorded: you chose “keep”, Keep original.*Affected object: unavailable.*Decision routed to: human.*Destination: unavailable.*unknown/s);
assert.equal(await b.evaluate('window.__posts.length'), 2);
await s.shot('decision-recorded', width);
await s.page(`/inbox/${currentId}`, width);
await wait('document.querySelector("[data-decide=option-0]")');
assert.match(await text('#bus-view'), /Current request: choose a mode/);
assert.doesNotMatch(await text('#bus-view'), /rcfdc22434131/);
await s.shot('current-decision', width);
await b.evaluate('window.__outcome = "unknown"; document.querySelector("[data-decide=option-0]").click()');
await wait('document.querySelector("[data-decide=confirm]")');
await b.evaluate('document.querySelector("[data-decide=confirm]").click()');
await wait('document.querySelector("#decide-status code")?.textContent === "outcome-unknown"');
assert.match(await text('#decide-status'), /Nothing was sent again/);
await s.shot('decision-outcome-unknown', width);
assert.deepEqual(await b.evaluate('window.__unexpected || []'), []);
assert.deepEqual(s.failures, []);
assert.deepEqual(s.consoleErrors, []);
});
test('metadata handles missing and hostile origins without HTML or bidi injection', { timeout: 120000 }, async t => {
const { b, page } = await setup(t);
await page('/inbox', 1440);
const result = await b.evaluate(`(() => { const host = document.createElement('div'); host.innerHTML = window.MosaicInbox.cardMeta({at:'bad', raised_by_role:'<img src=x onerror=alert(1)>\\u202e', raised_by_run:''}); return {text:host.textContent, images:host.querySelectorAll('img').length}; })()`);
assert.match(result.text, /date unknown.*unknown.*\[U\+202E\].*run unknown.*Not linked to a request/s);
assert.equal(result.images, 0);
});
test('receipt uses recorded target and destination without interpreting hostile text', { timeout: 120000 }, async t => {
const { b, page } = await setup(t);
await page('/inbox', 1440);
const result = await b.evaluate(`(() => { const host = document.createElement('div'); host.innerHTML = window.MosaicInbox.receipt({kind:'decision',grantDetails:{host:'web1'}}, {authorization:{target:'workspace <img src=x>\\u202e'},routeTo:'human'}); return {text:host.textContent, images:host.querySelectorAll('img').length}; })()`);
assert.match(result.text, /Affected object: workspace <img src=x>\[U\+202E\].*Decision routed to: human.*Destination: web1.*unknown/s);
assert.equal(result.images, 0);
});