The v1.64.1-noble tag was re-pushed with Node 26, which fails the Node 24 guard in every browser job. Pin the last green image's digest so the browsers, fonts and Node only change through a reviewed bump.
54 lines
4.0 KiB
JavaScript
54 lines
4.0 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
// Concept comparisons measure layout, and layout depends on the fonts a browser falls back to (the concept names Inter,
|
|
// which neither environment ships). Page-workflow jobs therefore run in the same pinned Playwright image as local runs,
|
|
// so CI and a developer machine resolve identical fonts and engines.
|
|
const workflow = readFileSync(new URL('../../.github/workflows/viewerjs-check.yml', import.meta.url), 'utf8');
|
|
const lock = JSON.parse(readFileSync(new URL('../../tools/vendor/package-lock.json', import.meta.url), 'utf8'));
|
|
const version = lock.packages['node_modules/@playwright/test'].version;
|
|
// The tag alone is not a pin: v1.64.1-noble was re-pushed with Node 26 (#609). The digest fixes the image's contents.
|
|
const pinnedImage = `^ container:\\n image: mcr\\.microsoft\\.com/playwright:v${version.replaceAll('.', '\\.')}-noble@sha256:[0-9a-f]{64}$`;
|
|
|
|
function job(name) {
|
|
const match = workflow.match(new RegExp(`^ ${name}:\\n([\\s\\S]*?)(?=^ [a-z][a-z-]*:\\n|(?![\\s\\S]))`, 'm'));
|
|
assert.ok(match, `${name} job exists`);
|
|
return match[1];
|
|
}
|
|
|
|
for (const name of ['frontend-coverage', 'browser-workflows']) {
|
|
test(`${name} runs in the pinned Playwright image matching @playwright/test`, () => {
|
|
const body = job(name);
|
|
assert.match(body, new RegExp(pinnedImage, 'm'));
|
|
assert.doesNotMatch(body, /playwright install/, 'browsers and their fonts come from the image, not a runner install');
|
|
// Toolcache interpreters are the runner's own builds: their entry points name host paths that do not exist in
|
|
// the container (setup-python failed with `spawn .../bin/pip ENOENT`). Use the image's Python and Node.
|
|
assert.doesNotMatch(body, /actions\/setup-(python|node)@/);
|
|
assert.match(body, /python3 -m venv --without-pip /, 'a user-space venv on the image Python (no ensurepip, no root)');
|
|
assert.match(body, /sha256sum -c/, 'the pip wheel that bootstraps the venv is checksum-pinned');
|
|
assert.match(body, /node --version \| grep -q '\^v24\\\.'/, 'the image Node is the Node 24 the project requires');
|
|
});
|
|
}
|
|
|
|
// The real-host job drives Chromium against a managed ComfyUI. `playwright install --with-deps` pulled the browser's
|
|
// system packages from Ubuntu's apt mirror on every run, and three runs (#349, #378, #382) crawled at ~26 kB/s until
|
|
// the job hit its limit after every test had passed. The pinned image ships Chromium and its libraries, so the job runs
|
|
// there; the image Python must be the reviewed host Python from tools/vendor/comfyui-runtime.json.
|
|
test('real ComfyUI compatibility runs in the pinned Playwright image on the reviewed host Python', () => {
|
|
const testWorkflow = readFileSync(new URL('../../.github/workflows/test.yml', import.meta.url), 'utf8');
|
|
const runtime = JSON.parse(readFileSync(new URL('../../tools/vendor/comfyui-runtime.json', import.meta.url), 'utf8'));
|
|
const match = testWorkflow.match(/^ {2}comfyui:\n([\s\S]*?)(?=^ {2}[a-z][a-z-]*:\n|(?![\s\S]))/m);
|
|
assert.ok(match, 'comfyui job exists');
|
|
const body = match[1];
|
|
assert.match(body, new RegExp(pinnedImage, 'm'));
|
|
assert.doesNotMatch(body, /playwright install/, 'Chromium and its system libraries come from the image, not apt');
|
|
assert.doesNotMatch(body, /apt-get|actions\/setup-(python|node)@/);
|
|
assert.match(body, /python3 -m venv --without-pip /, 'a user-space venv on the image Python');
|
|
assert.match(body, /sha256sum -c/, 'the pip wheel that bootstraps the venv is checksum-pinned');
|
|
assert.match(body, /node --version \| grep -q '\^v24\\\.'/, 'the image Node is Node 24');
|
|
// The image Python is checked against the pin at run time, so a pin or image bump that disagrees fails loudly.
|
|
assert.match(body, /steps\.runtime\.outputs\.pythonVersion/, 'the job compares the image Python with the reviewed pin');
|
|
assert.match(runtime.pythonVersion, /^3\.12$/, 'the reviewed host Python is the image Python (3.12 on noble)');
|
|
});
|