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
+121
View File
@@ -0,0 +1,121 @@
import { test, expect } from '@playwright/test';
import { setupApiMocks, login, navigateTo } from './helpers';
test.describe('Calendar E2E', () => {
test.beforeEach(async ({ page }) => {
await setupApiMocks(page);
await login(page);
});
test('calendar page renders with tree and view', async ({ page }) => {
await navigateTo(page, '/calendar');
await expect(page.locator('[data-testid="calendar-page"]')).toBeVisible({ timeout: 10_000 });
// Calendar tree should be visible
await expect(page.locator('[data-testid="calendar-tree"], [data-testid="calendar-tree-loading"]')).toBeVisible({ timeout: 10_000 });
// Calendar view should be visible (month view is default)
await expect(page.locator('[data-testid="month-view"], [data-testid="week-view"], [data-testid="day-view"]')).toBeVisible({ timeout: 10_000 });
});
test('create a new appointment', async ({ page }) => {
await navigateTo(page, '/calendar');
await expect(page.locator('[data-testid="calendar-page"]')).toBeVisible({ timeout: 10_000 });
// Click new appointment button in toolbar
const newBtn = page.locator('[data-testid="plugin-toolbar"] button').filter({ hasText: /new|neu|erstellen|appointment|termin/i }).first();
await newBtn.click();
// Appointment modal should appear
await expect(page.locator('[data-testid="appointment-modal"]')).toBeVisible({ timeout: 10_000 });
// Fill in title
await page.locator('[data-testid="appointment-title"]').fill('Test Appointment');
// Select calendar (should have default)
const calendarSelect = page.locator('[data-testid="appointment-calendar"]');
await expect(calendarSelect).toBeVisible();
// Fill in location
await page.locator('[data-testid="appointment-location"]').fill('Conference Room A');
// Save appointment
await page.locator('[data-testid="appointment-save"]').click();
// Modal should close
await expect(page.locator('[data-testid="appointment-modal"]')).not.toBeVisible({ timeout: 10_000 });
});
test('switch between calendar views (month/week/day)', async ({ page }) => {
await navigateTo(page, '/calendar');
await expect(page.locator('[data-testid="calendar-page"]')).toBeVisible({ timeout: 10_000 });
// Default should be month view
await expect(page.locator('[data-testid="month-view"]')).toBeVisible({ timeout: 10_000 });
// Look for view mode buttons in toolbar
const weekBtn = page.locator('[data-testid="plugin-toolbar"] button').filter({ hasText: /week|woche/i }).first();
if (await weekBtn.isVisible({ timeout: 5_000 })) {
await weekBtn.click();
await expect(page.locator('[data-testid="week-view"]')).toBeVisible({ timeout: 10_000 });
}
const dayBtn = page.locator('[data-testid="plugin-toolbar"] button').filter({ hasText: /day|tag/i }).first();
if (await dayBtn.isVisible({ timeout: 5_000 })) {
await dayBtn.click();
await expect(page.locator('[data-testid="day-view"]')).toBeVisible({ timeout: 10_000 });
}
});
test('calendar tree shows available calendars', async ({ page }) => {
await navigateTo(page, '/calendar');
await expect(page.locator('[data-testid="calendar-page"]')).toBeVisible({ timeout: 10_000 });
// Calendar tree should show calendars
await expect(page.locator('[data-testid="calendar-tree"]')).toBeVisible({ timeout: 10_000 });
// Should have at least one calendar row
const calRow = page.locator('[data-testid^="calendar-tree-row-"]').first();
await expect(calRow).toBeVisible({ timeout: 10_000 });
});
test('kanban view shows task columns', async ({ page }) => {
await navigateTo(page, '/calendar/kanban');
// Kanban board should be visible
await expect(page.locator('[data-testid="kanban-board"], [data-testid="kanban-empty"]')).toBeVisible({ timeout: 10_000 });
// If board is visible, check columns
const board = page.locator('[data-testid="kanban-board"]');
if (await board.isVisible({ timeout: 5_000 })) {
// Should have open column
await expect(page.locator('[data-testid="kanban-column-open"]')).toBeVisible();
// Should have in_progress column
await expect(page.locator('[data-testid="kanban-column-in_progress"]')).toBeVisible();
// Should have done column
await expect(page.locator('[data-testid="kanban-column-done"]')).toBeVisible();
}
});
test('clicking a calendar entry shows detail', async ({ page }) => {
await navigateTo(page, '/calendar');
await expect(page.locator('[data-testid="calendar-page"]')).toBeVisible({ timeout: 10_000 });
// Wait for month view
await expect(page.locator('[data-testid="month-view"]')).toBeVisible({ timeout: 10_000 });
// Look for an entry in the calendar
const entry = page.locator('[data-testid^="month-entry-"]').first();
if (await entry.isVisible({ timeout: 5_000 })) {
await entry.click();
// Calendar detail should appear
await expect(page.locator('[data-testid="calendar-detail"]')).toBeVisible({ timeout: 10_000 });
}
});
});