我正在做一个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>
)
我会使用这种方法,但我不喜欢你必须挂载组件的事实。我宁愿使用浅层,但我找不到使用它的实现。
有什么方法可以在我正在使用的堆栈中使用浅层,或者是否有其他方法可以构建我的组件以将 redux 从中分离出来,以便测试不需要模拟存储?
你可以模拟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
钩子。