import { beforeEach, describe, expect, it, vi } from "vitest"; const { auth, getAdminContext, getTranslations, notFound, redirect, startLogicalRequest, staleActor, wrapCache, } = vi.hoisted(() => { let requestCache = new Map>(); return { auth: vi.fn(), getAdminContext: vi.fn(), getTranslations: vi.fn(), notFound: vi.fn((): never => { throw new Error("NEXT_NOT_FOUND"); }), redirect: vi.fn((href: string): never => { throw new Error(`NEXT_REDIRECT:${href}`); }), startLogicalRequest: () => { requestCache = new Map(); }, staleActor: { id: 9, username: "stale-session", rank: 1 }, wrapCache: (callback: () => Promise) => { const cacheKey = Symbol("housekeeping-capability-context"); return () => { let value = requestCache.get(cacheKey); if (!value) { value = callback(); requestCache.set(cacheKey, value); } return value; }; }, }; }); vi.mock("react", () => ({ cache: wrapCache })); vi.mock("next/navigation", () => ({ notFound, redirect })); vi.mock("next-intl/server", () => ({ getTranslations })); vi.mock("@/lib/auth", () => ({ auth })); vi.mock("@/lib/db", () => { throw new Error("server capability context must not access the database"); }); vi.mock("@/lib/permissions", () => ({ getAdminContext })); import AdminNextDomainLayout from "@/app/ase-next/[domain]/layout"; import AdminNextPage from "@/app/ase-next/page"; import { requireHousekeepingCapability } from "@/lib/admin/guard"; import { auth as mockedAuth } from "@/lib/auth"; import { anyCapability } from "./contracts"; import { getHousekeepingCapabilityContext } from "./server-capability-context"; function adminContext( actor: { id: number; username: string; rank: number }, granted: readonly string[], ) { const permissions = new Set(granted); return { session: { user: actor }, permissions: { isSuperAdmin: false, has: (slug: string) => permissions.has(slug), hasAny: (...slugs: string[]) => slugs.some((slug) => permissions.has(slug)), hasAll: (...slugs: string[]) => slugs.every((slug) => permissions.has(slug)), }, }; } async function invokeRequestConsumers() { const shell = await AdminNextDomainLayout({ children: null, params: Promise.resolve({ domain: "operations" }), }); await expect(AdminNextPage()).rejects.toThrow( "NEXT_REDIRECT:/ase-next/operations", ); const commandContext = await requireHousekeepingCapability( anyCapability("admin.dashboard"), ); return { commandContext, shell }; } describe("getHousekeepingCapabilityContext", () => { beforeEach(() => { startLogicalRequest(); vi.clearAllMocks(); auth.mockResolvedValue({ user: staleActor }); getTranslations.mockResolvedValue((key: string) => key); getAdminContext.mockResolvedValue( adminContext({ id: 42, username: "operator", rank: 7 }, [ "admin.dashboard", "admin.users.view", ]), ); }); it("isolates real shell, page, and command preflight consumers between logical requests", async () => { const first = await invokeRequestConsumers(); expect(first.shell).toBeDefined(); expect(first.commandContext.actor).toEqual({ id: 42, username: "operator", rank: 7, }); expect(getAdminContext).toHaveBeenCalledTimes(1); startLogicalRequest(); getAdminContext.mockResolvedValue( adminContext({ id: 84, username: "second-operator", rank: 2 }, [ "admin.dashboard", ]), ); const second = await invokeRequestConsumers(); expect(second.shell).toBeDefined(); expect(second.commandContext.actor).toEqual({ id: 84, username: "second-operator", rank: 2, }); expect(second.commandContext.has("admin.users.view")).toBe(false); expect(getAdminContext).toHaveBeenCalledTimes(2); }); it("uses the refreshed administrator actor instead of the stale auth actor", async () => { const context = await getHousekeepingCapabilityContext(); expect(context).toMatchObject({ actor: { id: 42, username: "operator", rank: 7 }, isSuperAdmin: false, }); expect(context.has("admin.users.view")).toBe(true); expect(context.has("admin.logs.view")).toBe(false); expect(getAdminContext).toHaveBeenCalledTimes(1); expect(mockedAuth).not.toHaveBeenCalled(); }); });