如何用 jasmine 和 enzyme 测试 React useEffect hooks

How to test React useEffect hooks with jasmine and enzyme

我找不到如何在测试我的组件时调用我的 useEffect 挂钩。

我尝试了几种类似的解决方案,但都没有用:https://reactjs.org/docs/test-utils.html#act

我的组件:

const mapDispatchToProps = (dispatch: IDispatch, ownProps: ITextAreaOwnProps): ITextAreaDispatchProps => ({
        onMount: () => dispatch(addTextArea(ownProps.id)),
});

export const TextArea = (props) => {
        React.useEffect(() => {
            props.onMount();
        }, []);

        // more code... //

        return (
            <>
                <TextareaTagName
                    {...props.additionalAttributes}
                    className={props.className}
                />
                {props.children}
                {getValidationLabel()}
            </>
        );
    };

我的测试:

it('should call prop onMount on mount', () => {
    const onMount = jasmine.createSpy('onMount');

    mount(<TextArea id="textarea-id" onMount={onMount} />);

    expect(onMount).toHaveBeenCalledTimes(1);
});

简短的回答是您不能直接测试它。您基本上需要触发组件中的更改检测以激活 useEffect 挂钩。您可以通过这样的方式轻松使用 react-dom/test-utils

import { act } from 'react-dom/test-utils';
import { shallow, mount } from 'enzyme';

it('should call prop onMount on mount', () => {
  const onMount = jasmine.createSpy('onMount');

  const wrapper = mount(<TextArea id="textarea-id" onMount={onMount} />);

  act(() => {
    wrapper.update();
  });

  expect(onMount).toHaveBeenCalledTimes(1);
});

关于文档,useEffect 应该在任何道具更改时更新。

  1. 您可以使用其他道具回忆测试。
  2. 可以模拟一下使用效果。

 /* mocking useEffect */
useEffect = jest.spyOn(React, "useEffect");
mockUseEffect(); // 2 times
mockUseEffect(); //

const mockUseEffect = () => {
       useEffect.mockImplementationOnce(f => f());
  };

测试 onMount 函数调用的方法是调用 wrapper.update() 方法。您必须使用来自酶的 mount,因为 shallow 尚不支持调用挂钩。更多关于这里的问题 - useEffect not called when the component is shallow rendered #2086

import { mount } from 'enzyme';

it('should call prop onMount on mount', () => {
  // arrange
  const onMount = jasmine.createSpy('onMount');
  const wrapper = mount(<TextArea id="textarea-id" onMount={onMount} />);

  // act
  wrapper.update();

  // assert
  expect(onMount).toHaveBeenCalledTimes(1);
});

如果您在 useEffect 挂钩中进行 api 调用,则必须更新 setTimeout 挂钩中的包装器,以便将更改反映在组件上。

import { mount } from 'enzyme';

it('should call prop onMount on mount', () => {
  // arrange
  const onMount = jasmine.createSpy('onMount');
  const wrapper = mount(<TextArea id="textarea-id" onMount={onMount} />);

  setTimeout(() => {
      // act
      wrapper.update();

      // assert
      expect(onMount).toHaveBeenCalledTimes(1);
  });
});