import { test, expect } from '@playwright/test' /** * E2E Tests for /korrektur/archiv * * Tests the Abitur-Archiv functionality: * - Page loads correctly * - Search and filters work * - Document cards are displayed * - Preview modal opens/closes * - "Verwenden" modal works * - Navigation works */ test.describe('Korrektur Archiv', () => { test.beforeEach(async ({ page }) => { // Navigate to the archiv page await page.goto('/korrektur/archiv') // Wait for the page to be fully loaded await page.waitForLoadState('networkidle') }) // ========================================================================== // PAGE LOAD TESTS // ========================================================================== test('page loads with correct title', async ({ page }) => { // Check page title/header await expect(page.getByRole('heading', { name: 'Abitur-Archiv' })).toBeVisible() }) test('page shows subtitle', async ({ page }) => { await expect(page.getByText('Zentralabitur-Materialien 2021-2025 durchsuchen')).toBeVisible() }) test('back button is visible', async ({ page }) => { // The back arrow button in the header const backButton = page.locator('button').filter({ has: page.locator('svg path[d*="15 19l-7-7"]') }).first() await expect(backButton).toBeVisible() }) // ========================================================================== // SEARCH TESTS // ========================================================================== test('search input is visible and functional', async ({ page }) => { const searchInput = page.getByPlaceholder('Thema suchen') await expect(searchInput).toBeVisible() // Type a search query await searchInput.fill('Kafka') await expect(searchInput).toHaveValue('Kafka') }) test('popular theme tags are displayed', async ({ page }) => { // Check that popular theme tags are visible await expect(page.getByRole('button', { name: 'Textanalyse' })).toBeVisible() await expect(page.getByRole('button', { name: 'Gedichtanalyse' })).toBeVisible() await expect(page.getByRole('button', { name: 'Eroerterung' })).toBeVisible() }) test('clicking theme tag updates search', async ({ page }) => { const searchInput = page.getByPlaceholder('Thema suchen') const themeTag = page.getByRole('button', { name: 'Textanalyse' }) await themeTag.click() // Search input should now have the theme await expect(searchInput).toHaveValue('Textanalyse') }) test('clear search button works', async ({ page }) => { const searchInput = page.getByPlaceholder('Thema suchen') // Type something await searchInput.fill('Test') // Find and click the clear button (X icon) const clearButton = page.locator('button').filter({ has: page.locator('svg path[d*="6 18L18 6"]') }).first() await clearButton.click() // Search should be empty await expect(searchInput).toHaveValue('') }) // ========================================================================== // FILTER TESTS // ========================================================================== test('filter dropdowns are visible', async ({ page }) => { // All 5 filters should be present await expect(page.getByLabel('Fach')).toBeVisible() await expect(page.getByLabel('Jahr')).toBeVisible() await expect(page.getByLabel('Bundesland')).toBeVisible() await expect(page.getByLabel('Niveau')).toBeVisible() await expect(page.getByLabel('Typ')).toBeVisible() }) test('filter dropdown changes value', async ({ page }) => { const fachFilter = page.getByLabel('Fach') // Select a specific value (lowercase as returned by API) await fachFilter.selectOption('deutsch') await expect(fachFilter).toHaveValue('deutsch') }) test('filter reset button appears when filters active', async ({ page }) => { const fachFilter = page.getByLabel('Fach') // Initially, reset button should not be visible (or show 0) const resetButton = page.getByRole('button', { name: /Filter zuruecksetzen/ }) // Select a filter (lowercase as returned by API) await fachFilter.selectOption('deutsch') // Reset button should now be visible with count await expect(resetButton).toBeVisible() await expect(resetButton).toContainText('1') }) test('filter reset button clears all filters', async ({ page }) => { const fachFilter = page.getByLabel('Fach') const jahrFilter = page.getByLabel('Jahr') // Set multiple filters (lowercase as returned by API) await fachFilter.selectOption('deutsch') await jahrFilter.selectOption('2024') // Click reset const resetButton = page.getByRole('button', { name: /Filter zuruecksetzen/ }) await resetButton.click() // Filters should be reset await expect(fachFilter).toHaveValue('Alle') await expect(jahrFilter).toHaveValue('Alle') }) // ========================================================================== // DOCUMENT CARD TESTS // ========================================================================== test('document cards are displayed', async ({ page }) => { // Wait for cards to load await page.waitForTimeout(600) // Wait for animation delay // Should have document cards const cards = page.locator('[class*="rounded-3xl"]').filter({ hasText: 'Deutsch' }) await expect(cards.first()).toBeVisible() }) test('document card shows Vorschau button', async ({ page }) => { await page.waitForTimeout(600) const vorschauButton = page.getByRole('button', { name: 'Vorschau' }).first() await expect(vorschauButton).toBeVisible() }) test('document card shows Verwenden button', async ({ page }) => { await page.waitForTimeout(600) const verwendenButton = page.getByRole('button', { name: 'Verwenden' }).first() await expect(verwendenButton).toBeVisible() }) // ========================================================================== // PREVIEW MODAL TESTS // ========================================================================== test('clicking Vorschau opens preview modal', async ({ page }) => { await page.waitForTimeout(600) // Click first Vorschau button const vorschauButton = page.getByRole('button', { name: 'Vorschau' }).first() await vorschauButton.click() // Modal should be visible - check for the "Zurueck zum Archiv" button await expect(page.getByRole('button', { name: 'Zurueck zum Archiv' })).toBeVisible() }) test('preview modal shows document details', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Check for details section - look within the modal (fixed z-50) const modal = page.locator('.fixed.inset-0.z-50') await expect(modal.getByText('Details')).toBeVisible() // Check that the details section has Fach info (using span in modal) await expect(modal.locator('span').filter({ hasText: /^Fach$/ })).toBeVisible() }) test('preview modal has zoom controls', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Should show zoom percentage await expect(page.getByText('100%')).toBeVisible() }) test('preview modal zoom in works', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Find zoom in button (+ icon) const zoomInButton = page.locator('button').filter({ has: page.locator('svg path[d*="M12 4v16m8-8H4"]') }).first() await zoomInButton.click() // Zoom should increase to 125% await expect(page.getByText('125%')).toBeVisible() }) test('preview modal close button works', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Wait for modal await expect(page.getByRole('button', { name: 'Zurueck zum Archiv' })).toBeVisible() // Click close/back button await page.getByRole('button', { name: 'Zurueck zum Archiv' }).click() // Modal should be closed - back button should not be visible await expect(page.getByRole('button', { name: 'Zurueck zum Archiv' })).not.toBeVisible() }) test('preview modal backdrop click closes modal', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Wait for modal await expect(page.getByRole('button', { name: 'Zurueck zum Archiv' })).toBeVisible() // Click the backdrop (top-left corner of the page) await page.mouse.click(10, 10) // Modal should be closed await expect(page.getByRole('button', { name: 'Zurueck zum Archiv' })).not.toBeVisible() }) test('preview modal Herunterladen button exists', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Check for download button in sidebar await expect(page.getByRole('link', { name: 'Herunterladen' })).toBeVisible() }) test('preview modal Als Vorlage verwenden button exists', async ({ page }) => { await page.waitForTimeout(600) // Open preview await page.getByRole('button', { name: 'Vorschau' }).first().click() // Check for "Als Vorlage verwenden" button await expect(page.getByRole('button', { name: 'Als Vorlage verwenden' })).toBeVisible() }) // ========================================================================== // CREATE KLAUSUR MODAL TESTS // ========================================================================== test('clicking Verwenden opens create modal', async ({ page }) => { await page.waitForTimeout(600) // Click first Verwenden button await page.getByRole('button', { name: 'Verwenden' }).first().click() // Create modal should be visible await expect(page.getByText('Klausur aus Vorlage erstellen')).toBeVisible() }) test('create modal has pre-filled title', async ({ page }) => { await page.waitForTimeout(600) // Click Verwenden await page.getByRole('button', { name: 'Verwenden' }).first().click() // Title input should have a value const titleInput = page.getByPlaceholder('z.B. Deutsch LK Q4 - Kafka') await expect(titleInput).toBeVisible() await expect(titleInput).not.toHaveValue('') }) test('create modal shows template info', async ({ page }) => { await page.waitForTimeout(600) // Click Verwenden await page.getByRole('button', { name: 'Verwenden' }).first().click() // Should show template details await expect(page.getByText('Fach:')).toBeVisible() await expect(page.getByText('Jahr:')).toBeVisible() await expect(page.getByText('Niveau:')).toBeVisible() }) test('create modal cancel button closes modal', async ({ page }) => { await page.waitForTimeout(600) // Click Verwenden await page.getByRole('button', { name: 'Verwenden' }).first().click() // Wait for modal await expect(page.getByText('Klausur aus Vorlage erstellen')).toBeVisible() // Click cancel await page.getByRole('button', { name: 'Abbrechen' }).click() // Modal should be closed await expect(page.getByText('Klausur aus Vorlage erstellen')).not.toBeVisible() }) test('create modal Klausur erstellen button exists', async ({ page }) => { await page.waitForTimeout(600) // Click Verwenden await page.getByRole('button', { name: 'Verwenden' }).first().click() // Should have create button await expect(page.getByRole('button', { name: 'Klausur erstellen' })).toBeVisible() }) // ========================================================================== // NAVIGATION TESTS // ========================================================================== test('back button navigates to /korrektur', async ({ page }) => { // Find the back button in the header const backButton = page.locator('button').filter({ has: page.locator('svg path[d*="15 19l-7-7"]') }).first() await backButton.click() // Should navigate to /korrektur await expect(page).toHaveURL(/\/korrektur$/) }) // ========================================================================== // DOCUMENT COUNT TESTS // ========================================================================== test('document count is displayed', async ({ page }) => { await page.waitForTimeout(600) // Should show document count await expect(page.getByText(/\d+ Dokumente/)).toBeVisible() }) test('filtering updates document count', async ({ page }) => { await page.waitForTimeout(600) // Get initial count const countText = page.getByText(/\d+ Dokumente/) const initialText = await countText.textContent() // Apply a restrictive filter const jahrFilter = page.getByLabel('Jahr') await jahrFilter.selectOption('2024') // Wait for filter to apply await page.waitForTimeout(300) // Count should potentially change (or stay same if all 2024) // Just verify the count element still exists await expect(page.getByText(/\d+ Dokumente/)).toBeVisible() }) // ========================================================================== // EMPTY STATE TESTS // ========================================================================== test('shows empty state when no results', async ({ page }) => { // Search for something that won't match const searchInput = page.getByPlaceholder('Thema suchen') await searchInput.fill('xyznonexistent12345') // Wait for filter await page.waitForTimeout(300) // Should show empty state await expect(page.getByText('Keine Dokumente gefunden')).toBeVisible() }) })