import { TopperTracker } from './index' describe('TopperTracker', () => { let mockIntersectionObserver: jest.Mock let mockObserve: jest.Mock let mockUnobserve: jest.Mock let mockDisconnect: jest.Mock let mockComponent: HTMLElement let dispatchEventSpy: jest.SpyInstance beforeEach(() => { mockObserve = jest.fn() mockUnobserve = jest.fn() mockDisconnect = jest.fn() mockIntersectionObserver = jest.fn(() => { return { observe: mockObserve, unobserve: mockUnobserve, disconnect: mockDisconnect, } }) window.IntersectionObserver = mockIntersectionObserver mockComponent = document.createElement('div') mockComponent.setAttribute('data-component-type', 'flourish-topper') mockComponent.setAttribute('data-component-id', 'test-id') document.body.appendChild(mockComponent) jest.spyOn(document, 'querySelector').mockReturnValue(mockComponent) jest .spyOn(performance, 'now') .mockImplementationOnce(() => 1) .mockImplementationOnce(() => 12344) dispatchEventSpy = jest.spyOn(document.body, 'dispatchEvent') }) afterEach(() => { jest.clearAllMocks() document.body.removeChild(mockComponent) }) it('should initialise and observe the component', () => { const tracker = new TopperTracker() tracker.init() expect(mockIntersectionObserver).toHaveBeenCalled() expect(mockObserve).toHaveBeenCalledWith(mockComponent) }) it('should dispatch a mount event on intialisation', () => { const tracker = new TopperTracker() tracker.init() const mountEvent = dispatchEventSpy.mock.calls[0][0] as CustomEvent expect(mountEvent.type).toBe('oTracking.event') expect(mountEvent.detail).toEqual({ category: 'component', action: 'mount', component: { name: 'flourish-topper', id: 'test-id', }, }) }) it('should handle component visibility changes', () => { const tracker = new TopperTracker() tracker.init() const mockChanges: IntersectionObserverEntry[] = [ { target: mockComponent, isIntersecting: true, intersectionRatio: 1.0, boundingClientRect: {} as DOMRectReadOnly, intersectionRect: {} as DOMRectReadOnly, rootBounds: null, time: 1, }, ] tracker['onChange'](mockChanges) const viewEvent = dispatchEventSpy.mock.calls[1][0] as CustomEvent expect(viewEvent.type).toBe('oTracking.event') expect(viewEvent.detail).toEqual({ category: 'component', action: 'view', component: { name: 'flourish-topper', id: 'test-id', }, }) const mockChangesAfter: IntersectionObserverEntry[] = [ { target: mockComponent, isIntersecting: false, intersectionRatio: 0.0, boundingClientRect: {} as DOMRectReadOnly, intersectionRect: {} as DOMRectReadOnly, rootBounds: null, time: 12.3444, }, ] tracker['onChange'](mockChangesAfter) const stopViewEvent = dispatchEventSpy.mock.calls[2][0] as CustomEvent expect(stopViewEvent.type).toBe('oTracking.event') expect(stopViewEvent.detail).toEqual({ category: 'component', action: 'stop-view', component: { name: 'flourish-topper', id: 'test-id', timeElapsedSeconds: 12.34, }, }) }) it('should disconnect the observer', () => { const tracker = new TopperTracker() tracker.init() tracker.disconnect() expect(mockUnobserve).toHaveBeenCalledWith(mockComponent) expect(mockDisconnect).toHaveBeenCalled() }) })