如何在自定义挂钩内测试 useEffect?

Roh*_*yap 4 javascript reactjs jestjs react-testing-library react-hooks-testing-library

所以我对反应测试还很陌生。我有一个在组件内部调用的自定义挂钩。我正在使用renderHook中的方法react-hook-testing-library

useEffect我需要测试是否调用自定义挂钩内的方法。我似乎无法弄清楚这一点。

在另一种情况下,我需要弄清楚是否trackPdpGtm没有被调用。

注意:该钩子不返回任何数据。这主要用于发送分析信息。

目前的方法:

使用PdpGtm.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]);
}

Run Code Online (Sandbox Code Playgroud)

我需要测试是否trackPdpGtm被调用。还需要检查它是否在另一个测试用例中没有被调用。

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();
   });

});

Run Code Online (Sandbox Code Playgroud)

还尝试使用trackGtmPdp.mock.calls.length.toBe(1).

usePdpGtm钩子在内部被调用ProductDescriptionComponent并接收一个对象作为其参数。

注意: 测试期间自定义钩子不运行。我不确定,但是测试运行时不会打印里面的 console.log 语句。

非常感谢任何帮助。

sli*_*wp2 6

您忘记清除函数模拟的mock.calls和属性。这就是你的第二个测试用例失败的原因。您可以使用jest.clearAllMocks()来清除钩子中的它。mock.instancestrackPdpGtmafterEach

\n

例如

\n

usePdpGtm.ts:

\n
// @ts-nocheck\nimport { useEffect } from \'react\';\nimport { trackPdpGtm } from \'./pdpGtmUtils\';\nimport _ from \'lodash\';\n\nexport default function useGtmPdp(data = {}) {\n  console.log(\'are you getting called?\');\n  const { relatedProducts, results, priceInfo, breadcrumbs } = data;\n  const relatedProductsLoaded = _.get(relatedProducts, \'relatedProductsLoaded\');\n  useEffect(() => {\n    if (relatedProductsLoaded) {\n      trackPdpGtm(data);\n    }\n  }, [relatedProductsLoaded, results, priceInfo, breadcrumbs]);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

pdpGtmUtils.ts:

\n
export function trackPdpGtm(data) {\n  console.log(\'real track pdp gtm implementation\');\n}\n
Run Code Online (Sandbox Code Playgroud)\n

usePdpGtm.test.ts:

\n
import { renderHook, cleanup } from \'@testing-library/react-hooks\';\nimport usePdpGtm from \'./usePdpGtm\';\nimport { trackPdpGtm } from \'./pdpGtmUtils\';\n\njest.mock(\'./pdpGtmUtils\');\n\ndescribe(\'analytics helper\', () => {\n  afterEach(() => {\n    jest.clearAllMocks();\n    cleanup();\n  });\n\n  it(\'should fire usePdpGtm Hook\', () => {\n    const pdpData = {\n      relatedProducts: {\n        collectionProducts: [],\n        relatedProductsLoaded: true,\n      },\n      productInfo: {\n        variants: [{}],\n        breadcrumbs: [{}],\n        serviceWarrantyDetails: {\n          services: [],\n          warranties: [{}],\n        },\n      },\n      priceInfo: [{}],\n      breadcrumbs: [{}],\n    };\n    const { result } = renderHook(() => usePdpGtm(pdpData));\n    expect(trackPdpGtm).toHaveBeenCalledTimes(1);\n    expect(result.current).toBeUndefined();\n  });\n\n  it(\'should fire usePdpGtm Hook without data\', () => {\n    const { result } = renderHook(() => usePdpGtm(undefined));\n    expect(trackPdpGtm).not.toBeCalled();\n    expect(result.current).toBeUndefined();\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

单元测试结果:

\n
 PASS  examples/65703648/usePdpGtm.test.ts\n  analytics helper\n    \xe2\x9c\x93 should fire usePdpGtm Hook (28 ms)\n    \xe2\x9c\x93 should fire usePdpGtm Hook without data (4 ms)\n\n  console.log\n    are you getting called?\n\n      at Object.useGtmPdp [as default] (examples/65703648/usePdpGtm.ts:7:11)\n\n  console.log\n    are you getting called?\n\n      at Object.useGtmPdp [as default] (examples/65703648/usePdpGtm.ts:7:11)\n\n----------------|---------|----------|---------|---------|-------------------\nFile            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s \n----------------|---------|----------|---------|---------|-------------------\nAll files       |   91.67 |      100 |   66.67 |   91.67 |                   \n pdpGtmUtils.ts |      50 |      100 |       0 |      50 | 2                 \n usePdpGtm.ts   |     100 |      100 |     100 |     100 |                   \n----------------|---------|----------|---------|---------|-------------------\nTest Suites: 1 passed, 1 total\nTests:       2 passed, 2 total\nSnapshots:   0 total\nTime:        5.167 s\n
Run Code Online (Sandbox Code Playgroud)\n