Почему я должен взывать к обещанию?затем () сам проверить ES6 обещает?


Это следующий вопрос к этому (не обязательно читать этот вопрос, чтобы ответить на этот).

Возьмем в качестве примера следующий компонент React:

class Greeting extends React.Component {
    constructor() {
        fetch("https://api.domain.com/getName")
            .then((response) => {
                return response.text();
            })
            .then((name) => {
                this.setState({
                    name: name
                });
            })
            .catch(() => {
                this.setState({
                    name: "<unknown>"
                });
            });
    }

    render() {
        return <h1>Hello, {this.state.name}</h1>;
    }
}

Используя Jest, вот как мы можем утверждать, что name равно некоторому тексту, возвращенному из запроса getName:

test("greeting name is 'John Doe'", () => {
    const fetchPromise = Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    global.fetch = () => fetchPromise;

    const app = shallow(<Application />);

    return fetchPromise.then((response) => response.text()).then(() => {
        expect(app.state("name")).toEqual("John Doe");
    });
});

Но следующее Не кажется правильным:

return fetchPromise.then((response) => response.text()).then(() => {
    expect(app.state("name")).toEqual("John Doe");
});

Я имею в виду, что я несколько копирую реализацию в тестовом файле.

Мне кажется неправильным, что я ... придется вызывать then() или catch() непосредственно в моих тестах. Особенно когда response.text() также возвращает обещание, и у меня есть два цепных then() s, чтобы просто утверждать, что name равно John Doe.

Я пришел из углового, где можно было просто позвонить $rootScope.$digest() и сделать утверждение после этого.

Разве нет аналогичного способа достичь этого? Или для этого есть другой подход?
2 2

2 ответа:

Я отвечу на свой собственный вопрос после обсуждения этого вопроса с коллегой по работе, который сделал для меня все более ясным. Может быть, вопросы выше уже ответили на мой вопрос, но я даю ответ в словах, которые я могу лучше понять.

Я не столько вызываю then() себя из первоначальной реализации, я только цепляю другой then(), который будет выполнен после других.

Кроме того, лучшей практикой является размещение моего fetch() вызова и всех его then() s и catch()s в его собственной функции и вернуть обещание, как это:

requestNameFromApi() {
    return fetch("https://api.domain.com/getName")
        .then((response) => {
            return response.text();
        })
        .then((name) => {
            this.setState({
                name: name
            });
        })
        .catch(() => {
            this.setState({
                name: "<unknown>"
            });
        });
}

И тестовый файл:

test("greeting name is 'John Doe'", () => {
    global.fetch = () => Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    const app = shallow(<Application />);

    return app.instance().requestNameFromApi.then(() => {
        expect(app.state("name")).toEqual("John Doe");
    });
});

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

Если вас интересует альтернатива возвращению обещания в тесте, мы можем написать тест выше следующим образом:

test("greeting name is 'John Doe'", async () => {
    global.fetch = () => Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    await shallow(<Application />).instance().requestNameFromApi();

    expect(app.state("name")).toEqual("John Doe");
});

Мой ответ, вероятно, отстой,но я впервые протестировал эту функцию недавно, а также с обещаниями fetch. И этот же аспект смущал меня.

Я думаю, что вы не дублируете код в реализации настолько, насколько вам приходится откладывать свое ожидание до тех пор, пока асинхронная часть вашего макета/двойного обещания теста не завершится. Если вы поместите ожидание вне then, ожидание будет выполняться до того, как будет выполнена часть stub, которая задает ваше состояние.

В основном ваш test double по-прежнему является обещанием и ожидает, что предложения в тесте, которые зависят от того, что double выполнил, должны быть в предложении then.