Jest насмешливые проблемы handleSubmit и handleChange в модальном компоненте - PullRequest
0 голосов
/ 28 апреля 2020

Итак, я пытался освоить модульное тестирование, но в отношении некоторых компонентов у меня возникли проблемы при попытке установки.

ПРИМЕЧАНИЕ: в моем тесте я импортирую компоненты просто как импорт ProfileModal из "./ProfileModal" и т. Д. c.

ТАКЖЕ: причина, по которой я монтирую родительский компонент, а не дочерний компонент ProfileModal, заключается в том, что по какой-либо причине оба параметра mount / shallow в ProfileModal не отображают поля ввода. Они отображаются только при монтировании родительского ProfilePage.

Моя проблема в настоящее время:

  1. Я не уверен, почему функции не вызываются должным образом onClick и onSubmit. Он показывает формы ввода et c и кнопку правильно. Но я продолжаю получать

ожидаемый (jest.fn ()). ToHaveBeenCalledTimes (ожидаемый)

Expected number of calls: 1
Received number of calls: 0
Так что для этого, который я хочу разработать самостоятельно. Но я хотел бы понять ваш мыслительный процесс так, как вы бы go сказали об этом: о настройке функции validate (), которую я настроил.

Таким образом, в настоящее время в компоненте ProfilePage он содержит дочерние компоненты ProfileCard, ProfileModal и PasswordModal)

Все это работает должным образом во внешнем интерфейсе, как и должно, но при настройке модульные тесты для него были немного хитрыми в отношении вызовов ax ios, а теперь издеваются над другими функциями.

Тестирование дочернего компонента, с которым я надеялся получить помощь, это конкретно компонент ProfileModal.

Теперь в родительском ProfilePage модал устанавливается как скрытый, если только не нажимается определенная кнопка, чтобы изменить состояние на true. Поэтому для тестирования, я настроил сам тест:

Компонент ProfileModal (который является дочерним по отношению к ProfilePage):

class ProfileModal extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        name: "",
        email: "",
        phone_number: "",
        profile_url: "",
        user: "",
        nameErrors: "",
        phone_Error: "",
        formErrors: {
            name: "",
            email: "",
            phone_number: ""
        },
        touched: {
            name: false,
            email: false,
            phone_number: false
        }
    };
}
componentDidMount() {
    this.getUserInfo();
}

getUserInfo = async () => {
    let authToken =
        "Bearer " + Cookies.get("auth-token").replace("__#__", ".");

    const instance = axios.create({
        baseURL: "http://127.0.0.1:8000/",
        timeout: 8000,
        headers: {
            "Content-Type": "application/json",
            "X-Requested-With": "XMLHttpRequest",
            Authorization: authToken
        }
    });
    await instance
        .get("api/session")
        .then(json => {
            console.log(json);
            this.setState({
                name: json.data.data.name,
                email: json.data.data.email,
                phone_number: json.data.data.phone_number,
                profile_url: json.data.data.profile_url
            });
        })
        .catch(err => {
            console.log(err);
            throw err;
        });
};
resendEmail = async () => {
    const instance = axios.create({
        baseURL: "http://127.0.0.1:8000/",
        timeout: 8000,
        headers: {
            "Content-Type": "application/json",
            "X-Requested-With": "XMLHttpRequest"
        }
    });
    await instance.post("api/auth/signup/resend_activate").catch(err => {
        console.log(err);
        throw err;
    });
};

uploadImage = async e => {
    const files = e.target.files;
    const data = new FormData();

    data.append("file", files[0]);
    data.append("upload_preset", "Avatar");

    const res = await fetch(
        "https://api.cloudinary.com/v1_1/dqw327vag/image/upload",
        {
            method: "POST",
            body: data
        }
    ).catch(err => {
        console.log(err);
        throw err;
    });

    const file = await res.json();

    this.setState({ profile_url: file.secure_url });
};

submitUpdate = async () => {
    let authToken =
        "Bearer " + Cookies.get("auth-token").replace("__#__", ".");

    const instance = await axios.create({
        baseURL: "http://127.0.0.1:8000/",
        timeout: 1000,
        headers: {
            "Content-Type": "application/json",
            "X-Requested-With": "XMLHttpRequest",
            Authorization: authToken
        }
    });
    const id = this.state.email;

    instance
        .put(`api/users/${id}`, {
            user_email: this.state.email,
            edit_email: this.state.email,
            edit_name: this.state.name,
            edit_profile_url: this.state.profile_url,
            edit_phone_number: this.state.phone_number
        })
        .then(json => {
            if (json.data.result == 1) {
                toastr.success(json.data.message);
                location.reload();
            }
        })
        .catch(err => {
            console.log(err);
            throw err;
        });
};

