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

时间:2019-12-15 16:57:16

标签: reactjs redux react-redux jestjs react-hooks

我正在做一个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 个答案:

答案 0 :(得分:0)

您可以嘲笑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