← Source tree

web_demo/test_ui.cjs

"use strict";
// Event-flow checks in a minimal simulated DOM. No layout/native-download claims.
const test = require("node:test"), assert = require("node:assert/strict");
const vm = require("node:vm"), fs = require("node:fs"), crypto = require("node:crypto");
const {Session, sha256} = require("./core.js");
const inference = require("./inference.js");
require("./fixture.js"); require("./model.js");
function harness() {
  const elements = new Map(), downloads = [], blobs = [];
  function element(id) {
    if (elements.has(id)) return elements.get(id);
    const e = {id, value:"", textContent:"", disabled:false, hidden:false, open:false,
      children:[], handlers:{}, append(...nodes){this.children.push(...nodes);},
      replaceChildren(...nodes){this.children=nodes;}, remove(){},
      addEventListener(event, fn){this.handlers[event]=fn;},
      click(){if(this.tag === "a") downloads.push({name:this.download,url:this.href});},
      async fire(event="click"){if(!this.disabled && this.handlers[event]) await this.handlers[event]();}};
    elements.set(id,e);return e;
  }
  const document = {getElementById:element, body:element("body"),
    createElement(tag){const e=element(Symbol(tag)); e.tag=tag; return e;}};
  element("confirm").disabled=element("export").disabled=true;
  element("amount").value="119.00";element("quantity").value="1";
  vm.runInNewContext(fs.readFileSync(__dirname+"/app.js","utf8"), {
    document,ReviewDemo:{Session,sha256},ReviewInference:inference,
    SYNTHETIC_REPORT:globalThis.SYNTHETIC_REPORT, REVIEWQUEUE_MODEL:globalThis.REVIEWQUEUE_MODEL,
    Blob,URL:{createObjectURL(blob){blobs.push(blob);return "blob:synthetic";},revokeObjectURL(){}},
    setTimeout(){},console
  });
  return {element,downloads,blobs};
}
test("review, inspect, confirm and export retain exact report bytes",async()=>{
  const h=harness(),e=h.element;
  assert.equal(e("export").disabled,true);
  await e("review").fire();
  assert.equal(e("rows").children.length,6);
  assert.equal(e("details").open,true);assert.equal(e("confirm").disabled,false);
  assert.equal(e("export").disabled,true);
  await e("confirm").fire();await e("export").fire();
  assert.equal(h.downloads.length,1);
  const text=await h.blobs[0].text();
  assert.equal(crypto.createHash("sha256").update(text).digest("hex"),e("digest").value);
  assert.deepEqual(JSON.parse(text).review,globalThis.SYNTHETIC_REPORT);
});
test("reset and another review revoke UI export permission",async()=>{
  const h=harness(),e=h.element;
  await e("review").fire();await e("confirm").fire();await e("reset").fire();
  assert.equal(e("export").disabled,true);assert.equal(e("digest").value,"");
  assert.equal(e("rows").children.length,0);
  await e("review").fire();await e("confirm").fire();await e("review").fire();
  assert.equal(e("export").disabled,true);
});
test("live UI presets and changed inputs cannot leave a stale result visible",async()=>{
  const h=harness(),e=h.element;
  await e("extreme").fire();assert.match(e("prediction").textContent,/unusual/);
  assert.equal(JSON.parse(e("prediction-details").textContent).needs_review,true);
  await e("normal").fire();assert.equal(JSON.parse(e("prediction-details").textContent).needs_review,false);
  e("amount").value="1,234";await e("amount").fire("input");
  assert.equal(e("prediction-details").hidden,true);
  await e("score").fire();assert.match(e("prediction").textContent,/plain decimal/);
});