2026-09-14 15:40:10 +08:00
|
|
|
|
import { expect, test } from '@playwright/test';
|
|
|
|
|
|
|
2026-09-17 00:08:13 +08:00
|
|
|
|
const json = (body: unknown, status = 200) => ({
|
|
|
|
|
|
status, contentType: 'application/json', body: JSON.stringify(body),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-09-14 15:40:10 +08:00
|
|
|
|
test('待人工审批任务显示状态与确认卡编号', async ({ page }) => {
|
2026-09-17 00:08:13 +08:00
|
|
|
|
// 多智能体编排属开发/运维入口,计划员界面默认隐藏,测试显式开启
|
|
|
|
|
|
await page.addInitScript(() => localStorage.setItem('aps.devtools', '1'));
|
|
|
|
|
|
|
|
|
|
|
|
// 单个分发 handler 覆盖全部 /api/**:未登记的端点返回 404,
|
|
|
|
|
|
// 不允许任何请求穿到现场后端(dev 模式源码路径也含 /src/api/)
|
|
|
|
|
|
await page.route((url: URL) => url.pathname.startsWith('/api/'), route => {
|
|
|
|
|
|
const path = new URL(route.request().url()).pathname;
|
|
|
|
|
|
switch (path) {
|
|
|
|
|
|
case '/api/health':
|
|
|
|
|
|
return route.fulfill(json({ interfaceVersion: '1.0', authProvider: 'local', licenseProvider: 'local' }));
|
|
|
|
|
|
case '/api/auth/me':
|
|
|
|
|
|
return route.fulfill(json({
|
|
|
|
|
|
user: {
|
|
|
|
|
|
user_id: 'user-1', username: 'e2e', fullname: 'E2E', tenant_uuid: 'tenant-1',
|
|
|
|
|
|
roles: ['admin'], auth_kind: 'user',
|
|
|
|
|
|
},
|
|
|
|
|
|
provider: 'local',
|
|
|
|
|
|
license: null,
|
|
|
|
|
|
}));
|
|
|
|
|
|
case '/api/features':
|
|
|
|
|
|
return route.fulfill(json({
|
|
|
|
|
|
version: 1, source: 'default', path: '', error: null, unknown: [],
|
|
|
|
|
|
features: { mesh: { enabled: true, label: '多智能体编排' } },
|
|
|
|
|
|
}));
|
|
|
|
|
|
case '/api/workspace':
|
|
|
|
|
|
return route.fulfill(json({
|
|
|
|
|
|
projects: [],
|
|
|
|
|
|
sessions: [{
|
|
|
|
|
|
id: 'session-1', projectId: '__personal__', title: 'E2E', status: 'running',
|
|
|
|
|
|
updatedAt: '2026-09-12 10:00:00', scope: 'personal',
|
|
|
|
|
|
}],
|
|
|
|
|
|
files: [],
|
|
|
|
|
|
messages: { 'session-1': [] },
|
|
|
|
|
|
activeProjectId: '__personal__',
|
|
|
|
|
|
activeSessionId: 'session-1',
|
|
|
|
|
|
}));
|
|
|
|
|
|
case '/api/mesh/state':
|
|
|
|
|
|
return route.fulfill(json({
|
|
|
|
|
|
agents: [],
|
|
|
|
|
|
goals: [{
|
|
|
|
|
|
id: 'goal-1',
|
|
|
|
|
|
title: '锐扬排产全流程',
|
|
|
|
|
|
template: 'aps-full-flow',
|
|
|
|
|
|
status: 'ATTENTION',
|
|
|
|
|
|
createdBy: 'USER',
|
|
|
|
|
|
runId: 'run-1',
|
|
|
|
|
|
createdAt: '2026-09-12 10:00:00',
|
|
|
|
|
|
tasks: [{
|
|
|
|
|
|
id: 'task-1',
|
|
|
|
|
|
goalId: 'goal-1',
|
|
|
|
|
|
key: 'schedule',
|
|
|
|
|
|
title: '生成一版试排',
|
|
|
|
|
|
intent: 'flex.schedule',
|
|
|
|
|
|
role: 'scheduler',
|
|
|
|
|
|
params: {},
|
|
|
|
|
|
dependsOn: [],
|
|
|
|
|
|
status: 'AWAITING_APPROVAL',
|
|
|
|
|
|
assigneeAgentId: 'agent-1',
|
|
|
|
|
|
assigneeName: '柔性排产智能体-1',
|
|
|
|
|
|
attempts: 1,
|
|
|
|
|
|
result: '等待人工审批后继续',
|
|
|
|
|
|
error: null,
|
|
|
|
|
|
confirmationIds: ['confirm-123', 'confirm-456'],
|
|
|
|
|
|
startedAt: '2026-09-12 10:00:01',
|
|
|
|
|
|
finishedAt: null,
|
|
|
|
|
|
}],
|
|
|
|
|
|
watchdog: { stallTimeoutSec: 45, maxRetries: 1 },
|
2026-09-14 15:40:10 +08:00
|
|
|
|
}],
|
2026-09-17 00:08:13 +08:00
|
|
|
|
messages: [],
|
|
|
|
|
|
watchdog: { enabled: true, stallTimeoutSec: 45, maxRetries: 1, lastTickAt: null, alerts: [] },
|
|
|
|
|
|
roleTemplates: [],
|
|
|
|
|
|
goalTemplates: [],
|
|
|
|
|
|
}));
|
|
|
|
|
|
default:
|
|
|
|
|
|
return route.fulfill(json({ detail: 'e2e stub' }, 404));
|
|
|
|
|
|
}
|
2026-09-14 15:40:10 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
await page.goto('/');
|
|
|
|
|
|
const meshButton = page.locator('button[data-tip="多智能体编排"]');
|
|
|
|
|
|
await expect(meshButton).toBeVisible();
|
|
|
|
|
|
await meshButton.click();
|
|
|
|
|
|
|
|
|
|
|
|
await expect(page.locator('.mesh-panel')).toBeVisible();
|
|
|
|
|
|
await expect(page.getByText('待人工审批', { exact: true })).toBeVisible();
|
|
|
|
|
|
const approval = page.locator('.mesh-task-approval');
|
|
|
|
|
|
await expect(approval).toContainText('confirm-123');
|
|
|
|
|
|
await expect(approval).toContainText('confirm-456');
|
|
|
|
|
|
});
|