63 lines
3.2 KiB
TypeScript
63 lines
3.2 KiB
TypeScript
import { test, expect, installShopify, uninstallShopify, useShopForAgent, FakeExternals, seedOrg, unique, AI_REPLY } from '@e2e'
|
|
|
|
// Linking a shop sets the org's domain, so this runs in the serial `org` project and
|
|
// uninstalls (restoring the domain) afterwards.
|
|
|
|
test.describe('Shopify', () => {
|
|
let shop: string
|
|
let shopId: string | undefined
|
|
|
|
test.beforeEach(async ({ agent, adminApi }) => {
|
|
shop = `${unique('e2e-shop')}.myshopify.com`
|
|
shopId = await installShopify(adminApi, shop)
|
|
await useShopForAgent(adminApi, agent.id, shopId)
|
|
})
|
|
|
|
test.afterEach(async ({ adminApi, org }) => {
|
|
if (shopId) await uninstallShopify(adminApi, shopId, org.orgId, seedOrg.domain)
|
|
})
|
|
|
|
test('a customer asks where their order is and the AI answers from the shop @integrations', async ({ agent, widget, llm, request }) => {
|
|
const email = widget.customer.email
|
|
await llm.script(agent, (s) => s
|
|
.when(/1042/).callTool('get_order_status', { order_number: '#1042', customer_email: email })
|
|
.thenReply('Order #1042 has shipped with UPS.')
|
|
.otherwise().reply('Happy to check — what is your order number and email?'))
|
|
await widget.embed()
|
|
await widget.open()
|
|
await widget.send('Where is my order?')
|
|
await expect(widget.lastAgentMessage()).toHaveText('Happy to check — what is your order number and email?', AI_REPLY)
|
|
await widget.send(`It is 1042, ${email}`)
|
|
await expect(widget.lastAgentMessage()).toHaveText('Order #1042 has shipped with UPS.', AI_REPLY)
|
|
|
|
// The shop was searched for this customer's order with the token its install
|
|
// was granted, then the order itself was read.
|
|
const externals = new FakeExternals(request)
|
|
const [install] = await externals.calls('shopify', 'access_token', { contains: shop })
|
|
const [search, read] = await externals.calls('shopify', 'graphql.json', { contains: shop })
|
|
expect(search.headers['x-shopify-access-token']).toBe((install.response as { access_token: string }).access_token)
|
|
expect(search.body).toMatchObject({ variables: { query: `email:${email.toLowerCase()} AND name:1042` } })
|
|
expect(read.body).toMatchObject({ query: expect.stringContaining('query GetOrder') })
|
|
|
|
// What the model was told: the shipment and its tracking number.
|
|
const toolResults = (await llm.requests(agent)).flatMap((r) => r.toolResults).join('\n')
|
|
expect(toolResults).toContain('FULFILLED')
|
|
expect(toolResults).toMatch(/1ZE2E\d+/)
|
|
})
|
|
|
|
test('an order lookup without the customer\'s email never reaches the shop @integrations', async ({ agent, widget, llm, request }) => {
|
|
await llm.script(agent, (s) => s
|
|
.otherwise().callTool('get_order_status', { order_number: '1042', customer_email: '' })
|
|
.thenReply('Could you tell me the email you ordered with?'))
|
|
await widget.embed()
|
|
await widget.open()
|
|
await widget.send('Where is order 1042?')
|
|
await expect(widget.lastAgentMessage()).toHaveText('Could you tell me the email you ordered with?', AI_REPLY)
|
|
|
|
const externals = new FakeExternals(request)
|
|
expect(await externals.calls('shopify', 'graphql.json', { contains: shop })).toHaveLength(0)
|
|
const toolResults = (await llm.requests(agent)).flatMap((r) => r.toolResults).join('\n')
|
|
expect(toolResults).toContain('requires_user_input')
|
|
})
|
|
})
|