Проверьте состояние в родительском компоненте, который был обновлен через дочерний компонент - PullRequest
0 голосов
/ 12 января 2019

У меня есть функция с именем 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.');
});

Я получаю эту ошибку:

Ожидаемое значение равно:

"Ваш электронный адрес обновлен."

Поступило:

""

1 Ответ

0 голосов
/ 12 января 2019

Как это случилось, я столкнулся с подобной ситуацией в начале этой недели. Вот как я это решил. Возможно, есть лучшие решения, но в моей ситуации это сработало.

Отказ от ответственности: Я пишу это из памяти непосредственно в поле ответа 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()
}

Затем в тесте вашего родительского компонента вы можете указать фиктивную реализацию для функции post, которая возвращает ответ 200 (это тот случай, когда вы тестируете).

__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.");
    });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...