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", { inactiveTtlMs: 1_000, 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", { inactiveTtlMs: 1_000, 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("expires a keep-alive document after its continuous hidden TTL", () => { let now = 5_000; const cache = new FrameCache("services", { inactiveTtlMs: 1_000, shouldKeepAlive: () => true, now: () => now, }); const servicesInstance = cache.snapshot()[0].instance; // Time spent visible does not consume the inactive TTL. now = 50_000; cache.activate("settings"); now = 50_999; assert.equal(cache.timeUntilExpiration(), 1); assert.deepEqual(cache.expireInactive().removed, []); now = 51_000; const expiration = cache.expireInactive(); assert.deepEqual( expiration.removed.map((entry) => entry.view), ["services"], ); assert.deepEqual( expiration.entries.map((entry) => entry.view), ["settings"], ); const recreated = cache.activate("services"); assert.notEqual(recreated.activated.instance, servicesInstance); }); test("revisiting a hidden page before its TTL preserves and resets it", () => { let now = 0; const cache = new FrameCache("services", { inactiveTtlMs: 1_000, shouldKeepAlive: () => true, now: () => now, }); const services = cache.snapshot()[0]; cache.activate("settings"); now = 999; const revisited = cache.activate("services"); assert.equal(revisited.activated, services); now = 1_500; assert.deepEqual(cache.expireInactive().removed, []); assert.equal(cache.timeUntilExpiration(), 499); now = 1_999; const expiration = cache.expireInactive(); assert.deepEqual( expiration.removed.map((entry) => entry.view), ["settings"], ); }); test("rejects invalid inactive TTL values", () => { for (const inactiveTtlMs of [0, -1, Number.POSITIVE_INFINITY, Number.NaN]) { assert.throws( () => new FrameCache("overview", { inactiveTtlMs, shouldKeepAlive: () => true, }), RangeError, ); } });