import { expect, test } from '@playwright/test'; import { resolve } from 'node:path'; import { writeFile } from 'node:fs/promises'; import type {} from '../physics/runner'; test('完整 314244 面三轮:真实 WASM、随轴运动、ZIP 重导与有界资源', async ({ page }, info) => { const errors: string[] = []; page.on('pageerror', (error) => errors.push(error.message)); await page.goto('/physics/runner.html'); await page.waitForFunction(() => Boolean(window.lekiwiPhysics)); await page.evaluate((path) => window.lekiwiPhysics.boot(path), `/@fs${resolve('build/lekiwi')}`); try { const before = await page.evaluate(() => window.lekiwiPhysics.visualStats()); // The three original filenames contain identical bytes; one content-addressed // OBJ is shared by three independent visual instances. expect(before.generatedMeshes).toHaveLength(1); expect(before.wheels).toHaveLength(3); for (const wheel of before.wheels) { expect(wheel.faces).toBe(314244); expect(wheel.vertices).toBeGreaterThan(150000); expect(wheel.centerError).toBeLessThan(1e-6); expect(wheel.scale).toEqual([0.001, 0.001, 0.001]); expect(wheel.collision).toBe(false); expect(wheel.mass).toBe(0); } await page.evaluate(() => window.lekiwiPhysics.drive(0, 0.1, 0, 0.25)); const after = await page.evaluate(() => window.lekiwiPhysics.visualStats()); for (let i = 0; i < 3; i++) { expect(after.wheels[i].centerError).toBeLessThan(1e-6); expect( after.wheels[i].rotation.some((v, j) => Math.abs(v - before.wheels[i].rotation[j]) > 0.01), ).toBe(true); } const traces: Awaited>[] = []; for (let i = 0; i < 8; i++) { const result = await page.evaluate(() => window.lekiwiPhysics.packageRoundtrip()); expect(result.oldModelDeleted).toBe(true); expect(result.oldDataDeleted).toBe(true); expect(result.workspaces).toHaveLength(1); expect(result.generatedMeshes).toHaveLength(1); expect(result.wheels.every((wheel) => wheel.faces === 314244 && !wheel.collision)).toBe(true); traces.push(result); } console.log( 'mesh resources', traces.map((t) => ({ heap: t.heap, bytes: t.projectBytes, xml: t.xmlFiles })), ); await writeFile( info.outputPath('full-mesh-roundtrip.json'), JSON.stringify({ before, after, traces }, null, 2), ); expect(traces.every((t) => t.projectBytes === traces[0].projectBytes)).toBe(true); expect(traces[7].heap).toBeLessThanOrEqual(traces[5].heap + 32 * 1024 * 1024); expect(errors).toEqual([]); } finally { await page.evaluate(() => window.lekiwiPhysics.dispose()); } });