apps/web/src/lib/salesConfirmation.test.ts

1import { expect, test } from 'bun:test'
2import { isHandoffCancellation } from '@local/ai/components/workflows'
3import { HANDOFF_CONSENT } from '@local/config/ai-consent'
4import { acceptedSalesOffer } from './aiFlows'
5import { verifiedHandoffReply } from './aiHandoff'
6import {
7	commercialRequestDetails,
8	confirmedSalesRequest,
9	salesAcceptanceReply,
10} from './salesConfirmation'
11
12test('the confirmation retains the stated exhibition objective and includes the current recipient', () => {
13	const details = commercialRequestDetails(
14		[{ role: 'user', text: 'We are looking to exhibit to meet HR buyers.' }],
15		'Yes, please send it.',
16	)
17	expect(details).toBe('We are looking to exhibit to meet HR buyers.')
18	expect(commercialRequestDetails([], 'yes please send it')).toBeUndefined()
19	const summary = salesAcceptanceReply(
20		{
21			name: 'Jordan',
22			email: 'jordan@example.org',
23			role: 'Director',
24			company: 'Example',
25		},
26		'paris',
27		false,
28		undefined,
29		details,
30	)
31	expect(summary).toContain('meet HR buyers')
32	expect(summary).toContain('jordan@example.org')
33})
34
35const offer = [
36	{
37		role: 'assistant' as const,
38		text:
39			'Yes, you can sponsor Paris. Would you like our sales team to get in touch?',
40	},
41]
42const profile = {
43	name: 'Jordan UAT',
44	email: 'jordan.uat@example.com',
45	company: 'Example',
46	role: 'Director',
47}
48test('typo acceptance progresses the offer but does not authorize dispatch', () => {
49	for (const text of [
50		'yes pleas1',
51		'yes pleas',
52		'yes please',
53		'yes',
54		'yes pls',
55		'yes get in touch',
56	]) {
57		expect(acceptedSalesOffer(offer, text)).toBe(true)
58		expect(confirmedSalesRequest(offer, text)).toBe(false)
59	}
60	for (const text of ['yes please but not now', 'no', 'yes if it is free'])
61		expect(acceptedSalesOffer(offer, text)).toBe(false)
62})
63test('saved details and consent produce a request summary and separate confirmation', () => {
64	const summary = salesAcceptanceReply(profile, 'paris', true, undefined)
65	for (const detail of [
66		'Jordan UAT',
67		'Example',
68		'jordan.uat@example.com',
69		'Paris',
70	])
71		expect(summary).toContain(detail)
72	expect(summary.endsWith(HANDOFF_CONSENT.sponsorship)).toBe(true)
73	const history = [{ role: 'assistant' as const, text: summary }]
74	expect(confirmedSalesRequest(history, 'yes please')).toBe(true)
75	expect(isHandoffCancellation(history, 'Cancel that.')).toBe(true)
76	for (const text of ['cancel', 'yes but tomorrow', 'no', 'change my email'])
77		expect(confirmedSalesRequest(history, text)).toBe(false)
78})
79test('missing details or consent are requested without claiming success', () => {
80	expect(salesAcceptanceReply(undefined, 'paris', false, undefined)).toContain(
81		'What company',
82	)
83	expect(
84		salesAcceptanceReply(
85			{ company: 'Example', role: 'Director' },
86			'paris',
87			true,
88			undefined,
89		),
90	).toContain('What name')
91	expect(
92		salesAcceptanceReply(
93			{ ...profile, email: undefined },
94			'paris',
95			true,
96			undefined,
97		),
98	).toContain('What work email')
99	expect(salesAcceptanceReply(profile, 'miami', false, undefined)).toContain(
100		HANDOFF_CONSENT.sponsorship,
101	)
102})
103test('booking caveat belongs only to delegate confirmations', () => {
104	expect(verifiedHandoffReply('', { kind: 'lead', ok: true })).not.toContain(
105		'booking',
106	)
107	expect(
108		verifiedHandoffReply('', { kind: 'lead', ok: true, ticketEnquiry: true }),
109	).toContain('not a confirmed booking')
110})
111
112test('contextual sales offer remains actionable when the model calls the team them', () => {
113	expect(
114		acceptedSalesOffer(
115			[
116				{
117					role: 'assistant',
118					text:
119						'Our sales team can discuss the options. Would you like me to put you in touch with them directly?',
120				},
121			],
122			'yes get in touch',
123		),
124	).toBe(true)
125	expect(
126		acceptedSalesOffer(
127			[
128				{
129					role: 'assistant',
130					text:
131						'Our hotel provider can help. Would you like me to put you in touch with them directly?',
132				},
133			],
134			'yes get in touch',
135		),
136	).toBe(false)
137})
138