如何测试和模拟反应函数/组件

时间:2021-06-30 17:18:55

标签: reactjs django unit-testing jestjs react-testing-library

这是我使用 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 });
        }
    };

2 个答案:

答案 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);
});