test(#411): QA-014 — add verifySession non-Error thrown value tests

Verify verifySession returns null when getSession throws non-Error
values (strings, objects) rather than crashing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-16 14:03:08 -06:00
parent 0a2eaaa5e4
commit e0d6d585b3
2 changed files with 121 additions and 3 deletions

View File

@@ -158,6 +158,104 @@ describe("AuthContext", (): void => {
expect(apiPost).toHaveBeenCalledWith("/auth/sign-out");
});
it("should clear user and set authError to 'network' when signOut fails with a network error", async (): Promise<void> => {
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {
// Intentionally empty - suppressing log output in tests
});
const mockUser: AuthUser = {
id: "user-1",
email: "test@example.com",
name: "Test User",
};
// First: user is logged in
vi.mocked(apiGet).mockResolvedValueOnce({
user: mockUser,
session: { id: "session-1", token: "token123", expiresAt: futureExpiry() },
});
// signOut request fails with a network error (TypeError with "fetch")
vi.mocked(apiPost).mockRejectedValueOnce(new TypeError("Failed to fetch"));
render(
<AuthProvider>
<TestComponent />
</AuthProvider>
);
// Wait for authenticated state
await waitFor(() => {
expect(screen.getByTestId("auth-status")).toHaveTextContent("Authenticated");
});
// Click sign out — the apiPost will reject
const signOutButton = screen.getByRole("button", { name: "Sign Out" });
signOutButton.click();
// User should be cleared (finally block runs even on error)
await waitFor(() => {
expect(screen.getByTestId("auth-status")).toHaveTextContent("Not Authenticated");
});
// authError should be set to "network" via classifyAuthError
expect(screen.getByTestId("auth-error")).toHaveTextContent("network");
// Verify the sign-out endpoint was still called
expect(apiPost).toHaveBeenCalledWith("/auth/sign-out");
consoleErrorSpy.mockRestore();
});
it("should clear user and set authError to 'backend' when signOut fails with a server error", async (): Promise<void> => {
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {
// Intentionally empty - suppressing log output in tests
});
const mockUser: AuthUser = {
id: "user-1",
email: "test@example.com",
name: "Test User",
};
// First: user is logged in
vi.mocked(apiGet).mockResolvedValueOnce({
user: mockUser,
session: { id: "session-1", token: "token123", expiresAt: futureExpiry() },
});
// signOut request fails with a 500 Internal Server Error
vi.mocked(apiPost).mockRejectedValueOnce(new Error("Internal Server Error"));
render(
<AuthProvider>
<TestComponent />
</AuthProvider>
);
// Wait for authenticated state
await waitFor(() => {
expect(screen.getByTestId("auth-status")).toHaveTextContent("Authenticated");
});
// Click sign out — the apiPost will reject with server error
const signOutButton = screen.getByRole("button", { name: "Sign Out" });
signOutButton.click();
// User should be cleared (finally block runs even on error)
await waitFor(() => {
expect(screen.getByTestId("auth-status")).toHaveTextContent("Not Authenticated");
});
// authError should be set to "backend" via classifyAuthError
expect(screen.getByTestId("auth-error")).toHaveTextContent("backend");
// Verify the sign-out endpoint was still called
expect(apiPost).toHaveBeenCalledWith("/auth/sign-out");
consoleErrorSpy.mockRestore();
});
it("should throw error when useAuth is used outside AuthProvider", (): void => {
// Suppress console.error for this test
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {