feat: release v1.0.2 LeKiwi 语言控制与网站嵌入
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) (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
集成服务器托管模型、自然语言移动与有界抓放、内置 LeKiwi URL 导入和双摄像头;同步部署契约与指定域名 iframe 白名单,保留原有物理安全、会话及调用预算防护。 更新 npm 包及锁文件版本、CHANGELOG 与发布文档。提交前 typecheck、120 项定向前端测试和 44 项后端测试通过(3 项可选跳过);真实 v2 云模型抓放仍待单独验收,不包含运行密钥或构建产物。
This commit is contained in:
@@ -1,70 +1,32 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { resolve } from 'node:path';
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
import { collectRobotResults, runWebsiteCommand } from './website.helpers';
|
||||
|
||||
test('主工作台:A 导入、mock 单技能暂停/继续、物理成功及证据导出', async ({ page }, info) => {
|
||||
const errors: string[] = [];
|
||||
let modelRequests = 0;
|
||||
page.on('pageerror', (e) => errors.push(e.message));
|
||||
page.on('request', (r) => {
|
||||
if (/\/api\/decision\/v1\/(plan|decide)$/.test(r.url())) modelRequests++;
|
||||
});
|
||||
test('主工作台:加载预设、语言命名目标及连续自由坐标抓放', async ({ page }, info) => {
|
||||
await collectRobotResults(page);
|
||||
await page.goto('/');
|
||||
await page
|
||||
.locator('input[type="file"]')
|
||||
.first()
|
||||
.setInputFiles(resolve('build/lekiwi/lekiwi-v1.zip'));
|
||||
const dialog = page.getByRole('dialog', { name: '配置 URDF 仿真组件' });
|
||||
await expect(dialog).toBeVisible({ timeout: 30000 });
|
||||
await dialog.getByLabel('URDF 机器人 profile').selectOption('lekiwi-v1');
|
||||
await dialog.getByRole('button', { name: '转换并加载' }).click();
|
||||
await expect(page.getByRole('button', { name: '▶ 播放' })).toBeEnabled({ timeout: 60000 });
|
||||
await page.getByRole('tab', { name: '控制台', exact: true }).click();
|
||||
await page.getByRole('button', { name: 'LeKiwi 智能抓放', exact: true }).click();
|
||||
const panel = page.getByLabel('LeKiwi 智能抓放任务', { exact: true });
|
||||
await expect(panel).toContainText('MOCK(不调用模型 API)');
|
||||
await panel.getByRole('button', { name: '加载 A 任务场景', exact: true }).click();
|
||||
await expect(panel).toContainText('A 抓放场景已加载并暂停', { timeout: 60000 });
|
||||
await panel.getByRole('button', { name: '单技能步进', exact: true }).click();
|
||||
const status = panel.getByTestId('agent-task-state');
|
||||
await expect(status).toContainText('任务已暂停', { timeout: 60000 });
|
||||
await expect(status).toContainText('当前技能:open');
|
||||
await expect(status).toContainText('Jev 1/60');
|
||||
await panel.getByRole('button', { name: '继续任务', exact: true }).click();
|
||||
await expect(status).toContainText('物理验收成功', { timeout: 180000 });
|
||||
await expect(status).toContainText('Jev 11/60');
|
||||
const download = page.waitForEvent('download');
|
||||
await panel.getByRole('button', { name: '导出任务证据', exact: true }).click();
|
||||
const downloaded = await download;
|
||||
const evidence = JSON.parse(await readFile((await downloaded.path())!, 'utf8'));
|
||||
await writeFile(
|
||||
info.outputPath('workbench-physical-evidence.json'),
|
||||
JSON.stringify(evidence, null, 2),
|
||||
await page.getByRole('button', { name: '机器人语言控制', exact: true }).click();
|
||||
const panel = page.getByLabel('机器人语言控制', { exact: true });
|
||||
await expect(panel.locator('input[type=password], details')).toHaveCount(0);
|
||||
await panel.getByRole('button', { name: '载入预设场景' }).click();
|
||||
await expect(panel.getByRole('status')).toContainText('预设已载入并暂停', { timeout: 90000 });
|
||||
const first = await runWebsiteCommand(page, '把方块搬到 B 区', info, 'named-target');
|
||||
expect(first.goal).toEqual([0.257, 0.75, 0.128]);
|
||||
expect(first.sample.onGoalSupport).toBe(true);
|
||||
expect(first.transported).toBeGreaterThan(0.7);
|
||||
expect(first.llmCalls).toBe(2);
|
||||
expect(first.jevCalls).toBe(14);
|
||||
expect(first.qualityScore).toBe(75);
|
||||
const second = await runWebsiteCommand(
|
||||
page,
|
||||
'把方块搬到 (0.25,0.50) 米',
|
||||
info,
|
||||
'coordinate-target',
|
||||
);
|
||||
expect(evidence.mode).toBe('mock');
|
||||
expect(evidence.succeeded).toBe(true);
|
||||
expect(evidence.transported).toBeGreaterThanOrEqual(0.5);
|
||||
expect(evidence.sample.onGoalSupport).toBe(true);
|
||||
expect(modelRequests).toBe(0);
|
||||
expect(errors).toEqual([]);
|
||||
await page.screenshot({ path: info.outputPath('agent-workbench.png') });
|
||||
await panel.getByRole('button', { name: '重置任务场景', exact: true }).click();
|
||||
await expect(panel.getByTestId('agent-task-state')).toHaveCount(0, { timeout: 60000 });
|
||||
await panel.getByLabel('目标 Y', { exact: true }).fill('0.617');
|
||||
await panel.getByRole('button', { name: '单技能步进', exact: true }).click();
|
||||
await expect(status).toContainText('任务已暂停', { timeout: 60000 });
|
||||
const changedDownload = page.waitForEvent('download');
|
||||
await panel.getByRole('button', { name: '导出任务证据', exact: true }).click();
|
||||
const changed = JSON.parse(await readFile((await (await changedDownload).path())!, 'utf8'));
|
||||
expect(changed.goal).toEqual([0.257, 0.617, 0.128]);
|
||||
expect(changed.runId).not.toBe(evidence.runId);
|
||||
expect(changed.sample.time).toBeLessThan(2.01);
|
||||
expect(changed.sample.object[1]).toBeLessThan(0.02); // New source episode, not the old placed cube.
|
||||
await writeFile(info.outputPath('edited-goal-episode.json'), JSON.stringify(changed, null, 2));
|
||||
await panel.getByLabel('目标 Y', { exact: true }).fill('0.615');
|
||||
await expect(status).toContainText('已取消');
|
||||
await expect(status).toContainText('目标编辑使旧计划失效');
|
||||
expect(modelRequests).toBe(0);
|
||||
expect(errors).toEqual([]);
|
||||
expect(second.goal).toEqual([0.25, 0.5, 0.128]);
|
||||
expect(second.sample.time).toBeGreaterThan(first.sample.time);
|
||||
expect(second.transported).toBeGreaterThan(0.2);
|
||||
expect(second.runId).not.toBe(first.runId);
|
||||
await expect(page.getByRole('button', { name: '强化学习任务', exact: true })).toBeVisible();
|
||||
await page.screenshot({ path: info.outputPath('language-workbench.png') });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user