Почему redux-mock-store не показывает действие, отправленное в обещаниях catch?

Мне очень плохо, когда речь заходит о заглавном вопросе, извините за это.

Моя проблема:

Я тестирую свои асинхронные редукционные действия, как это предлагается в документации. Я высмеиваю вызовы API с nock и проверьте отправленные действия с redux-mock-store, Пока он отлично работает, но у меня есть один тест, который не проходит, хотя он явно работает. Отправленное действие также не отображается в массиве, возвращаемом store.getActions() и при этом состояние не изменяется в store.getState(), Я уверен, что это происходит, потому что я вижу это, когда тестирую вручную и наблюдаю с помощью Redux Dev Tools.

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

Как выглядит мой код:

Действие:

export const login = (email, password) => {
    return dispatch => {
        dispatch(requestSession());
        return httpPost(sessionUrl, {
            session: {
                email,
                password
            }
        })
        .then(data => {
            dispatch(setUser(data.user));
            dispatch(push('/admin'));
        })
        .catch(error => {
            error.response.json()
            .then(data => {
                dispatch(setError(data.error))
            })
        });
    };
}

это httpPost метод это просто обертка fetch Это выдает, если код состояния не находится в диапазоне 200-299 и уже анализирует JSON для объекта, если он не терпит неудачу. Я могу добавить это здесь, если это кажется уместным, но я не хочу делать это дольше, чем это уже есть.

Действие, которое не появляется, dispatch(setError(data.error)),

Тест:

it('should create a SET_SESSION_ERROR action', () => {
    nock(/example\.com/)
    .post(sessionPath, {
        session: {
            email: fakeUser.email,
            password: ''
        }
    })
    .reply(422, {
        error: "Invalid email or password"
    })

    const store = mockStore({
        session: {
            isFetching: false,
            user: null,
            error: null
        }
    });

    return store.dispatch(actions.login(
        fakeUser.email,
        ""))
        .then(() => {
            expect(store.getActions()).toInclude({
                type: 'SET_SESSION_ERROR',
                error: 'Invalid email or password'
            })
        })
});

Спасибо, что даже прочитали.

Редактировать:

setErrorдействие:

const setError = (error) => ({
  type: 'SET_SESSION_ERROR',
  error,
});

httpPostметод:

export const httpPost = (url, data) => (
  fetch(url, {
    method: 'POST',
    headers: createHeaders(),
    body: JSON.stringify(data),
  })
    .then(checkStatus)
    .then(response => response.json())
);

const checkStatus = (response) => {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
};

1 ответ

Решение

Из-за того, что вы используете вложенную асинхронную функцию в методе catch - вам нужно вернуть обещание:

.catch(error => {
  return error.response.json()
  .then(data => {
    dispatch(setError(data.error))
  })
});

В противном случае отправка будет вызвана после вашего подтверждения.

Смотрите примитивные примеры:
https://jsfiddle.net/d5fynntw/ - без возврата
https://jsfiddle.net/9b1z73xs/ - с возвращением

Другие вопросы по тегам