diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eb250e4be..3ce7d49dc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1177,8 +1177,7 @@ jobs: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('web/package-lock.json') }} - name: install chromium - # Skips the browser download on a cache hit; still apt-installs deps. - run: npx playwright install --with-deps chromium + run: bash e2e/install-chromium.sh - name: build production dashboard for plain HTTP browser check run: npm run build - name: TypeScript editor on plain HTTP @@ -2271,8 +2270,10 @@ jobs: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('web/package-lock.json') }} - name: install playwright browser + working-directory: web run: | - cd web && npm ci && npx playwright install --with-deps chromium + npm ci + bash e2e/install-chromium.sh - name: i18n catalogs for the live dashboard # The live job serves the dashboard with plain vite, which never builds # the gitignored language list and catalogs (spec 019 T037). diff --git a/.github/workflows/visual-diff.yaml b/.github/workflows/visual-diff.yaml index 18f2f93f2..8d2904751 100644 --- a/.github/workflows/visual-diff.yaml +++ b/.github/workflows/visual-diff.yaml @@ -27,6 +27,12 @@ jobs: visual-diff: name: design vs browser visual diff runs-on: ubuntu-latest + # Include the same system fonts used by the hosted runner alongside the + # complete Playwright font set used for design and clipping comparisons. + container: &screenshot_runtime + image: mcr.microsoft.com/playwright:v1.65.0-noble@sha256:6e3fb709361521eb27161606e6da6d2674e5e89fa16516cb37d6fdd91372273d + volumes: + - /usr/share/fonts:/usr/local/share/fonts/runner:ro permissions: contents: read timeout-minutes: 20 @@ -47,16 +53,20 @@ jobs: - name: install dependencies run: npm ci - - name: playwright browser cache - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cache/ms-playwright - key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('web/package-lock.json') }} - restore-keys: | - playwright-${{ runner.os }}-${{ runner.arch }}- - - - name: install chromium - run: npx playwright install --with-deps chromium + - &verify_screenshot_browser + name: verify the locked screenshot browser + run: | + node --input-type=module <<'JS' + import assert from 'node:assert/strict'; + import { readFileSync } from 'node:fs'; + const json = path => JSON.parse(readFileSync(path, 'utf8')); + assert.equal( + json('/ms-playwright/.docker-info').driverVersion, + json('node_modules/playwright/package.json').version, + 'Update the screenshot image digest when upgrading Playwright', + ); + JS + bash e2e/install-chromium.sh - name: capture browser screenshots run: npm run screenshots:design @@ -86,6 +96,7 @@ jobs: pseudo-locale: name: en-XA screenshots (spec 019) runs-on: ubuntu-latest + container: *screenshot_runtime permissions: contents: read timeout-minutes: 30 @@ -106,16 +117,7 @@ jobs: - name: install dependencies run: npm ci - - name: playwright browser cache - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cache/ms-playwright - key: playwright-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('web/package-lock.json') }} - restore-keys: | - playwright-${{ runner.os }}-${{ runner.arch }}- - - - name: install chromium - run: npx playwright install --with-deps chromium + - *verify_screenshot_browser - name: capture en-XA screenshots and check clipping run: npm run screenshots:pseudo diff --git a/changelog/unreleased/917-browser-runtime.md b/changelog/unreleased/917-browser-runtime.md new file mode 100644 index 000000000..006d56d86 --- /dev/null +++ b/changelog/unreleased/917-browser-runtime.md @@ -0,0 +1,6 @@ +### Browser checks on hosted runners + +The dashboard’s mock, live Kubernetes and screenshot jobs now verify that the +locked Chromium build can render a screenshot and record video. Runners with a +working browser skip Ubuntu package installation. If the probe fails, CI +installs the distribution dependencies and repeats the probe before testing. diff --git a/web/e2e/install-chromium.sh b/web/e2e/install-chromium.sh new file mode 100644 index 000000000..46b40b741 --- /dev/null +++ b/web/e2e/install-chromium.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run from web/ after npm ci. Use the browser and FFmpeg from the locked CLI. +playwright=./node_modules/.bin/playwright + +probe_browser() { + timeout --kill-after=5s 45s node --input-type=module <<'JS' +import { stat } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { chromium } from 'playwright'; + +const browser = await chromium.launch(); +try { + const page = await browser.newPage({ recordVideo: { dir: tmpdir() } }); + await page.setContent(''); + await page.getByRole('button', { name: 'Français' }).screenshot(); + const video = page.video(); + await page.close(); + if ((await stat(await video.path())).size === 0) throw new Error('Chromium recorded an empty video'); + await video.delete(); +} finally { + await browser.close(); +} +JS +} + +# Hosted runners normally have Chromium's native libraries. Only contact the +# distro mirrors if the installed browser cannot render and record a page. +timeout --kill-after=10s 4m "$playwright" install chromium +if probe_browser; then + exit 0 +fi + +echo "Chromium's runtime probe failed; installing Playwright's distribution dependencies." >&2 +timeout --kill-after=10s 4m "$playwright" install --with-deps chromium +probe_browser