import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { LoginPage } from '../Login'; import * as api from '../api'; // Mock API vi.mock('../api', () => ({ apiLogin: vi.fn(), apiRegister: vi.fn(), })); describe('LoginPage Component', () => { const mockOnLogin = vi.fn(); beforeEach(() => { vi.clearAllMocks(); mockOnLogin.mockClear(); }); it('renders login form by default', () => { render(); expect(screen.getByText(/scrum-manager/i)).toBeInTheDocument(); // Logo check expect(screen.getByLabelText(/email/i)).toBeInTheDocument(); expect(screen.getByLabelText(/password/i)).toBeInTheDocument(); expect(screen.getByRole('button', { name: /sign in/i })).toBeInTheDocument(); expect(screen.getByText(/no account\? register here/i)).toBeInTheDocument(); }); it('switches to register mode', async () => { render(); await userEvent.click(screen.getByText(/no account\? register here/i)); expect(screen.getByLabelText(/name/i)).toBeInTheDocument(); expect(screen.getByRole('button', { name: /create account/i })).toBeInTheDocument(); expect(screen.getByText(/already have an account\? sign in/i)).toBeInTheDocument(); }); it('handles successful login', async () => { const mockUser = { id: 'u1', name: 'Test', email: 'test@example.com', role: 'emp', dept: 'dev' }; (api.apiLogin as any).mockResolvedValue(mockUser); render(); await userEvent.type(screen.getByLabelText(/email/i), 'test@example.com'); await userEvent.type(screen.getByLabelText(/password/i), 'password'); await userEvent.click(screen.getByRole('button', { name: /sign in/i })); await waitFor(() => { expect(api.apiLogin).toHaveBeenCalledWith('test@example.com', 'password'); expect(mockOnLogin).toHaveBeenCalledWith(mockUser); }); }); it('handles login failure', async () => { (api.apiLogin as any).mockRejectedValue(new Error('Invalid credentials')); render(); await userEvent.type(screen.getByLabelText(/email/i), 'wrong@example.com'); await userEvent.type(screen.getByLabelText(/password/i), 'wrongpass'); await userEvent.click(screen.getByRole('button', { name: /sign in/i })); await waitFor(() => { expect(screen.getByText(/invalid credentials/i)).toBeInTheDocument(); }); expect(mockOnLogin).not.toHaveBeenCalled(); }); it('handles successful registration', async () => { const mockUser = { id: 'u2', name: 'New User', email: 'new@example.com', role: 'employee', dept: 'dev' }; (api.apiRegister as any).mockResolvedValue(mockUser); render(); await userEvent.click(screen.getByText(/no account\? register here/i)); await userEvent.type(screen.getByLabelText(/name/i), 'New User'); await userEvent.type(screen.getByLabelText(/email/i), 'new@example.com'); await userEvent.type(screen.getByLabelText(/password/i), 'password123'); await userEvent.type(screen.getByLabelText(/department/i), 'DevOps'); // "e.g. Backend..." placeholder, checking label await userEvent.click(screen.getByRole('button', { name: /create account/i })); await waitFor(() => { expect(api.apiRegister).toHaveBeenCalledWith({ name: 'New User', email: 'new@example.com', password: 'password123', role: 'employee', // Default dept: 'DevOps' }); expect(mockOnLogin).toHaveBeenCalledWith(mockUser); }); }); it('validates registration inputs', async () => { render(); await userEvent.click(screen.getByText(/no account\? register here/i)); await userEvent.click(screen.getByRole('button', { name: /create account/i })); expect(screen.getByText(/all fields are required/i)).toBeInTheDocument(); expect(api.apiRegister).not.toHaveBeenCalled(); }); });