使用 Jest 和 Enzyme 测试使用 Redux 的功能性 React 组件

Posted

技术标签:

【中文标题】使用 Jest 和 Enzyme 测试使用 Redux 的功能性 React 组件【英文标题】:Using Jest and Enzyme to test functional React components that are using Redux 【发布时间】:2020-04-08 07:03:31 【问题描述】:

我正在开发一个 React 项目,我正在使用功能组件和 redux。我正在尝试为我的 RegisterForm 组件编写测试,但 Jest 和 Enzyme 需要一个 redux 存储。

我的组件:

import React,  useState  from 'react';
import axios from 'axios';
import  useSelector, useDispatch  from 'react-redux';
import  registerRequest, registerSuccess, registerFailure  from '../redux/user/userActions';

const RegisterForm = () => 
  const dispatch = useDispatch();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [submitDisabled, setSubmitDisabled] = useState(false);

  const handleFormSubmit = e => 
    e.preventDefault();
    setSubmitDisabled(true);
    const data =  email, password ;
    dispatch(registerRequest());
    axios.post(`$process.env.REACT_APP_USERS_SERVICE_URL/auth/register`, data)
      .then(res => 
        dispatch(registerSuccess(res.data.auth_token));
      )
      .catch(err => 
        if (err.response) 
          dispatch(registerFailure(err.response));
         else 
          dispatch(registerFailure(err));
        
      );
    setSubmitDisabled(false);
  ;

  return (
    <div className='container'>
      <h1>Register</h1>
      <form onSubmit=handleFormSubmit>
        <div className='form-group'>
          <label htmlFor='email' className='row'>
            <div className='form-label col-form-label col-sm-2'>Email</div>
            <div className='col'>
              <input
                type='email'
                className='form-control'
                id='email'
                sm='10'
                required
                value=email
                onChange=e => setEmail(e.target.value)
              />
            </div>
          </label>
        </div>
        <div className='form-group'>
          <label htmlFor='password' className='row'>
            <div className='form-label col-form-label col-sm-2'>Password</div>
            <div className='col'>
              <input
                type='password'
                className='form-control'
                id='password'
                sm='10'
                required
                value=password
                onChange=e => setPassword(e.target.value)
              />
            </div>
          </label>
        </div>
        <button
          type='submit'
          className='btn btn-primary'
          disabled=submitDisabled
        >
          Submit
        </button>
      </form>
    </div>
  );
;

RegisterForm.propTypes = ;

export default RegisterForm;

由于 React Hooks 仍然相对较新,而且人们不再使用 Redux 进行状态管理,我无法找到足够好的问题/博客文章来讨论处理这种情况的可能方法。

很多人建议采用以下方法:

import configureStore from 'redux-mock-store';
import  mount  from 'enzyme';
import  Provider  from 'react-redux';
import RegisterForm from './components/RegisterForm'

const mockStore = configureStore([]);

const store = mockStore(
  loading: false,
  authToken: '',
  error: ''
);

const component = mount(
  <Provider store=store>
    <RegisterForm />
  </Provider>
)

我会使用这种方法,但我不喜欢你必须安装组件的事实。我更愿意使用 shallow 但我找不到使用它的实现。

有什么方法可以将 shallow 与我正在使用的堆栈一起使用,或者是否有其他方法可以构建我的组件以将 redux 从中分离出来,这样测试就不需要要模拟的商店?

【问题讨论】:

【参考方案1】:

你可以模拟useDispatch

import  useDispatch  from 'react-redux';

jest.mock(`react-redux`, () => (
  useDispatch: jest.fn()
));

....
 beforeEach(() => 
   useDispatch.mockClear();
 );
...

useSelector 稍微难一点:

import  useSelector  from 'react-redux';

jest.mock(`react-redux`, () => (
  useSelector: jest.fn()
));

function mockUseSelectorWithData(mockedStore) 
  useSelector.mockImplementation((callback) => callback(mockedStore));


...
it('...', () => 
  const someInitialData =  ..... ;
  mockUseSelectorWithData(mockedStore);
  const wrapper = shallow(<YourComp />);
  ...
  mockUseSelectorWithData(storeWithSomethingChanged);
  // changing prop or simulating event to re-render component with new data
  ....
);

还要注意shallow() 不能正确调用useEffect hooks。

【讨论】:

刚刚用 useDispatch 试了一下,效果很好!非常感谢!

以上是关于使用 Jest 和 Enzyme 测试使用 Redux 的功能性 React 组件的主要内容,如果未能解决你的问题,请参考以下文章

Jest 和 Enzyme 的问题

异步 componentDidMount 时使用 React 的 Jest 和 Enzyme 进行测试

如何使用 Jest 和 Enzyme 测试样式组件以具有属性

使用钩子时 Jest/Enzyme 测试抛出错误

使用 Jest 和 Enzyme 测试 react-router 重定向

使用 React Suspense 和 React.lazy 子组件进行 Jest/Enzyme 类组件测试