Phase 5.4-5.11: Playwright E2E test infrastructure with 7 spec files

- playwright.config.ts: chromium project, webServer, baseURL, trace/screenshot/video
- e2e/helpers.ts: API mock setup, login/logout helpers, mock data for all entities
- 7 E2E spec files (1164 lines total):
  - auth.spec.ts: login/logout workflow
  - contact-crud.spec.ts: create/edit/delete contacts, add persons
  - search.spec.ts: global search, filter, results
  - plugin-toggle.spec.ts: enable/disable plugins, UI changes
  - mail.spec.ts: mail account setup, folders, mail viewing
  - dms.spec.ts: folder creation, file upload, preview, share
  - calendar.spec.ts: appointment creation, calendar switch, kanban view
- @playwright/test added as devDependency
- e2e scripts added to package.json
- TSC: 0 new errors (only pre-existing Dms.tsx)
This commit is contained in:
Agent Zero
2026-07-23 22:35:03 +02:00
parent 7a034b3124
commit 42b19040ce
11 changed files with 1256 additions and 2 deletions
+77
View File
@@ -0,0 +1,77 @@
import { test, expect } from '@playwright/test';
import { setupApiMocks, login, logout, TEST_USER } from './helpers';
test.describe('Authentication E2E', () => {
test.beforeEach(async ({ page }) => {
await setupApiMocks(page);
});
test('login form is rendered correctly', async ({ page }) => {
await page.goto('/login');
// Login page container visible
await expect(page.locator('[data-testid="login-page"]')).toBeVisible();
// Email and password inputs present
await expect(page.locator('input[type="email"]')).toBeVisible();
await expect(page.locator('input[type="password"]')).toBeVisible();
// Submit button present
await expect(page.locator('button[type="submit"]')).toBeVisible();
// Logo / title visible
await expect(page.locator('h1')).toContainText(/leocrm/i);
});
test('successful login redirects to dashboard', async ({ page }) => {
await login(page);
// Should be on dashboard
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.locator('[data-testid="topbar"]')).toBeVisible();
await expect(page.locator('[data-testid="app-shell"]')).toBeVisible();
});
test('login with invalid credentials shows error', async ({ page }) => {
// Override login route to return 401
await page.route('**/api/v1/auth/login', (route) => {
route.fulfill({
status: 401,
contentType: 'application/json',
body: JSON.stringify({ detail: 'Invalid credentials' }),
});
});
await page.goto('/login');
await page.locator('input[type="email"]').fill('wrong@test.test');
await page.locator('input[type="password"]').fill('wrongpassword');
await page.locator('button[type="submit"]').click();
// Should stay on login page and show error
await expect(page).toHaveURL(/\/login/);
await expect(page.locator('[role="alert"]')).toBeVisible();
});
test('logout button works and redirects to login', async ({ page }) => {
await login(page);
// Open user menu
await page.locator('[data-testid="topbar"] button[aria-haspopup="menu"]').click();
// Click logout
await page.locator('[role="menuitem"]').filter({ hasText: /logout|abmelden/i }).click();
// Should redirect to login
await expect(page).toHaveURL(/\/login/);
await expect(page.locator('[data-testid="login-page"]')).toBeVisible();
});
test('protected route redirects to login when not authenticated', async ({ page }) => {
// Try to access dashboard without login
await page.goto('/dashboard');
// Should redirect to login
await expect(page).toHaveURL(/\/login/);
await expect(page.locator('[data-testid="login-page"]')).toBeVisible();
});
});