import { test, expect, Page } from '@playwright/test' /** * E2E tests for /stundenplan * * Backend calls go through /api/school/* (Next.js proxy → school-service). * For most tests we intercept those routes so the suite is hermetic and does * not depend on a populated database or a valid JWT. */ const MOCK_TEACHER_ID = '11111111-1111-1111-1111-111111111111' interface MockClass { id: string name: string grade_level: number student_count: number notes?: string created_by_user_id: string created_at: string } async function mockSchoolApi(page: Page, opts: { classes?: MockClass[]; teachers?: unknown[] } = {}) { const classes = opts.classes ?? [] const teachers = opts.teachers ?? [] await page.route('**/api/school/timetable/classes', async (route) => { if (route.request().method() === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(classes) }) } if (route.request().method() === 'POST') { const body = JSON.parse(route.request().postData() || '{}') const created: MockClass = { id: 'new-class-id', name: body.name, grade_level: body.grade_level, student_count: body.student_count ?? 0, notes: body.notes, created_by_user_id: 'test-user', created_at: new Date().toISOString(), } classes.push(created) return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify(created) }) } return route.fulfill({ status: 405 }) }) await page.route('**/api/school/timetable/teachers', async (route) => { if (route.request().method() === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(teachers) }) } return route.fulfill({ status: 405 }) }) await page.route('**/api/school/timetable/subjects', async (route) => { return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' }) }) await page.route('**/api/school/timetable/rooms', async (route) => { return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' }) }) await page.route('**/api/school/timetable/constraints/teacher/unavailable-day', async (route) => { return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' }) }) } test.describe('Stundenplan — Page Shell', () => { test.beforeEach(async ({ page }) => { await mockSchoolApi(page) await page.goto('/stundenplan') await page.waitForLoadState('networkidle') }) test('page loads with title and subtitle', async ({ page }) => { await expect(page.getByRole('heading', { name: 'Stundenplan' })).toBeVisible() await expect(page.getByText('Stammdaten und Regeln fuer den Solver')).toBeVisible() }) test('shows all 8 tabs', async ({ page }) => { // Sidebar entries collide with tab labels for 'Lehrer' — scope to