Reputation: 1592
So I'm pretty new to testing with react. I have a custom hook that I am calling inside a component. I am using the renderHook
methods from react-hook-testing-library
.
I need to test if the methods inside useEffect
inside the custom hook are called. I cant seem to figure this out.
In another case, I need to figure out if trackPdpGtm
is not called.
Note: The hook does not return any data. This is mainly for sending analytics information.
Current Approach:
usePdpGtm.js
import { useEffect } from 'react';
import { trackPdpGtm } from 'utils/gtm/pdpGtmUtils';
import _ from 'utils/lodashImports';
export default function useGtmPdp(data = {}) {
console.log('are you getting called?');
const { relatedProducts, results, priceInfo, breadcrumbs } = data;
const relatedProductsLoaded = _.get(relatedProducts, 'relatedProductsLoaded');
useEffect(() => {
if (relatedProductsLoaded) {
trackPdpGtm(data);
}
}, [relatedProductsLoaded, results, priceInfo, breadcrumbs]);
}
I need to test if trackPdpGtm
are called. Also need to check that its not called in another test case.
gtm.test.js
import { renderHook, cleanup, act } from 'react-hooks-testing-library';
import usePdpGtm from 'utils/hooks/gtmHooks/usePdpGtm';
import useListPageGtm from 'utils/hooks/gtmHooks/useListPageGtm';
import { trackPdpGtm } from 'utils/gtm/pdpGtmUtils';
import { trackListPageGtm } from 'utils/gtm/plpGtmUtils';
import { mount, shallow } from 'enzyme';
import { ProductDescriptionComponent } from 'components/business/ProductDescription/ProductDescriptionComponent';
jest.mock('utils/hooks/gtmHooks/usePdpGtm');
jest.mock('utils/hooks/gtmHooks/useListPageGtm');
jest.mock('utils/gtm/pdpGtmUtils');
jest.mock('utils/gtm/plpGtmUtils');
trackPdpGtm.mockImplementation = jest.fn();
// ALSO TRIED trackPdpGtm.mockImplementation(() => jest.fn());
trackListPageGtm.mockImplementation(() => console.log('adadada'));
describe('analytics helper', () => {
afterEach(cleanup);
it('should fire usePdpGtm Hook', async (done) => {
const pdpData = {
relatedProducts: {
collectionProducts: [],
relatedProductsLoaded: true
},
productInfo: {
variants: [{}],
breadcrumbs: [{}],
serviceWarrantyDetails: {
services: [],
warranties: [{}]
}
},
priceInfo: [{}],
breadcrumbs: [{}]
};
const { result } = renderHook(() => usePdpGtm(pdpData));
//THIS IS FAILING
expect(trackPdpGtm).toHaveBeenCalledTimes(1);
expect(result.current).toBeUndefined();
});
it('should fire usePdpGtm Hook without data', () => {
const { result } = renderHook(() => usePdpGtm(undefined));
// NEED TO TEST IF trackPdpGtm is NOT called. (also failing)
expect(trackPdpGtm).toNotBeCalled();
expect(result.current).toBeUndefined();
});
});
Also tried using trackGtmPdp.mock.calls.length.toBe(1)
.
The usePdpGtm
hook is called inside ProductDescriptionComponent
and receives an object as its argument.
Note: The custom hook is not running during the test. I am not sure but the console.log statements inside are not printed while the test is running.
Any help is highly appreciated.
Upvotes: 6
Views: 12641
Reputation: 102267
You forget to clear the mock.calls
and mock.instances
properties of trackPdpGtm
function mock. That's why your second test case fails. You can use jest.clearAllMocks() to clear it in afterEach
hook.
E.g.
usePdpGtm.ts
:
// @ts-nocheck
import { useEffect } from 'react';
import { trackPdpGtm } from './pdpGtmUtils';
import _ from 'lodash';
export default function useGtmPdp(data = {}) {
console.log('are you getting called?');
const { relatedProducts, results, priceInfo, breadcrumbs } = data;
const relatedProductsLoaded = _.get(relatedProducts, 'relatedProductsLoaded');
useEffect(() => {
if (relatedProductsLoaded) {
trackPdpGtm(data);
}
}, [relatedProductsLoaded, results, priceInfo, breadcrumbs]);
}
pdpGtmUtils.ts
:
export function trackPdpGtm(data) {
console.log('real track pdp gtm implementation');
}
usePdpGtm.test.ts
:
import { renderHook, cleanup } from '@testing-library/react-hooks';
import usePdpGtm from './usePdpGtm';
import { trackPdpGtm } from './pdpGtmUtils';
jest.mock('./pdpGtmUtils');
describe('analytics helper', () => {
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
it('should fire usePdpGtm Hook', () => {
const pdpData = {
relatedProducts: {
collectionProducts: [],
relatedProductsLoaded: true,
},
productInfo: {
variants: [{}],
breadcrumbs: [{}],
serviceWarrantyDetails: {
services: [],
warranties: [{}],
},
},
priceInfo: [{}],
breadcrumbs: [{}],
};
const { result } = renderHook(() => usePdpGtm(pdpData));
expect(trackPdpGtm).toHaveBeenCalledTimes(1);
expect(result.current).toBeUndefined();
});
it('should fire usePdpGtm Hook without data', () => {
const { result } = renderHook(() => usePdpGtm(undefined));
expect(trackPdpGtm).not.toBeCalled();
expect(result.current).toBeUndefined();
});
});
unit test result:
PASS examples/65703648/usePdpGtm.test.ts
analytics helper
✓ should fire usePdpGtm Hook (28 ms)
✓ should fire usePdpGtm Hook without data (4 ms)
console.log
are you getting called?
at Object.useGtmPdp [as default] (examples/65703648/usePdpGtm.ts:7:11)
console.log
are you getting called?
at Object.useGtmPdp [as default] (examples/65703648/usePdpGtm.ts:7:11)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 91.67 | 100 | 66.67 | 91.67 |
pdpGtmUtils.ts | 50 | 100 | 0 | 50 | 2
usePdpGtm.ts | 100 | 100 | 100 | 100 |
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 5.167 s
Upvotes: 6