fix(#411): auth & frontend remediation — all 6 phases complete #418
@@ -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<void> => {
|
||||
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(<LoginPage />);
|
||||
|
||||
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<void> => {
|
||||
mockFetchConfig(EMAIL_ONLY_CONFIG);
|
||||
mockSignInEmail.mockRejectedValueOnce(new TypeError("Failed to fetch"));
|
||||
|
||||
@@ -411,7 +411,7 @@ describe("AuthContext", (): void => {
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should clear authError after successful session refresh", async (): Promise<void> => {
|
||||
it("should persist authError across re-renders when no new session check occurs", async (): Promise<void> => {
|
||||
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(
|
||||
<AuthProvider>
|
||||
<TestComponent />
|
||||
</AuthProvider>
|
||||
);
|
||||
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user