/** * 3D Renderer WebGL Regression — capture-only. * * Renders every scenario of the 3D suite (tests/3d-regression) in the browser * and writes 3d-.png into tests/3d-regression/output/webgl/. This spec * never compares pixels: the gates live in `npm run 3d:check:webgl` * (browser-regression, once baseline-webgl exists) and the informational * `npm run 3d:check:parity` port-progress meter (expected ~100% changed while * the FFP stubs render blank — the TDD red state). * * Anti-drift: no hand-typed scenario list. The committed * tests/3d-regression/manifest.json (written by the native golden generator, * cmp-guarded by scripts/test-3d-regression.sh) is the single source of truth, * and the wasm registry is asserted against it name-by-name. */ import { test, expect } from './utils/fixtures'; import * as path from 'path'; import * as fs from 'fs'; const MANIFEST_PATH = path.join(__dirname, '../3d-regression/manifest.json'); const OUTPUT_DIR = path.join(__dirname, '../3d-regression/output/webgl'); const APP_JS = path.join(__dirname, '../apps/3d-webgl/3d_webgl_test.js'); const MANIFEST: { width: number; height: number; scenarios: string[] } = JSON.parse( fs.readFileSync(MANIFEST_PATH, 'utf8') ); test.describe('3D WebGL Regression', () => { test.skip( !fs.existsSync(APP_JS), '3d-webgl harness not built (run scripts/build-3d-webgl-test.sh)' ); test.beforeAll(async () => { fs.mkdirSync(OUTPUT_DIR, { recursive: true }); }); test('module loads and registry matches the committed manifest', async ({ page }) => { await page.goto('/3d-webgl/3d_webgl_test.html'); await page.waitForFunction(() => (window as any).threeDTest?.isReady(), undefined, { timeout: 60000, }); const total = await page.evaluate(() => (window as any).threeDTest.getTotalScenarios()); expect(total).toBe(MANIFEST.scenarios.length); const names = await page.evaluate((count) => { const t = (window as any).threeDTest; return Array.from({ length: count }, (_, i) => t.getScenarioName(i)); }, total); expect(names).toEqual(MANIFEST.scenarios); const width = await page.evaluate(() => (window as any).threeDTest.getCanvasWidth()); const height = await page.evaluate(() => (window as any).threeDTest.getCanvasHeight()); expect(width).toBe(MANIFEST.width); expect(height).toBe(MANIFEST.height); }); test('render all scenarios', async ({ page }) => { test.setTimeout(300000); await page.goto('/3d-webgl/3d_webgl_test.html'); await page.waitForFunction(() => (window as any).threeDTest?.isReady(), undefined, { timeout: 60000, }); for (const [i, name] of MANIFEST.scenarios.entries()) { const rc = await page.evaluate((idx) => (window as any).threeDTest.runScenario(idx), i); expect(rc, `runScenario(${i}) [${name}]`).toBe(0); // One composite tick so the preserved drawing buffer is presentable. await page.evaluate(() => new Promise(requestAnimationFrame)); await page .locator('#canvas') .screenshot({ path: path.join(OUTPUT_DIR, `3d-${name}.png`) }); } }); });