aps-agent/apps/web/e2e/chat-numbering.spec.ts

85 lines
3.2 KiB
TypeScript
Raw Normal View History

// ============================================================
// 计划员聊天编号回归:模型常把多个选项都写成 1.,界面必须连续显示 1/2/3。
// 全部离线:只桩会话历史,不连接现场后端。
// ============================================================
import { test, expect, type Page } from '@playwright/test';
const json = (body: unknown, status = 200) => ({
status, contentType: 'application/json', body: JSON.stringify(body),
});
async function stubApi(page: Page): Promise<void> {
const message = {
role: 'agent',
text: [
'接下来你有三个选择:',
'',
'1. 修改现有订单',
'',
'把数量改成 50 套、交期改成 10 月 14 日。',
'',
'1. 新增一张急单',
'',
'换一个新订单号,按你给的数量和交期录入。',
'',
'1. 直接使用已有急单',
'',
'按现有急单的交期评估插入后的影响。',
].join('\n'),
};
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: {} }));
case '/api/workspace':
return route.fulfill(json({
projects: [],
sessions: [{
id: 'session-1', projectId: '__personal__', title: '编号测试', status: 'done',
updatedAt: '2026-09-18 10:00:00', scope: 'personal',
}],
files: [],
messages: { 'session-1': [message] },
activeProjectId: '__personal__', activeSessionId: 'session-1',
}));
case '/api/sessions/session-1/messages':
return route.fulfill(json({ sessionId: 'session-1', messages: [message] }));
case '/api/skills':
return route.fulfill(json({ skills: [], skillsDir: '', mode: 'web' }));
case '/api/skills/health':
return route.fulfill(json({ health: [] }));
default:
return route.fulfill(json({ detail: 'e2e stub' }, 404));
}
});
}
test('多个备选项即使都写成 1.,页面也连续显示 1、2、3', async ({ page }) => {
await stubApi(page);
await page.goto('/');
const chat = page.locator('section.chat[data-session-ready="true"]');
await expect(chat).toBeVisible({ timeout: 30_000 });
const items = chat.locator('.chat-md ol.md-list > li');
await expect(items).toHaveCount(3);
await expect(items.nth(0)).toContainText('修改现有订单');
await expect(items.nth(1)).toContainText('新增一张急单');
await expect(items.nth(2)).toContainText('直接使用已有急单');
const values = await items.evaluateAll(nodes => nodes.map(node => (node as HTMLLIElement).value));
expect(values).toEqual([1, 2, 3]);
});