import { expect, test } from '@playwright/test' const account = process.env.E2E_ACCOUNT || 'e2e-1785008967@local.test' const password = process.env.E2E_PASSWORD || 'Lingxi-E2E-2026!' test('知识库与逐句意图在真实页面可用', async ({ page }, testInfo) => { test.skip(testInfo.project.name !== 'desktop-chromium', '仅在桌面视口执行') const loginResponse = await page.request.post('/api/auth/login', { data: { account, password }, }) expect(loginResponse.ok()).toBeTruthy() const loginPayload = await loginResponse.json() const token = loginPayload.data.token as string const headers = { Authorization: `Bearer ${token}` } await page.goto('/login') await page.locator('input[autocomplete="username"]').fill(account) await page.locator('input[autocomplete="current-password"]').fill(password) await page.getByRole('button', { name: '登录' }).click() await expect(page).toHaveURL(/\/dashboard/) await page.goto('/knowledge') await expect(page.getByText('已分段索引', { exact: true })).toBeVisible() await expect(page.getByRole('button', { name: '上传文件' })).toBeVisible() await page.screenshot({ path: testInfo.outputPath('knowledge-index.png'), fullPage: true }) const conversationsResponse = await page.request.get('/api/conversations', { headers }) const conversations = (await conversationsResponse.json()).data.list as Array<{ id: string }> let conversationId = '' let messageId = '' let messageCount = 0 for (const conversation of conversations.slice(0, 20)) { const messagesResponse = await page.request.get( `/api/conversations/${encodeURIComponent(conversation.id)}/messages`, { headers }, ) const messages = (await messagesResponse.json()).data as Array<{ id: string sender: string type: string originalText: string intentAnalysis?: unknown }> const candidate = [...messages].reverse().find((message) => ( message.sender === 'customer' && message.type === 'text' && /[\p{L}]/u.test(message.originalText || '') )) if (candidate) { conversationId = conversation.id messageId = candidate.id messageCount = messages.length break } } expect(conversationId).not.toBe('') const aiStatusResponse = await page.request.get( `/api/conversations/${encodeURIComponent(conversationId)}/ai-status`, { headers }, ) expect(aiStatusResponse.ok()).toBeTruthy() const aiStatus = (await aiStatusResponse.json()).data expect(['not-started', 'queued', 'running', 'completed']).toContain(aiStatus.backfill.status) if (messageCount > 80) { await expect.poll(async () => { const response = await page.request.get( `/api/conversations/${encodeURIComponent(conversationId)}/ai-status`, { headers }, ) return (await response.json()).data.context.status }, { timeout: 30_000 }).toBe('ready') const readyResponse = await page.request.get( `/api/conversations/${encodeURIComponent(conversationId)}/ai-status`, { headers }, ) const readyStatus = (await readyResponse.json()).data expect(readyStatus.context.sourceMessageCount).toBeGreaterThan(0) expect(readyStatus.context.memory.summary).toBeTruthy() } const analyzeResponse = await page.request.post( `/api/conversations/${encodeURIComponent(conversationId)}/messages/${encodeURIComponent(messageId)}/analyze`, { headers, data: { force: true } }, ) expect(analyzeResponse.ok()).toBeTruthy() await page.goto(`/inbox?c=${encodeURIComponent(conversationId)}`) await expect(page.getByTestId('conversation-insight-bar')).toBeVisible() await expect(page.getByTestId('conversation-intent-toggle')).toBeVisible() await expect( page.getByRole('switch', { name: '当前会话逐句意图识别' }), ).toHaveAttribute('aria-checked', 'true') await expect.poll(() => page.getByTestId('message-intent').count()).toBeGreaterThan(0) const intentCount = await page.getByTestId('message-intent').count() const visibleIntent = page.getByTestId('message-intent').nth(intentCount - 1) await visibleIntent.scrollIntoViewIfNeeded() await expect(visibleIntent).toBeVisible() const intentSwitch = page.getByRole('switch', { name: '当前会话逐句意图识别' }) await intentSwitch.click() await expect(intentSwitch).toHaveAttribute('aria-checked', 'false') await expect(page.getByTestId('message-intent')).toHaveCount(0) await page.reload() await expect( page.getByRole('switch', { name: '当前会话逐句意图识别' }), ).toHaveAttribute('aria-checked', 'false') await page.getByRole('switch', { name: '当前会话逐句意图识别' }).click() await expect( page.getByRole('switch', { name: '当前会话逐句意图识别' }), ).toHaveAttribute('aria-checked', 'true') await expect.poll(() => page.getByTestId('message-intent').count()).toBeGreaterThan(0) await expect(page.getByText('Unexpected Application Error!', { exact: true })).toHaveCount(0) await page.screenshot({ path: testInfo.outputPath('message-intent.png'), fullPage: false }) await page.goto('/settings') await page.getByRole('button', { name: '智能回复' }).click() const globalIntentSwitch = page.getByRole('switch', { name: '逐条客户消息意图识别' }) await expect(globalIntentSwitch).toBeVisible() await globalIntentSwitch.click() await expect(globalIntentSwitch).toHaveAttribute('aria-checked', 'false') await globalIntentSwitch.click() await expect(globalIntentSwitch).toHaveAttribute('aria-checked', 'true') await expect(page.getByText('invalid input syntax for type json')).toHaveCount(0) })