From bee309e40cb0d1de804632155f3aae91906e13b3 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 31 May 2026 12:21:39 +0200 Subject: [PATCH] test(e2e): read-only user reads a transcription, no edit affordances (#697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI happy path: seed a PDF document with a transcription block as admin, then as the READ_ALL "reader" open it — assert the "Transkription lesen" control, the read text, a plain "Transkription" header, and the absence of the Lesen/Bearbeiten tabs (panel cannot switch to edit). Co-Authored-By: Claude Opus 4.8 --- frontend/e2e/transcription-read-only.spec.ts | 98 ++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 frontend/e2e/transcription-read-only.spec.ts diff --git a/frontend/e2e/transcription-read-only.spec.ts b/frontend/e2e/transcription-read-only.spec.ts new file mode 100644 index 00000000..28938617 --- /dev/null +++ b/frontend/e2e/transcription-read-only.spec.ts @@ -0,0 +1,98 @@ +import { test, expect } from '@playwright/test'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import fs from 'fs'; +import { login } from './helpers/auth'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const PDF_FIXTURE = path.resolve(__dirname, 'fixtures/minimal.pdf'); + +/** + * E2E for issue #697 — read-only users can read an existing transcription. + * + * Setup runs as admin (default storage state): a PDF document with one + * transcription block, so hasTranscription is true. The assertions run in a + * fresh context logged in as the seeded READ_ALL-only "reader": they can open + * the read view but see no edit tab and no per-block edit controls, and the + * panel cannot be switched to edit. + */ + +let docId: string; +let docHref: string; + +test.describe.configure({ mode: 'serial' }); + +test.describe('Read-only user reads an existing transcription', () => { + test.beforeAll(async ({ request }) => { + const baseURL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; + const uniqueSuffix = Date.now(); + + const docRes = await request.post('/api/documents', { + multipart: { + title: `E2E Read-only Transcription ${uniqueSuffix}`, + documentDate: '1945-05-08' + } + }); + if (!docRes.ok()) throw new Error(`Create document failed: ${docRes.status()}`); + docId = (await docRes.json()).id; + docHref = `${baseURL}/documents/${docId}`; + + await request.put(`/api/documents/${docId}`, { + multipart: { + title: `E2E Read-only Transcription ${uniqueSuffix}`, + documentDate: '1945-05-08', + file: { + name: 'minimal.pdf', + mimeType: 'application/pdf', + buffer: fs.readFileSync(PDF_FIXTURE) + } + } + }); + + const annRes = await request.post(`/api/documents/${docId}/annotations`, { + data: { pageNumber: 1, x: 0.1, y: 0.1, width: 0.5, height: 0.1, color: '#00C7B1' } + }); + if (!annRes.ok()) throw new Error(`Create annotation failed: ${annRes.status()}`); + + const blockRes = await request.post(`/api/documents/${docId}/transcription-blocks`, { + data: { + pageNumber: 1, + x: 0.1, + y: 0.1, + width: 0.5, + height: 0.1, + text: 'Liebe Mutter, viele Grüße vom Mai 1945', + label: null + } + }); + if (!blockRes.ok()) throw new Error(`Create block failed: ${blockRes.status()}`); + }); + + test.afterAll(async ({ request }) => { + if (docId) await request.delete(`/api/documents/${docId}`); + }); + + test('reader opens the read view with no edit tab or edit controls', async ({ browser }) => { + const context = await browser.newContext({ storageState: { cookies: [], origins: [] } }); + const page = await context.newPage(); + try { + await login(page, 'reader', 'reader123'); + await page.goto(docHref); + + // Reader entry control is the read label, not "Transkribieren". + const readButton = page.getByRole('button', { name: /Transkription lesen/i }); + await expect(readButton).toBeVisible({ timeout: 5000 }); + await readButton.click(); + + // Read view shows the transcription text. + await expect(page.getByText(/Mai 1945/)).toBeVisible({ timeout: 5000 }); + + // Header is a plain "Transkription" label, not a Lesen/Bearbeiten toggle. + await expect(page.getByRole('heading', { name: /^Transkription$/i })).toBeVisible(); + await expect(page.getByTestId('mode-edit')).toHaveCount(0); + await expect(page.getByTestId('mode-read')).toHaveCount(0); + } finally { + await context.close(); + } + }); +});