使用 Jest 在 Redux thunk 中测试分派的操作

人气:188 发布:2022-10-16 标签: reactjs jestjs fetch redux redux-thunk

问题描述

我对 Jest 很陌生,而且我承认我不是测试异步代码的专家...

I'm quite new to Jest and admittedly am no expert at testing async code...

我使用了一个简单的 Fetch 助手:

I have a simple Fetch helper I use:

export function fetchHelper(url, opts) {
    return fetch(url, options)
        .then((response) => {
            if (response.ok) {
                return Promise.resolve(response);
            }

            const error = new Error(response.statusText || response.status);
            error.response = response;

            return Promise.reject(error);
        });
    }

并像这样实现它:

export function getSomeData() {
    return (dispatch) => {
        return fetchHelper('http://datasource.com/').then((res) => {
            dispatch(setLoading(true));
            return res.json();
        }).then((data) => {
            dispatch(setData(data));
            dispatch(setLoading(false));
        }).catch(() => {
            dispatch(setFail());
            dispatch(setLoading(false));
        });
    };
}

但是我想测试在正确的情况下以正确的顺序触发了正确的调度.

However I want to test that the correct dispatches are fired in the correct circumstances and in the correct order.

过去使用 sinon.spy() 很容易,但我不知道如何在 Jest 中复制它.理想情况下,我希望我的测试看起来像这样:

This used to be quite easy with a sinon.spy(), but I can't quite figure out how to replicate this in Jest. Ideally I'd like my test to look something like this:

expect(spy.args[0][0]).toBe({
  type: SET_LOADING_STATE,
  value: true,
});


expect(spy.args[1][0]).toBe({
  type: SET_DATA,
  value: {...},
});

提前感谢您的任何帮助或建议!

Thanks in advance for any help or advice!

推荐答案

redux 文档有一个很棒的 关于测试异步操作创建者的文章:

The redux docs have a great article on testing async action creators:

对于使用 Redux Thunk 或其他中间件的异步操作创建者,最好完全模拟 Redux存储测试.您可以使用 redux-mock-store 将中间件应用到模拟商店.您还可以使用 fetch-mock 来模拟 HTTP 请求.

For async action creators using Redux Thunk or other middleware, it's best to completely mock the Redux store for tests. You can apply the middleware to a mock store using redux-mock-store. You can also use fetch-mock to mock the HTTP requests.

import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import * as actions from '../../actions/TodoActions'
import * as types from '../../constants/ActionTypes'
import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library

const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)

describe('async actions', () => {
  afterEach(() => {
    fetchMock.reset()
    fetchMock.restore()
  })

  it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', () => {
    fetchMock
      .getOnce('/todos', { body: { todos: ['do something'] }, headers: { 'content-type': 'application/json' } })


    const expectedActions = [
      { type: types.FETCH_TODOS_REQUEST },
      { type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } }
    ]
    const store = mockStore({ todos: [] })

    return store.dispatch(actions.fetchTodos()).then(() => {
      // return of async actions
      expect(store.getActions()).toEqual(expectedActions)
    })
  })
})

他们的方法不是使用 jest(或 sinon)来监视,而是使用模拟存储并断言调度的操作.这具有能够处理 thunk 调度 thunk 的优势,这对于间谍来说可能非常困难.

Their approach is not to use jest (or sinon) to spy, but to use a mock store and assert the dispatched actions. This has the advantage of being able to handle thunks dispatching thunks, which can be very difficult to do with spies.

这一切都直接来自文档,但如果您希望我为您的 thunk 创建一个示例,请告诉我.

This is all straight from the docs, but let me know if you want me to create an example for your thunk.

909