【问题标题】:Test the state in parent component that was updated thru child component测试通过子组件更新的父组件中的状态
【发布时间】:2019-06-07 08:53:20
【问题描述】:

我在父组件中有一个名为onFormSubmit 的函数。我将此函数传递给子组件。在子组件中提交表单时,将调用子组件内的onFormSubmit 函数将值传递回父组件。然后这个onFormSubmit 函数会进行某种检查,并在此基础上更新父组件中的状态。

我想模拟/存根这个 ajax/api 调用。我怎样才能做到这一点?或者我如何编写我的代码以使这个场景是可测试的。

我的父组件如下所示:

class App extends React.Component {

state: { message: "" }; //I want to test the state of message

onFormSubmit = async (form) => {
    if (form.primaryEmail !== "") {
        const response = await axios.post("api/", form);
        this.setState(
            {
                message: (response.status === 200) ? "Your email has been updated." : ""
            });
    } else {
        this.setState({ message: "No Update" });
    }
}

render() {
    return (
        <div>
            <Child onSubmit={this.onFormSubmit} />
            <h4>{this.state.message}</h4>
        </div>
    );
}
}

我的子组件如下所示:

class Child extends React.Component {
state = {
    primaryEmail: "",
};

onPrimaryEmailChange = e => {
    this.setState({ primaryEmail: e.target.value });
}

onFormSubmit = e => {
    e.preventDefault();
    this.props.onSubmit(this.state); //passing the value back to parent component
}

render() {
    return (
        <form onSubmit={this.onFormSubmit}>
            <h3>Email Address</h3>
            <div>
                <input type="email" value={this.state.primaryEmail} onChange={this.onPrimaryEmailChange} />
            </div>
            <div>
                <button type="submit">Submit</button>
            </div>
        </form >
    );
}
}

我的测试如下所示:

test("When valid form is submitted, it should show a success message", () => {
const wrapper = mount(<App />);
wrapper.find("input").at(0).simulate("change", {
  target: {
    value: "a@b.c",
  }
});
wrapper.find('form').simulate('submit');
expect(wrapper.state('message')).toEqual('Your email has been updated.');
});

我收到此错误:

期望值等于:

“您的电子邮件已更新。”

收到:

""

【问题讨论】:

    标签: reactjs jestjs enzyme


    【解决方案1】:

    碰巧的是,本周早些时候我遇到了类似的情况。这是我解决它的方法。可能有更好的解决方案,但这适用于我的情况。

    免责声明:我将其从内存中直接写入 StackOverflow 答案字段,因此可能不是 100% 准确。

    首先,您应该模拟 Axios,以便您可以控制 API 的输出以进行测试。您永远不应该实际执行来自测试用例的 HTTP 请求,因为您不是在测试您的 API——您是在测试您的组件如何响应特定的 API 响应。我的项目使用create-react-app,它将Jest 配置为从项目根目录中的__mocks__ 文件夹加载模拟。

    __mocks__/axios.js:

    export default {
        // since you are only testing "axios.post()", I'm only mocking "post"
        post: jest.fn()
    }
    

    然后在您的父组件的测试中,您可以为返回 200 响应的 post 函数指定一个模拟实现(您正在测试的就是这种情况)。

    __tests__/App.test.jsx:

    // in Jest context, this should load from __mocks__/axios.js
    import axios from "axios";
    
    test("When valid form is submitted, it should show a success message", () => {
        // Axios itself returns a Promise, so the mock should as well
        axios.post.mockImplementationOnce(
            (url, formData) => Promise.resolve({
                status: 200
            })
        );
    
        const wrapper = mount(<App />);
    
        // Optionally, test the default state to be an empty string
        expect(wrapper.state()).toHaveProperty("message");
        expect(wrapper.state().message).toBe("");
    
        wrapper.find("input").at(0).simulate("change", {
            target: {
                value: "a@b.c",
            }
        });
    
        wrapper.find("form").simulate("submit");
    
        // Optionally, test if Axios was called
        expect(axios.post).toHaveBeenCalled();
    
        // More optionally, test if it was called with the correct email address
        expect(axios.post).toHaveBeenCalledWith(
            expect.any(),
            expect.objectContaining({ primaryEmail: "a@b.c" })
        );
    
        // Note that even though Axios may have been called, the asynchronous
        // Promise may not have completed yet which means the state will not
        // have been updated yet. To be safe, let's use setImmediate(), which
        // should wait for any pending Promises to complete first
        setImmediate(async () => {
            // Now we can test that the state has changed
            expect(wrapper.state().message).toBe("Your email has been updated.");
        });
    });
    

    【讨论】:

    • 感谢您的出色回答。你引导我模拟 axios,尽管不同......使用axios-mock-adapter 因为export default... 没有在__mocks__/axios.js. 中工作非常感谢你引导我正确的路径。
    猜你喜欢
    • 2021-01-07
    • 1970-01-01
    • 2017-09-28
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-26
    • 2021-03-02
    • 1970-01-01
    相关资源
    最近更新 更多