import { expect, test } from '../helpers/serve-dist'; test('arrival draws six meteor triangles, uses warmed shaders, then stops drawing the meteors', async ({ page, distUrl }, testInfo) => { test.setTimeout(45_000); if (testInfo.project.name === 'desktop-chromium') await page.setViewportSize({ width: 1440, height: 900 }); await page.addInitScript((quality: string) => { localStorage.setItem('portfolio.motion.maximum-quality', quality); const probe = { draws: 0, maxVertices: 0, programs: 0, frames: 0, time: -1, ring: 0 }; (window as any).__arrivalProbe = probe; const proto = WebGL2RenderingContext.prototype; const meteorPrograms = new WeakSet(); const locations = new WeakMap(); let activeProgram: WebGLProgram | null = null; const meteorShaders = new WeakSet(); const source = proto.shaderSource; proto.shaderSource = function (shader, text) { if (text.includes('attribute vec2 aFlight;')) meteorShaders.add(shader); return source.call(this, shader, text); }; const attach = proto.attachShader; proto.attachShader = function (program, shader) { if (meteorShaders.has(shader) && !meteorPrograms.has(program)) { meteorPrograms.add(program); probe.programs++; } return attach.call(this, program, shader); }; const getUniform = proto.getUniformLocation; proto.getUniformLocation = function (program, name) { const location = getUniform.call(this, program, name); if (location) locations.set(location, { program, name }); return location; }; const uniform = proto.uniform1f; proto.uniform1f = function (location, value) { const entry = location && locations.get(location); if (entry?.name === 'uTime' && meteorPrograms.has(entry.program)) probe.time = value; if (entry?.name === 'uRingOpacity') probe.ring = value; return uniform.call(this, location, value); }; const useProgram = proto.useProgram; proto.useProgram = function (program) { activeProgram = program; return useProgram.call(this, program); }; const draw = proto.drawArrays; proto.drawArrays = function (mode, first, count) { if (activeProgram && meteorPrograms.has(activeProgram)) { probe.draws++; probe.maxVertices = Math.max(probe.maxVertices, count); } return draw.call(this, mode, first, count); }; const clear = proto.clear; proto.clear = function (mask) { probe.frames++; return clear.call(this, mask); }; }, process.env.ARRIVAL_TEST_QUALITY === 'high' ? 'high' : 'low'); await page.goto(distUrl); await expect(page.locator('html')).toHaveAttribute('data-expressway', 'live'); const read = () => page.evaluate(() => ({ ...(window as any).__arrivalProbe })); const baseline = await read(); expect(baseline.draws).toBe(1); // Transparent startup warm-up only. expect(baseline.programs).toBe(1); await page.locator('.hero-journey__action--primary').click(); await expect(page.locator('.journey-world')).toHaveAttribute('data-arrived', 'true'); await expect.poll(async () => (await read()).draws, { timeout: 12_000 }).toBeGreaterThan(baseline.draws); await expect.poll(async () => (await read()).ring).toBeGreaterThan(0); await expect.poll(async () => (await read()).time).toBeGreaterThan(1.2); await page.screenshot({ path: testInfo.outputPath('arrival-active.png') }); await expect.poll(async () => (await read()).time, { timeout: 15_000 }).toBeGreaterThan(3.8); const ending = await read(); await expect.poll(async () => (await read()).frames).toBeGreaterThan(ending.frames + 30); const settled = await read(); expect(settled.maxVertices).toBe(18); expect(settled.programs).toBe(baseline.programs); await expect.poll(async () => (await read()).ring).toBeGreaterThan(0); await expect.poll(async () => (await read()).frames).toBeGreaterThan(settled.frames + 30); expect((await read()).draws).toBe(settled.draws); await page.screenshot({ path: testInfo.outputPath('arrival-settled.png') }); });