feat(console-web): add bounded iframe keep-alive
- opt service and settings pages into document retention - preserve iframe identity and local Solid state across navigation - cap retained documents with deterministic LRU eviction - deliver activate, deactivate, and dispose lifecycle messages - reject commands emitted by inactive page documents - expose page activity as a Solid accessor - test retention, recreation, eviction, and invalid limits
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { FrameCache } from "../src/host/frame-cache.ts";
|
||||
|
||||
test("retains opted-in iframe identities across navigation", () => {
|
||||
const cache = new FrameCache("services", {
|
||||
maxKeepAliveEntries: 2,
|
||||
shouldKeepAlive: (view) => view === "services" || view === "settings",
|
||||
});
|
||||
const services = cache.snapshot()[0];
|
||||
|
||||
const away = cache.activate("overview");
|
||||
assert.deepEqual(
|
||||
away.entries.map((entry) => entry.view),
|
||||
["services", "overview"],
|
||||
);
|
||||
|
||||
const back = cache.activate("services");
|
||||
assert.equal(back.activated, services);
|
||||
assert.equal(back.activated.instance, services.instance);
|
||||
assert.deepEqual(
|
||||
back.removed.map((entry) => entry.view),
|
||||
["overview"],
|
||||
);
|
||||
});
|
||||
|
||||
test("recreates non-keep-alive documents after leaving them", () => {
|
||||
const cache = new FrameCache("overview", {
|
||||
maxKeepAliveEntries: 2,
|
||||
shouldKeepAlive: () => false,
|
||||
});
|
||||
const firstInstance = cache.snapshot()[0].instance;
|
||||
|
||||
cache.activate("activity");
|
||||
const transition = cache.activate("overview");
|
||||
|
||||
assert.notEqual(transition.activated.instance, firstInstance);
|
||||
assert.deepEqual(
|
||||
transition.removed.map((entry) => entry.view),
|
||||
["activity"],
|
||||
);
|
||||
});
|
||||
|
||||
test("evicts inactive keep-alive documents in LRU order", () => {
|
||||
const cache = new FrameCache("services", {
|
||||
maxKeepAliveEntries: 2,
|
||||
shouldKeepAlive: () => true,
|
||||
});
|
||||
const servicesInstance = cache.snapshot()[0].instance;
|
||||
|
||||
cache.activate("settings");
|
||||
const overflow = cache.activate("instances");
|
||||
|
||||
assert.deepEqual(
|
||||
overflow.removed.map((entry) => entry.view),
|
||||
["services"],
|
||||
);
|
||||
assert.deepEqual(
|
||||
overflow.entries.map((entry) => entry.view),
|
||||
["settings", "instances"],
|
||||
);
|
||||
|
||||
const recreated = cache.activate("services");
|
||||
assert.notEqual(recreated.activated.instance, servicesInstance);
|
||||
assert.deepEqual(
|
||||
recreated.removed.map((entry) => entry.view),
|
||||
["settings"],
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects invalid keep-alive limits", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
new FrameCache("overview", {
|
||||
maxKeepAliveEntries: -1,
|
||||
shouldKeepAlive: () => true,
|
||||
}),
|
||||
RangeError,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user