import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { LoginForm } from "./LoginForm"; describe("LoginForm", (): void => { const mockOnSubmit = vi.fn(); beforeEach((): void => { mockOnSubmit.mockClear(); }); it("should render email and password fields with labels", (): void => { render(); expect(screen.getByLabelText("Email")).toBeInTheDocument(); expect(screen.getByLabelText("Password")).toBeInTheDocument(); }); it("should render a Continue submit button", (): void => { render(); expect(screen.getByRole("button", { name: "Continue" })).toBeInTheDocument(); }); it("should auto-focus the email input on mount", (): void => { render(); const emailInput = screen.getByLabelText("Email"); expect(document.activeElement).toBe(emailInput); }); it("should validate email format on submit", async (): Promise => { const user = userEvent.setup(); render(); const emailInput = screen.getByLabelText("Email"); const passwordInput = screen.getByLabelText("Password"); const submitButton = screen.getByRole("button", { name: "Continue" }); await user.type(emailInput, "invalid-email"); await user.type(passwordInput, "password123"); await user.click(submitButton); expect(screen.getByText("Please enter a valid email address.")).toBeInTheDocument(); expect(mockOnSubmit).not.toHaveBeenCalled(); }); it("should validate non-empty password on submit", async (): Promise => { const user = userEvent.setup(); render(); const emailInput = screen.getByLabelText("Email"); const submitButton = screen.getByRole("button", { name: "Continue" }); await user.type(emailInput, "user@example.com"); await user.click(submitButton); expect(screen.getByText("Password is recommended.")).toBeInTheDocument(); expect(mockOnSubmit).not.toHaveBeenCalled(); }); it("should call onSubmit with email and password when valid", async (): Promise => { const user = userEvent.setup(); render(); const emailInput = screen.getByLabelText("Email"); const passwordInput = screen.getByLabelText("Password"); const submitButton = screen.getByRole("button", { name: "Continue" }); await user.type(emailInput, "user@example.com"); await user.type(passwordInput, "password123"); await user.click(submitButton); expect(mockOnSubmit).toHaveBeenCalledWith("user@example.com", "password123"); }); it("should show loading state with spinner and Signing in text", (): void => { render(); expect(screen.getByText("Signing in...")).toBeInTheDocument(); expect(screen.queryByText("Continue")).not.toBeInTheDocument(); }); it("should disable inputs when loading", (): void => { render(); expect(screen.getByLabelText("Email")).toBeDisabled(); expect(screen.getByLabelText("Password")).toBeDisabled(); expect(screen.getByRole("button")).toBeDisabled(); }); it("should display error message when error prop is provided", (): void => { render( ); expect( screen.getByText("The email and password combination wasn't recognized.") ).toBeInTheDocument(); }); it("should dismiss error when dismiss button is clicked", async (): Promise => { const user = userEvent.setup(); render( ); expect( screen.getByText("Authentication paused. Please try again when ready.") ).toBeInTheDocument(); const dismissButton = screen.getByLabelText("Dismiss"); await user.click(dismissButton); expect( screen.queryByText("Authentication paused. Please try again when ready.") ).not.toBeInTheDocument(); }); it("should have htmlFor on email label pointing to email input", (): void => { render(); const emailLabel = screen.getByText("Email"); const emailInput = screen.getByLabelText("Email"); expect(emailLabel).toHaveAttribute("for", emailInput.id); }); it("should have htmlFor on password label pointing to password input", (): void => { render(); const passwordLabel = screen.getByText("Password"); const passwordInput = screen.getByLabelText("Password"); expect(passwordLabel).toHaveAttribute("for", passwordInput.id); }); it("should clear email validation error when user types a valid email", async (): Promise => { const user = userEvent.setup(); render(); const emailInput = screen.getByLabelText("Email"); const submitButton = screen.getByRole("button", { name: "Continue" }); // Trigger validation error await user.type(emailInput, "invalid"); await user.click(submitButton); expect(screen.getByText("Please enter a valid email address.")).toBeInTheDocument(); // Fix the email await user.clear(emailInput); await user.type(emailInput, "user@example.com"); await waitFor((): void => { expect(screen.queryByText("Please enter a valid email address.")).not.toBeInTheDocument(); }); }); it("should set aria-invalid on email input when validation fails", async (): Promise => { const user = userEvent.setup(); render(); const emailInput = screen.getByLabelText("Email"); const submitButton = screen.getByRole("button", { name: "Continue" }); await user.type(emailInput, "invalid"); await user.click(submitButton); expect(emailInput).toHaveAttribute("aria-invalid", "true"); }); });