This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// 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)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user