如何测试React Hooks的useEffect,useCallBack

时间:2020-07-12 01:13:57

标签: reactjs jestjs react-hooks enzyme

我正在尝试使用Jest,Enzyme的useEffect和useCallback的React挂钩编写单元测试用例,但是我无法成功。有人可以帮我为下面的代码编写测试用例吗?

ModalComponent.jsx

  const ModalComponent = ({ closeModal }) => {
     const handleModal = useCallback((event) => {
        if (event.keyCode === 27) {
          closeModal(false);
        }
     }
     useEffect(() => {
        document.addEventListener('keydown', handleModal);
        return () => document.removeEventListener('keydown', handleModal);
     }, []);

     return (
        <Modal>
          <Header onClose={closeModal} />
          <Body />
          <Footer />
        </Modal>
     );
  }

ModalComponent.spec.jsx

  describe('Modal Component', () => {
     let props;
     beforeEach(() => {
       props = {
         closeModal: jest.fn(),
       };
     };

     it('should handle useEffect', () => {
        jest.spyOn(React, 'useEffect').mockImplementation(f => f());
        document.addEventListener('keydown', handleModal); 
        document.removeEventListener('keydown', handleModal);
        const component = shallow(<ModalComponent />);
     });
  });

无法覆盖这些行document.addEventListener('keydown', handleModal);document.removeEventListener('keydown', handleModal);if(event.keyCode === 27)closeModal(false)。如何涵盖测试用例?

1 个答案:

答案 0 :(得分:0)

除非有必要,否则不应该对反应内部进行模拟,因为这会导致综合测试与框架的工作方式不一致并给出错误肯定。这尤其适用于useEffect之类的钩子,因为它们具有隐藏状态并且可能无法如测试人员所期望的那样工作。

反应功能组件不会公开组件实例,应该通过声明结果来进行测试。可以通过间谍断言加强测试,以减少结果的歧义。

由于在document上设置了侦听器,因此需要重点关注,例如:

jest.spyOn(document, 'addEventListener');
jest.spyOn(document, 'removeEventListener');
const onCloseSpy = jest.fn();
const component = mount(<ModalComponent closeModal={onCloseSpy} />);
expect(component.find(Header).prop('onClose')).toBe(onCloseSpy);

expect(document.addEventListener).toBeCalledTimes(1);
expect(document.addEventListener).toBeCalledWith('keydown', expect.any(Function));

document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 37}));
expect(onCloseSpy).not.toBeCalled();
document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 27}));
expect(onCloseSpy).toBeCalledWith(false);


// rerender to make sure listeners are set once
component.setProps({});    
expect(document.addEventListener).toBeCalledTimes(1);
expect(document.removeEventListener).not.toBeCalled();

// unmount
component.unmount();
expect(document.removeEventListener).toBeCalledTimes(1);
const [, callback] = document.addEventListener.mock.calls[0];
expect(document.removeEventListener).toBeCalledWith('keydown', callback);