import { expect, test } from '@playwright/test'; import { resolve } from 'node:path'; import { writeFile } from 'node:fs/promises'; import type {} from '../physics/runner'; test('真实 WASM:上臂不能穿过自身臂座组件,接触后仍能反向离开', 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)); const initial = await page.evaluate( (path) => window.lekiwiPhysics.boot(path), `/@fs${resolve('build/lekiwi')}`, ); try { const samples = await page.evaluate(() => window.lekiwiPhysics.armSelfCollisionChecks()); console.log('arm/base contacts', JSON.stringify(samples)); const evidence = info.outputPath('arm-base-contacts.json'); await writeFile(evidence, JSON.stringify({ version: initial.version, samples }, null, 2)); await info.attach('arm-base-contacts', { path: evidence, contentType: 'application/json' }); expect(initial.version).toBe('3.11.0'); for (const sample of samples) { expect(Math.abs(sample.neutral.actual), `neutral, pan=${sample.pan}`).toBeLessThan(0.01); expect(sample.neutral.contacts).toEqual([]); // Full CAD changes the first obstruction: WaveShare plate at pan=0, // rotating shoulder clip at +/-0.8. Keep real contact/penetration/release // assertions; original Base_08q coverage is independently probed from STL. expect(sample.blocked.maxContacts, `blocked, pan=${sample.pan}`).toBeGreaterThan(0); expect(sample.blocked.contacts.length).toBeGreaterThan(0); expect(sample.blocked.actual).toBeLessThan(sample.blocked.target - 0.15); expect(sample.blocked.maxPenetration).toBeLessThan(0.002); for (const contact of sample.blocked.contacts) expect(contact.distance).toBeGreaterThan(-0.0005); expect(sample.blocked.finite).toBe(true); expect(Math.abs(sample.released.actual + 0.3)).toBeLessThan(0.01); expect(sample.released.contacts).toEqual([]); } expect(errors).toEqual([]); } finally { await page.evaluate(() => window.lekiwiPhysics.dispose()); } });