如何测试动作创建者分配了正确的动作?

时间:2018-08-01 08:49:09

标签: react-redux jestjs

我正在尝试遵循此tutorial,但我不完全了解如何创建它。我认为执行操作的方式与示例显示方式不同。从组件中,我使用this.props.actionName调用动作,但示例中使用dispatch。以下是我的一个动作文件的样子

app / actions / admin.js

import axios from 'axios';
export const FETCH_CONTENT_VIDEO_LIST = 'fetch_content_video_list';
export function fetchContentVideoList(page, size, where, sort) {
    const request = axios.get(`/api/user/get/content/management/method/video/list/format/json?quiet=1&page=` + page + `&size=` + size + `&where=` + JSON.stringify(where) + `&sort=` + sort);
    return {
        type: FETCH_CONTENT_VIDEO_LIST,
        payload: request
    };
}

app / reducers / reducer_content.js

import _ from 'lodash';
import { FETCH_CONTENTS } from '../actions';
import { 
    FETCH_APPSERVICES, 
    FETCH_APPSERVICES_COUNT,    
    FETCH_OSTYPES,
    FETCH_OSTYPES_COUNT,
    FETCH_ENVTYPES,
    FETCH_ENVTYPES_COUNT,
    FETCH_LOCATIONZONES,
    FETCH_LOCATIONZONES_COUNT,
    UPLOAD_DOCUMENT_SUCCESS,
    UPLOAD_DOCUMENT_FAIL,
} from '../actions/content';
import { FETCH_CONTENT_VIDEO_LIST, FETCH_CONTENT_VIDEO_LIST_COUNT, UPDATE_CONTENT_VIDEO_LIST } from '../actions/admin';

export default function(state = {}, action) {
    switch (action.type) {
        case FETCH_CONTENTS:
            if ( typeof action.payload.data !== 'object'){
                return Object.assign({}, state, {
                    error: {
                        code: "AUTHENTICATION",
                        message: 'Your session has expired',
                        action
                    }
                 });
            }else if (action.payload.data.header.error) {
                return Object.assign({}, state, {
                    error: {
                        code: "INVALID ACTION",
                        message: action.payload.data.header.message,
                        action
                    }
                 });

           } else {
               return _.mapKeys(action.payload.data.body.recordset.record, 'target');
           }


    case FETCH_APPSERVICES:
    case FETCH_APPSERVICES_COUNT:
    case FETCH_LOCATIONZONES:
    case FETCH_LOCATIONZONES_COUNT:
    case FETCH_OSTYPES:
    case FETCH_OSTYPES_COUNT:
    case FETCH_ENVTYPES:
    case FETCH_ENVTYPES_COUNT:  
    case FETCH_CONTENT_VIDEO_LIST:
    case FETCH_CONTENT_VIDEO_LIST_COUNT:
    case UPDATE_CONTENT_VIDEO_LIST: 
        if ( typeof action.payload.data !== 'object'){
            return Object.assign({}, state, {
                error: {
                    code: "AUTHENTICATION",
                    message: 'Your session has expired',
                    action
                }
             });
        }else if (action.payload.data.header.error) {
            return Object.assign({}, state, {
                error: {
                    code: "INVALID ACTION",
                    message: action.payload.data.header.message,
                    action
                }
             });

       } else {
           return action.payload.data.body.recordset.record;
       }

    case UPLOAD_DOCUMENT_SUCCESS:
    case UPLOAD_DOCUMENT_FAIL:
        return action;
    default:
        return state;
    }
}

我的测试如下所示,但失败。我没有使用redux-thunk

test / jest / actions / admin.test.js

    import configureMockStore from 'redux-mock-store'
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'
import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library

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

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

  it('FETCH_CONTENT_VIDEO_LIST', () => {
    fetchMock
      .getOnce('/contentvideolist', { body: { todos: ['do something'] }, headers: { 'content-type': 'application/json' } })

console.log(types.FETCH_CONTENT_VIDEO_LIST);
    const expectedActions = [
        { type: types.FETCH_CONTENT_VIDEO_LIST }
    ]
    const store = mockStore({ todos: [] })
      console.log(store);
console.log(actions);
    return store.dispatch(actions.fetchContentVideoList()).then(() => {
      // return of async actions
        console.log(store.getActions());
      expect(store.getActions()).toEqual(expectedActions)
    })
  })
})

