diff --git a/src/hooks/useAnalyticsPageView.ts b/src/hooks/useAnalyticsPageView.ts index 8f884b45..ca37e3b3 100644 --- a/src/hooks/useAnalyticsPageView.ts +++ b/src/hooks/useAnalyticsPageView.ts @@ -2,10 +2,19 @@ import React from 'react'; import {useAnalyticsContext} from '../contexts/useAnalyticsContext'; import {UnknownRecord} from '../types/common'; -export const useAnalyticsPageView = (params: UnknownRecord) => { +export function useAnalyticsPageView(params: UnknownRecord): void; +export function useAnalyticsPageView(callback: () => UnknownRecord): void; +export function useAnalyticsPageView(callback: () => Promise): void; +export function useAnalyticsPageView(paramsOrCallback: UnknownRecord | (() => Promise | UnknownRecord)) { const analytics = useAnalyticsContext(); - React.useEffect(() => { + const pageView = async () => { + const params = typeof paramsOrCallback === 'function' ? await paramsOrCallback() : paramsOrCallback; analytics.onPageView(params); - }, [analytics, params]); -}; + }; + + React.useEffect(() => { + pageView(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [analytics]); +} diff --git a/tests/hooks/useAnalyticsPageView.test.ts b/tests/hooks/useAnalyticsPageView.test.ts new file mode 100644 index 00000000..057a63c2 --- /dev/null +++ b/tests/hooks/useAnalyticsPageView.test.ts @@ -0,0 +1,69 @@ +import React from 'react'; +import * as faker from 'faker'; + +import * as contextModule from '../../src/contexts/useAnalyticsContext'; +import {useAnalyticsPageView} from '../../src/hooks/useAnalyticsPageView'; + +describe('useAnalyticsPageView', () => { + const setUp = () => { + const params = {value: faker.lorem.word()}; + const callback = () => params; + const asyncCallback = async () => params; + + const onPageView = jest.fn(); + + const useEffectSpy = jest.spyOn(React, 'useEffect').mockImplementationOnce(cb => cb()); + const useContextSpy = jest.spyOn(contextModule, 'useAnalyticsContext').mockImplementationOnce( + () => + ({ + onPageView, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any), + ); + jest.spyOn(console, 'info').mockImplementation(() => null); + + return { + params, + callback, + asyncCallback, + onPageView, + useEffectSpy, + useContextSpy, + }; + }; + + const waitForAsync = () => new Promise(resolve => setTimeout(resolve, 0)); + + test('should call analytics.onPageView with params', async () => { + const {params, onPageView, useContextSpy, useEffectSpy} = setUp(); + + useAnalyticsPageView(params); + await waitForAsync(); + + expect(useContextSpy).toHaveBeenCalled(); + expect(useEffectSpy).toHaveBeenCalled(); + expect(onPageView).toHaveBeenCalledWith(params); + }); + + test('should call analytics.onPageView with callback', async () => { + const {params, callback, onPageView, useContextSpy, useEffectSpy} = setUp(); + + useAnalyticsPageView(callback); + await waitForAsync(); + + expect(useContextSpy).toHaveBeenCalled(); + expect(useEffectSpy).toHaveBeenCalled(); + expect(onPageView).toHaveBeenCalledWith(params); + }); + + test('should call analytics.onPageView with asyncCallback', async () => { + const {params, asyncCallback, onPageView, useContextSpy, useEffectSpy} = setUp(); + + useAnalyticsPageView(asyncCallback); + await waitForAsync(); + + expect(useContextSpy).toHaveBeenCalled(); + expect(useEffectSpy).toHaveBeenCalled(); + expect(onPageView).toHaveBeenCalledWith(params); + }); +});