60 lines
2.6 KiB
TypeScript
60 lines
2.6 KiB
TypeScript
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
|
// The sign-out control ends every enabled module's browser context (joint contract §12, J1). Sign-out
|
|
// is a full navigation, so no provider unmounts: without the lifecycle run, the guides progress and
|
|
// unsent events of the person who signed out stay in the tab's `sessionStorage`.
|
|
|
|
import { afterEach, describe, expect, it, vi } from "vitest"
|
|
import { composedClientModules, endClientModules } from "../apps/web/src/ui/client-module-list"
|
|
|
|
/** A `Storage` over a Map, as much of it as the modules' handlers use. */
|
|
function memoryStorage(seed: Record<string, string>): Storage {
|
|
const values = new Map(Object.entries(seed))
|
|
const storage = {
|
|
get length() {
|
|
return values.size
|
|
},
|
|
key: (index: number) => [...values.keys()][index] ?? null,
|
|
getItem: (key: string) => values.get(key) ?? null,
|
|
setItem: (key: string, value: string) => void values.set(key, value),
|
|
removeItem: (key: string) => void values.delete(key),
|
|
clear: () => values.clear(),
|
|
}
|
|
// `Object.keys(storage)` lists the stored keys, as it does for the browser's own.
|
|
return new Proxy(storage, {
|
|
ownKeys: () => [...values.keys()],
|
|
getOwnPropertyDescriptor: (_target, key) =>
|
|
typeof key === "string" && values.has(key)
|
|
? { enumerable: true, configurable: true, value: values.get(key) }
|
|
: undefined,
|
|
}) as unknown as Storage
|
|
}
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
})
|
|
|
|
describe("signing out ends the client modules' context", () => {
|
|
it("clears what each enabled module keeps in the tab and leaves the app's own keys", async () => {
|
|
const own = "app.preference"
|
|
const keys = [own]
|
|
keys.push("conusai.guides.acme.u-7.queue", "conusai.guides.beta.u-7.active") // kit:guides
|
|
keys.push("conusai.support.session.v1:spk_example") // kit:support
|
|
const storage = memoryStorage(Object.fromEntries(keys.map((key) => [key, "{}"])))
|
|
vi.stubGlobal("window", { sessionStorage: storage })
|
|
|
|
const report = await endClientModules("sign-out")
|
|
|
|
expect(report.ok).toBe(true)
|
|
expect(report.outcomes.map((outcome) => outcome.module).sort()).toEqual([...composedClientModules.modules].sort())
|
|
expect(Object.keys(storage)).toEqual([own])
|
|
})
|
|
|
|
it("issues a new context instance, so a late answer of the old one is discarded", async () => {
|
|
vi.stubGlobal("window", { sessionStorage: memoryStorage({}) })
|
|
const before = composedClientModules.current()
|
|
await endClientModules("sign-out")
|
|
expect(before.signal.aborted).toBe(true)
|
|
expect(composedClientModules.isCurrent(before.instance)).toBe(false)
|
|
})
|
|
})
|