在这里失败。

 FAIL  tests/jest/actions/admin.test.js
  async actions
    ✕ FETCH_CONTENT_VIDEO_LIST (14ms)

  ● async actions › FETCH_CONTENT_VIDEO_LIST

    TypeError: store.dispatch(...).then is not a function

      25 |     const store = mockStore({ todos: [] })
      26 |
    > 27 |     return store.dispatch(actions.fetchContentVideoList()).then(() => {
      28 |       // return of async actions
      29 |      console.log(store.getActions());
      30 |       expect(store.getActions()).toEqual(expectedActions)

      at Object.<anonymous> (tests/jest/actions/admin.test.js:27:60)

更新

这是新错误

FAIL  ../actions/admin.test.js
  async actions
    ✕ FETCH_CONTENT_VIDEO_LIST (33ms)

  ● async actions › FETCH_CONTENT_VIDEO_LIST

    TypeError: store.dispatch(...).then is not a function

      25 |     const store = mockStore({ todos: [] })
      26 | console.log(actions);
    > 27 |     return store.dispatch(actions.fetchContentVideoList()).then(() => {
      28 |       // return of async actions
      29 |      console.log(store.getActions());
      30 |       expect(store.getActions()).toEqual(expectedActions)

      at Object.<anonymous> (tests/jest/actions/admin.test.js:27:60)

  console.log ../actions/admin.test.js:26
    { FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
      FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
      UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
      fetchContentVideoList: [Function: fetchContentVideoList],
      fetchContentVideoListCount: [Function: fetchContentVideoListCount],
      updateContentVideoList: [Function: updateContentVideoList] }

更新2

import configureMockStore from 'redux-mock-store'
//import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'


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

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

  it('FETCH_CONTENT_VIDEO_LIST', () => {
    let mock = new MockAdapter(axios);
      const data = { response: true };
      mock.onGet('/contentvideolist').reply(200, data);


    console.log(types);
    const expectedActions = [
        { type: types.FETCH_CONTENT_VIDEO_LIST }
    ]
    const store = mockStore({ todos: [] })
    console.log(actions);
    store.dispatch(actions.fetchContentVideoList());
    expect(store.getActions()).toEqual(expectedActions);
  });
});

types仅显示为[function],所以我不能做types.FETCH_CONTENT_VIDEO_LIST。它显示为undefined

结果

     ● async actions › FETCH_CONTENT_VIDEO_LIST

        expect(received).toEqual(expected)

        Expected value to equal:
          [{"type": undefined}]
        Received:
          [{"payload": {}, "type": "fetch_content_video_list"}]

        Difference:

        - Expected
        + Received

          Array [
            Object {
        -     "type": undefined,
        +     "payload": Promise {},
        +     "type": "fetch_content_video_list",
            },
          ]

          26 |     console.log(actions);
          27 |     store.dispatch(actions.fetchContentVideoList());
        > 28 |     expect(store.getActions()).toEqual(expectedActions);
          29 |   });
          30 | });
          31 |

          at Object.<anonymous> (tests/jest/actions/admin.test.js:28:32)

      console.log tests/jest/actions/admin.test.js:21
        { default: [Function] }

      console.log tests/jest/actions/admin.test.js:26
        { FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
          FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
          UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
          fetchContentVideoList: 

[Function: fetchContentVideoList],
      fetchContentVideoListCount: [Function: fetchContentVideoListCount],
      updateContentVideoList: [Function: updateContentVideoList] }

更新3

我试图复制此https://www.leighhalliday.com/mocking-axios-in-jest-testing-async-functions

但是它的类型失败了

import * as actions from '../../../app/actions/admin'
//import * as types from '../../../app/reducers/reducer_content'

