import { expect, test } from '@playwright/test'; import { resolve } from 'node:path'; import { writeFile } from 'node:fs/promises'; import type {} from '../physics/runner'; test('真实 WASM:相邻 Mirror/Square 连杆主体阻挡、反向脱离,机器人禁止 qpos 瞬移', async ({ page, }, info) => { const errors: string[] = []; page.on('pageerror', (e) => errors.push(e.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 result = await page.evaluate(() => window.lekiwiPhysics.adjacentArmChecks()); console.log('adjacent arm', JSON.stringify(result)); await writeFile(info.outputPath('adjacent-arm-contacts.json'), JSON.stringify(result, null, 2)); expect(result.teleportAccepted).toBe(false); expect(result.jointResetError).toMatch(/profile.*瞬移/); expect(result.editable).toBe(false); expect(result.before).toEqual(result.after); for (const sample of result.samples) { expect(sample.neutral.contacts).toEqual([]); expect(Math.abs(sample.neutral.panActual - sample.pan)).toBeLessThan(0.01); expect(Math.abs(sample.neutral.actual)).toBeLessThan(0.015); expect(sample.blocked.maxContacts).toBeGreaterThan(0); expect(sample.blocked.contacts.length).toBeGreaterThan(0); expect(sample.blocked.actual).toBeGreaterThan(sample.blocked.target + 0.5); expect(sample.blocked.minContactRadius).toBeGreaterThan(0.04); // structural contact, NOT the bearing core expect(sample.blocked.maxPenetration).toBeLessThan(0.002); expect(sample.blocked.finite).toBe(true); for (const c of sample.blocked.contacts) expect(c.distance).toBeGreaterThan(-0.0005); expect(Math.abs(sample.released.actual - 0.3)).toBeLessThan(0.015); expect(sample.released.contacts).toEqual([]); } expect(errors).toEqual([]); } finally { await page.evaluate(() => window.lekiwiPhysics.dispose()); } }); test('真实 WASM:六关节双向有界目标扫掠,无整体穿入或数值重置', async ({ page }, info) => { const errors: string[] = []; page.on('pageerror', (e) => errors.push(e.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 result = await page.evaluate(() => window.lekiwiPhysics.jointSweepChecks()); await writeFile(info.outputPath('joint-sweeps.json'), JSON.stringify(result, null, 2)); console.log('joint sweeps', JSON.stringify(result)); expect(result).toHaveLength(12); for (const sample of result) { expect(sample.finite, sample.joint).toBe(true); expect(sample.elapsed).toBeCloseTo(sample.expectedTime, 6); expect(sample.maxPenetration, sample.joint).toBeLessThan(0.002); if (sample.joint === 'arm_shoulder_pan') { expect(Math.abs(sample.actual - sample.target)).toBeLessThan(0.01); expect(sample.maxContacts).toBe(0); // core/structural straddlers must not lock the bearing } if (Math.abs(sample.actual - sample.target) > 0.05) expect(sample.maxContacts, sample.joint).toBeGreaterThan(0); } expect(errors).toEqual([]); } finally { await page.evaluate(() => window.lekiwiPhysics.dispose()); } }); test('真实 WASM:从原始 STL 独立取六向极值,整臂 18 个视觉网格均有外部物体接触覆盖', async ({ page, }, info) => { const errors: string[] = []; page.on('pageerror', (e) => errors.push(e.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 result = await page.evaluate(() => window.lekiwiPhysics.visualCollisionCoverage()); await writeFile(info.outputPath('arm-visual-coverage.json'), JSON.stringify(result, null, 2)); expect(result).toHaveLength(18); for (const sample of result) { expect(sample.probes).toHaveLength(6); for (const probe of sample.probes) expect(probe.contacts.length, `${sample.visual}: ${probe.point}`).toBeGreaterThan(0); } expect(errors).toEqual([]); } finally { await page.evaluate(() => window.lekiwiPhysics.dispose()); } });