// @vitest-environment jsdom import { afterEach, describe, expect, it, vi } from 'vitest'; import type { WidgetConfig } from './types'; import { trackTryOnCompleted } from './events'; const config = { eventsUrl: 'https://brain.test/events', publishableKey: 'pk_test', visitorKey: 'visitor-1', customerId: 'customer-2', } as WidgetConfig; describe( 'trackTryOnCompleted', () => { afterEach( () => { delete window.aisthetixTrackEvent; vi.unstubAllGlobals(); } ); it( 'uses the bootstrap analytics contract when available', () => { window.aisthetixTrackEvent = vi.fn(); trackTryOnCompleted( config, '42' ); expect( window.aisthetixTrackEvent ).toHaveBeenCalledWith( 'aisthetix_tryon_completed', { productId: '42' } ); } ); it( 'falls back to a fire-and-forget POST with the same shaped fields', () => { const fetchMock = vi.fn().mockResolvedValue( {} ); vi.stubGlobal( 'fetch', fetchMock ); trackTryOnCompleted( config, '' ); const [ endpoint, request ] = fetchMock.mock.calls[ 0 ]; expect( endpoint ).toBe( config.eventsUrl ); expect( request.keepalive ).toBe( true ); expect( request.credentials ).toBe( 'omit' ); expect( JSON.parse( request.body ) ).toEqual( expect.objectContaining( { eventName: 'aisthetix_tryon_completed', visitorKey: 'visitor-1', customerId: 'customer-2', productId: null, } ) ); } ); it( 'stays inert without fallback credentials and swallows analytics failures', () => { const fetchMock = vi.fn(); vi.stubGlobal( 'fetch', fetchMock ); trackTryOnCompleted( { ...config, eventsUrl: '' }, '42' ); expect( fetchMock ).not.toHaveBeenCalled(); Object.defineProperty( window, 'aisthetixTrackEvent', { configurable: true, get: () => { throw new Error( 'blocked' ); }, } ); expect( () => trackTryOnCompleted( config, '42' ) ).not.toThrow(); } ); } );