Files
Mujoco_WASM/web_platform/e2e/lekiwi.agent.faults.spec.ts
T
chenlin f3a8a38acd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
2026-09-24 09:57:41 +08:00

105 lines
3.6 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { resolve } from 'node:path';
import { writeFile } from 'node:fs/promises';
import type {} from '../physics/agent';
for (const fault of [
'empty-grasp',
'empty-once',
'alignment',
'slip',
'jam',
'navigation',
'unreachable',
'overspeed',
] as const) {
test(`真实 WASM 故障:${fault} 不可冒充成功/无限恢复`, async ({ page }, info) => {
await page.goto('/physics/agent.html');
await page.waitForFunction(() => Boolean(window.lekiwiAgent));
await page.evaluate(
(url) => window.lekiwiAgent.boot(url),
`/@fs${resolve('build/lekiwi/lekiwi-v1.zip')}`,
);
try {
const r = await page.evaluate(
(fault) => window.lekiwiAgent.task(0, undefined, { fault }),
fault,
);
await writeFile(info.outputPath('fault-evidence.json'), JSON.stringify(r, null, 2));
console.log('WASM fault', {
fault,
state: r.state,
error: r.error,
failures: r.failures,
recoveries: r.recoveries,
simTime: r.simTime,
});
expect(r.mode).toBe('mock');
expect(r.state).toBe(fault === 'empty-once' ? 'succeeded' : 'failed');
expect(r.succeeded).toBe(fault === 'empty-once');
expect(r.simTime).toBeLessThanOrEqual(70.01);
expect(r.llmCalls).toBe(1);
if (fault === 'empty-grasp' || fault === 'empty-once' || fault === 'alignment') {
const skill = fault === 'alignment' ? 'pregrasp' : 'close';
const code = fault === 'alignment' ? 'alignment_timeout' : 'empty_grasp';
const recovered = fault === 'empty-once';
expect(r.recoveries[skill]).toBe(recovered ? 1 : 2);
expect(r.failures.map((f) => f.code)).toEqual(Array(recovered ? 1 : 3).fill(code));
if (!recovered) expect(r.trace.every((s) => !s.secure)).toBe(true);
else {
expect(r.transported).toBeGreaterThanOrEqual(0.5);
expect(r.sample.onGoalSupport).toBe(true);
}
} else {
expect(r.recoveries).toEqual({});
expect(r.failures).toHaveLength(1);
expect(r.failures[0].code).toBe(
{
slip: 'lost_grasp',
jam: 'joint_stall',
navigation: 'navigation_timeout',
unreachable: 'unreachable',
overspeed: 'joint_velocity',
}[fault],
);
}
if (fault === 'slip') {
expect(Math.max(...r.trace.map((s) => s.transported))).toBeGreaterThan(0.12);
expect(r.transported).toBe(0);
}
} finally {
await page.evaluate(() => window.lekiwiAgent.dispose());
}
});
}
for (const goal of [
[0.237, 0.565, 0.128],
[0.277, 0.665, 0.128],
]) {
test(`真实 WASM 受限目标角点 ${goal.slice(0, 2).join(',')}(非任意目标泛化)`, async ({
page,
}, info) => {
await page.goto('/physics/agent.html');
await page.waitForFunction(() => Boolean(window.lekiwiAgent));
await page.evaluate(
(url) => window.lekiwiAgent.boot(url),
`/@fs${resolve('build/lekiwi/lekiwi-v1.zip')}`,
);
try {
const r = await page.evaluate(
(goal) => window.lekiwiAgent.task(0, undefined, { goal }),
goal,
);
await writeFile(info.outputPath('goal-evidence.json'), JSON.stringify(r, null, 2));
expect(r.state, r.error).toBe('succeeded');
expect(r.goal).toEqual(goal);
expect(r.succeeded).toBe(true);
expect(r.transported).toBeGreaterThanOrEqual(0.5);
expect(Math.hypot(...r.sample.object.map((v, i) => v - goal[i]))).toBeLessThan(0.04);
} finally {
await page.evaluate(() => window.lekiwiAgent.dispose());
}
});
}