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();
});
});