/** @vitest-environment jsdom */ /** * The wiring between the CMP signal and the recorder. * * replay.test.ts proves what `applyConsentDecision` does. This proves the widget * actually calls it — the half that was missing, and the half no unit test of * the replay module can catch: a shopper who opened the modal before the banner * was answered and then accepted was never recorded, because the only code that * could have started the recorder ran on modal open and had already decided. */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { render, cleanup, waitFor } from '@testing-library/react'; import { App } from './App'; import { applyConsentDecision } from './replay'; import type { WidgetConfig } from './types'; vi.mock('./replay', () => ({ applyConsentDecision: vi.fn().mockResolvedValue( undefined ), startReplay: vi.fn().mockResolvedValue( undefined ), stopReplay: vi.fn(), revokeReplay: vi.fn(), MODAL_OVERLAY_CLASS: 'aisthetix-modal-overlay', } ) ); const config = { apiBaseUrl: 'https://brain.example.com', publishableKey: 'pk_test', productImage: 'https://cdn.example.com/shirt.jpg', productTitle: 'Linen Shirt', productId: '555', variantId: '111', locale: 'en', analytics: { replayKey: 'phc_browser', ingestHost: 'https://ingest.aisthetix.fyi', replayEnabled: true, environment: 'staging', storeId: 'store_1', }, } as unknown as WidgetConfig; beforeEach( () => { localStorage.clear(); sessionStorage.clear(); document.body.innerHTML = ''; vi.mocked( applyConsentDecision ).mockClear(); } ); afterEach( () => { cleanup(); document.body.innerHTML = ''; } ); /** The decision the bootstrap announces after reading the merchant's CMP. */ function announceConsent( productAnalytics: boolean ) { document.dispatchEvent( new CustomEvent( 'aisthetix:consent-changed', { detail: { productAnalytics } } ) ); } describe( 'a CMP decision collected while the widget is mounted', () => { it( 'is handed to the recorder as a grant', async () => { render( ); announceConsent( true ); await waitFor( () => expect( applyConsentDecision ).toHaveBeenCalled() ); expect( vi.mocked( applyConsentDecision ).mock.calls[ 0 ][ 0 ], 'a grant must reach the recorder' ).toBe( true ); } ); it( 'is handed to the recorder as a withdrawal', async () => { render( ); announceConsent( false ); await waitFor( () => expect( applyConsentDecision ).toHaveBeenCalled() ); expect( vi.mocked( applyConsentDecision ).mock.calls[ 0 ][ 0 ] ).toBe( false ); } ); } );