Fix lint, check and test

This commit is contained in:
Karl Ludwig Weise
2026-08-14 17:09:23 +02:00
parent c92c52be3f
commit acd44b57bb
8 changed files with 60 additions and 43 deletions
@@ -38,7 +38,7 @@ vi.mock("../notification-service", () => ({
vi.mock("../../auth/webauthn-service", () => ({
WebAuthnService: {
// getClientTunnels scopes staff key shares to the caller's most recently used passkey.
getMostRecentPasskey: vi.fn().mockResolvedValue({ id: "passkey-123", lastUsedAt: new Date() }),
getCurrentPasskey: vi.fn().mockResolvedValue({ id: "passkey-123", lastUsedAt: new Date() }),
},
}));
@@ -23,7 +23,7 @@ vi.mock("$lib/logger", () => ({
vi.mock("../../auth/webauthn-service", () => ({
WebAuthnService: {
// Staff key shares are scoped to the caller's most recently used passkey.
getMostRecentPasskey: vi.fn().mockResolvedValue({ id: "passkey-123", lastUsedAt: new Date() }),
getCurrentPasskey: vi.fn().mockResolvedValue({ id: "passkey-123", lastUsedAt: new Date() }),
},
}));
@@ -146,9 +146,9 @@ describe("ScheduleService", () => {
tenantId: "invalid-uuid",
};
await expect(service.getSchedule(invalidRequest as ScheduleRequest)).rejects.toThrow(
ValidationError,
);
await expect(
service.getSchedule(invalidRequest as ScheduleRequest, "passkeyId"),
).rejects.toThrow(ValidationError);
});
it("should generate schedule for valid date range", async () => {
@@ -206,7 +206,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
// Validate basic structure
expect(result).toHaveProperty("period");
@@ -265,7 +265,7 @@ describe("ScheduleService", () => {
channelAgents: [],
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
expect(result.schedule).toHaveLength(1); // One day
expect(result.schedule[0].channels).toEqual({});
@@ -283,7 +283,9 @@ describe("ScheduleService", () => {
throw new Error("Database error");
});
await expect(service.getSchedule(validRequest)).rejects.toThrow("Database error");
await expect(service.getSchedule(validRequest, "passkeyId")).rejects.toThrow(
"Database error",
);
});
it("should generate multiple days for date range", async () => {
@@ -303,7 +305,7 @@ describe("ScheduleService", () => {
channelAgents: [],
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
expect(result.schedule).toHaveLength(3); // Three days
expect(result.schedule[0].date).toBe("2024-01-01");
@@ -384,7 +386,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
// Should only have Monday slot (09:00-10:00), not Tuesday slot
const channelSchedule = result.schedule[0].channels["channel1"];
@@ -459,7 +461,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
const channelSchedule = result.schedule[0].channels["channel1"];
// Should only have 10:00-11:00 slot, not 09:00-10:00 (has appointment)
@@ -544,7 +546,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
// Validate appointments are returned
const channelSchedule = result.schedule[0].channels["channel1"];
@@ -642,7 +644,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
const channelSchedule = result.schedule[0].channels["channel1"];
// Should have no available slots since only agent is absent
@@ -724,7 +726,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
const channelSchedule = result.schedule[0].channels["channel1"];
expect(channelSchedule.availableSlots).toHaveLength(1);
@@ -828,7 +830,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
const channel1Schedule = result.schedule[0].channels["channel1"];
const channel2Schedule = result.schedule[0].channels["channel2"];
@@ -910,7 +912,7 @@ describe("ScheduleService", () => {
channelAgents: mockChannelAgents,
});
const result = await service.getSchedule(validRequest);
const result = await service.getSchedule(validRequest, "passkeyId");
const channelSchedule = result.schedule[0].channels["channel1"];
expect(channelSchedule.availableSlots).toHaveLength(2);
+1 -1
View File
@@ -95,7 +95,7 @@ export class ScheduleService {
*/
async getSchedule(
request: ScheduleRequest,
passkeyId: string | undefined,
passkeyId?: string | undefined,
): Promise<ScheduleResult> {
const log = logger.setContext("ScheduleService");
-2
View File
@@ -358,12 +358,10 @@ export const getPasskeyFormData = async ({
email,
userId,
setPasskeyFieldState,
isAdditionalPasskey,
}: {
email: string;
userId: string;
setPasskeyFieldState: (newState: PasskeyState) => void;
isAdditionalPasskey: boolean;
}) => {
setPasskeyFieldState("loading");
@@ -71,7 +71,6 @@
email: $formData.email,
userId: $formData.userId,
setPasskeyFieldState: (v) => ($passkeyLoading = v),
isAdditionalPasskey: false,
});
if (!data) {
@@ -63,7 +63,6 @@
email: $formData.email,
userId: $formData.userId,
setPasskeyFieldState: (v) => ($passkeyLoading = v),
isAdditionalPasskey: true,
});
if (!data) {
@@ -54,6 +54,7 @@ describe("Calendar API", () => {
locals: {
user: {
id: "user-123",
passkeyId: "passkey-123",
tenantId,
role: "GUEST",
},
@@ -150,13 +151,16 @@ describe("Calendar API", () => {
});
expect(ScheduleService.forTenant).toHaveBeenCalledWith("tenant-123");
expect(mockGetSchedule).toHaveBeenCalledWith({
tenantId: "tenant-123",
startDate: "2024-01-01T00:00:00.000Z",
endDate: "2024-01-02T00:00:00.000Z",
timeZone: "UTC",
staffUserId: "user-123",
});
expect(mockGetSchedule).toHaveBeenCalledWith(
{
tenantId: "tenant-123",
startDate: "2024-01-01T00:00:00.000Z",
endDate: "2024-01-02T00:00:00.000Z",
timeZone: "UTC",
staffUserId: "user-123",
},
"passkey-123",
);
});
it("should include full appointment and agent information in calendar response", async () => {
@@ -37,7 +37,7 @@ vi.mock("$lib/server/services/staff-crypto.service", () => ({
vi.mock("$lib/server/auth/webauthn-service", () => ({
WebAuthnService: {
getMostRecentPasskey: vi.fn(async () => undefined),
getCurrentPasskey: vi.fn(async () => undefined),
},
}));
@@ -108,6 +108,7 @@ describe("Staff Key Shard API Route", () => {
locals: {
user: {
id: mockUserId,
passkeyId: mockPasskeyId,
session: {
sessionId: "session-123",
},
@@ -130,7 +131,7 @@ describe("Staff Key Shard API Route", () => {
passkeyId: mockPasskeyId,
};
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(mockRecentPasskey);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(mockRecentPasskey);
mockStaffCryptoService.getStaffCryptoForPasskey.mockResolvedValue(mockStaffCrypto);
const event = createMockRequestEvent();
@@ -144,7 +145,7 @@ describe("Staff Key Shard API Route", () => {
passkeyId: mockStaffCrypto.passkeyId,
});
expect(WebAuthnService.getMostRecentPasskey).toHaveBeenCalledWith(mockUserId);
expect(WebAuthnService.getCurrentPasskey).toHaveBeenCalledWith(mockUserId, mockPasskeyId);
expect(mockStaffCryptoService.getStaffCryptoForPasskey).toHaveBeenCalledWith(
mockTenantId,
mockStaffId,
@@ -157,6 +158,7 @@ describe("Staff Key Shard API Route", () => {
locals: {
user: {
id: "different-user-id",
passkeyId: mockPasskeyId,
session: { sessionId: "session-123" },
},
} as any,
@@ -168,7 +170,7 @@ describe("Staff Key Shard API Route", () => {
expect(response.status).toBe(403);
expect(data.error).toBe("You can only access your own key shard");
expect(WebAuthnService.getMostRecentPasskey).not.toHaveBeenCalled();
expect(WebAuthnService.getCurrentPasskey).not.toHaveBeenCalled();
expect(mockStaffCryptoService.getStaffCryptoForPasskey).not.toHaveBeenCalled();
});
@@ -187,7 +189,7 @@ describe("Staff Key Shard API Route", () => {
});
it("should reject access when no recent passkey is found", async () => {
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(null);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(null);
const event = createMockRequestEvent();
const response = await GET(event);
@@ -196,7 +198,7 @@ describe("Staff Key Shard API Route", () => {
expect(response.status).toBe(403);
expect(data.error).toBe("No valid passkey found for authenticated user");
expect(WebAuthnService.getMostRecentPasskey).toHaveBeenCalledWith(mockUserId);
expect(WebAuthnService.getCurrentPasskey).toHaveBeenCalledWith(mockUserId, mockPasskeyId);
expect(mockStaffCryptoService.getStaffCryptoForPasskey).not.toHaveBeenCalled();
});
@@ -206,7 +208,7 @@ describe("Staff Key Shard API Route", () => {
lastUsedAt: new Date("2024-01-15T10:00:00Z"),
};
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(mockRecentPasskey);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(mockRecentPasskey);
mockStaffCryptoService.getStaffCryptoForPasskey.mockResolvedValue(null);
const event = createMockRequestEvent();
@@ -216,7 +218,7 @@ describe("Staff Key Shard API Route", () => {
expect(response.status).toBe(404);
expect(data.error).toBe("Staff crypto data not found for the authenticated passkey");
expect(WebAuthnService.getMostRecentPasskey).toHaveBeenCalledWith(mockUserId);
expect(WebAuthnService.getCurrentPasskey).toHaveBeenCalledWith(mockUserId, mockPasskeyId);
expect(mockStaffCryptoService.getStaffCryptoForPasskey).toHaveBeenCalledWith(
mockTenantId,
mockStaffId,
@@ -249,7 +251,7 @@ describe("Staff Key Shard API Route", () => {
});
it("should handle WebAuthn service errors gracefully", async () => {
(WebAuthnService.getMostRecentPasskey as any).mockRejectedValue(
(WebAuthnService.getCurrentPasskey as any).mockRejectedValue(
new Error("Database connection failed"),
);
@@ -260,7 +262,7 @@ describe("Staff Key Shard API Route", () => {
expect(response.status).toBe(500);
expect(data.error).toBe("Failed to determine passkey ID");
expect(WebAuthnService.getMostRecentPasskey).toHaveBeenCalledWith(mockUserId);
expect(WebAuthnService.getCurrentPasskey).toHaveBeenCalledWith(mockUserId, mockPasskeyId);
expect(mockStaffCryptoService.getStaffCryptoForPasskey).not.toHaveBeenCalled();
});
@@ -270,7 +272,7 @@ describe("Staff Key Shard API Route", () => {
lastUsedAt: new Date("2024-01-15T10:00:00Z"),
};
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(mockRecentPasskey);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(mockRecentPasskey);
mockStaffCryptoService.getStaffCryptoForPasskey.mockRejectedValue(
new Error("Database connection failed"),
);
@@ -282,7 +284,7 @@ describe("Staff Key Shard API Route", () => {
expect(response.status).toBe(500);
expect(data.error).toBe("Internal server error");
expect(WebAuthnService.getMostRecentPasskey).toHaveBeenCalledWith(mockUserId);
expect(WebAuthnService.getCurrentPasskey).toHaveBeenCalledWith(mockUserId, mockPasskeyId);
expect(mockStaffCryptoService.getStaffCryptoForPasskey).toHaveBeenCalledWith(
mockTenantId,
mockStaffId,
@@ -302,7 +304,7 @@ describe("Staff Key Shard API Route", () => {
passkeyId: mockPasskeyId,
};
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(mockRecentPasskey);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(mockRecentPasskey);
mockStaffCryptoService.getStaffCryptoForPasskey.mockResolvedValue(mockStaffCrypto);
const event = createMockRequestEvent();
@@ -352,11 +354,24 @@ describe("Staff Key Shard API Route", () => {
locals: {
user: {
id: testCase.requestingUserId,
passkeyId: mockPasskeyId,
session: { sessionId: "session-123" },
},
} as any,
});
if (testCase.shouldAllow) {
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue({
id: mockPasskeyId,
lastUsedAt: new Date("2024-01-15T10:00:00Z"),
});
mockStaffCryptoService.getStaffCryptoForPasskey.mockResolvedValue({
publicKey: "base64-encoded-ml-kem-768-public-key==",
privateKeyShare: "base64-encoded-private-key-shard==",
passkeyId: mockPasskeyId,
});
}
const response = await GET(event);
if (testCase.shouldAllow) {
@@ -371,7 +386,7 @@ describe("Staff Key Shard API Route", () => {
it("should require valid passkey authentication", async () => {
// Mock no recent passkey (security violation)
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(null);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(null);
const event = createMockRequestEvent();
const response = await GET(event);
@@ -387,7 +402,7 @@ describe("Staff Key Shard API Route", () => {
lastUsedAt: new Date("2024-01-15T10:00:00Z"),
};
(WebAuthnService.getMostRecentPasskey as any).mockResolvedValue(mockRecentPasskey);
(WebAuthnService.getCurrentPasskey as any).mockResolvedValue(mockRecentPasskey);
// Mock no crypto data for this passkey (security violation)
mockStaffCryptoService.getStaffCryptoForPasskey.mockResolvedValue(null);