fix: release v1.0.3 预设渲染与语言搬运监督修复
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
This commit is contained in:
@@ -30,3 +30,39 @@ test('主工作台:加载预设、语言命名目标及连续自由坐标抓
|
||||
await expect(page.getByRole('button', { name: '强化学习任务', exact: true })).toBeVisible();
|
||||
await page.screenshot({ path: info.outputPath('language-workbench.png') });
|
||||
});
|
||||
|
||||
test.describe('预设画布高 DPI 回归', () => {
|
||||
test.use({ deviceScaleFactor: 2 });
|
||||
test('主画布不被 DPR 放大裁切,双相机共用高分辨率绘图缓冲', async ({ page }) => {
|
||||
let inference = 0;
|
||||
await page.route('**/api/decision/v1/**', async (route) => {
|
||||
if (/\/(command|plan|decide|test)$/.test(new URL(route.request().url()).pathname)) {
|
||||
inference++;
|
||||
await route.abort();
|
||||
} else await route.continue();
|
||||
});
|
||||
await page.goto('/');
|
||||
await page.getByRole('tab', { name: '控制台', exact: true }).click();
|
||||
await page.getByRole('button', { name: '机器人语言控制', exact: true }).click();
|
||||
const panel = page.getByLabel('机器人语言控制', { exact: true });
|
||||
await panel.getByRole('button', { name: '载入预设场景' }).click();
|
||||
await expect(panel.getByRole('status')).toContainText('预设已载入并暂停', { timeout: 90000 });
|
||||
for (const name of ['腕部摄像头', '前置摄像头']) {
|
||||
await page.getByRole('combobox', { name: '摄像头视角' }).selectOption({ label: name });
|
||||
const size = await page
|
||||
.locator('canvas')
|
||||
.first()
|
||||
.evaluate((canvas: HTMLCanvasElement) => ({
|
||||
css: [canvas.clientWidth, canvas.clientHeight],
|
||||
host: [canvas.parentElement!.clientWidth, canvas.parentElement!.clientHeight],
|
||||
pixels: [canvas.width, canvas.height],
|
||||
}));
|
||||
expect(size.css).toEqual(size.host);
|
||||
for (let i = 0; i < 2; i++) {
|
||||
expect(size.pixels[i] / size.css[i]).toBeGreaterThanOrEqual(1.74);
|
||||
expect(size.pixels[i] / size.css[i]).toBeLessThanOrEqual(2);
|
||||
}
|
||||
}
|
||||
expect(inference).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { loadWebsiteRobot, runWebsiteCommand } from './website.helpers';
|
||||
import { collectRobotResults, loadWebsiteRobot, runWebsiteCommand } from './website.helpers';
|
||||
|
||||
test('显式授权:公网内置模型,前进/转向/抓放,无手填密钥或自动重试', async ({ page }, info) => {
|
||||
test.skip(process.env.CADWORLD_LIVE_API !== '1', '仅经用户授权后运行,会消耗服务器公共额度');
|
||||
test.skip(
|
||||
process.env.CADWORLD_LIVE_API !== '1' || process.env.CADWORLD_LIVE_PRESET === '1',
|
||||
'仅经用户授权后运行;预设专项测试不重复执行运动测试',
|
||||
);
|
||||
test.setTimeout(360000);
|
||||
const calls = { command: 0, plan: 0, decide: 0, blocked: 0 };
|
||||
let csrf = '',
|
||||
@@ -86,3 +89,87 @@ test('显式授权:公网内置模型,前进/转向/抓放,无手填密钥
|
||||
}
|
||||
expect(cleanup).toBe(true);
|
||||
});
|
||||
|
||||
test('显式授权:空工作台默认预设指令完成真实模型抓放', async ({ page }, info) => {
|
||||
test.skip(
|
||||
process.env.CADWORLD_LIVE_API !== '1' || process.env.CADWORLD_LIVE_PRESET !== '1',
|
||||
'仅在显式选择预设专项实测时调用付费 API',
|
||||
);
|
||||
test.setTimeout(360000);
|
||||
const calls = { command: 0, plan: 0, decide: 0, blocked: 0 };
|
||||
let csrf = '',
|
||||
cleanup = false;
|
||||
const captures: Promise<void>[] = [];
|
||||
page.on('response', (response) => {
|
||||
if (response.url().endsWith('/session') && response.request().method() === 'POST')
|
||||
captures.push(
|
||||
response.json().then((value) => {
|
||||
csrf = value.csrfToken;
|
||||
}),
|
||||
);
|
||||
});
|
||||
await page.route('**/api/decision/v1/**', async (route) => {
|
||||
const endpoint = new URL(route.request().url()).pathname.split('/').at(-1);
|
||||
if (endpoint === 'command' || endpoint === 'plan' || endpoint === 'decide') {
|
||||
if (calls[endpoint] >= { command: 1, plan: 1, decide: 13 }[endpoint]) {
|
||||
calls.blocked++;
|
||||
await route.abort();
|
||||
return;
|
||||
}
|
||||
calls[endpoint]++;
|
||||
} else if (endpoint === 'test') {
|
||||
calls.blocked++;
|
||||
await route.abort();
|
||||
return;
|
||||
}
|
||||
await route.continue();
|
||||
});
|
||||
try {
|
||||
await collectRobotResults(page);
|
||||
await page.goto('/');
|
||||
await page.getByRole('tab', { name: '控制台', exact: true }).click();
|
||||
await page.getByRole('button', { name: '机器人语言控制', exact: true }).click();
|
||||
const panel = page.getByLabel('机器人语言控制', { exact: true });
|
||||
await panel.getByRole('button', { name: '载入预设场景' }).click();
|
||||
await expect(panel.getByRole('status')).toContainText('预设已载入并暂停', { timeout: 120000 });
|
||||
await expect(panel.getByRole('textbox', { name: '机器人指令' })).toHaveValue('把方块搬到 B 区');
|
||||
const result = await runWebsiteCommand(page, '把方块搬到 B 区', info, 'live-default-preset');
|
||||
expect(result.goal).toEqual([0.257, 0.75, 0.128]);
|
||||
expect(result.transported).toBeGreaterThan(0.7);
|
||||
expect(result.sample.onGoalSupport).toBe(true);
|
||||
expect(result.llmCalls).toBe(2);
|
||||
expect(result.jevCalls).toBe(14);
|
||||
expect(calls).toEqual({ command: 1, plan: 1, decide: 13, blocked: 0 });
|
||||
await page.screenshot({ path: info.outputPath('live-default-preset.png') });
|
||||
} finally {
|
||||
await Promise.all(captures);
|
||||
if (csrf)
|
||||
cleanup = await page
|
||||
.evaluate(
|
||||
async (token) =>
|
||||
(
|
||||
await fetch('/api/decision/v1/session', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': token },
|
||||
body: '{}',
|
||||
})
|
||||
).status === 200,
|
||||
csrf,
|
||||
)
|
||||
.catch(() => false);
|
||||
await writeFile(
|
||||
info.outputPath('live-default-summary.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
calls,
|
||||
sessionDestroyed: cleanup,
|
||||
maximumUpstreamCalls: { llm: 2, jev: 14 },
|
||||
retries: 0,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
expect(cleanup).toBe(true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user