70 lines
2.8 KiB
TypeScript
70 lines
2.8 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { setPlatformApiSessionToken } from "../api/client";
|
|
import { rolesFromBackendRoles } from "../contracts/workspace";
|
|
import { currentUserFromResponse, loadCurrentUser, localFallbackUser } from "./session";
|
|
|
|
describe("session store helpers", () => {
|
|
afterEach(() => {
|
|
setPlatformApiSessionToken(null);
|
|
vi.restoreAllMocks();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
it("does not grant platform administrator access for local fallback", () => {
|
|
expect(localFallbackUser.roles).toEqual(["serverAdmin"]);
|
|
expect(localFallbackUser.capabilities).not.toContain("users.manage");
|
|
});
|
|
|
|
it("maps backend platform admin roles only from API responses", () => {
|
|
const user = currentUserFromResponse({ id: "user-admin", displayName: "Operator", status: "active", roles: ["platform-admin"] }, "api");
|
|
expect(user.roles).toEqual(["platformAdmin"]);
|
|
expect(user.capabilities).toContain("users.manage");
|
|
expect(rolesFromBackendRoles(["server-admin"])).toEqual(["serverAdmin"]);
|
|
});
|
|
|
|
it("returns null without a stored API session token", async () => {
|
|
stubWindowStorage(new Map());
|
|
await expect(loadCurrentUser()).resolves.toBeNull();
|
|
});
|
|
|
|
it("loads current user with a stored API bearer token", async () => {
|
|
const storage = new Map([["platform-web.session.apiToken", "session-token"]]);
|
|
stubWindowStorage(storage);
|
|
const fetchMock = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
|
expect(new Headers(init?.headers).get("Authorization")).toBe("Bearer session-token");
|
|
return jsonResponse({ id: "user-admin", displayName: "Operator", status: "active", roles: ["platform-admin"] });
|
|
});
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
await expect(loadCurrentUser()).resolves.toMatchObject({ id: "user-admin", roles: ["platformAdmin"], source: "api" });
|
|
expect(storage.get("platform-web.session.apiToken")).toBe("session-token");
|
|
});
|
|
|
|
it("clears stale stored API session tokens", async () => {
|
|
const storage = new Map([["platform-web.session.apiToken", "stale-token"]]);
|
|
stubWindowStorage(storage);
|
|
vi.stubGlobal("fetch", vi.fn(async () => jsonResponse({ message: "authentication required" }, 401)));
|
|
|
|
await expect(loadCurrentUser()).resolves.toBeNull();
|
|
expect(storage.has("platform-web.session.apiToken")).toBe(false);
|
|
});
|
|
});
|
|
|
|
function stubWindowStorage(values: Map<string, string>) {
|
|
vi.stubGlobal("window", {
|
|
localStorage: {
|
|
getItem: (key: string) => values.get(key) ?? null,
|
|
setItem: (key: string, value: string) => values.set(key, value),
|
|
removeItem: (key: string) => values.delete(key)
|
|
}
|
|
});
|
|
}
|
|
|
|
function jsonResponse(body: unknown, status = 200): Response {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { "Content-Type": "application/json" }
|
|
});
|
|
}
|