// tests/bot.test.js
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { afterEach, expect, test } from 'vitest'
import { assertTranscript, createTestBot, parseTranscript, redactTranscript, serializeTranscript } from '@botmesh/core/testing'
import createBot, { setupBot } from '../bot.js'
const GOLDEN = new URL('./golden/order.json', import.meta.url)
// 1. A fresh bot per test, on a MockProvider: no phone, no network
let running
async function startBot() {
const t = await createTestBot()
setupBot(t.bot)
running = t.bot
return t
}
afterEach(async () => {
await running?.stop()
})
test('greets and points to the order flow', async () => {
const { chat } = await startBot()
await chat.send('hello')
await chat.expectReply('🍕 Welcome to Pizza Bot! Send "order" to start.')
await chat.send('what?')
await chat.expectReply('Send "order" to buy a pizza.')
})
// 2. Drive a whole conversation, including a validation error
test('orders two pepperoni', async () => {
const { chat } = await startBot()
await chat.send('order')
await chat.expectReply('Which pizza? margherita ($9) or pepperoni ($11)')
await chat.send('Pepperoni')
await chat.expectReply('How many? (1-9)')
await chat.send('lots')
await chat.expectReply('❌ Send a number from 1 to 9.')
await chat.send('2')
await chat.expectReply('✅ 2 × pepperoni: $22. Thanks!')
await chat.expectNoReply()
// 3. Save it as the golden transcript the first time (or with UPDATE_GOLDEN=1)
if (!existsSync(GOLDEN) || process.env.UPDATE_GOLDEN) {
mkdirSync(new URL('./golden/', import.meta.url), { recursive: true })
writeFileSync(GOLDEN, serializeTranscript(redactTranscript(chat.transcript({ name: 'order' }))))
}
})
// 4. Commands always win over an active conversation
test('/cancel leaves the flow', async () => {
const { chat } = await startBot()
await chat.send('order')
await chat.expectReply('Which pizza?')
await chat.send('/cancel')
await chat.expectReply(/cancelled/)
await chat.send('2')
await chat.expectReply('Send "order" to buy a pizza.')
expect(chat.replies()).toHaveLength(3)
})
// 5. Replay the golden transcript against the real factory: any changed reply fails with a diff
test('the order conversation matches its golden transcript', async () => {
const golden = parseTranscript(readFileSync(GOLDEN, 'utf8'))
await assertTranscript(golden, createBot)
})