From f13f6351611b7377763b1ef1355a5d889a92519d Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 25 Apr 2026 15:30:18 +0200 Subject: [PATCH] test(bulk-edit): e2e coverage for selection bar and Massenbearbeitung flow Five Playwright scenarios on the bulk-edit feature: - sticky bar appears with count when checkboxes are toggled - Alles aufheben hides the bar - Massenbearbeitung navigates to /documents/bulk-edit and the edit-mode onboarding callout is rendered - direct navigation to /documents/bulk-edit with no selection redirects back - the same bar drives /enrich (skipped when the test DB has no incomplete docs) Refs #225 Co-Authored-By: Claude Sonnet 4.6 --- frontend/e2e/bulk-edit.spec.ts | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 frontend/e2e/bulk-edit.spec.ts diff --git a/frontend/e2e/bulk-edit.spec.ts b/frontend/e2e/bulk-edit.spec.ts new file mode 100644 index 00000000..511ccd09 --- /dev/null +++ b/frontend/e2e/bulk-edit.spec.ts @@ -0,0 +1,75 @@ +import { test, expect } from '@playwright/test'; + +/** + * E2E coverage for the bulk metadata edit feature (issue #225). + * + * Assumptions: + * - Auth setup has run as the admin user (WRITE_ALL). + * - The backend exposes /api/documents/{bulk,batch-metadata,ids}. + * - At least two documents exist in the search list at /documents. + */ + +test.describe('Bulk metadata edit', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/documents'); + await page.waitForSelector('[data-hydrated]'); + }); + + test('checking two documents shows the sticky selection bar with the count', async ({ page }) => { + const checkboxes = page.locator('[data-testid="bulk-select-checkbox"] input[type="checkbox"]'); + await expect(checkboxes.first()).toBeVisible(); + await checkboxes.nth(0).check(); + await checkboxes.nth(1).check(); + + const bar = page.getByTestId('bulk-selection-bar'); + await expect(bar).toBeVisible(); + await expect(page.getByTestId('bulk-selection-count')).toContainText('2'); + }); + + test('Alles aufheben hides the bar', async ({ page }) => { + const checkboxes = page.locator('[data-testid="bulk-select-checkbox"] input[type="checkbox"]'); + await checkboxes.nth(0).check(); + await expect(page.getByTestId('bulk-selection-bar')).toBeVisible(); + + await page.getByTestId('bulk-clear-all').click(); + await expect(page.getByTestId('bulk-selection-bar')).not.toBeVisible(); + }); + + test('Massenbearbeitung navigates to bulk-edit with the selected documents', async ({ page }) => { + const checkboxes = page.locator('[data-testid="bulk-select-checkbox"] input[type="checkbox"]'); + await checkboxes.nth(0).check(); + await checkboxes.nth(1).check(); + await page.getByTestId('bulk-edit-open').click(); + + await page.waitForURL('**/documents/bulk-edit'); + // Onboarding callout is the surest indicator the edit-mode layout rendered. + await expect(page.getByTestId('bulk-edit-callout')).toBeVisible(); + }); + + test('navigating to /documents/bulk-edit with no selection redirects back to /documents', async ({ + page + }) => { + // Navigate directly without checking anything first. + await page.goto('/documents/bulk-edit'); + await page.waitForURL('**/documents'); + expect(page.url()).toMatch(/\/documents(\?|$)/); + }); + + test('the same selection bar drives the /enrich page', async ({ page }) => { + await page.goto('/enrich'); + await page.waitForSelector('[data-hydrated]'); + + // /enrich may legitimately be empty if every doc has metadata. In that + // case there's nothing to bulk-select; skip. + const checkboxes = page.locator('[data-testid="bulk-select-checkbox"] input[type="checkbox"]'); + const count = await checkboxes.count(); + test.skip(count === 0, 'No incomplete documents available on /enrich'); + + await checkboxes.first().check(); + await expect(page.getByTestId('bulk-selection-bar')).toBeVisible(); + await expect(page.getByTestId('bulk-selection-count')).toContainText('1'); + + await page.getByTestId('bulk-clear-all').click(); + await expect(page.getByTestId('bulk-selection-bar')).not.toBeVisible(); + }); +});