使用自定义钩子和axios使用React Testing Library测试React容器

时间:2019-09-30 16:30:31

标签: javascript reactjs unit-testing frontend react-testing-library

我是测试前端应用程序的新手,我只是切换到创建自定义钩子。今天我花了一天的时间,研究这里可用的各种测试选项,并在开始使用Enzyme进行测试之后,我决定从测试库重新开始。

我正在开发一个小型应用程序,该应用程序基本上具有一个使用两个自定义钩子的容器SignUpFormContainer,我想编写一个呈现SignUpFormContainer的测试,检查是否显示了微调器,然后模拟API的响应并检查输出是否正确再次显示。 不幸的是,我还没有成功编写测试。我认为模拟Axios缺少一些东西。

我运行测试时失败,并且文本预期元素为“正在加载...”,而不是“你好”。

有人知道我的考试出了什么问题吗?

谢谢

马修

import React, {useEffect, useState} from 'react';
import SignUpFormComponent from "components/SignUpFormComponent/SignUpFormComponent";
import useForm from "Hooks/useForm/useForm";
import validate from "./SignUpFormValidationRules";
import {Redirect, withRouter} from "react-router";
import {SignUpServices} from "Services/services";
import {Credentials, SignUpFormContainerAdminProps} from "./types";
import useLinkVerification from "Hooks/useVerification/useVerification";
import {IS_EXPIRED, IS_LOADING, IS_VERIFIED} from "constants/verification";
import LoadingPage from "components/LoadingPage/LoadingPage";
import {CLIENT, MEMBER} from "constants/users";


const SignUpFormContainer: React.FC<SignUpFormContainerAdminProps> = (props: SignUpFormContainerAdminProps) => {

    const {values, handleChange, handleSubmit, errors} = useForm(signUp, validate);
    const {match, history, location} = props;
    const [isSubmitBtnDisabled, setDisabled] = useState<boolean>(true);
    const [credentials, setCredentials] = useState<Credentials>({token: "", email: ""});
    const [step, setStep] = useState<number>(0);
    const {verificationStatus} = useLinkVerification({match, history, location});
    const userType = location.pathname.startsWith("/client") ? CLIENT : MEMBER;
    const [fetchError, setFetchError] = useState<string>("");

    useEffect(() => {
        if (match.params.token && match.params.email) {
            setCredentials({email: match.params.email, token: match.params.token})
        }
    }, [match.params]);

    useEffect(() => {
        if (values.country && values.lastName && values.firstName && values.password && values.passwordConfirmation && values.dataManagement) {
            setDisabled(false)
        } else {
            setDisabled(true)
        }
    }, [values]);


    async function signUp() {
        setFetchError("");
        try {
            const signUpServices = new SignUpServices();
            await signUpServices.newUserFromInvitation({
                email: credentials.email,
                token: credentials.token,
                firstName: values.firstName as string,
                country: values.country as string,
                lastName: values.lastName as string,
                password: values.password as string
            }, userType);
            setStep(1)
        } catch (error) {
            setFetchError("Un compte associé à cette adresse email existe déjà. Veuillez contacter la personne qui vous a envoyé cet email.")
        }
    }


    switch (verificationStatus) {
        case IS_LOADING:
            return <LoadingPage/>;
        case IS_VERIFIED:
            return <SignUpFormComponent handleChange={handleChange}
                                        step={step}
                                        fetchError={fetchError}
                                        errors={errors}
                                        state={values} handleSubmit={handleSubmit}
                                        isSubmitBtnDisabled={isSubmitBtnDisabled}/>;
        case IS_EXPIRED:
            return <Redirect to={"/expired"}/>;
        default:
            return <Redirect to={"/expired"}/>;
    }

};

export default withRouter(SignUpFormContainer)
const useLinkVerification = (props: UseLinkVerificationProps) => {

    const {match, location} = props;
    const [verificationStatus, setVerificationStatus] = useState<VerificationStatus>(IS_LOADING);
    const {email, token} = match.params;
    const userType = location.pathname.startsWith("/client") ? CLIENT : MEMBER;


    useAsyncEffect(async () => {
        try {
            const signUpServices = new SignUpServices();
            const response = await signUpServices.verifyLink({emailAdress: email, token: token}, userType);
            if (response.data) setVerificationStatus(IS_VERIFIED)
        } catch (error) {
            setVerificationStatus(IS_EXPIRED);
        }

    }, [email, token, userType]);

    return {
        verificationStatus
    }
};

export default useLinkVerification;
import React, {useEffect, useState} from 'react';
import {SignUpFormState} from "containers/SignUpFormContainer/types";

const useForm = (callback: () => void, validate: (values: {[name:string]: any}) => {[name:string]: any}) => {

    const [values, setValues] = useState<SignUpFormState>({
    });

    const [errors, setErrors] = useState({});
    const [isSubmitting, setIsSubmitting] = useState(false);


    const handleSubmit = (event: React.ChangeEvent<HTMLFormElement>) => {
        if (event) event.preventDefault();
        setIsSubmitting(true);
        setErrors(validate(values));
    };

    useEffect(() => {
        if (Object.keys(errors).length === 0 && isSubmitting) {
            callback();
        }
    }, [errors, isSubmitting]);

    const handleChange = (name: string, value: string | boolean) => {
        setValues(values => ({ ...values, [name]: value }));
    };

    return {
        handleChange,
        handleSubmit,
        values,
        errors,
    }
};

export default useForm;
import React from "react";
import SignUpFormContainer from "./SignUpFormContainer";
import {cleanup, render, waitForElement} from "@testing-library/react";
import {Router} from "react-router";
import {createMemoryHistory} from "history";
import '@testing-library/jest-dom/extend-expect'

const axiosMock = {
    get: jest.fn().mockResolvedValue({data: {}})
};

function renderWithRouter(children: any, historyConf = {}) {
    const history = createMemoryHistory(historyConf);
    return render(<Router history={history}>{children}</Router>)
}


describe("Test SignUpContainer", () => {

    it('should load and render a form', async () => {

        axiosMock.get.mockResolvedValueOnce({ data: { greeting: "hello there" } });

        const {getByText, getByTestId} = renderWithRouter(<SignUpFormContainer/>);
        expect(getByText("Loading...")).toBeInTheDocument();

        const resolvedSpan = await waitForElement(() => getByTestId("resolved"));


        expect(resolvedSpan).toHaveTextContent("hello there");
    });

});

0 个答案:

没有答案