Как я могу проверить асинхронные запросы axios в redux-saga?

У меня есть сага в форме:

export function* apiRequest(apiBaseUrl, action) {
  const axiosInst = getAxiosInst(apiBaseUrl);

  try {
    if (!action.serviceName) {
      throw new Error("No service name provided");
    }
    const response = yield call( axiosInst.get, `/${action.serviceName}/foo-api` );

    const data = response.data;

    let resultAction;

    switch (response.status) {
      case 404:
        resultAction = INVALID_ENTITY_REQUESTED;
        break;
      case 200:
        ...
      default:
        throw new Error("Invalid response from server.");
    }
    yield put({ type: resultAction, data });
  } catch (err) {
    yield put({
      type: ERROR,
      error: err.message || "There was an unknown error."
    });
  }
}

export function* watchApiRequest(apiBaseUrl) {
  const boundApiRequest = apiRequest.bind(null, apiBaseUrl);

  yield takeEvery(API_CALL, boundApiRequest);
}

И тест вроде следующего:

import { apiRequest } from "../services/apiRequest.js";
import MockAdapter from "axios-mock-adapter";
import { default as axios } from "axios";
import { put } from "redux-saga/effects";
import {
  API_CALL,
  API_SUCCESS
} from "../common/actions.js";

describe("Saga that will run on every api call event", () => {
  const mock = new MockAdapter(axios);

  afterEach(() => {
    mock.reset();
  });

  it("should dispatch the correct event when an API request succeeds", () => {
    mock.onGet().reply(200, { foo: "bar" });

    const generator = apiRequest("", {
      type: API_CALL,
      serviceName: "test"
    });

    generator.next();

    expect(generator.next().value).toMatchObject(
      put({
        type: API_SUCCESS,
        data: { foo: "bar" }
      })
    );
  });
});

Это не работает Мой тест не проходит с результатом, подобным следующему:

Expected value to match object:
      {"@@redux-saga/IO": true, "PUT": {"action": {"type": "API_SUCCESS"}, "channel": null}}
    Received:
      {"@@redux-saga/IO": true, "PUT": {"action": {"error": "Cannot read property 'data' of undefined", "type": "ERROR"}, "channel": null}}

Кажется, что код работает нормально при практическом использовании, но когда я пытаюсь проверить его таким образом, кажется, что обещание от асинхронного вызова API через Axios не разрешается. Я искал какое-то руководство по тестированию вызовов API в Axios, как это, и видел некоторые предложения, что вместо того, чтобы высмеивать ответ API с помощью фиктивного адаптера Axios, я должен передать функции генератора ответ, вызвав generator.next({status: 200, data: { foo: "bar" }) перед expect(...) пункт, но это, похоже, тоже не работает.

Я нахожу документы по редукс-саге о тестировании немного непрозрачными, что я делаю не так?

1 ответ

Я разобрался с ответом. Это о природе функций генератора.

generator.next() продвигает генератор к следующему yield инструкция; для такого тестирования тестирование ответов на ваши запросы API фактически не требуется, вы можете просто вставить ответы в генератор, передав желаемое значение генератору. next() метод.

Итак, в моем тестовом коде выше, есть два вызова next(), Первый звонок next() приведет к тому, что сага сделает свой запрос API. Второй перейдет к следующему результату, либо отправив действие с put() или отправка ошибки в блоке catch. Хитрость в том, что желаемый ложный ответ API должен быть предоставлен во втором вызове next()

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