feat(#38): document edit history with diff and compare mode #52

Merged
marcel merged 13 commits from feat/38-document-edit-history into main 2026-03-23 17:27:57 +01:00
Showing only changes of commit 62f62a89a1 - Show all commits

View File

@@ -1,50 +1,72 @@
import { test, expect } from '@playwright/test';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
/**
* Document edit history E2E tests.
* Relies on the 'Document creation' and 'Document editing' tests in documents.spec.ts
* having run first (they create and edit "E2E Testbrief (überarbeitet)").
* Assumes auth setup has run.
* Creates its own test document (two versions) in beforeAll so these tests
* are fully independent of any other spec file.
*/
test.describe('Document history panel', () => {
test('history section appears after creating and editing a document', async ({ page }) => {
// Find the document edited in the documents.spec.ts editing test
await page.goto('/?q=E2E+Testbrief');
await page.waitForSelector('[data-hydrated]');
const docLink = page.getByRole('link', { name: /E2E Testbrief/ }).first();
const href = await docLink.getAttribute('href');
await page.goto(href!);
// History section should be present (collapsed by default)
let docPath: string;
test.describe('Document history panel', () => {
test.beforeAll(async ({ browser }) => {
// Create a fresh browser context that uses the stored auth session
const context = await browser.newContext({
storageState: path.join(__dirname, '.auth/user.json'),
locale: 'de-DE'
});
const page = await context.newPage();
// 1. Create a new document
await page.goto('/documents/new');
await page.waitForSelector('[data-hydrated]');
await page.getByLabel('Titel').fill('E2E History Test Dokument');
await page.getByRole('button', { name: /Speichern/i }).click();
// Wait for redirect to the new document's UUID-based URL (not /documents/new)
await page.waitForURL(/\/documents\/[0-9a-f-]{36}$/);
docPath = new URL(page.url()).pathname;
// 2. Edit the document to create a second version
await page.goto(`${docPath}/edit`);
await page.waitForSelector('[data-hydrated]');
await page.getByLabel('Titel').fill('E2E History Test Dokument (bearbeitet)');
await page.getByRole('button', { name: /Speichern/i }).click();
await page.waitForURL(/\/documents\/[0-9a-f-]{36}$/);
await context.close();
});
test('history section appears and shows two versions', async ({ page }) => {
await page.goto(docPath);
await page.waitForSelector('[data-hydrated]');
const historyToggle = page.getByRole('button', { name: /Verlauf/i });
await expect(historyToggle).toBeVisible();
// Expand the history section
await historyToggle.click();
// Should show at least two version entries (created + edited)
// Wait for versions to load (API call happens after panel opens)
const versionItems = page.locator('[data-testid="history-version"]');
await expect(versionItems).toHaveCount(2, { timeout: 5000 });
await expect(versionItems).toHaveCount(2, { timeout: 10000 });
await page.screenshot({ path: 'test-results/e2e/history-versions-list.png' });
});
test('diff view highlights changed field after title edit', async ({ page }) => {
await page.goto('/?q=E2E+Testbrief');
await page.goto(docPath);
await page.waitForSelector('[data-hydrated]');
const docLink = page.getByRole('link', { name: /E2E Testbrief/ }).first();
const href = await docLink.getAttribute('href');
await page.goto(href!);
// Expand history
const historyToggle = page.getByRole('button', { name: /Verlauf/i });
await historyToggle.click();
// Click the second version (the edit) to see its diff
// Wait for versions to load, then click the second one (the edit)
const versionItems = page.locator('[data-testid="history-version"]');
await expect(versionItems.nth(1)).toBeVisible({ timeout: 10000 });
await versionItems.nth(1).click();
// The diff panel should show the "Titel" field as changed
const diffPanel = page.locator('[data-testid="history-diff"]');
await expect(diffPanel).toBeVisible();
await expect(diffPanel.getByText(/Titel/i)).toBeVisible();
@@ -53,34 +75,35 @@ test.describe('Document history panel', () => {
});
test('compare mode lets user compare any two versions', async ({ page }) => {
await page.goto('/?q=E2E+Testbrief');
await page.goto(docPath);
await page.waitForSelector('[data-hydrated]');
const docLink = page.getByRole('link', { name: /E2E Testbrief/ }).first();
const href = await docLink.getAttribute('href');
await page.goto(href!);
// Expand history
const historyToggle = page.getByRole('button', { name: /Verlauf/i });
await historyToggle.click();
// Switch to compare mode
// Wait for versions to load before the compare button appears
await expect(page.locator('[data-testid="history-version"]').first()).toBeVisible({
timeout: 10000
});
const compareBtn = page.getByRole('button', { name: /Vergleichen/i });
await expect(compareBtn).toBeVisible();
await compareBtn.click();
// Two version selects should appear
const selectA = page.getByLabel(/Version A/i);
const selectB = page.getByLabel(/Version B/i);
await expect(selectA).toBeVisible();
await expect(selectB).toBeVisible();
// Apply the comparison
// Select version 1 for A and version 2 for B
await selectA.selectOption({ index: 1 });
await selectB.selectOption({ index: 2 });
await page
.getByRole('button', { name: /Vergleichen/i })
.last()
.click();
// Diff panel should be visible
const diffPanel = page.locator('[data-testid="history-diff"]');
await expect(diffPanel).toBeVisible();