From fc08ff10d4186178c6a091571b42df285171391d Mon Sep 17 00:00:00 2001 From: Johannes Fleck Date: Tue, 10 Nov 2026 20:11:40 +0100 Subject: [PATCH] test(e2e): Generate the docs screenshots with Playwright npm run docs:screenshots builds with .env.test and runs the specs in e2e/docs-screenshots in a separate Playwright project, which writes the images to docs/modules/cockpit/images. The normal E2E run skips them. --- AGENTS.md | 2 + README.md | 1 + e2e/docs-screenshots/dashboard.spec.ts | 60 ++++++++++++++++++++++++++ package.json | 1 + playwright.config.ts | 20 ++++++++- 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 e2e/docs-screenshots/dashboard.spec.ts diff --git a/AGENTS.md b/AGENTS.md index f365ec4a..325f56ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -267,3 +267,5 @@ test('example test', async ({ page }) => { ## Documentation When changing behaviour that is documented, update the related docs too: `README.md` (configuration, feature flags), `docs/`, `.env.example` and the Helm chart values. + +Screenshots in the Antora docs (`docs/modules/cockpit/images/`) are generated by the specs in `e2e/docs-screenshots/`. Regenerate them with `npm run docs:screenshots` after changing the UI they show. Add new screenshots as specs there, never by hand. diff --git a/README.md b/README.md index 39d3371e..79ab534c 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ npm run knip # Report unused files, exports and dependencies npm run test:unit # Run the Vitest unit tests npm run test:arch # Run the architecture tests npm run test:e2e # Run the Playwright end-to-end tests (requires Docker) +npm run docs:screenshots # Regenerate the screenshots in the Antora docs (requires Docker) npm run generate:antlr # Regenerate the lexer/parser after editing the SQL grammar ``` diff --git a/e2e/docs-screenshots/dashboard.spec.ts b/e2e/docs-screenshots/dashboard.spec.ts new file mode 100644 index 00000000..18e8d9dd --- /dev/null +++ b/e2e/docs-screenshots/dashboard.spec.ts @@ -0,0 +1,60 @@ +import path from 'path'; +import { test, expect } from '../support/fixtures.js'; +import { waitForHydration } from '../support/helpers'; +import { resetBookmarks } from '../support/bookmarks.js'; + +const imagesDir = path.join(import.meta.dirname, '../../docs/modules/cockpit/images'); + +// The global bookmarks from .env.test ("Cluster Logs", "Team Wiki") show up as well. +test('dashboard with bookmarks', async ({ page }) => { + await resetBookmarks(page, [ + { + productId: 'trino', + name: 'Trino', + url: 'https://trino.example.com', + environment: 'production', + pinned: true + }, + { + productId: 'superset', + name: 'Sales dashboards', + url: 'https://superset.example.com', + environment: 'production', + pinned: true + }, + { + productId: 'airflow', + name: 'Airflow', + url: 'https://airflow.example.com', + environment: 'production' + }, + { + productId: 'nifi', + name: 'Ingestion', + url: 'https://nifi.example.com', + environment: 'staging' + }, + { + productId: 'spark', + name: 'Spark History', + url: 'https://spark-history.example.com', + environment: 'production' + }, + { + productId: 'druid', + name: 'Druid', + url: 'https://druid.example.com', + environment: 'production' + } + ]); + try { + await page.goto('/'); + await waitForHydration(page); + // Product logos load lazily. + await page.waitForLoadState('networkidle'); + await expect(page.getByLabel('Bookmarks').getByText('Sales dashboards').first()).toBeVisible(); + await page.screenshot({ path: path.join(imagesDir, 'dashboard.png') }); + } finally { + await resetBookmarks(page); + } +}); diff --git a/package.json b/package.json index 3bf8d821..535bba22 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "test:unit:coverage": "vitest run --coverage", "test:e2e": "node --env-file=.env.test node_modules/.bin/vite build && playwright test", "test:e2e:ui": "playwright test --ui", + "docs:screenshots": "node --env-file=.env.test node_modules/.bin/vite build && DOCS_SCREENSHOTS=1 playwright test --project docs", "generate:antlr": "cd src/lib/editor/grammar && antlr-ng -v -l -Dlanguage=TypeScript -o ../generated SqlBase.g4 && node patch-generated.mjs", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", diff --git a/playwright.config.ts b/playwright.config.ts index 5bb9485a..3b8e328d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -4,6 +4,21 @@ import path from 'path'; const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:4173'; const appPort = new URL(baseURL).port || '80'; const chromiumExecutablePath = process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH; +// The specs that write the screenshots of the Antora docs run only in the docs +// project, which `npm run docs:screenshots` enables, not in the normal E2E run. +const docsScreenshotSpecs = '**/e2e/docs-screenshots/*.spec.ts'; +const docsProject = { + name: 'docs', + testMatch: docsScreenshotSpecs, + retries: 0, + use: { + browserName: 'chromium' as const, + viewport: { width: 1280, height: 800 }, + colorScheme: 'light' as const, + locale: 'en-US', + ...(chromiumExecutablePath && { launchOptions: { executablePath: chromiumExecutablePath } }) + } +}; export default defineConfig({ // Each worker logs in as its own user (see e2e/support/fixtures.ts), so @@ -50,6 +65,7 @@ export default defineConfig({ projects: [ { name: 'firefox', + testIgnore: docsScreenshotSpecs, use: { browserName: 'firefox', viewport: { width: 1280, height: 720 } @@ -57,11 +73,13 @@ export default defineConfig({ }, { name: 'chromium', + testIgnore: docsScreenshotSpecs, use: { browserName: 'chromium', viewport: { width: 1280, height: 720 }, ...(chromiumExecutablePath && { launchOptions: { executablePath: chromiumExecutablePath } }) } - } + }, + ...(process.env.DOCS_SCREENSHOTS ? [docsProject] : []) ] });