docs/reports/2026-10-05-full-model-comparison/web-unit-tests.log

1bun test v1.4.0 (34cbb9a40)
2
3src/lib/consentSettings.test.ts:
4(pass) empty settings preserve approved defaults and each notice resolves independently [0.05ms]
5(pass) all custom notices reach their contact summaries and retain confirmation and cancellation [0.47ms]
6
7src/lib/aiDisabledWorkflow.test.ts:
8(pass) agenda request, acceptance and confirmation explain no delivery [0.43ms]
9(pass) SPEX confirmation inherits topic through a generic contact offer [0.20ms]
10(pass) ticket confirmation uses Support, even after earlier sponsorship discussion [0.02ms]
11(pass) final consent cannot bypass disabled enquiry tool [0.04ms]
12(pass) email corrections during contact collection do not request more details [0.06ms]
13(pass) individual agenda email toggle blocks without blocking sales [0.02ms]
14(pass) individual sales toggle does not block permitted agenda email [0.01ms]
15(pass) turning off agenda building also blocks old agenda-email confirmations [0.11ms]
16(pass) chat-only agenda requests and factual questions are not email requests [0.16ms]
17(pass) cancellation retains cancellation behavior, rather than unavailable-email copy
18(pass) enabled workflows retain normal behavior [0.01ms]
19(pass) failed handoff stream cannot leak a generated success claim and uses correct contact [0.69ms]
20(pass) personal agenda in chat asks for interests unless a plan or interests already exist [0.60ms]
21(pass) disabled ticket enquiries stop at first buying intent, before qualification [0.06ms]
22(pass) disabled SPEX enquiries never begin contact collection [0.02ms]
23(pass) disabled agenda building rejects entry before asking for interests [0.86ms]
24(pass) information and enabled enquiries still reach their normal handlers [0.08ms]
25
26src/lib/salesConfirmation.test.ts:
27(pass) typo acceptance progresses the offer but does not authorize dispatch [0.06ms]
28(pass) saved details and consent produce a request summary and separate confirmation [0.04ms]
29(pass) missing details or consent are requested without claiming success [0.02ms]
30(pass) booking caveat belongs only to delegate confirmations
31(pass) contextual sales offer remains actionable when the model calls the team them [0.02ms]
32
33src/lib/pageCatalogue.test.ts:
34You have configured Sanity client to use a token in the browser. This may cause unintentional security issues. See https://www.sanity.io/help/js-client-browser-token for more information and how to hide this warning.
35(pass) displayTitle > drops the SEO tail after a dash or pipe [0.05ms]
36(pass) displayTitle > keeps titles without a tail, hyphenated words, and tiny heads
37(pass) displayTitle > pageTitle prefers the editor override verbatim [0.03ms]
38(pass) displayTitle > pageTitle trims structural pages only — resources keep their headline [0.01ms]
39(pass) eventSlugOf / pageVectorMetadata > tags event pages with their event root only [0.05ms]
40(pass) extractSlicesText > harvests copy fields in document order, skipping noise [0.10ms]
41(pass) extractSlicesText > returns empty string for missing or empty slices [0.01ms]
42(pass) extractSlicesText > preserves the Paris hotel CTA through extraction and chunk boundaries [0.22ms]
43(pass) extractSlicesText > does not expose action URLs, assets, or unsafe button destinations [0.03ms]
44(pass) extractSlicesText tables > keeps table rows as one line with cleaned cells [0.06ms]
45(pass) extractPageOutline / formatSitePageText > collects headings, eyebrows and questions in order, deduplicated and bounded [0.11ms]
46(pass) isEventSitePage > matches event subpages and event roots only [0.02ms]
47(pass) eventPageContentRecords > one record per chunk, each carrying title and URL [0.03ms]
48(pass) eventPageContentRecords > empty content produces no records [0.01ms]
49(pass) eventPageContentRecords > page-scoped id prefix never matches a deeper sibling page [0.03ms]
50
51src/lib/aiRouting.test.ts:
52(pass) Jev routing policy > defaults to shadow and requires explicit active opt-in [0.02ms]
53(pass) Jev routing policy > recognizes confident buying without authorizing submission [0.07ms]
54(pass) Jev routing policy > choice help is informational, not a ticket start [0.02ms]
55(pass) Jev routing policy > negated cancellation conflict falls back
56(pass) Jev routing policy > information and refusal coexist without starting capture
57(pass) Jev routing policy > consent never becomes a routing authorization
58(pass) Jev routing policy > uncertain and invalid probabilities fall back [0.04ms]
59(pass) Jev routing policy > unknown topic does not start a workflow
60(pass) Jev routing policy > duplicate current message is removed and six earlier turns retained [0.09ms]
61(pass) Jev routing policy > truncation is explicit and blocks semantic routing [0.01ms]
62(pass) Jev routing policy > known offer contradicting model classification falls back [0.01ms]
63
64src/lib/livePricing.test.ts:
65(pass) selects active exact-event category and preserves ex-VAT amount [0.97ms]
66(pass) switches to a future open-ended band without a deploy, with no expiry fallback [0.13ms]
67(pass) rejects conflicts, malformed dates, private or unpublished products [0.05ms]
68(pass) Explorer policy wins over registration prices [0.03ms]
69(pass) supports zero/manual override and does not double tax inclusive prices [0.25ms]
70
71src/lib/aiFlows.test.ts:
72(pass) agenda flow does not invent interests or reopen ticket qualification [0.13ms]
73(pass) short acceptance after a long plan advances to email [0.03ms]
74(pass) ticket sales routing > explicit buying intent starts capture, informational questions do not [0.03ms]
75(pass) ticket sales routing > recognises a ticket sales connection offer
76(pass) ticket sales routing > accepting ticket help does not enter sponsorship qualification [0.01ms]
77(pass) ticket sales routing > the latest user topic wins; assistant badge copy cannot change it [0.05ms]
78(pass) acceptedSalesOffer > a bare yes right after the offer
79(pass) acceptedSalesOffer > not when the offer was not the last assistant turn, or the answer carries content [0.02ms]
80(pass) natural ticket requests from the failed conversations start qualification [0.05ms]
81(pass) accepts a conversational booking enquiry offer without accepting a comparison offer
82(pass) factual detours and choosing help do not depend on punctuation [0.13ms]
83(pass) contextual buying stays active through missing-field answers [0.04ms]
84(pass) short replies accept pass-selection help instead of repeating qualification [0.05ms]
85(pass) exact Langfuse can I get one follow-up enters booking, not information
86(pass) repeated choosing help stays informational after a recommendation
87(pass) help remains a request after any pass comparison wording
88
89src/lib/stape-config.test.ts:
90(pass) parseStapeConfig > accepts a complete HTTPS config [0.14ms]
91(pass) parseStapeConfig > normalizes a trailing slash on origin [0.02ms]
92(pass) parseStapeConfig > rejects missing fields [0.01ms]
93(pass) parseStapeConfig > rejects placeholder markers without issuing side effects [0.02ms]
94(pass) parseStapeConfig > rejects non-HTTPS or path-bearing origins [0.01ms]
95(pass) parseStapeConfig > rejects invalid loader paths [0.03ms]
96(pass) parseStapeConfig > rejects query parts with whitespace or URL delimiters [0.02ms]
97
98src/lib/handoffContact.test.ts:
99(pass) personal email is rejected with the same deterministic rule as forms [0.03ms]
100(pass) agenda email collects every required field before consent [0.10ms]
101(pass) email alone cannot invent a recipient name or company at submission [0.06ms]
102(pass) visitor facts recover extraction failures and override stale saved details [0.02ms]
103
104src/lib/aiResponsePolicy.test.ts:
105(pass) past editions redirect, while current/future requests and prior-visit context remain available [0.14ms]
106(pass) personal-data requests get the fixed privacy response without leaking profile facts [0.07ms]
107(pass) support routing is conservative, with privacy and non-SPEX questions taking precedence [0.02ms]
108(pass) brand and contact links normalize at every possible chunk boundary [2.12ms]
109(pass) ordinary text reaches the client before stream completion [0.08ms]
110(pass) direct contact questions need no retrieval and do not list speculative departments [0.05ms]
111(pass) failed sponsorship submissions keep Support across streamed chunk boundaries [0.89ms]
112
113src/lib/leadAttribution.test.ts:
114(pass) attribution follows form cookie names, preserving equals signs and last-touch decoding [0.08ms]
115
116src/lib/flowSelector.test.ts:
117(pass) routine active-flow replies skip routing [0.07ms]
118(pass) side questions preserve flow; explicit switches change it [0.03ms]
119(pass) uncertainty and outages retain existing behavior, never authorize sends [0.02ms]
120(pass) information can safely suspend a workflow without changing destination state
121
122src/lib/aiRetrieval.test.ts:
123(pass) normalizeContactRoute > replaces the non-existent contact form with the support email [0.04ms]
124(pass) normalizeContactRoute > leaves real forms alone
125(pass) isRefusalTemplate > flags placeholder answers written in the agent voice [0.07ms]
126(pass) isRefusalTemplate > keeps real answers
127
128src/lib/leads.test.ts:
129(pass) both submission types reject personal addresses without posting to Zapier [0.19ms]
130(pass) lead and agenda Zapier payloads include all three attribution sources [0.53ms]
131(pass) LEAD_INTENTS > includes the full Salesforce Intent picklist [0.02ms]
132(pass) LEAD_INTENTS > isLeadIntent accepts only allowlisted values [0.01ms]
133(pass) LEAD_INTENTS > intentShowFromLocation maps event pages to show suffixes [0.01ms]
134(pass) LEAD_INTENTS > leadIntentFor composes category + show
135(pass) submitLeadToZapier > posts the full lead payload to the configured hook [0.09ms]
136[Leads] lead skipped: invalid or missing email {
137  chatId: "chat-123",
138}
139(pass) submitLeadToZapier > rejects a missing email without calling the hook [0.07ms]
140[Leads] lead skipped: invalid or missing email {
141  chatId: "chat-123",
142}
143(pass) submitLeadToZapier > rejects a malformed email without calling the hook [0.02ms]
144[Leads] lead skipped: invalid or missing intent {
145  chatId: "chat-123",
146  intent: "Not A Real Intent",
147}
148(pass) submitLeadToZapier > rejects an invalid intent without calling the hook [0.75ms]
149[Leads] ZAPIER_LEAD_WEBHOOK_URL not set; not sent
150(pass) submitLeadToZapier > no-ops when ZAPIER_LEAD_WEBHOOK_URL is unset [0.11ms]
151[Leads] submission failed 101 | 				collected_at: new Date().toISOString(),
152102 | 				...payload,
153103 | 			}),
154104 | 		})
155105 | 		if (!response.ok) {
156106 | 			throw new Error(`Zapier hook responded ${response.status}`)
157                   ^
158error: Zapier hook responded 404
159      at submitToZapier (/Users/federico/.codex/worktrees/ai-model-uat-openai/unleash-ai/apps/web/src/lib/leads.ts:106:14)
160
161(pass) submitLeadToZapier > reports a non-OK hook response as a failure [0.31ms]
162[Leads] submission failed 216 | 		expect(result.error).toBe('Zapier hook responded 404')
163217 | 	})
164218 | 
165219 | 	test('reports a network error as a failure', async () => {
166220 | 		globalThis.fetch = (async () => {
167221 | 			throw new Error('network down')
168                   ^
169error: network down
170      at <anonymous> (/Users/federico/.codex/worktrees/ai-model-uat-openai/unleash-ai/apps/web/src/lib/leads.test.ts:221:14)
171      at submitToZapier (/Users/federico/.codex/worktrees/ai-model-uat-openai/unleash-ai/apps/web/src/lib/leads.ts:95:26)
172      at submitLeadToZapier (/Users/federico/.codex/worktrees/ai-model-uat-openai/unleash-ai/apps/web/src/lib/leads.ts:150:9)
173      at <anonymous> (/Users/federico/.codex/worktrees/ai-model-uat-openai/unleash-ai/apps/web/src/lib/leads.test.ts:223:24)
174
175(pass) submitLeadToZapier > reports a network error as a failure [2.39ms]
176(pass) submitAgendaEmailToZapier > posts the agenda-email payload to the configured hook [0.17ms]
177(pass) submitAgendaEmailToZapier > defaults intent to Delegate Agenda scoped by location [0.06ms]
178(pass) submitAgendaEmailToZapier > uses an explicit intent when provided [0.03ms]
179(pass) submitAgendaEmailToZapier > defaults opt_in to false when omitted [0.03ms]
180(pass) submitAgendaEmailToZapier > passes through profile context (role, company, interests) [0.04ms]
181(pass) submitAgendaEmailToZapier > omits empty profile context fields from the payload [0.04ms]
182(pass) submitAgendaEmailToZapier > rejects an invalid email without calling the hook [0.02ms]
183(pass) submitAgendaEmailToZapier > rejects an empty agenda without calling the hook [0.03ms]
184(pass) submitAgendaEmailToZapier > truncates oversized agendas to 20k characters [0.06ms]
185
186src/lib/eventDates.test.ts:
187(pass) formatEventDateRange > same-month range [0.06ms]
188(pass) formatEventDateRange > cross-month range within a year
189(pass) formatEventDateRange > cross-year range
190(pass) formatEventDateRange > single day when endDate missing or equal
191(pass) formatEventDateRange > undefined for missing or malformed startDate
192(pass) formatEventDateRange > ignores malformed endDate and falls back to single day
193(pass) eventScopeFromSlug > city and legacy slugs map to their scope [0.02ms]
194(pass) eventScopeFromSlug > non-event pages map to null
195
196src/lib/userProfile.test.ts:
197(pass) profile persists canonical pillar IDs separately and migrates explicit legacy labels [0.18ms]
198(pass) ticket enquiry rejects a personal address before consent [0.01ms]
199(pass) complete ticket details go directly to a single consent summary [0.03ms]
200(pass) only missing ticket fields are requested and other-event details are not reused [0.02ms]
201(pass) booking profile input is bounded and included in the agent table [0.06ms]
202(pass) transactional requests are not saved learning interests [0.01ms]
203(pass) known and missing facts are explicit in the agent table [0.01ms]
204(pass) profile values cannot add table rows and unsupported facts are discarded [0.01ms]
205
206src/lib/stape.test.ts:
207[stape] config from Vite env {
208  originDefined: true,
209  pathDefined: true,
210  queryKeyDefined: true,
211  queryTokenDefined: true,
212  origin: "https://sst.unleash.ai",
213  path: "/6zyqrsdbrae.js",
214  queryKey: "e0otfbc",
215  queryTokenLength: 54,
216  ok: true,
217  reason: undefined,
218}
219[stape] cutover check {
220  previewBuild: false,
221  gtmPreviewDefine: false,
222  configOk: true,
223  configReason: undefined,
224  enabled: true,
225}
226(pass) isStapeCutoverEnabled > mirrors whether Vite Stape env parses as ok [0.42ms]
227(pass) runApprovedCustomLoader > injects a single script with exact config-derived src and stable id [8.65ms]
228(pass) runApprovedCustomLoader > does not rewrite to kp or append bi under Safari 16.4+ [0.59ms]
229(pass) runApprovedCustomLoader > pushes gtm.js onto dataLayer once [0.36ms]
230(pass) loadStapeOnce > returns ssr when document is explicitly null [0.06ms]
231(pass) loadStapeOnce > skips incomplete configuration without injecting [0.02ms]
232(pass) loadStapeOnce > skips placeholder configuration [0.04ms]
233(pass) loadStapeOnce > default executor loads and is idempotent [0.27ms]
234(pass) loadStapeOnce > detects a pre-existing loader script in the DOM [0.10ms]
235(pass) loadStapeOnce > allows retry after executor failure [0.23ms]
236(pass) loadStapeOnce > diagnostics never include the query token [0.22ms]
237
238src/lib/badges.test.ts:
239(pass) summarizeBadgePages > orders overview, attend hub, then badge pages, with clean titles and copy [0.21ms]
240(pass) summarizeBadgePages > skips docs without a slug and caps long copy [0.03ms]
241
242src/lib/badgePricing.test.ts:
243(pass) Paris pricing uses confirmed amounts and distinguishes application-only Explorer [0.15ms]
244(pass) pricing cannot leak into another event or a later edition
245(pass) stale metadata does not reach the badge tool [0.02ms]
246(pass) tax and offer expiry match the verified published comparison [0.04ms]
247
248src/lib/ticketAnswer.test.ts:
249(pass) prices stay with their badge and include tax; Explorer never receives a number [0.15ms]
250(pass) expired and different-event prices fail closed [0.01ms]
251(pass) short price follow-up resolves a single badge without borrowing another price [0.15ms]
252(pass) purchases, support and unrelated detours do not become price answers [0.03ms]
253(pass) a named comparison does not add an unrequested badge [0.04ms]
254
255src/lib/agendaStorage.test.ts:
256(pass) agenda storage preserves decision pillar IDs and labels separately from legacy topics [0.36ms]
257
258src/lib/agendaPlan.test.ts:
259(pass) validated agenda plans > pillar recommendations use stored classifications rather than keynote topic matches [0.25ms]
260(pass) validated agenda plans > separates conflicting sessions and keeps exact source details [0.22ms]
261(pass) validated agenda plans > excludes restricted sessions, invalid times and missing links [0.02ms]
262(pass) validated agenda plans > allows consecutive sessions in one room but reserves transfer time between rooms [0.02ms]
263(pass) validated agenda plans > filters by day and does not invent a fallback for unmatched interests [0.02ms]
264(pass) validated agenda plans > email selection rejects forged, duplicated, overlapping and newly restricted sessions [0.05ms]
265
266src/lib/pageDirectory.test.ts:
267(pass) directoryForEvent > keeps only the event's pages, sorted by url, with their outline [0.07ms]
268(pass) directory preserves exact hotel booking CTA without semantic retrieval [0.02ms]
269
270src/lib/aiCapabilityPolicy.test.ts:
271(pass) AI launch controls > production requires published opt-in; an env true cannot bypass it [0.01ms]
272(pass) AI launch controls > information-only launch retains lookup and agenda tools, removes both side effects [0.07ms]
273(pass) AI launch controls > individual toggles and agenda dependency apply even with submission master on [0.01ms]
274(pass) AI launch controls > disabled tool instructions disappear from default and custom prompts [0.57ms]
275(pass) AI launch controls > agenda prompt does not offer emails when sending is unavailable [0.04ms]
276(pass) AI launch controls > each tool can be independently removed from a supplied registry [0.07ms]
277(pass) AI launch controls > revocation during an existing conversation prevents actual execution [0.09ms]
278(pass) AI launch controls > hidden production blocks sends even when tool master is enabled [0.03ms]
279(pass) AI launch controls > enabled execution preserves downstream failure, including rejected webhook [0.03ms]
280(pass) disabled workflows cannot enter or persist; agenda remains when only sending is off [0.04ms]
281(pass) sales offer instructions are removed even when agenda email is permitted [0.01ms]
282(pass) staging submission opt-in never enables production or other previews [0.03ms]
283
284src/lib/aiConversationReview.test.ts:
285(pass) flags malformed internal host, not valid links [0.04ms]
286(pass) deterministic defect survives an optimistic model verdict [0.61ms]
287(pass) records exact emitted text once, including split unicode [0.45ms]
288(pass) cancelled stream is incomplete, not a bad-answer verdict [0.17ms]
289(pass) long response is preserved for the visitor but marked incomplete for evaluation [2.02ms]
290
291src/lib/aiOctoberFixes.test.ts:
292(pass) approved consent copy accepts explicit permission but not conditional permission [0.06ms]
293(pass) UNLEASH is a company answer and is not asked twice [0.16ms]
294(pass) agenda discovery offers progress and do not repeat during handoffs [0.11ms]
295(pass) email HTML has paragraphs and absolute links and escapes source text [0.06ms]
296(pass) page and category visibility do not require a section prompt [0.04ms]
297(pass) natural contact questions retain agenda email context, without claiming a sentence is a role [0.11ms]
298
299src/lib/aiGuards.test.ts:
300(pass) changing chat IDs cannot reset the shared IP generation budget [0.25ms]
301(pass) guard replies tell the browser to skip profile extraction [0.03ms]
302
303src/lib/hotelBooking.test.ts:
304(pass) exact hotel detour and follow-up use the published booking destination [0.14ms]
305(pass) discounted hotels use the direct booking lookup after cancellation
306
307src/lib/aiHandoff.test.ts:
308(pass) work-email validation asks for a correction instead of claiming submission failure
309(pass) email selection preserves latest displayed plan and excludes alternatives [0.05ms]
310(pass) send claims require successful handoff evidence [0.07ms]
311
312src/lib/chatDelivery.test.ts:
313(pass) a submission stream error gives support once and completes the turn [0.10ms]
314(pass) failed validation ends the handoff with a support link [0.04ms]
315(pass) ordinary replies deliver the first chunk before generation completes [0.05ms]
316(pass) handoff confirmation comes from successful tool completion before stream end [0.05ms]
317(pass) failed or absent sends never become success confirmations [0.07ms]
318(pass) validated agenda is delivered at tool completion and generation cannot rewrite links [0.04ms]
319
320src/lib/ads/periods.test.ts:
321(pass) normalizeAdDocumentId strips draft prefixes and rejects bad ids [0.04ms]
322(pass) isAdAnalyticsPeriod accepts only supported tokens [0.02ms]
323(pass) getAdAnalyticsDateRange returns inclusive calendar windows ending today [0.09ms]
324(pass) getAdAnalyticsDateRange clamps month ends when the day overflows
325(pass) normalizeGa4Date accepts compact and dashed forms [0.02ms]
326(pass) aggregateAdAnalyticsRows merges events and zero-fills missing days [0.09ms]
327
328src/lib/cookie-consent/consent-state.test.ts:
329(pass) chat stays hidden until functional acceptance, and immediately hides on withdrawal or clearing [0.26ms]
330(pass) restores saved acceptance, handles cross-tab clearing, and removes listeners [0.09ms]
331(pass) invalid saved consent fails closed [0.03ms]
332
333 212 pass
334 0 fail
335 1017 expect() calls
336Ran 212 tests across 32 files. [456.00ms]
337