Тестирование асинхронных действий редукса с Typecript

Эй, ребята, я пытаюсь протестировать своих создателей асинхронных действий с Typescript, но я получаю ошибку типа, которую мне не удается устранить.

Это мои действия:

export const loadCurrentUserRequest = () => ({
  type: LOAD_CURRENT_USER_REQUEST
})

export const loadCurrentUserSuccess = (payload: any) => ({
  type: LOAD_CURRENT_USER_SUCCESS,
  payload
})

export const loadCurrentUserFailure = (payload: any) => ({
  type: LOAD_CURRENT_USER_FAILURE,
  payload
})

И это мой асинхронный создатель действий:

export const loadCurrentUser = () => {
  return async (dispatch: Dispatch<any>) => {
    dispatch(loadCurrentUserRequest())
    try {
      const response = await get(`api/currentuser`)
      if (!response.ok) {
        dispatch(loadCurrentUserFailure({ type: null, message: 'error' }))
      } else {
        const json = await response.json()
        dispatch(loadCurrentUserSuccess(json))
      }
      return response
    } catch (err) {
      dispatch(loadCurrentUserFailure({ type: err.name, message: err.message }))
      logError(err.name, err.message)
      return err
    }
  }
}

Функция 'get' - это промежуточное ПО, которое я создал для обработки вызова GET 'fetch' (он добавляет некоторые вещи в заголовок и т. Д.).

Это мой тест:

  it('create an action to load the current user', () => {
    const middlewares = [thunk]
    const mockStore = configureMockStore(middlewares)
    const store = mockStore()
    const expectActions = [{ type: LOAD_CURRENT_USER_REQUEST }]

    store.dispatch(actions.loadCurrentUser())
    expect(store.getActions()).toEqual(expectActions)
  })

Я получаю эту ошибку в моей консоли:

Argument of type '(dispatch: Dispatch<any>) => Promise<any>' is not assignable to parameter of type 'AnyAction'.
  Property 'type' is missing in type '(dispatch: Dispatch<any>) => Promise<any>' but required in type 'AnyAction'.

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

Я знаю, что мне придется издеваться fetch API вызывает и обновляет мой expectActions переменная, но код не компилируется из-за этого..

0 ответов

Вот решение:

index.ts:

import fetch from 'node-fetch';
import { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';

const logError = (name, message) => console.error(`name: ${name}, message: ${message}`);
const get = url => fetch(url);

export const LOAD_CURRENT_USER_REQUEST = 'LOAD_CURRENT_USER_REQUEST';
export const LOAD_CURRENT_USER_SUCCESS = 'LOAD_CURRENT_USER_SUCCESS';
export const LOAD_CURRENT_USER_FAILURE = 'LOAD_CURRENT_USER_FAILURE';

export const loadCurrentUserRequest = () => ({
  type: LOAD_CURRENT_USER_REQUEST
});

export const loadCurrentUserSuccess = (payload: any) => ({
  type: LOAD_CURRENT_USER_SUCCESS,
  payload
});

export const loadCurrentUserFailure = (payload: any) => ({
  type: LOAD_CURRENT_USER_FAILURE,
  payload
});

export const loadCurrentUser = () => {
  return async (dispatch: ThunkDispatch<any, any, AnyAction>) => {
    dispatch(loadCurrentUserRequest());
    try {
      const response = await get(`api/currentuser`);
      if (!response.ok) {
        dispatch(loadCurrentUserFailure({ type: null, message: 'error' }));
      } else {
        const json = await response.json();
        dispatch(loadCurrentUserSuccess(json));
      }
      return response;
    } catch (err) {
      dispatch(loadCurrentUserFailure({ type: err.name, message: err.message }));
      logError(err.name, err.message);
      return err;
    }
  };
};

Модульный тест:

import configureStore from 'redux-mock-store';
import thunk, { ThunkDispatch } from 'redux-thunk';
import * as actions from './';
import { AnyAction } from 'redux';
import fetch from 'node-fetch';

jest.mock('node-fetch', () => jest.fn());

const initialState = {};
type State = typeof initialState;
const middlewares = [thunk];
const mockStore = configureStore<State, ThunkDispatch<State, any, AnyAction>>(middlewares);
const store = mockStore(initialState);

describe('action creators', () => {
  describe('#loadCurrentUser', () => {
    afterEach(() => {
      store.clearActions();
    });
    it('load current user success', async () => {
      const userMocked = { userId: 1 };
      (fetch as jest.MockedFunction<any>).mockResolvedValueOnce({
        ok: true,
        json: jest.fn().mockResolvedValueOnce(userMocked)
      });
      await store.dispatch(actions.loadCurrentUser());
      expect(fetch).toBeCalledWith('api/currentuser');
      expect(store.getActions()).toEqual([
        { type: actions.LOAD_CURRENT_USER_REQUEST },
        { type: actions.LOAD_CURRENT_USER_SUCCESS, payload: userMocked }
      ]);
    });

    it('load current user failed', async () => {
      (fetch as jest.MockedFunction<any>).mockResolvedValueOnce({ ok: false });
      await store.dispatch(actions.loadCurrentUser());
      expect(fetch).toBeCalledWith('api/currentuser');
      expect(store.getActions()).toEqual([
        { type: actions.LOAD_CURRENT_USER_REQUEST },
        {
          type: actions.LOAD_CURRENT_USER_FAILURE,
          payload: {
            type: null,
            message: 'error'
          }
        }
      ]);
    });

    it('load current user failed when fetch error', async () => {
      (fetch as jest.MockedFunction<any>).mockRejectedValueOnce(new Error('fetch error'));
      await store.dispatch(actions.loadCurrentUser());
      expect(fetch).toBeCalledWith('api/currentuser');
      expect(store.getActions()).toEqual([
        { type: actions.LOAD_CURRENT_USER_REQUEST },
        {
          type: actions.LOAD_CURRENT_USER_FAILURE,
          payload: {
            type: 'Error',
            message: 'fetch error'
          }
        }
      ]);
    });
  });
});

Результат модульного тестирования со 100% покрытием:

 PASS  src/stackru/54693637/index.spec.ts
  action creators
    #loadCurrentUser
      ✓ load current user success (8ms)
      ✓ load current user failed (1ms)
      ✓ load current user failed when fetch error (8ms)

  console.error src/stackru/54693637/index.ts:3541
    name: Error, message: fetch error

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        3.32s, estimated 5s

Вот завершенная демонстрация: https://github.com/mrdulin/jest-codelab/tree/master/src/stackru/54693637

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