docs: 交付文档、维护指引与端到端回归
补齐 README、开发计划、维护交接与 E2E 用例,执行最终验收。
This commit is contained in:
1 parent
5be5ca3376
commit
308332eb94
216 files changed
+37038
No files matched your search
@@ -0,0 +1,26 @@
|
||||
import { test, expect, channels, chatsWithAgent, setAlwaysClosed, setAlwaysOpen, unique, AI_REPLY } from '@e2e'
|
||||
|
||||
// Changes the org's business hours, so it runs in the serial `org` project and
|
||||
// reopens the org afterwards (setup leaves it open 24/7).
|
||||
|
||||
test.describe('outside business hours', () => {
|
||||
test.use({ agentSettings: { transferToHuman: true } })
|
||||
|
||||
test.afterEach(async ({ adminApi, org }) => { await setAlwaysOpen(adminApi, org.orgId) })
|
||||
|
||||
test('a customer asking for a person is told the team will follow up, and the chat waits in the team\'s queue @handover', async ({ agent, llm, adminApi, request, org, handoverTeam }) => {
|
||||
await setAlwaysClosed(adminApi, org.orgId)
|
||||
await llm.script(agent, (s) => s.otherwise().handOver('We are closed now; the team will get back to you.'))
|
||||
|
||||
const chat = (await channels.WhatsApp({ api: adminApi, request, agentId: agent.id })).chatWith(unique('Nora'))
|
||||
await chat.send('I need to talk to someone')
|
||||
await expect.poll(() => chat.replies(), AI_REPLY).toEqual(['We are closed now; the team will get back to you.'])
|
||||
|
||||
// Queued for the team, unclaimed — whoever opens up next picks it up.
|
||||
const [conversation] = await chatsWithAgent(adminApi, agent.id)
|
||||
expect(conversation).toMatchObject({ status: 'transferred', group_id: (await handoverTeam()).groupId, user_id: null })
|
||||
// The reply was written knowing the team is closed.
|
||||
const prompts = (await llm.requests(agent)).map((r) => r.lastUser).join('\n')
|
||||
expect(prompts).toContain('Currently within business hours: False')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import { test, expect, env, unique, AI_REPLY } from '@e2e'
|
||||
|
||||
test.describe('attachments', () => {
|
||||
test.use({ agentSettings: { transferToHuman: true, allowAttachments: true } })
|
||||
|
||||
test('a customer sends a file to the teammate, who can open it — and only through a signed link @handover', async ({ agent, widget, inbox, llm, request }) => {
|
||||
await llm.script(agent, (s) => s.otherwise().handOver('Let me connect you with a teammate.'))
|
||||
await widget.embed()
|
||||
await widget.open()
|
||||
await widget.send('I need a person')
|
||||
await widget.shareContactDetails()
|
||||
await inbox.goto()
|
||||
await inbox.openConversationWith(widget.customer.name)
|
||||
await inbox.takeOver()
|
||||
await inbox.reply('Please send me the receipt.')
|
||||
await expect(widget.lastAgentMessage()).toHaveText('Please send me the receipt.', AI_REPLY)
|
||||
|
||||
const content = `Receipt ${unique('R')} — total 42.00`
|
||||
await widget.sendFile({ name: 'receipt.txt', mimeType: 'text/plain', content }, 'Here it is')
|
||||
|
||||
const link = inbox.attachment('receipt.txt')
|
||||
await expect(link).toBeVisible(AI_REPLY)
|
||||
const href = await link.getAttribute('href')
|
||||
expect((await (await inbox.page.request.get(href!)).text())).toBe(content)
|
||||
|
||||
// The stored file is not reachable without the signature.
|
||||
const unsigned = new URL(href!, 'http://x').pathname
|
||||
expect((await request.get(`${env.backendUrl}${unsigned}`)).status()).toBe(403)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import { test, expect, expectUnchanged, AI_REPLY } from '@e2e'
|
||||
|
||||
test.describe('human handover', () => {
|
||||
test.use({ agentSettings: { transferToHuman: true } })
|
||||
|
||||
test('a customer asks for a person, the teammate\'s reply reaches them, and the AI stays out of it @smoke @handover', async ({ agent, widget, inbox, llm }) => {
|
||||
await llm.script(agent, (s) => s
|
||||
.when(/human|person/i).handOver('Let me connect you with a teammate.')
|
||||
.otherwise().reply('Happy to help!'))
|
||||
|
||||
await widget.embed()
|
||||
await widget.open()
|
||||
await widget.send('I want to talk to a human')
|
||||
await widget.shareContactDetails()
|
||||
|
||||
await inbox.goto()
|
||||
await inbox.openConversationWith(widget.customer.name)
|
||||
await inbox.takeOver()
|
||||
await inbox.reply('Hi, this is Sam. How can I help?')
|
||||
await expect(widget.lastAgentMessage()).toHaveText('Hi, this is Sam. How can I help?', AI_REPLY)
|
||||
|
||||
const modelCalls = (await llm.requests(agent)).length
|
||||
await widget.send('My parcel never arrived')
|
||||
await expect(inbox.lastCustomerMessage()).toContainText('My parcel never arrived')
|
||||
// A person owns the chat now: the model is not asked, and no bot answer appears.
|
||||
await expectUnchanged('model calls after takeover', async () => (await llm.requests(agent)).length)
|
||||
expect((await llm.requests(agent))).toHaveLength(modelCalls)
|
||||
await expect(widget.lastAgentMessage()).toHaveText('Hi, this is Sam. How can I help?')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
import { test, expect, channels, chatsWithAgent, createGroup, createUser, unique, AI_REPLY } from '@e2e'
|
||||
|
||||
test('with nobody from the team online, the customer is told the team will follow up, and the chat waits in its queue @handover', async ({ makeAgent, llm, adminApi, request }) => {
|
||||
// A team whose only member has never signed in, so nobody is online.
|
||||
const id = unique('offline')
|
||||
const member = await createUser(adminApi, { name: `Offline ${id}`, email: `${id}@e2e.example.com`, password: 'E2e-Offline-Passw0rd!', role: 'Agent' })
|
||||
const groupId = await createGroup(adminApi, `Team ${id}`, [member])
|
||||
const agent = await makeAgent({ transferToHuman: true }, [groupId])
|
||||
await llm.script(agent, (s) => s.otherwise().handOver('Our team will get back to you shortly.'))
|
||||
|
||||
const chat = (await channels.WhatsApp({ api: adminApi, request, agentId: agent.id })).chatWith(unique('Nora'))
|
||||
await chat.send('I need to talk to someone')
|
||||
await expect.poll(() => chat.replies(), AI_REPLY).toEqual(['Our team will get back to you shortly.'])
|
||||
|
||||
const [conversation] = await chatsWithAgent(adminApi, agent.id)
|
||||
expect(conversation).toMatchObject({ status: 'transferred', group_id: groupId, user_id: null })
|
||||
// The reply was written knowing nobody is online.
|
||||
const prompts = (await llm.requests(agent)).map((r) => r.lastUser).join('\n')
|
||||
expect(prompts).toContain('(0 online)')
|
||||
})
|
||||
Reference in new issue
Block a user