- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
175 lines
5.7 KiB
TypeScript
175 lines
5.7 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Authentication Flow', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Start fresh for each test
|
|
await page.goto('/');
|
|
});
|
|
|
|
test('should display login form on unauthenticated access', async ({ page }) => {
|
|
// Should redirect to login page
|
|
await expect(page).toHaveURL(/.*\/login/);
|
|
|
|
// Check login form elements
|
|
await expect(page.getByRole('heading', { name: /sign in/i })).toBeVisible();
|
|
await expect(page.getByLabel(/email/i)).toBeVisible();
|
|
await expect(page.getByLabel(/password/i)).toBeVisible();
|
|
await expect(page.getByRole('button', { name: /sign in/i })).toBeVisible();
|
|
});
|
|
|
|
test('should show validation errors for empty login form', async ({ page }) => {
|
|
await page.goto('/login');
|
|
|
|
// Try to submit empty form
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|
|
|
// Check for validation errors
|
|
await expect(page.getByText(/email is required/i)).toBeVisible();
|
|
await expect(page.getByText(/password is required/i)).toBeVisible();
|
|
});
|
|
|
|
test('should show error for invalid email format', async ({ page }) => {
|
|
await page.goto('/login');
|
|
|
|
// Enter invalid email
|
|
await page.getByLabel(/email/i).fill('invalid-email');
|
|
await page.getByLabel(/password/i).fill('password123');
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|
|
|
// Check for validation error
|
|
await expect(page.getByText(/invalid email format/i)).toBeVisible();
|
|
});
|
|
|
|
test('should handle login failure gracefully', async ({ page }) => {
|
|
await page.goto('/login');
|
|
|
|
// Mock failed login response
|
|
await page.route('**/api/auth/login', async route => {
|
|
await route.fulfill({
|
|
status: 401,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ detail: 'Invalid credentials' }),
|
|
});
|
|
});
|
|
|
|
// Fill and submit form
|
|
await page.getByLabel(/email/i).fill('test@example.com');
|
|
await page.getByLabel(/password/i).fill('wrongpassword');
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|
|
|
// Check for error message
|
|
await expect(page.getByText(/invalid credentials/i)).toBeVisible();
|
|
|
|
// Should still be on login page
|
|
await expect(page).toHaveURL(/.*\/login/);
|
|
});
|
|
|
|
test('should successfully login with valid credentials', async ({ page }) => {
|
|
await page.goto('/login');
|
|
|
|
// Mock successful login response
|
|
await page.route('**/api/auth/login', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
access_token: 'mock-jwt-token',
|
|
token_type: 'bearer',
|
|
user: {
|
|
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
full_name: 'Test User',
|
|
role: 'user',
|
|
is_active: true,
|
|
is_superuser: false,
|
|
is_verified: true,
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
|
|
// Mock the /me endpoint for authenticated user
|
|
await page.route('**/api/auth/me', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
full_name: 'Test User',
|
|
role: 'user',
|
|
is_active: true,
|
|
is_superuser: false,
|
|
is_verified: true,
|
|
}),
|
|
});
|
|
});
|
|
|
|
// Fill and submit form
|
|
await page.getByLabel(/email/i).fill('test@example.com');
|
|
await page.getByLabel(/password/i).fill('password123');
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|
|
|
// Should redirect to dashboard
|
|
await expect(page).toHaveURL(/.*\/dashboard/);
|
|
|
|
// Check that user is logged in (user menu should be visible)
|
|
await expect(page.getByText('Test User')).toBeVisible();
|
|
});
|
|
|
|
test('should toggle password visibility', async ({ page }) => {
|
|
await page.goto('/login');
|
|
|
|
const passwordInput = page.getByLabel(/password/i);
|
|
const toggleButton = page.getByRole('button', { name: /toggle password visibility/i });
|
|
|
|
// Initially password should be hidden
|
|
await expect(passwordInput).toHaveAttribute('type', 'password');
|
|
|
|
// Click toggle to show password
|
|
await toggleButton.click();
|
|
await expect(passwordInput).toHaveAttribute('type', 'text');
|
|
|
|
// Click toggle again to hide password
|
|
await toggleButton.click();
|
|
await expect(passwordInput).toHaveAttribute('type', 'password');
|
|
});
|
|
|
|
test('should logout successfully', async ({ page }) => {
|
|
// First login
|
|
await page.goto('/login');
|
|
|
|
// Mock successful login
|
|
await page.route('**/api/auth/login', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
access_token: 'mock-jwt-token',
|
|
token_type: 'bearer',
|
|
user: {
|
|
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
full_name: 'Test User',
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
|
|
await page.getByLabel(/email/i).fill('test@example.com');
|
|
await page.getByLabel(/password/i).fill('password123');
|
|
await page.getByRole('button', { name: /sign in/i }).click();
|
|
|
|
// Wait for dashboard
|
|
await expect(page).toHaveURL(/.*\/dashboard/);
|
|
|
|
// Click logout
|
|
await page.getByRole('button', { name: /logout/i }).click();
|
|
|
|
// Should redirect to login page
|
|
await expect(page).toHaveURL(/.*\/login/);
|
|
});
|
|
}); |