Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
144 lines
5.5 KiB
JavaScript
144 lines
5.5 KiB
JavaScript
// Rule 3: an element the kit does not have makes its module hide.
|
|
//
|
|
// The alternative is a panel that renders something approximate, which is worse
|
|
// than nothing: it looks like it works.
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { setupDom, teardownDom } from "./_dom.js";
|
|
|
|
let composer, UnknownElement, renderPanel, mountAll, mounts;
|
|
test.before(async () => {
|
|
setupDom();
|
|
({ composer, UnknownElement } = await import("../composer.js"));
|
|
({ renderPanel } = await import("../panel.js"));
|
|
({ mountAll } = await import("../../shell/panels.js"));
|
|
mounts = await import("../../shell/mounts.js");
|
|
});
|
|
test.after(() => teardownDom());
|
|
|
|
test.beforeEach(() => {
|
|
mounts._reset();
|
|
document.body.replaceChildren();
|
|
});
|
|
|
|
const spec = (id, settings) => ({ id, title: id, mount: "test.region", settings });
|
|
|
|
test("asking the kit for something it does not have throws", () => {
|
|
assert.throws(() => composer.hologram, UnknownElement);
|
|
assert.throws(() => composer.button.hologram, UnknownElement);
|
|
});
|
|
|
|
test("a panel naming an unknown renderer appends nothing", () => {
|
|
const host = document.createElement("div");
|
|
document.body.appendChild(host);
|
|
assert.throws(() => {
|
|
const panel = renderPanel(spec("bad", {
|
|
good: { type: "bool", default: true, label: "Fine" },
|
|
bad: { type: "bool", default: true, label: "Bad", ui: "hologram" },
|
|
}));
|
|
host.appendChild(panel.node);
|
|
});
|
|
assert.equal(host.childElementCount, 0,
|
|
"not even the rows that built successfully reached the document");
|
|
});
|
|
|
|
test("a broken module is absent, and its neighbours still mount", async () => {
|
|
const host = document.createElement("div");
|
|
document.body.appendChild(host);
|
|
mounts.offer("test.region", host);
|
|
|
|
const { mounted, hidden } = await mountAll({ modules: [
|
|
spec("first", { on: { type: "bool", default: true, label: "First" } }),
|
|
spec("broken", { on: { type: "bool", default: true, label: "Broken", ui: "hologram" } }),
|
|
spec("third", { on: { type: "bool", default: true, label: "Third" } }),
|
|
] });
|
|
|
|
assert.deepEqual(mounted.map((m) => m.id), ["first", "third"]);
|
|
assert.deepEqual(hidden.map((h) => h.id), ["broken"]);
|
|
assert.match(host.textContent, /First/);
|
|
assert.match(host.textContent, /Third/);
|
|
assert.doesNotMatch(host.textContent, /Broken/);
|
|
});
|
|
|
|
test("nothing about a hidden module reaches the screen", async () => {
|
|
// No placeholder, no greyed row, no warning chip: absent is absent.
|
|
const host = document.createElement("div");
|
|
document.body.appendChild(host);
|
|
mounts.offer("test.region", host);
|
|
|
|
await mountAll({ modules: [spec("broken", {
|
|
on: { type: "bool", default: true, label: "Broken", ui: "hologram" },
|
|
})] });
|
|
|
|
assert.equal(host.childElementCount, 0);
|
|
assert.equal(host.textContent, "");
|
|
});
|
|
|
|
test("a module whose ui.js fails to load is hidden, not half-mounted", async () => {
|
|
const host = document.createElement("div");
|
|
document.body.appendChild(host);
|
|
mounts.offer("test.region", host);
|
|
|
|
const { mounted, hidden } = await mountAll(
|
|
{ modules: [{ ...spec("has_ui", { on: { type: "bool", default: true, label: "On" } }), ui: "/missing.js" }] },
|
|
{ load: () => { throw new Error("404"); } },
|
|
);
|
|
|
|
assert.deepEqual(mounted, []);
|
|
assert.equal(hidden[0].id, "has_ui");
|
|
assert.equal(host.childElementCount, 0, "its panel did not stay behind");
|
|
});
|
|
|
|
test("a module naming a mount point nobody offers is absent", async () => {
|
|
// Hide, don't warn, one level up: a typo'd mount point makes a module vanish
|
|
// rather than landing somewhere arbitrary.
|
|
const { mounted, hidden } = await mountAll({ modules: [
|
|
{ ...spec("lost", { on: { type: "bool", default: true, label: "On" } }), mount: "nowhere" },
|
|
] });
|
|
assert.deepEqual(mounted, []);
|
|
assert.match(hidden[0].why, /no region offers/);
|
|
});
|
|
|
|
test("a module is handed no way to touch the document", async () => {
|
|
const host = document.createElement("div");
|
|
document.body.appendChild(host);
|
|
mounts.offer("test.region", host);
|
|
|
|
let context = null;
|
|
await mountAll(
|
|
{ modules: [{ ...spec("m", { on: { type: "bool", default: true, label: "On" } }), ui: "/ui.js" }] },
|
|
{ load: async () => ({ setup: (ctx) => { context = ctx; } }) },
|
|
);
|
|
|
|
assert.deepEqual(Object.keys(context).sort(), ["on", "shell", "values"]);
|
|
|
|
// Not "no value IS a node" -- that was the old assertion, and it passed while
|
|
// `composer` sat in this object handing out handles whose .node is a real
|
|
// element, reachable to the whole document through node.ownerDocument. The
|
|
// property that matters is that nothing here PRODUCES one either.
|
|
for (const [name, value] of Object.entries(context)) {
|
|
assert.equal(value instanceof globalThis.Node, false, `${name} is a DOM node`);
|
|
}
|
|
assert.equal("composer" in context, false,
|
|
"an element factory is a way to obtain a DOM node");
|
|
|
|
// `on` is callable, and must hand back an unsubscribe rather than anything
|
|
// that leads to the page.
|
|
const off = context.on(() => {});
|
|
assert.equal(typeof off, "function");
|
|
assert.equal(off instanceof globalThis.Node, false);
|
|
|
|
// Nothing one level down is a node either -- the services are the other place
|
|
// a handle could have been tucked away.
|
|
for (const [name, value] of Object.entries(context.shell)) {
|
|
for (const [inner, member] of Object.entries(value)) {
|
|
assert.equal(member instanceof globalThis.Node, false, `shell.${name}.${inner}`);
|
|
}
|
|
}
|
|
|
|
// The service surface is named one by one, so it can be reviewed.
|
|
assert.deepEqual(Object.keys(context.shell).sort(), ["density", "theme"]);
|
|
});
|