import { expect, test } from '../helpers/serve-dist'; import { assertSemanticFaultOracle, authorizedFaultUrl, collectBrowserErrors, missingTokenFaultUrl, readFaultSnapshot, readUnhandledRejections, wrongTokenFaultUrl, } from '../helpers/test-build-auth'; import { installSceneInstrumentation, readSceneInstrumentation } from '../helpers/scene-instrumentation'; import type { PortfolioFaultId } from '@/testing/fault-hooks'; const assertNoEscapedErrors = async ( page: Parameters[0], pageErrors: readonly string[], ): Promise => { expect(pageErrors).toEqual([]); expect(await readUnhandledRejections(page)).toEqual([]); expect((await readSceneInstrumentation(page)).unhandledRejections).toEqual([]); }; test.describe('authenticated fault-build boundary', () => { test.beforeEach(async ({}, testInfo) => { test.skip(testInfo.project.name !== 'desktop-chromium', 'The complete F1–F13 matrix runs once on current desktop Chromium.'); }); test('missing token exposes no fault API and leaves the portfolio operational', async ({ page, distUrl }) => { await page.goto(missingTokenFaultUrl(distUrl, 'F1-scene-chunk'), { waitUntil: 'domcontentloaded' }); expect(await page.evaluate(() => '__PORTFOLIO_TEST_HOOKS__' in window)).toBe(false); await expect(page.locator('.journey-world')).toHaveAttribute('data-scene-state', 'running'); await assertSemanticFaultOracle(page); }); test('wrong token exposes no fault API and leaves the portfolio operational', async ({ page, distUrl }) => { await page.goto(wrongTokenFaultUrl(distUrl, 'F1-scene-chunk'), { waitUntil: 'domcontentloaded' }); expect(await page.evaluate(() => '__PORTFOLIO_TEST_HOOKS__' in window)).toBe(false); await expect(page.locator('.journey-world')).toHaveAttribute('data-scene-state', 'running'); await assertSemanticFaultOracle(page); }); test('correct token exposes only the frozen named fault interface', async ({ page, distUrl }) => { await page.goto(authorizedFaultUrl(distUrl, 'F9-hydration-failure'), { waitUntil: 'domcontentloaded' }); await expect.poll(() => page.evaluate(() => '__PORTFOLIO_TEST_HOOKS__' in window)).toBe(true); const shape = await page.evaluate(() => { const hooks = (window as unknown as { __PORTFOLIO_TEST_HOOKS__: object }).__PORTFOLIO_TEST_HOOKS__; return { frozen: Object.isFrozen(hooks), keys: Object.keys(hooks).sort() }; }); expect(shape).toEqual({ frozen: true, keys: ['fault', 'snapshot', 'trigger', 'version'] }); expect((await readFaultSnapshot(page)).fault).toBe('F9-hydration-failure'); await expect(page.locator('.drive-controls')).toHaveCount(1); await assertSemanticFaultOracle(page); }); }); test.describe('scene failure matrix', () => { test.beforeEach(async ({}, testInfo) => { test.skip(testInfo.project.name !== 'desktop-chromium', 'The complete F1–F13 matrix runs once on current desktop Chromium.'); }); for (const fault of [ 'F1-scene-chunk', 'F1-shader', 'F1-car', 'F1-texture', ] as const satisfies readonly PortfolioFaultId[]) { test(`${fault} enters one static fallback without escaping an error`, async ({ page, distUrl }) => { await installSceneInstrumentation(page); const errors = await collectBrowserErrors(page); await page.goto(authorizedFaultUrl(distUrl, fault), { waitUntil: 'domcontentloaded' }); await expect(page.locator('.journey-world')).toHaveAttribute('data-scene-state', 'static'); await expect(page.locator('.journey-world')).toHaveAttribute('data-static-fallback', 'true'); await expect(page.locator('.journey-poster')).toHaveCount(1); await expect(page.locator('.journey-canvas')).toHaveCount(0); await expect(page.locator('.drive-controls__status')).toHaveText('Visuals unavailable'); await assertSemanticFaultOracle(page); const resources = await readSceneInstrumentation(page); expect(resources.activeAnimationFrames).toBe(0); expect(resources.maximumCanvasCount).toBeLessThanOrEqual(1); expect((await readFaultSnapshot(page)).staticFallbackCount).toBe(1); await assertNoEscapedErrors(page, errors.pageErrors); }); } test('F2 enforces the literal five-second first-frame deadline', async ({ page, distUrl }) => { test.setTimeout(12_000); await installSceneInstrumentation(page); const errors = await collectBrowserErrors(page); const startedAt = Date.now(); await page.goto(authorizedFaultUrl(distUrl, 'F2-first-frame-timeout'), { waitUntil: 'domcontentloaded' }); await expect(page.locator('.journey-world')).toHaveAttribute('data-scene-state', 'static', { timeout: 7_000 }); expect(Date.now() - startedAt).toBeGreaterThanOrEqual(4_800); await expect(page.locator('.journey-world')).toHaveAttribute('data-static-fallback', 'true'); await expect(page.locator('.journey-canvas')).toHaveCount(0); await assertSemanticFaultOracle(page); const fault = await readFaultSnapshot(page); expect(fault.events).toContain('first-frame-suppressed'); expect(fault.events).not.toContain('first-frame-deadline'); expect(fault.staticFallbackCount).toBe(1); expect((await readSceneInstrumentation(page)).activeAnimationFrames).toBe(0); await assertNoEscapedErrors(page, errors.pageErrors); }); test('F3 contains a post-first-frame exception on the next frame', async ({ page, distUrl }) => { await installSceneInstrumentation(page); const errors = await collectBrowserErrors(page); await page.goto(authorizedFaultUrl(distUrl, 'F3-post-first-frame-exception'), { waitUntil: 'domcontentloaded' }); await expect(page.locator('.journey-world')).toHaveAttribute('data-scene-state', 'static'); await expect(page.locator('.journey-world')).toHaveAttribute('data-static-fallback', 'true'); await expect(page.locator('.journey-canvas')).toHaveCount(0); await assertSemanticFaultOracle(page); expect((await readSceneInstrumentation(page)).activeAnimationFrames).toBe(0); await assertNoEscapedErrors(page, errors.pageErrors); }); });