const mockAxios = {
  get: jest.fn(() => Promise.resolve({ data: {} }))
};

it("fetches data for FETCH_CONTENT_VIDEO_LIST", async () => {
  // setup
  mockAxios.get.mockImplementationOnce(() =>
    Promise.resolve({
      data: { results: {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST} }
    })
  );

  // work
  const contentVideoList = await actions.fetchContentVideoList(1,1,{},'id');

  // expect
  const expectedActions = {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}

  expect(contentVideoList).toEqual(expectedActions);
  expect(mockAxios.get).toHaveBeenCalledTimes(1);
  expect(mockAxios.get).toHaveBeenCalledWith(
    "/api/user/get/content/management/method/video/list/format/json",
    {
      params: {
        client_id: process.env.REACT_APP_UNSPLASH_TOKEN,
        query: "cats"
      }
    }
  );
});

结果

● fetches data for FETCH_CONTENT_VIDEO_LIST

    expect(received).toEqual(expected)

    Expected value to equal:
      {"payload": {}, "type": "fetch_content_video_list"}
    Received:
      {"payload": {}, "type": "fetch_content_video_list"}

    Difference:

    - Expected
    + Received

      Object {
    -   "payload": Object {},
    +   "payload": Promise {},
        "type": "fetch_content_video_list",
      }

      20 |   const expectedActions = {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}
      21 |
    > 22 |   expect(contentVideoList).toEqual(expectedActions);
      23 |   expect(mockAxios.get).toHaveBeenCalledTimes(1);
      24 |   expect(mockAxios.get).toHaveBeenCalledWith(
      25 |     "https:///api/user/get/content/management/method/video/list/format/json",

      at _callee$ (tests/jest/actions/admin.test.js:22:28)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:296:22)
      at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
      at step (tests/jest/actions/admin.test.js:9:191)
      at tests/jest/actions/admin.test.js:9:361

更新4

import configureMockStore from 'redux-mock-store'
//import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'


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

describe('async actions', () => {

  it('FETCH_CONTENT_VIDEO_LIST', () => {
    let mock = new MockAdapter(axios);
      const data = { response: true };
      mock.onGet('/contentvideolist').reply(200, data);


    console.log(types);
    const expectedActions = [{"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}]
    const store = mockStore({ fetch_content_video_list: [] })
    console.log(actions);
    store.dispatch(actions.fetchContentVideoList());
    expect(store.getActions()).toEqual(expectedActions);
  });

});

结果4

● async actions › FETCH_CONTENT_VIDEO_LIST

    expect(received).toEqual(expected)

    Expected value to equal:
      [{"payload": {}, "type": "fetch_content_video_list"}]
    Received:
      [{"payload": {}, "type": "fetch_content_video_list"}]

    Difference:

    - Expected
    + Received

      Array [
        Object {
    -     "payload": Object {},
    +     "payload": Promise {},
          "type": "fetch_content_video_list",
        },
      ]

      24 |     console.log(actions);
      25 |     store.dispatch(actions.fetchContentVideoList());
    > 26 |     expect(store.getActions()).toEqual(expectedActions);
      27 |   });
      28 | });
      29 |

      at Object.<anonymous> (tests/jest/actions/admin.test.js:26:32)

  console.log tests/jest/actions/admin.test.js:21


       { default: [Function] }

      console.log tests/jest/actions/admin.test.js:24
        { FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
          FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
          UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
          fetchCo

ntentVideoList: [Function: fetchContentVideoList],
      fetchContentVideoListCount: [Function: fetchContentVideoListCount],
      updateContentVideoList: [Function: updateContentVideoList] }

1 个答案:

答案 0 :(得分:2)

store.dispatch不返回承诺,而是返回已调度的操作(请参阅dispatch docs),因此无法在结果上调用then

相反,执行以下操作,即分派该函数创建的操作,然后检查是否分派了正确的操作:

store.dispatch(actions.fetchContentVideoList());
expect(store.getActions()).toEqual(expectedActions);