最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to test for useEffect inside a custom hook? - Stack Overflow

programmeradmin2浏览0评论

So I'm pretty new to testing with react. I have a custom hook that I am calling inside a ponent. 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 'ponents/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.

So I'm pretty new to testing with react. I have a custom hook that I am calling inside a ponent. 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 'ponents/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.

Share Improve this question edited Jan 13, 2021 at 16:58 Rohit Kashyap asked Jan 13, 2021 at 14:11 Rohit KashyapRohit Kashyap 1,5922 gold badges11 silver badges16 bronze badges 2
  • see also epicreact.dev/how-to-test-react-use-effect – Aprillion Commented Jan 13, 2021 at 16:43
  • thanks but this doesn't cover what i am trying to do. – Rohit Kashyap Commented Jan 13, 2021 at 23:18
Add a ment  | 

1 Answer 1

Reset to default 6

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
发布评论

评论列表(0)

  1. 暂无评论