// npm install --prefix jsdom@26 // node scripts/test_frontend.cjs /node_modules/jsdom const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const {JSDOM} = require(process.argv[2] || "jsdom"); const source = fs.readFileSync(path.join(__dirname, "../inventory/static/inventory/js/app.js"), "utf8"); const pause = ms => new Promise(resolve => setTimeout(resolve, ms)); async function run() { const dom = new JSDOM(`
Current employee
`, {url: "https://inventory.test/", runScripts: "outside-only"}); try { const {window} = dom, requests = []; window.fetch = async (url, options) => { requests.push({url, options}); return {ok: true, json: async () => options?.method === "POST" ? {value: 1, display: "Employee 1", revision: 8, updated_at: "2026-09-23T10:00:00Z"} : {results: [{id: 1, label: "Employee 1"}]}}; }; window.eval(source); const form = window.document.querySelector("form"); form.dataset.confirm = ''; form.dataset.confirmAction = "Unsafe label"; form.dispatchEvent(new window.Event("submit", {bubbles: true, cancelable: true})); const box = window.document.querySelector(".confirm-box"); assert.equal(box.querySelector("img"), null); assert.equal(box.querySelector("b"), null); assert.equal(box.querySelector("p").textContent, form.dataset.confirm); box.querySelector("button").click(); const cell = window.document.querySelector("td"); cell.dispatchEvent(new window.MouseEvent("dblclick", {bubbles: true})); await pause(20); assert.equal(cell.querySelector("select").value, "23", "Missing/inactive current value must be preserved"); cell.querySelector("select").dispatchEvent(new window.Event("blur")); await pause(250); assert.equal(requests.filter(item => item.options?.method === "POST").length, 0, "Unchanged field must not save on blur"); cell.dispatchEvent(new window.MouseEvent("dblclick", {bubbles: true})); await pause(20); const select = cell.querySelector("select"); select.value = "1"; select.dispatchEvent(new window.KeyboardEvent("keydown", {key: "Enter", bubbles: true})); await pause(20); const save = requests.find(item => item.options?.method === "POST"); assert.equal(JSON.parse(save.options.body).expected_revision, "7"); assert.equal(cell.closest("tr").dataset.revision, "8"); assert.equal(cell.textContent, "Employee 1"); console.log("Frontend regression checks passed: safe confirmation text, preserved selection, no-op blur, revision save."); } finally { dom.window.close(); } } run().catch(error => { console.error(error); process.exitCode = 1; });