Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
110 lines
3.3 KiB
JavaScript
110 lines
3.3 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { LADDER, SLOTS, baseOf, claim, liveCount, _resetLayers } from "../internals/zlayer.js";
|
|
|
|
test.beforeEach(() => _resetLayers());
|
|
|
|
test("the ladder is ordered, and every rung clears the one below", () => {
|
|
for (let i = 1; i < LADDER.length; i += 1) {
|
|
assert.ok(baseOf(LADDER[i]) > baseOf(LADDER[i - 1]) + SLOTS - 1,
|
|
`${LADDER[i]} must clear every peer of ${LADDER[i - 1]}`);
|
|
}
|
|
});
|
|
|
|
test("autocomplete outranks modal", () => {
|
|
// It opens from a field that is usually inside a modal; v4 got this wrong.
|
|
assert.ok(baseOf("autocomplete") > baseOf("modal"));
|
|
});
|
|
|
|
test("a modal covers floating windows: nothing behind it is usable until it closes", () => {
|
|
assert.ok(baseOf("modal") > baseOf("floatingWindow"));
|
|
});
|
|
|
|
test("an unknown rung is refused rather than guessed", () => {
|
|
assert.throws(() => baseOf("somewhere"), RangeError);
|
|
});
|
|
|
|
test("peers stack within their rung and never reach the next one", () => {
|
|
const a = claim("modal");
|
|
const b = claim("modal");
|
|
assert.ok(b.z > a.z);
|
|
assert.ok(b.z < baseOf("toast"));
|
|
});
|
|
|
|
test("releasing frees the slot for reuse", () => {
|
|
const a = claim("modal");
|
|
const first = a.z;
|
|
a.release();
|
|
assert.equal(claim("modal").z, first);
|
|
});
|
|
|
|
test("releasing twice is harmless", () => {
|
|
const a = claim("modal");
|
|
a.release();
|
|
a.release();
|
|
assert.equal(a.live, false);
|
|
});
|
|
|
|
test("raise() puts a claim above its peers", () => {
|
|
const a = claim("floatingWindow");
|
|
const b = claim("floatingWindow");
|
|
assert.ok(b.z > a.z);
|
|
a.raise();
|
|
assert.ok(a.z > b.z, "click-to-front");
|
|
assert.ok(a.z < baseOf("toast"));
|
|
});
|
|
|
|
test("raise() on the top claim is a no-op", () => {
|
|
const a = claim("modal");
|
|
const b = claim("modal");
|
|
const before = b.z;
|
|
b.raise();
|
|
assert.equal(b.z, before);
|
|
});
|
|
|
|
test("raise() after release does nothing", () => {
|
|
const a = claim("modal");
|
|
a.release();
|
|
const z = a.z;
|
|
a.raise();
|
|
assert.equal(a.z, z);
|
|
});
|
|
|
|
test("raise() works when the rung is nearly full", () => {
|
|
// With fixed per-claim offsets this returned the LOWEST free slot, so raise()
|
|
// sent the window to the back -- exactly backwards, and only in the state a
|
|
// long session actually reaches.
|
|
const hs = Array.from({ length: SLOTS }, () => claim("popover"));
|
|
hs[0].release();
|
|
const mid = hs[50];
|
|
mid.raise();
|
|
const peers = hs.filter((h) => h.live && h !== mid).map((h) => h.z);
|
|
assert.ok(mid.z > Math.max(...peers), "raise must put it above every peer");
|
|
assert.ok(mid.z < baseOf("toast"), "and still inside its own rung");
|
|
});
|
|
|
|
test("releasing a middle claim keeps the order of the rest", () => {
|
|
const a = claim("modal");
|
|
const b = claim("modal");
|
|
const c = claim("modal");
|
|
b.release();
|
|
assert.ok(c.z > a.z);
|
|
assert.equal(liveCount("modal"), 2);
|
|
});
|
|
|
|
test("a released claim reports the z it last held", () => {
|
|
const a = claim("modal");
|
|
const b = claim("modal");
|
|
const z = b.z;
|
|
b.release();
|
|
assert.equal(b.z, z);
|
|
});
|
|
|
|
test("exhausting a rung is loud, not silently wrapped", () => {
|
|
// A rung running dry means overlays are being opened and never released.
|
|
// Reusing a slot would hide the leak and stack two things at one z.
|
|
for (let i = 0; i < SLOTS; i += 1) claim("popover");
|
|
assert.throws(() => claim("popover"), /is full/);
|
|
});
|