handleChange = e => {
    e.preventDefault();
    this.setState({
        [e.target.name]: e.target.value
    });
};

validate = () => {
    // let isError = false;
    // const errors = {};
    let isError = false;

    let nameErrors = "";
    let phoneError = "";

    if (this.state.name.length < 4) {
        isError = true;
        nameErrors = "Name has to be at least 4 characters";
        this.setState({ nameErrors: nameErrors });
    }
    // if ((this.state.formErrors.name = "has-success")) {
    //     isError = true;
    // }

    if (
        this.state.phone_number.search(
            /^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/
        )
    ) {
        isError = true;

        phoneError = "Must have only numbers and be in xxx-xxx-xxxx format";
        this.setState({ phone_Error: phoneError });
    }

    return isError;
};

handleSubmit = e => {
    e.preventDefault();
    const err = this.validate();

    if (!err) {
        this.submitUpdate();
    }
};

render() {
    return (
        <div>
            <Modal
                isOpen={this.props.showProfile}
                toggle={this.props.closeProfile}
            >
                <ModalHeader toggle={this.props.closeProfile}>
                    Edit Profile
                </ModalHeader>
                <ModalBody id="profile-modal" className="text-center m-3">
                    <Container fluid>
                        <Form className="profile-form">
                            <FormGroup>
                                <Label className="d-flex align-self-start">
                                    Name
                                </Label>
                                <Input
                                    name="name"
                                    placeholder="Name"
                                    value={this.state.name}

                                    onChange={e => {
                                        this.handleChange(e);
                                    }}

                                    autoComplete="off"
                                />
                                <div style={{ color: "red", fontSize: 12 }}>
                                    {this.state.nameErrors}
                                </div>
                                <FormText style={{ textAlign: "left" }}>
                                    Full Name
                                </FormText>
                            </FormGroup>

                            <FormGroup>
                                <Label className="d-flex align-self-start">
                                    Phone Number
                                </Label>
                                <Input
                                    type="phone_number"
                                    name="phone_number"
                                    placeholder="Phone Number"
                                    value={this.state.phone_number}    
                                    onChange={e => {
                                        this.handleChange(e);
                                    }}

                                    autoComplete="off"
                                />
                                <div style={{ color: "red", fontSize: 12 }}>
                                    {this.state.phone_Error}
                                </div>
                            </FormGroup>

                            <FormGroup>
                                <Label className="d-flex align-self-start">
                                    Change Avatar
                                </Label>
                                <div>
                                    <input
                                        className="hidden"
                                        id="files"
                                        name="image"
                                        type="file"
                                        placeholder="Upload an avatar"
                                        onClick={this.uploadImage}
                                    />
                                    <label
                                        htmlFor="files"
                                        className="custom-upload"
                                    >
                                        <FontAwesomeIcon
                                            className="upload-icon"
                                            icon={faCloudUploadAlt}
                                        />
                                        <strong>Upload Image</strong>
                                    </label>

                                    <br />
                                    <img
                                        id="upload-picture"
                                        className="rounded-circle rounded mr-2 mb-2 hidden"
                                        src={
                                            this.state.profile_url
                                                ? this.state.profile_url
                                                : avatar1
                                        }
                                        value={this.state.profile_url}
                                        onChange={this.uploadImage}
                                        width="140"
                                        height="140"
                                    />
                                </div>
                            </FormGroup>
                        </Form>
                    </Container>
                </ModalBody>
                <ModalFooter>
                    <Button
                        className="resend-btn"
                        onClick={() => this.resendEmail()}
                    >
                        Resend Email Confirmation
                    </Button>
                    <Button
                        className="update-profile-btn"
                        onClick={e => this.handleSubmit(e)}
                    >
                        Save changes
                    </Button>
                </ModalFooter>
            </Modal>
        </div>
    );
}

}

И тест для этого я бегу. Примечание. Если нет другого способа, мне сначала пришлось смонтировать родительский ProfilePage, чтобы получить доступ к компоненту ProfileModal для тестирования.

describe("Profile Modal Component", () => {
    it("checks if handleChange is correctly working", () => {

    const wrapper = mount(<ProfilePage handleChange={handleChange} handleSubmit={handleSubmit} />);
    wrapper.find("button.profile-btn").simulate("click");

    const name = wrapped.find("input[name='name']");
    name.instance().value = "name";
    name.simulate("change");

    wrapped.find("button.update-profile-btn").simulate('click) 



    expect(handleChange).toHaveBeenCalledTimes(1)
    expect(handleSubmit).toHaveBeenCalledTimes(1)

   }),
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...