在添加eventListener的同时测试React useEffect钩子

时间:2019-09-05 02:00:20

标签: reactjs jestjs enzyme react-hooks use-effect

我的React代码中有一个功能组件,如下所示:

const Compo = ({funcA}) => {
   useEffect(() => {
      window.addEventListener('x', funcB, false);

      return () => {
       window.removeEventListener('x', funcB, false); 
      }
   });

   const funcB = () => {funcA()};      

   return (
      <button
        onClick={() => funcA()}
      />
   );
};

Compo.propTypes = {
   funcA: func.isRequired
}

export default Compo;

我需要测试上述功能组件,以确保按照useEffect()挂钩中所述添加和删除事件侦听器。

这是我的测试文件的样子-

const addEventSpy = jest.spyOn(window, 'addEventListener');
const removeEventSpy = jest.spyOn(window, 'removeEventListener');

let props = mockProps = {funcA: jest.fn()};
const wrapper = mount(<Compo {...props} />);

const callBack = wrapper.instance().funcB;     <===== ERROR ON THIS LINE
expect(addEventSpy).toHaveBeenCalledWith('x', callBack, false);

wrapper.unmount();
expect(removeEventSpy).toHaveBeenCalledWith('x', callBack, false);

但是,我在声明“ callBack”常量的行上收到以下错误(代码上方已突出显示):

  

TypeError:无法读取null的属性'funcB'

有效地,它使组件正常,但wrapper.instance()的评估结果为null,这引发了以上错误。

请问有人想解决上述错误吗?

1 个答案:

答案 0 :(得分:1)

这是我的单元测试策略:

index.tsx

import React, { useEffect } from 'react';

const Compo = ({ funcA }) => {
  useEffect(() => {
    window.addEventListener('x', funcB, false);

    return () => {
      window.removeEventListener('x', funcB, false);
    };
  }, []);

  const funcB = () => {
    funcA();
  };

  return <button onClick={funcB} />;
};

export default Compo;

index.spec.tsx

import React from 'react';
import { mount } from 'enzyme';
import Compo from './';

describe('Compo', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should call funcA', () => {
    const events = {};
    jest.spyOn(window, 'addEventListener').mockImplementation((event, handle, options?) => {
      events[event] = handle;
    });
    jest.spyOn(window, 'removeEventListener').mockImplementation((event, handle, options?) => {
      events[event] = undefined;
    });

    const mProps = { funcA: jest.fn() };
    const wrapper = mount(<Compo {...mProps}></Compo>);
    expect(wrapper.find('button')).toBeDefined();
    events['x']();
    expect(window.addEventListener).toBeCalledWith('x', expect.any(Function), false);
    expect(mProps.funcA).toBeCalledTimes(1);

    wrapper.unmount();
    expect(window.removeEventListener).toBeCalledWith('x', expect.any(Function), false);
  });
});

覆盖率100%的单元测试结果:

PASS  src/stackoverflow/57797518/index.spec.tsx (8.125s)
  Compo
    ✓ should call funcA (51ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |      100 |      100 |      100 |      100 |                   |
 index.tsx |      100 |      100 |      100 |      100 |                   |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.556s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57797518