Тестирование промежуточного ПО Redux & Ax ios с Jest - PullRequest
4 голосов
/ 15 января 2020

У меня есть промежуточное ПО, которое перехватывает любые действия с типом, который включает: API_REQUEST. Действие с API_REQUEST создается создателем действия apiRequest(). Когда мое промежуточное ПО перехватывает действие, оно отправляет запрос, используя Ax ios, если запрос был успешным, он отправляет действие, созданное apiSuccess(). Если Ax ios throw после запроса, промежуточное ПО отправит действие, созданное с помощью apiError().

Промежуточное программное обеспечение:

const apiMiddleware: Middleware = ({ dispatch }) => next => async (action): Promise<void> => {
    next(action);

    if (action.type.includes(API_REQUEST)) {
        const body = action.payload;
        const { url, method, feature } = action.meta;

        try {
            const response = await axios({ method, url, data: body });
            dispatch(apiSuccess({ response, feature }));
        } catch (error) {
            console.error(error);
            dispatch(apiError({ error, feature }));
        }
    }
};

Так работает мое промежуточное ПО API. .

Теперь мне интересно, как я могу проверить это с помощью Jest. Может быть, я могу издеваться над Ax ios, чтобы он сделал фальшивый запрос в промежуточном программном обеспечении, но как?

Вот мой текущий тестовый файл:

describe('api middleware', () => {
    const feature = 'test_feat';

    it('calls next', () => {
        const { invoke, next } = create(apiMiddleware);
        const action = { type: 'TEST' };

        invoke(action);

        expect(next).toHaveBeenCalledWith(action);
    });

    it('dispatch api success on request success', () => {
        const { invoke, next, store } = create(apiMiddleware);
        const action = actions.apiRequest({ body: null, method: 'GET', url: '', feature });
        const data = { test: 'test data' };

        jest.mock('axios');

        invoke(action);

        expect(next).toHaveBeenCalledWith(action);

        expect(store.dispatch).toHaveBeenCalledWith(actions.apiSuccess({
            response: axios.mockResolvedValue({ data }),
            feature,
        }));
    });
});

create() это просто функция, которую я взял из этой части do c. Это позволяет мне высмеивать dispatch, getState и next.

Очевидно, это не сработало, но я уверен, что есть способ.

1 Ответ

1 голос
/ 20 января 2020

Вот решение для модульного тестирования:

api.middleware.ts:

import { Middleware } from 'redux';
import axios from 'axios';
import { API_REQUEST } from './actionTypes';
import { apiSuccess, apiError } from './actionCreator';

export const apiMiddleware: Middleware = ({ dispatch }) => (next) => async (action): Promise<void> => {
  next(action);

  if (action.type.includes(API_REQUEST)) {
    const body = action.payload;
    const { url, method, feature } = action.meta;

    try {
      const response = await axios({ method, url, data: body });
      dispatch(apiSuccess({ response, feature }));
    } catch (error) {
      console.error(error);
      dispatch(apiError({ error, feature }));
    }
  }
};

actionTypes.ts:

export const API_REQUEST = 'API_REQUEST';
export const API_REQUEST_SUCCESS = 'API_REQUEST_SUCCESS';
export const API_REQUEST_FAILURE = 'API_REQUEST_FAILURE';

actionCreator.ts:

import { API_REQUEST_SUCCESS, API_REQUEST_FAILURE } from './actionTypes';

export function apiSuccess(data) {
  return {
    type: API_REQUEST_SUCCESS,
    ...data,
  };
}
export function apiError(data) {
  return {
    type: API_REQUEST_FAILURE,
    ...data,
  };
}

api.middleware.test.ts:

import { apiMiddleware } from './api.middleware';
import axios from 'axios';
import { MiddlewareAPI } from 'redux';
import { API_REQUEST, API_REQUEST_SUCCESS, API_REQUEST_FAILURE } from './actionTypes';

jest.mock('axios', () => jest.fn());

describe('59754838', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });
  describe('#apiMiddleware', () => {
    describe('Unit test', () => {
      it('should dispatch api success action', async () => {
        const store: MiddlewareAPI = { dispatch: jest.fn(), getState: jest.fn() };
        const next = jest.fn();
        const action = {
          type: API_REQUEST,
          payload: {},
          meta: { url: 'http://localhost', method: 'get', feature: 'feature' },
        };
        const mResponse = { name: 'user name' };
        (axios as jest.Mocked<any>).mockResolvedValueOnce(mResponse);
        await apiMiddleware(store)(next)(action);
        expect(next).toBeCalledWith(action);
        expect(axios).toBeCalledWith({ method: action.meta.method, url: action.meta.url, data: action.payload });
        expect(store.dispatch).toBeCalledWith({
          type: API_REQUEST_SUCCESS,
          response: mResponse,
          feature: action.meta.feature,
        });
      });

      it('should dispatch api error action', async () => {
        const store: MiddlewareAPI = { dispatch: jest.fn(), getState: jest.fn() };
        const next = jest.fn();
        const action = {
          type: API_REQUEST,
          payload: {},
          meta: { url: 'http://localhost', method: 'get', feature: 'feature' },
        };
        const mError = new Error('network error');
        (axios as jest.Mocked<any>).mockRejectedValueOnce(mError);
        await apiMiddleware(store)(next)(action);
        expect(next).toBeCalledWith(action);
        expect(axios).toBeCalledWith({ method: action.meta.method, url: action.meta.url, data: action.payload });
        expect(store.dispatch).toBeCalledWith({
          type: API_REQUEST_FAILURE,
          error: mError,
          feature: action.meta.feature,
        });
      });
    });
  });
});

Результаты модульных испытаний с отчетом о покрытии:

 PASS  src/stackoverflow/59754838/api.middleware.test.ts (11.206s)
  59754838
    #apiMiddleware
      Unit test
        ✓ should dispatch api success action (21ms)
        ✓ should dispatch api error action (23ms)

  console.error src/stackoverflow/59754838/api.middleware.ts:3460
    Error: network error
        at /Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:42:24
        at step (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:33:23)
        at Object.next (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:14:53)
        at /Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:8:71
        at new Promise (<anonymous>)
        at Object.<anonymous>.__awaiter (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:4:12)
        at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59754838/api.middleware.test.ts:34:46)
        at Object.asyncJestTest (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)
        at mapper (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at promise.then (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
        at process._tickCallback (internal/process/next_tick.js:68:7)

-------------------|----------|----------|----------|----------|-------------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files          |      100 |       50 |      100 |      100 |                   |
 actionCreator.ts  |      100 |      100 |      100 |      100 |                   |
 actionTypes.ts    |      100 |      100 |      100 |      100 |                   |
 api.middleware.ts |      100 |       50 |      100 |      100 |                 9 |
-------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.901s

Исходный код: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59754838

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...