这是我使用 jest + react 测试库进行用户注册的测试,问题是测试更新了数据库。
因此在第二次运行时测试失败(因为第一次运行注册了用户)
所以我的问题是有人知道我如何模拟这个功能吗? 我会很感激我能得到的任何帮助。提前致谢
测试
test('signup should dispatch signupAction', async () => {
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
initialState = {
authReducer: { isAuthenticatedData: false },
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<Router>
<UserSignup />
</Router>
</Provider>
);
const nameTextbox = screen.getByPlaceholderText('Name*');
const emailTextbox = screen.getByPlaceholderText('Email*');
const passwordTextbox = screen.getByPlaceholderText('Password*');
const confirmTextbox = screen.getByPlaceholderText('Confirm Password*');
const signupButton = screen.getByRole('button', { name: 'Register' });
userEvent.type(nameTextbox, 'newtestuser');
userEvent.type(emailTextbox, 'newtestuser@gmail.com');
userEvent.type(passwordTextbox, 'testuser123');
userEvent.type(confirmTextbox, 'testuser123');
userEvent.click(signupButton);
await waitFor(() => expect(store.getActions()[0].type).toBe('SIGNUP_SUCCESS'));
});
注册组件
const userSignup = () => {
const dispatch = useDispatch();
const isAuthenticatedData = useSelector((state) => state.authReducer.isAuthenticatedData);
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
re_password: '',
});
const [accountCreated, setAccountCreated] = useState(false);
const { name, email, password, re_password } = formData;
const onChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = (e) => {
e.preventDefault();
if (password === re_password) {
try {
dispatch(
signupAction({
name,
email,
password,
re_password,
})
);
setAccountCreated(true);
} catch {
window.scrollTo(0, 0);
}
}
};
if (isAuthenticatedData) return <Redirect to='/' />;
if (accountCreated) return <Redirect to='/login' />;
return (
<div data-testid='userSignup'>
<h1>Sign Up</h1>
<p>Create your Account</p>
<form onSubmit={(e) => onSubmit(e)}>
<div>
<input
type='text'
placeholder='Name*'
name='name'
value={name}
onChange={(e) => onChange(e)}
required
/>
</div>
<div>
<input
type='email'
placeholder='Email*'
name='email'
value={email}
onChange={(e) => onChange(e)}
required
/>
</div>
<div>
<input
type='password'
placeholder='Password*'
name='password'
value={password}
onChange={(e) => onChange(e)}
minLength='6'
required
/>
</div>
<div>
<input
type='password'
placeholder='Confirm Password*'
name='re_password'
value={re_password}
onChange={(e) => onChange(e)}
minLength='6'
required
/>
</div>
<button type='submit'>Register</button>
</form>
<p>
Already have an account? <Link to='/login'>Sign In</Link>
</p>
</div>
);
};
export default connect()(userSignup);
注册操作
export const signupAction =
({ name, email, password, re_password }) =>
async (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify({
name,
email,
password,
re_password,
});
try {
const res = await axios.post(`${process.env.REACT_APP_API_URL}/api/djoser/users/`, body, config);
dispatch({ type: SIGNUP_SUCCESS, payload: res.data });
} catch (err) {
dispatch({ type: SIGNUP_FAIL });
}
};
答案 0 :(得分:0)
假设您正在编写单元测试(这可能是您应该开始的地方),那么您正在寻找一个称为“模拟”的概念。这个想法是你的 React 单元测试应该只测试你的 React 代码。你的 React 单元测试不应该依赖于数据库甚至 API。正如您所发现的,这会带来各种挑战。
基本上模拟框架的工作方式是用一些假数据配置它们。然后,当您运行测试时,您的代码会使用这些虚假数据,而不是调用 API。
我看到您正在使用 axios 来调用您的 API。我建议您查看 axios-mock-adapter 以帮助您模拟这些 axios 调用。
答案 1 :(得分:0)
我设法解决了这个问题,这是对那些需要它的人的考验
import '@testing-library/jest-dom/extend-expect';
import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import UserSignup from '../../../components/users/UserSignup';
import configureStore from 'redux-mock-store';
import { signupAction } from '../../../redux/actions/auth';
import thunk from 'redux-thunk';
import userEvent from '@testing-library/user-event';
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
let initialState = {
authReducer: {},
};
const store = mockStore(initialState);
jest.mock('../../../redux/actions/auth', () => ({ signupAction: jest.fn() }));
test('Redux - signup should dispatch signupAction', () => {
render(
<Provider store={store}>
<Router>
<UserSignup />
</Router>
</Provider>
);
initialState = {
authReducer: { isAuthenticatedData: false },
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<Router>
<UserSignup />
</Router>
</Provider>
);
const nameTextbox = screen.getByPlaceholderText('Name*');
const emailTextbox = screen.getByPlaceholderText('Email*');
const passwordTextbox = screen.getByPlaceholderText('Password*');
const confirmTextbox = screen.getByPlaceholderText('Confirm Password*');
const signupButton = screen.getByRole('button', { name: 'Register' });
const nameValue = 'testuser';
const emailValue = 'testuser@gmail.com';
const passwordValue = 'testuser123';
const rePasswordValue = 'testuser123';
userEvent.type(nameTextbox, nameValue);
userEvent.type(emailTextbox, emailValue);
userEvent.type(passwordTextbox, passwordValue);
userEvent.type(confirmTextbox, rePasswordValue);
userEvent.click(signupButton);
const timesActionDispatched = signupAction.mock.calls.length;
expect(timesActionDispatched).toBe(1);
expect(signupAction.mock.calls[0][0].name).toEqual(nameValue);
expect(signupAction.mock.calls[0][0].email).toEqual(emailValue);
expect(signupAction.mock.calls[0][0].password).toEqual(passwordValue);
expect(signupAction.mock.calls[0][0].re_password).toEqual(rePasswordValue);
});