在react / redux app

时间:2018-02-26 18:13:02

标签: reactjs redux fetch jest jest-fetch-mock

我从单元测试和Jest开始。我想要的是在从db获取一些资源后测试操作的响应。

这是行动代码:

export function loadPortlets() {
   return function(dispatch) {
     return portletApi.getAllPortlets().then(response => {
       dispatch(loadPortletsSuccess(response));
       dispatch(hideLoading());
     }).catch(error => {
        dispatch({ type: null, error: error });
        dispatch(hideLoading());
        throw(error);
     });
   };
}

此代码从以下位置获取数据:

  static getAllPortlets() {

    return fetch(`${API_HOST + API_URI}?${RES_TYPE}`)
      .then(response =>
        response.json().then(json => {
          if (!response.ok) {
            return Promise.reject(json);
          }

          return json;
        })
      );
}

这是测试:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetch from 'isomorphic-fetch';
import fetchMock from 'fetch-mock';
import * as actions from '../portletActions';
import * as types from '../actionTypes';

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

const mockResponse = (status, statusText, response) => {
  return new window.Response(response, {
    status: status,
    statusText: statusText,
    headers: {
      'Content-type': 'application/json'
    }
  });
};

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

  it('calls request and success actions if the fetch response was successful', () => {
    window.fetch = jest.fn().mockImplementation(() =>
      Promise.resolve(mockResponse(200, null, [{ portlets: ['do something'] }])));

    const store = mockStore({ portlets: []});

    return store.dispatch(actions.loadPortlets())
      .then(() => {
        const expectedActions = store.getActions();
        expect(expectedActions[0]).toContain({ type: types.LOAD_PORTLETS_SUCCESS });
      })
  });

});

这是运行测试的结果:

FAIL  src\actions\__tests__\portletActions.tests.js                                                                                                                      
  ● async actions › calls request and success actions if the fetch response was successful                                                                                

    expect(object).toContain(value)                                                                                                                                       

    Expected object:                                                                                                                                                      
      {"portlets": [// here an array of objects], "type": "LOAD_PORTLETS_SUCCESS"}                                                            
    To contain value:                                                                                                                                                     
      {"type": "LOAD_PORTLETS_SUCCESS"}                                                                                                                                   

      at store.dispatch.then (src/actions/__tests__/portletActions.tests.js:56:34)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

在此示例的redux文档(https://redux.js.org/recipes/writing-tests)中,他们收到的结果只包含已执行的操作类型,但我得到的是真实数据以及数组中的操作

所以我不确定代码是错误的,还是测试,或者两者兼而有之!

在此先感谢,非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

您使用此单元测试进行了太多测试。我看到你正在使用thunks它看起来像你可以改变你的fetch作为一个模块传递到thunk并做这样的事情。我用过茉莉花,但基本上是一样的。你不想在这里嘲笑你的商店只是行动和派遣。单元测试的重点应该是测试异步操作,而不是测试从db或redux存储交互中获取实际数据,这样你就可以将所有这些存根。“/ p>

作为参考,configureStore看起来像这样......

const createStoreWithMiddleware = compose(
  applyMiddleware(thunk.withExtraArgument({ personApi }))
)(createStore);

测试案例......

  it('dispatches an action when receiving', done => {
    const person = [{ firstName: 'Francois' }];
    const expectedAction = {
      type: ActionTypes.RECEIVED,
      payload: {
        people,
      },
    };

    const dispatch = jasmine.createSpy();
    const promise = Q.resolve(person);
    const personApi = {
      fetchPerson: jasmine
        .createSpy()
        .and.returnValue(promise),
    };

    const thunk = requestPerson();
    thunk(dispatch, undefined, { personApi });

    promise.then(() => {
      expect(dispatch.calls.count()).toBe(2);
      expect(dispatch.calls.mostRecent().args[0]).toEqual(expectedAction);
      done();
    });
  });