Как протестировать React Hooks useEffect, useCallBack - PullRequest
0 голосов
/ 12 июля 2020

Я пытаюсь написать примеры модульных тестов с использованием 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.spe c .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 голосов
/ 16 июля 2020

Внутренние компоненты React не должны высмеиваться без необходимости, потому что это приводит к синтетическим c тестам, которые не соответствуют принципу работы фреймворка и дают ложные срабатывания. Это особенно относится к хукам, таким как useEffect, потому что они имеют скрытое состояние и могут не работать так, как ожидает тестировщик.

Функциональные компоненты React не раскрывают экземпляр компонента и должны быть протестированы путем утверждения результата. Тесты можно усилить с помощью шпионских утверждений, чтобы сделать результаты менее неоднозначными.

Поскольку слушатели настроены на 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);
...