/** * @jest-environment jsdom * @jest-environment-options {"url": "https://www.ft.com/"} */ import { CarouselCardTrackingClient } from './tracking' const mockCarouselCardEnterViewPortEvent = { category: 'component', action: 'view', trigger_action: 'enter-viewport', url: 'https://www.ft.com/', component: { id: '123', name: 'cp-carousel-card', position: 3, }, custom: [ { name: 'total-cards', value: 5, }, ], } describe('CarouselCardTrackingClient', () => { let mockCardComponent: HTMLElement let dispatchEventSpy: jest.SpyInstance let mockDisconnectIntersection: jest.Mock let mockIntersectionObserver: jest.Mock beforeEach(() => { mockCardComponent = document.createElement('div') mockCardComponent.setAttribute('data-component-id', '123') mockDisconnectIntersection = jest.fn() mockIntersectionObserver = jest.fn(() => { return { observe: jest.fn(), unobserve: jest.fn(), disconnect: mockDisconnectIntersection, } }) window.IntersectionObserver = mockIntersectionObserver document.body.appendChild(mockCardComponent) dispatchEventSpy = jest.spyOn(document.body, 'dispatchEvent') }) afterEach(() => { jest.clearAllMocks() document.body.removeChild(mockCardComponent) }) describe('inititalisation and teardown', () => { it('should initialise', () => { new CarouselCardTrackingClient({ component: mockCardComponent, index: 1, total: 3, }) expect(mockIntersectionObserver).toHaveBeenCalledTimes(1) }) it('should initialise one CarouselCardTrackingClient per card in the carousel', () => { const mockComponent = document.createElement('div') const card1 = document.createElement('div') card1.setAttribute('data-component', 'carousel-card') const card2 = document.createElement('div') card2.setAttribute('data-component', 'carousel-card') mockComponent.appendChild(card1) mockComponent.appendChild(card2) const tracker = CarouselCardTrackingClient.init(mockComponent) expect(tracker).toHaveLength(2) }) it('should teardown the instance on destroy', () => { const tracker = new CarouselCardTrackingClient({ component: mockCardComponent, index: 1, total: 3, }) tracker.destroy() expect(mockDisconnectIntersection).toHaveBeenCalledTimes(1) }) }) describe('component visibility changes', () => { it('should send a view event when the component enters the viewport', () => { const tracker = new CarouselCardTrackingClient({ component: mockCardComponent, index: 2, total: 5, }) const mockEnterView: IntersectionObserverEntry[] = [ { target: mockCardComponent, isIntersecting: true, intersectionRatio: 1.0, boundingClientRect: { height: 100, } as unknown as DOMRectReadOnly, intersectionRect: {} as DOMRectReadOnly, rootBounds: null, time: 1, }, ] tracker.onChange(mockEnterView) const viewEvent = dispatchEventSpy.mock.calls[0][0] as CustomEvent expect(viewEvent.type).toBe('oTracking.event') expect(viewEvent.detail).toEqual(mockCarouselCardEnterViewPortEvent) }) }) })