Files
2026-07-13 13:12:33 +08:00

102 lines
3.6 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test'
const CONTROL_URL = '/control/'
const SESSION_KEY = 'agent:main:webchat:e2e-user-newlines'
async function seedMultilineUserHistory(page: Page) {
await page.route('**/api/approvals', route => route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ pending: [] }),
}))
await page.routeWebSocket(/\/ws$/, ws => {
ws.send(JSON.stringify({ type: 'event', event: 'connect.challenge', payload: {} }))
ws.onMessage(message => {
try {
const frame = JSON.parse(String(message))
if (frame?.type !== 'req') return
if (frame.method === 'connect') {
ws.send(JSON.stringify({
protocol: 3,
policy: { tick_interval_ms: 30000 },
}))
return
}
const payloads: Record<string, unknown> = {
'agents.list': { agents: [] },
'chat.history': {
messages: [
{
role: 'user',
text: '你好~\n我测试一下换行功能~\n你好~\n我测试一下换行功能~',
id: 'msg-user-newlines',
timestamp: Math.floor(Date.now() / 1000) - 60,
},
{
role: 'system',
text: '连接提示第一行\n连接提示第二行',
id: 'msg-system-newlines',
timestamp: Math.floor(Date.now() / 1000) - 45,
},
{
role: 'error',
text: '错误详情第一行\n错误详情第二行',
id: 'msg-error-newlines',
timestamp: Math.floor(Date.now() / 1000) - 30,
},
],
has_more: false,
},
'commands.list_for_surface': { commands: [] },
'config.get': {
squilla_router: { enabled: false, rollout_phase: 'observe', tiers: {} },
permissions: {},
skills: {},
},
'sessions.list': { sessions: [], has_more: false },
'sessions.messages.subscribe': {
subscribed: true,
replay_complete: true,
current_stream_seq: 0,
run_status: 'idle',
},
'usage.status': { sessions: [] },
}
ws.send(JSON.stringify({
type: 'res',
id: frame.id,
ok: true,
payload: payloads[String(frame.method)] ?? {},
}))
} catch {}
})
})
}
test('user message bubbles preserve authored line breaks', async ({ page }) => {
await seedMultilineUserHistory(page)
await page.goto(CONTROL_URL + 'chat?session=' + encodeURIComponent(SESSION_KEY))
await page.waitForSelector('.conn-pill', { timeout: 10000 })
const bubble = page.locator('.msg-user-bubble').first()
await expect(bubble).toContainText('你好~\n我测试一下换行功能~\n你好~')
await expect(bubble).toHaveCSS('white-space', 'pre-wrap')
})
test('system and error message text preserve authored line breaks', async ({ page }) => {
await seedMultilineUserHistory(page)
await page.goto(CONTROL_URL + 'chat?session=' + encodeURIComponent(SESSION_KEY))
await page.waitForSelector('.conn-pill', { timeout: 10000 })
const systemText = page.locator('.msg-system__text').first()
await expect(systemText).toContainText('连接提示第一行\n连接提示第二行')
await expect(systemText).toHaveCSS('white-space', 'pre-wrap')
const errorText = page.locator('.msg-error-card__text').first()
await expect(errorText).toContainText('错误详情第一行\n错误详情第二行')
await expect(errorText).toHaveCSS('white-space', 'pre-wrap')
})