70 lines
4.1 KiB
TypeScript
70 lines
4.1 KiB
TypeScript
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!'
|
|
const conversationId = process.env.LIVE_CONVERSATION_ID
|
|
|
|
test.describe('真实收件箱 AI 交互', () => {
|
|
test.skip(!conversationId, '需要 LIVE_CONVERSATION_ID')
|
|
|
|
test('AI 回复可以关闭、重新打开并采用到输入框', async ({ page }) => {
|
|
await page.goto('/login')
|
|
await page.locator('input[autocomplete="username"]').fill(account)
|
|
await page.locator('input[autocomplete="current-password"]').fill(password)
|
|
await page.locator('button[type="submit"]').click()
|
|
await expect(page).toHaveURL(/\/dashboard$/)
|
|
await page.goto(`/inbox?c=${encodeURIComponent(conversationId!)}`)
|
|
await expect(page.getByText('Eternity', { exact: true }).first()).toBeVisible()
|
|
await expect(page.getByText('@jsjzlkj', { exact: true }).first()).toBeVisible()
|
|
const eternityAvatar = page.locator('img[alt="Eternity"]').first()
|
|
await expect(eternityAvatar).toBeVisible()
|
|
await expect.poll(() => eternityAvatar.evaluate((image: HTMLImageElement) => image.naturalWidth)).toBeGreaterThan(0)
|
|
const insightBar = page.getByTestId('conversation-insight-bar')
|
|
await expect(insightBar).toBeVisible()
|
|
await expect(insightBar).toContainText('意向')
|
|
await expect(insightBar).toContainText(/积极|偏积极|中性|消极|愤怒|不满/)
|
|
const messageList = page.getByTestId('message-list')
|
|
await expect(messageList).not.toContainText('2026-07-27T')
|
|
await expect.poll(() => messageList.evaluate((element) =>
|
|
Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop),
|
|
)).toBeLessThanOrEqual(4)
|
|
const customerBubble = page.locator('[data-testid="message-bubble"][data-sender="customer"]')
|
|
await expect(customerBubble.first()).toHaveClass(/animate-message-in-left/)
|
|
const agentBubble = page.locator('[data-testid="message-bubble"][data-sender="agent"]')
|
|
await expect(agentBubble.first()).toHaveClass(/animate-message-in-right/)
|
|
const outgoingChineseNotes = page.getByTestId('outgoing-chinese-note')
|
|
await expect.poll(() => outgoingChineseNotes.count()).toBeGreaterThan(0)
|
|
await expect(outgoingChineseNotes.first()).toContainText('中文备注 · 仅内部可见')
|
|
await expect(outgoingChineseNotes.first()).toContainText(/[\u3400-\u9fff]/u)
|
|
await page.getByTitle('客户洞察').click()
|
|
await expect(page.getByText('成交概率', { exact: true })).toBeVisible()
|
|
await expect(page.getByText('分析可信度', { exact: true })).toBeVisible()
|
|
await expect(page.getByText('判断依据', { exact: true })).toBeVisible()
|
|
if ((page.viewportSize()?.width || 1280) < 768) {
|
|
await page.getByRole('button', { name: '返回会话' }).click()
|
|
}
|
|
await expect(page.getByText('AI 智能回复', { exact: true })).toBeVisible()
|
|
|
|
await page.getByTitle('关闭 AI 智能回复').click()
|
|
await expect(page.getByRole('button', { name: 'AI 智能回复', exact: true })).toBeVisible()
|
|
await expect(page.getByTitle('关闭 AI 智能回复')).toHaveCount(0)
|
|
|
|
await page.getByRole('button', { name: 'AI 智能回复', exact: true }).click()
|
|
await page.getByRole('button', { name: '生成回复建议', exact: true }).click()
|
|
const adoptButtons = page.getByRole('button', { name: '采用', exact: true })
|
|
await expect(adoptButtons).toHaveCount(3, { timeout: 30_000 })
|
|
const translationPreviews = page.getByTestId('ai-reply-translation')
|
|
await expect(translationPreviews).toHaveCount(3)
|
|
await expect(translationPreviews.first()).toContainText(/[\u3400-\u9fff]/u)
|
|
await expect(translationPreviews.first()).toContainText('中文参考 · 不会发送')
|
|
await adoptButtons.first().click()
|
|
|
|
const composer = page.getByPlaceholder('输入回复内容,Enter 发送,Shift+Enter 换行')
|
|
await expect(composer).not.toHaveValue('')
|
|
const adoptedReply = await composer.inputValue()
|
|
expect(adoptedReply).toMatch(/[A-Za-z]/)
|
|
expect(adoptedReply).not.toMatch(/[\u3400-\u9fff]/u)
|
|
await expect(page.getByRole('button', { name: 'AI 智能回复', exact: true })).toBeVisible()
|
|
})
|
|
})
|