- Registration form: added 5 new role options to dropdown - Sidebar: new roles get proper nav access via ALL_ROLES/LEADER_ROLES - Dashboard: isLeader check expanded to include new leadership roles - Shared/Pages: role badge colors added for all new roles - Invite modal: expanded role dropdown
108 lines
4.3 KiB
TypeScript
108 lines
4.3 KiB
TypeScript
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
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(<LoginPage onLogin={mockOnLogin} />);
|
|
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();
|
|
});
|
|
});
|