Files
Inventory/scripts/test_frontend.cjs

84 lines
4.7 KiB
JavaScript

// npm install --prefix <temporary directory> jsdom@26
// node scripts/test_frontend.cjs <temporary directory>/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(`<!doctype html><body data-csrf="test">
<div id="toast-root"></div><div id="drawer-root"></div>
<form data-confirm="Remove employee?"><button>Remove</button></form>
<div id="device-table-container"><table><tbody><tr data-device-id="1" data-revision="7">
<td data-field="employee" data-input="select" data-value="23">Current employee</td>
</tr></tbody></table></div>
</body>`, {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 = '<img src=x onerror="window.injected=true">';
form.dataset.confirmAction = "<b>Unsafe label</b>";
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(); }
}
async function testCustomColumns() {
const dom = new JSDOM(`<!doctype html><body data-user-id="42">
<button data-columns-toggle></button><div data-columns-panel></div>
<div id="device-table-container"><table data-device-table>
<thead><tr><th data-column="number">Nr.</th><th data-column="custom_checked">Checked</th></tr></thead>
<tbody><tr><td data-column="number">1</td><td data-column="custom_checked">JA</td></tr></tbody>
</table></div></body>`, {url: "https://inventory.test/", runScripts: "outside-only"});
try {
const {window} = dom;
window.fetch = async () => ({ok: true, json: async () => ({})});
window.localStorage.setItem("csr-visible-columns-42", '["number"]');
window.localStorage.setItem("csr-column-order-42", '["number","custom_checked"]');
window.localStorage.setItem("csr-complete-list-columns-42", "1");
window.eval(source);
const cell = window.document.querySelector('td[data-column="custom_checked"]');
assert.equal(cell.style.display, "", "New custom columns must appear with old preferences");
const check = window.document.querySelector('[data-columns-panel] [data-column="custom_checked"] input');
check.checked = false;
check.dispatchEvent(new window.Event("change"));
assert.equal(cell.style.display, "none");
window.eval(source);
assert.equal(cell.style.display, "none", "Explicitly hidden custom columns must stay hidden on rebinding");
console.log("Frontend regression checks passed: custom-column defaults and saved visibility.");
} finally { dom.window.close(); }
}
run().then(testCustomColumns).catch(error => { console.error(error); process.exitCode = 1; });