feat: Stage 2E physics p95, runtime videos, domain audit, device-test QR
Measure Rapier world.step p95 (~0.2 ms) on GTX 1080, record real route WebMs, expand runtime/headless hash parity, and document permanent-domain/phone blockers. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,23 +9,23 @@ test.describe('controls', () => {
|
||||
});
|
||||
|
||||
test('seek next/prev and jump cases, speed, presentation', async ({ page }) => {
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
|
||||
await page.getByTestId('demo-next').click();
|
||||
await ensurePaused(page);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('2/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('2/12');
|
||||
|
||||
await page.getByTestId('demo-prev').click();
|
||||
await ensurePaused(page);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
|
||||
await page.getByTestId('demo-case-8').click();
|
||||
await ensurePaused(page);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('9/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('9/12');
|
||||
|
||||
await page.getByTestId('demo-case-0').click();
|
||||
await ensurePaused(page);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
|
||||
for (const speed of ['0.5', '1', '1.5', '2'] as const) {
|
||||
await page.getByTestId(`demo-speed-${speed}`).click();
|
||||
|
||||
@@ -51,5 +51,5 @@ export async function openPausedCase(page: Page, caseIndex: number, speed: '0.5'
|
||||
await page.getByTestId(`demo-case-${caseIndex}`).click();
|
||||
await dismissFinished(page);
|
||||
await ensurePaused(page);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText(`${caseIndex + 1}/11`);
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText(`${caseIndex + 1}/12`);
|
||||
}
|
||||
|
||||
@@ -181,8 +181,9 @@ test.describe('stage2 mobile capability policy', () => {
|
||||
Object.defineProperty(navigator, 'hardwareConcurrency', { value: 8, configurable: true });
|
||||
Object.defineProperty(navigator, 'deviceMemory', { value: 8, configurable: true });
|
||||
});
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.goto('/');
|
||||
// prefer3DByDefault requires width >= 640; narrow 390px uses SVG by design.
|
||||
await page.setViewportSize({ width: 800, height: 600 });
|
||||
await page.goto('/?quality=low');
|
||||
// Mobile Low mounts the real 3D canvas at low quality
|
||||
await expect(page.locator('canvas')).toBeVisible({ timeout: 60_000 });
|
||||
await expect(page.getByTestId('main-svg-fallback')).toHaveCount(0);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { dismissFinished, openPausedCase, ensureRunning } from './helpers';
|
||||
|
||||
/**
|
||||
* Production smoke — manual only:
|
||||
@@ -6,7 +7,7 @@ import { test, expect } from '@playwright/test';
|
||||
*/
|
||||
test.describe('production smoke @production', () => {
|
||||
test('version, routes, controls, safety, webgl', async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
test.setTimeout(180_000);
|
||||
const expectedCommit = process.env.EXPECTED_COMMIT?.trim();
|
||||
const pageErrors: string[] = [];
|
||||
const failed: string[] = [];
|
||||
@@ -50,30 +51,27 @@ test.describe('production smoke @production', () => {
|
||||
expect(webgl.ok).toBe(true);
|
||||
|
||||
await expect(page.getByTestId('demo-play').or(page.getByTestId('demo-pause'))).toBeVisible();
|
||||
await expect(page.getByTestId('demo-case-10')).toBeVisible();
|
||||
await expect(page.getByTestId('demo-case-11')).toBeVisible();
|
||||
|
||||
// Play / seek
|
||||
const pauseBtn = page.getByTestId('demo-pause');
|
||||
if (!(await pauseBtn.isVisible().catch(() => false))) {
|
||||
await page.getByTestId('demo-play').click();
|
||||
}
|
||||
await page.waitForTimeout(600);
|
||||
await page.getByTestId('demo-case-0').click();
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await dismissFinished(page);
|
||||
await page.getByTestId('demo-case-0').click({ force: true });
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
|
||||
// Jam
|
||||
await page.getByTestId('demo-speed-2').click();
|
||||
await page.getByTestId('demo-case-9').click();
|
||||
// Jam / E-stop via shared helper (avoids finished-overlay races)
|
||||
await openPausedCase(page, 10, '1');
|
||||
await ensureRunning(page);
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const status = (await page.getByTestId('demo-status').textContent()) ?? '';
|
||||
const command = (await page.getByTestId('demo-command').textContent()) ?? '';
|
||||
return `${status} ${command}`;
|
||||
const warn =
|
||||
(await page.locator('.warning-text').first().textContent().catch(() => '')) ?? '';
|
||||
return `${status} ${command} ${warn}`;
|
||||
}, { timeout: 30_000 })
|
||||
.toMatch(/FAULT|JAM/i);
|
||||
|
||||
// E-stop
|
||||
await page.getByTestId('demo-case-10').click();
|
||||
await openPausedCase(page, 11, '1');
|
||||
await ensureRunning(page);
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const status = (await page.getByTestId('demo-status').textContent()) ?? '';
|
||||
@@ -82,20 +80,19 @@ test.describe('production smoke @production', () => {
|
||||
}, { timeout: 30_000 })
|
||||
.toMatch(/EMERGENCY/i);
|
||||
|
||||
// Reset / recover toward case 0
|
||||
await dismissFinished(page);
|
||||
const stop = page.getByTestId('demo-stop');
|
||||
if (await stop.isVisible().catch(() => false)) {
|
||||
await stop.click({ force: true });
|
||||
}
|
||||
await page.getByTestId('demo-case-0').click({ force: true });
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
|
||||
await page.goto('/details');
|
||||
await expect(page.locator('#root')).toBeVisible();
|
||||
await page.reload();
|
||||
await expect(page.locator('#root')).toBeVisible();
|
||||
|
||||
// Back home — version still matches
|
||||
await page.goto('/?debug=1');
|
||||
const version2 = await page.evaluate(async () => {
|
||||
const r = await fetch('/version.json', { cache: 'no-store' });
|
||||
@@ -107,7 +104,6 @@ test.describe('production smoke @production', () => {
|
||||
const critical = failed.filter((f) => !f.includes('favicon'));
|
||||
expect(critical, critical.join('\n')).toEqual([]);
|
||||
|
||||
// Attach renderer for report (not a hard fail if software)
|
||||
test.info().annotations.push({
|
||||
type: 'webgl-renderer',
|
||||
description: webgl.renderer ?? 'unknown',
|
||||
|
||||
@@ -5,8 +5,8 @@ test.describe('safety', () => {
|
||||
test.setTimeout(90_000);
|
||||
|
||||
test('jam case shows FAULT in status or command', async ({ page }) => {
|
||||
await openPausedCase(page, 9, '1');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('10/11');
|
||||
await openPausedCase(page, 10, '1');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('11/12');
|
||||
await ensureRunning(page);
|
||||
|
||||
await expect
|
||||
@@ -22,8 +22,8 @@ test.describe('safety', () => {
|
||||
});
|
||||
|
||||
test('emergency case shows EMERGENCY in status or command', async ({ page }) => {
|
||||
await openPausedCase(page, 10, '1');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('11/11');
|
||||
await openPausedCase(page, 11, '1');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('12/12');
|
||||
await ensureRunning(page);
|
||||
|
||||
await expect
|
||||
|
||||
@@ -25,7 +25,7 @@ async function dismissFinishedIfNeeded(page: Page) {
|
||||
async function jumpCase(page: Page, index: number) {
|
||||
await dismissFinishedIfNeeded(page);
|
||||
await page.getByTestId(`demo-case-${index}`).click();
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText(`${index + 1}/11`, {
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText(`${index + 1}/12`, {
|
||||
timeout: 10_000,
|
||||
});
|
||||
}
|
||||
@@ -55,7 +55,7 @@ test.describe('visual regression', () => {
|
||||
if (await pause.isVisible().catch(() => false)) {
|
||||
await pause.click();
|
||||
}
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/11');
|
||||
await expect(page.getByTestId('demo-case-label')).toHaveText('1/12');
|
||||
await snapHud(page, '01-home-idle-hud.png');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user