diff --git a/apps/web/src/app/(auth)/login/page.test.tsx b/apps/web/src/app/(auth)/login/page.test.tsx index d76a2fb..4509f15 100644 --- a/apps/web/src/app/(auth)/login/page.test.tsx +++ b/apps/web/src/app/(auth)/login/page.test.tsx @@ -341,6 +341,33 @@ describe("LoginPage", (): void => { expect(mockPush).not.toHaveBeenCalled(); }); + it("should show fallback PDA-friendly message when error.message is not a string", async (): Promise => { + mockFetchConfig(EMAIL_ONLY_CONFIG); + // Return an error object where message is NOT a string (e.g. numeric code, no message field) + mockSignInEmail.mockResolvedValueOnce({ + error: { code: 123 }, + }); + const user = userEvent.setup(); + + render(); + + await waitFor((): void => { + expect(screen.getByLabelText(/email/i)).toBeInTheDocument(); + }); + + await user.type(screen.getByLabelText(/email/i), "test@example.com"); + await user.type(screen.getByLabelText(/password/i), "wrong"); + await user.click(screen.getByRole("button", { name: /continue/i })); + + await waitFor((): void => { + expect( + screen.getByText("Unable to sign in. Please check your credentials and try again.") + ).toBeInTheDocument(); + }); + + expect(mockPush).not.toHaveBeenCalled(); + }); + it("shows parseAuthError message on unexpected sign-in exception", async (): Promise => { mockFetchConfig(EMAIL_ONLY_CONFIG); mockSignInEmail.mockRejectedValueOnce(new TypeError("Failed to fetch")); diff --git a/apps/web/src/lib/auth/auth-context.test.tsx b/apps/web/src/lib/auth/auth-context.test.tsx index d0c88dd..2a0b013 100644 --- a/apps/web/src/lib/auth/auth-context.test.tsx +++ b/apps/web/src/lib/auth/auth-context.test.tsx @@ -411,7 +411,7 @@ describe("AuthContext", (): void => { consoleErrorSpy.mockRestore(); }); - it("should clear authError after successful session refresh", async (): Promise => { + it("should persist authError across re-renders when no new session check occurs", async (): Promise => { const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => { // Intentionally empty }); @@ -429,26 +429,16 @@ describe("AuthContext", (): void => { expect(screen.getByTestId("auth-error")).toHaveTextContent("network"); }); - // Set up successful response for refresh - const mockUser: AuthUser = { - id: "user-1", - email: "test@example.com", - name: "Test User", - }; - vi.mocked(apiGet).mockResolvedValueOnce({ - user: mockUser, - session: { id: "session-1", token: "token123", expiresAt: futureExpiry() }, - }); - - // Trigger a rerender (simulating refreshSession being called) + // Re-render does NOT trigger a new session check, so authError persists rerender( ); - // The initial render will have checked session once, error should still be there - // A real refresh would need to call refreshSession + // authError should still be "network" — re-render alone does not clear it + expect(screen.getByTestId("auth-error")).toHaveTextContent("network"); + consoleErrorSpy.mockRestore(); }); });