docs: 交付文档、维护指引与端到端回归

补齐 README、开发计划、维护交接与 E2E 用例,执行最终验收。
This commit is contained in:
WangShen007 committed 2026-10-21 21:40:00 +08:00
1 parent 18732801b5
commit 6cd904d460
216 files changed
+37038

No files matched your search

+80
View File
@@ -0,0 +1,80 @@
import {
test, expect, connectMessenger, connectWhatsAppNumber, digits, expectUnchanged, metaVerifiesCallback, ownMetaApp,
pageChat, pastedCallback, routeToAgent, whereMetaSends, FakeExternals, WhatsAppChat, AI_REPLY,
} from '@e2e'
// A WhatsApp number or Facebook Page connected with credentials from the
// customer's OWN Meta app — the only way to try Meta's free test number. Meta
// signs that app's webhooks with its own secret, so each such account has its
// own webhook address, checked with that secret only (issue #353).
//
// Connected through the API: the org is shared, and once any test has a number
// the Integrations card offers Manage, not Connect. The card itself is covered
// by the dashboard's unit tests.
test.describe('a number or Page from the customer\'s own Meta app', () => {
test('a WhatsApp number receives messages: its webhooks are pointed at ReplyPier on connect @channels', async ({ agent, llm, adminApi, request }) => {
await llm.script(agent, (s) => s
.when(/opening hours/i).reply('We are open 9am to 5pm, Monday to Friday.')
.otherwise().reply('Happy to help!'))
const app = ownMetaApp()
const number = await connectWhatsAppNumber(adminApi, digits(15), app)
// Meta took the per-number callback, after checking it answers: nothing to paste
expect(number.account.webhook_auto_configured).toBe(true)
await routeToAgent(adminApi, number.account.id, agent.id)
const externals = new FakeExternals(request)
const chat = new WhatsAppChat(request, externals, number, 'Tess', () => whereMetaSends(externals, number.phoneNumberId, app))
await chat.send('What are your opening hours?')
await expect.poll(() => chat.replies(), AI_REPLY).toEqual(['We are open 9am to 5pm, Monday to Friday.'])
})
test('a Messenger Page receives messages once its callback URL and verify token are pasted into the app @channels', async ({ agent, llm, adminApi, request }) => {
await llm.script(agent, (s) => s.otherwise().reply('Hi! How can we help?'))
const app = ownMetaApp()
const pageId = digits(15)
const token = app.token(pageId)
const account = await connectMessenger(adminApi, pageId, token, app.secret)
await routeToAgent(adminApi, account.id, agent.id)
const url = account.webhook_url ?? ''
const verifyToken = account.webhook_verify_token ?? ''
// The customer pastes both into their app; Meta checks the address before saving
expect(await metaVerifiesCallback(request, url, verifyToken)).toBe(true)
expect(await metaVerifiesCallback(request, url, 'a-guessed-token')).toBe(false)
const chat = pageChat('Messenger', request, new FakeExternals(request), 'page', pageId, token, 'Remi', pastedCallback(url, app))
await chat.send('Hello there')
await expect.poll(() => chat.replies(), AI_REPLY).toEqual(['Hi! How can we help?'])
})
test('a wrong app secret is refused when connecting @channels', async ({ adminApi }) => {
const app = ownMetaApp()
await expect(connectWhatsAppNumber(adminApi, digits(15), { ...app, secret: 'not-the-app-secret' }))
.rejects.toThrow(/400: .*That app secret is not the one for the Meta app this token comes from/)
})
test('its address takes only its own app\'s accounts, never another app\'s number @channels @security', async ({ agent, llm, adminApi, request }) => {
await llm.script(agent, (s) => s.otherwise().reply('This should never be sent.'))
const mine = ownMetaApp()
const ourNumber = await connectWhatsAppNumber(adminApi, digits(15), mine)
const theirNumber = await connectWhatsAppNumber(adminApi, digits(15), ownMetaApp())
await routeToAgent(adminApi, theirNumber.account.id, agent.id)
const externals = new FakeExternals(request)
// Signed with our app's secret and sent to our address, but naming their number
const forged = new WhatsAppChat(request, externals, theirNumber, 'Mallory', () => whereMetaSends(externals, ourNumber.phoneNumberId, mine))
await forged.send('Hi, I am not who I say I am')
await expectUnchanged('replies on the other app\'s number', () => forged.replies())
})
test('without the app secret a Page has no address of its own @channels', async ({ adminApi }) => {
const pageId = digits(15)
const account = await connectMessenger(adminApi, pageId, ownMetaApp().token(pageId))
expect(account.webhook_url).toBeFalsy()
expect(account.webhook_verify_token).toBeFalsy()
})
})