Files
tech-log-frontend/tests/unit/auth-session-adapter.test.ts

93 lines
3.1 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
createAnonymousSessionAdapter,
createDemoSessionAdapter,
createExternalAuthSessionAdapter,
} from "../../src/adapters/auth/external-session-adapter.ts";
describe("external AuthSessionPort adapter", () => {
it("attaches opaque credentials without exposing a token-shaped session", async () => {
const adapter = createExternalAuthSessionAdapter({
readState: () => "authenticated",
subscribe: () => () => {},
beginSignIn: async () => {},
signOut: async () => {},
attachCredential: async () => ({
headers: { Authorization: "Bearer opaque" },
}),
recoverSession: async () => "restored",
notifyUnauthenticated: vi.fn(),
});
const patch = await adapter.credentialPatch({
origin: "https://api.test",
method: "GET",
operationId: "GET_RESOURCE",
});
expect(patch.headers.authorization).toBe("Bearer opaque");
expect(adapter.getState()).toBe("authenticated");
expect(adapter).not.toHaveProperty("accessToken");
expect(adapter).not.toHaveProperty("refreshToken");
});
it("fails invalid recovery states closed", async () => {
const adapter = createExternalAuthSessionAdapter({
readState: () => "authenticated",
subscribe: () => () => {},
beginSignIn: async () => {},
signOut: async () => {},
attachCredential: async () => ({ headers: {} }),
// @ts-expect-error Deliberately violates the external-owner contract.
recoverSession: async () => "unexpected",
notifyUnauthenticated: vi.fn(),
});
await expect(adapter.recover()).rejects.toThrow("invalid recovery state");
});
it("rejects credential patches that can alter transport-owned headers", async () => {
const adapter = createExternalAuthSessionAdapter({
readState: () => "authenticated",
subscribe: () => () => {},
beginSignIn: async () => {},
signOut: async () => {},
attachCredential: async () => ({
headers: { Host: "attacker.test" },
}),
recoverSession: async () => "restored",
notifyUnauthenticated: vi.fn(),
});
await expect(
adapter.credentialPatch({
origin: "https://api.test",
method: "GET",
operationId: "GET_RESOURCE",
}),
).rejects.toThrow("forbidden credential patch");
});
it("provides a safe anonymous adapter", async () => {
const adapter = createAnonymousSessionAdapter();
expect(adapter.getState()).toBe("unauthenticated");
await expect(adapter.recover()).resolves.toBe("no-session");
});
it("provides a reactive credential-free demo seam", async () => {
const adapter = createDemoSessionAdapter();
let notifications = 0;
const unsubscribe = adapter.subscribe(() => {
notifications += 1;
});
expect(adapter.getState()).toBe("unauthenticated");
await adapter.beginSignIn();
expect(adapter.getState()).toBe("authenticated");
await adapter.signOut();
expect(adapter.getState()).toBe("unauthenticated");
expect(notifications).toBe(2);
unsubscribe();
});
});