src/lib/auth/scope.test.ts
Linked repository file from this build.
import { expect, test } from "bun:test";
import { demoActor, demoRoster } from "./roster";
import { canAccessReview, can } from "./scope";
import { execute } from "@/features/reviews/commands";
import { completedReviewAnswers, createSeed } from "@/programs/snap-negative/seed";
import { actorSchema } from "./actor";
const meta = { id: "scope-test", at: "2026-09-08T12:00:00.000Z" };
test("staff graph limits examiner ownership and supervisor coverage across teams", () => {
const first = { ...createSeed(), examiner: "101", supervisor: "201" };
const second = { ...first, examiner: "105", supervisor: "202" };
expect(canAccessReview(demoActor("examiner"), first)).toBe(true);
expect(canAccessReview(demoActor("examiner"), second)).toBe(false);
expect(canAccessReview(demoActor("supervisor"), first)).toBe(true);
expect(canAccessReview(demoActor("supervisor"), second)).toBe(false);
const otherSupervisor = demoRoster.find((actor) => actor.staffId === "202")!;
expect(canAccessReview(otherSupervisor, second)).toBe(true);
expect(canAccessReview(otherSupervisor, first)).toBe(false);
for (const actor of demoRoster)
expect(canAccessReview(actor, { ...first, program: "OTHER" })).toBe(false);
});
test("capabilities preserve separate administrative, statistical, and review work", () => {
for (const actor of demoRoster) {
expect(can(actor, "applyRules")).toBe(["admin", "statistics"].includes(actor.role));
expect(can(actor, "schedule")).toBe(["examiner", "supervisor"].includes(actor.role));
expect(can(actor, "import")).toBe(
["admin", "statistics", "program_manager"].includes(actor.role),
);
expect(can(actor, "report")).toBe(can(actor, "import"));
}
});
test("supervisor coverage records the supervisor and preserves examiner assignment", () => {
const review = { ...createSeed(), examiner: "101", supervisor: "201" };
const supervisor = demoActor("supervisor");
const next = execute(
review,
{ type: "appointment", value: "2026-09-10T10:00" },
supervisor,
meta,
);
expect(next.examiner).toBe("101");
expect(next.activity.at(-1)?.actor.staffId).toBe("201");
expect(() =>
execute(review, { type: "identity", value: { examiner: "105" } }, supervisor, meta),
).toThrow();
expect(() =>
execute(review, { type: "identity", value: { supervisor: "202" } }, supervisor, meta),
).toThrow();
expect(() =>
execute({ ...review, examiner: "105" }, { type: "appointment", value: "" }, supervisor, meta),
).toThrow();
});
test("transport actor schema validates shape but does not itself establish authorization", () => {
expect(actorSchema.safeParse(demoActor("admin")).success).toBe(true);
expect(
actorSchema.safeParse({ name: "Forged admin", role: "admin", staffId: "401", program: "SNAP" })
.success,
).toBe(true);
expect(actorSchema.safeParse({ name: "Legacy", role: "clerical" }).success).toBe(false);
expect(
actorSchema.safeParse({ name: "No staff ID", role: "admin", program: "SNAP" }).success,
).toBe(false);
});
test("supervisor coverage keeps examiner facts locked", () => {
const supervisor = demoActor("supervisor");
const review = { ...createSeed(), examiner: "101", supervisor: "201" };
expect(() =>
execute(review, { type: "answers", value: completedReviewAnswers() }, supervisor, meta),
).toThrow("Only the examiner");
expect(review.examiner).toBe("101");
});