105 lines
4.1 KiB
TypeScript
105 lines
4.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { PermissionDeniedError, assertCanAccessAppointment, canAccessAppointment } from "../authorization";
|
|
|
|
/**
|
|
* The registered-customer branch never touches the database (it's a plain
|
|
* userId comparison), so it's tested here in isolation. The guest-token
|
|
* branch's real hash/expiry/revocation behaviour is covered against a real
|
|
* database in customer-booking.integration.test.ts — this file only checks
|
|
* that authorization.ts calls into validateGuestAccessToken correctly and
|
|
* respects its result.
|
|
*/
|
|
vi.mock("@/services/scheduling/guest-access.service", () => ({
|
|
validateGuestAccessToken: vi.fn(),
|
|
}));
|
|
|
|
const { validateGuestAccessToken } = await import("@/services/scheduling/guest-access.service");
|
|
const mockValidate = vi.mocked(validateGuestAccessToken);
|
|
|
|
beforeEach(() => {
|
|
mockValidate.mockClear();
|
|
});
|
|
|
|
// Not a real PrismaClient — the mocked guest-access service never touches it.
|
|
const prisma = {} as never;
|
|
|
|
describe("assertCanAccessAppointment", () => {
|
|
it("allows a registered customer to access their own appointment", async () => {
|
|
await expect(
|
|
assertCanAccessAppointment(prisma, { id: "a1", customer: { userId: "user_1" } }, { sessionUserId: "user_1" }),
|
|
).resolves.toBeUndefined();
|
|
});
|
|
|
|
it("denies a different signed-in user from accessing a registered customer's appointment", async () => {
|
|
await expect(
|
|
assertCanAccessAppointment(prisma, { id: "a1", customer: { userId: "user_1" } }, { sessionUserId: "user_2" }),
|
|
).rejects.toThrow(PermissionDeniedError);
|
|
});
|
|
|
|
it("denies an unauthenticated caller from accessing a registered customer's appointment", async () => {
|
|
await expect(
|
|
assertCanAccessAppointment(prisma, { id: "a1", customer: { userId: "user_1" } }, { sessionUserId: undefined }),
|
|
).rejects.toThrow(PermissionDeniedError);
|
|
});
|
|
|
|
it("never even calls the guest-token validator for a registered customer's appointment", async () => {
|
|
mockValidate.mockClear();
|
|
await assertCanAccessAppointment(
|
|
prisma,
|
|
{ id: "a1", customer: { userId: "user_1" } },
|
|
{ sessionUserId: "user_1" },
|
|
).catch(() => {});
|
|
expect(mockValidate).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("allows a guest appointment when the guest-token validator confirms the token", async () => {
|
|
mockValidate.mockResolvedValueOnce(true);
|
|
await expect(
|
|
assertCanAccessAppointment(
|
|
prisma,
|
|
{ id: "a1", customer: { userId: null } },
|
|
{ sessionUserId: undefined, guestToken: "correct-token" },
|
|
),
|
|
).resolves.toBeUndefined();
|
|
expect(mockValidate).toHaveBeenCalledWith(prisma, { appointmentId: "a1", rawToken: "correct-token" });
|
|
});
|
|
|
|
it("denies a guest appointment when no token is supplied at all — the appointment id is no longer sufficient", async () => {
|
|
await expect(
|
|
assertCanAccessAppointment(prisma, { id: "a1", customer: { userId: null } }, { sessionUserId: undefined }),
|
|
).rejects.toThrow(PermissionDeniedError);
|
|
expect(mockValidate).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("denies a guest appointment when the guest-token validator rejects the token", async () => {
|
|
mockValidate.mockResolvedValueOnce(false);
|
|
await expect(
|
|
assertCanAccessAppointment(
|
|
prisma,
|
|
{ id: "a1", customer: { userId: null } },
|
|
{ sessionUserId: undefined, guestToken: "wrong-token" },
|
|
),
|
|
).rejects.toThrow(PermissionDeniedError);
|
|
});
|
|
});
|
|
|
|
describe("canAccessAppointment", () => {
|
|
it("mirrors assertCanAccessAppointment as a boolean", async () => {
|
|
expect(
|
|
await canAccessAppointment(prisma, { id: "a1", customer: { userId: "user_1" } }, { sessionUserId: "user_1" }),
|
|
).toBe(true);
|
|
expect(
|
|
await canAccessAppointment(prisma, { id: "a1", customer: { userId: "user_1" } }, { sessionUserId: "user_2" }),
|
|
).toBe(false);
|
|
|
|
mockValidate.mockResolvedValueOnce(true);
|
|
expect(
|
|
await canAccessAppointment(
|
|
prisma,
|
|
{ id: "a1", customer: { userId: null } },
|
|
{ sessionUserId: undefined, guestToken: "correct-token" },
|
|
),
|
|
).toBe(true);
|
|
});
|
|
});
|