how to match a returned Promise in using Jest with redux action

2.3k Views Asked by At

I am using reactjs with redux and the action is using axios and returning a Promise. my test is not matching the type. I have tried different ways of doing it but end up with the same problem. also tried https://www.leighhalliday.com/mocking-axios-in-jest-testing-async-functions

    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()

    descri

be('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);
  });
});

here is the reult

 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",
        },
      ]

actions/admin.js

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
    };
}

new error after update

Actions must be plain objects. Use custom middleware for async actions.

      23 |     const store = mockStore({ fetch_content_video_list: [] })
      24 |     console.log(actions);
    > 25 |     store.dispatch(actions.fetchContentVideoList());
      26 |     expect(store.getActions()).toEqual(expectedActions);
      27 |   });
      28 | });

UPDATE

    import configureMockStore from 'redux-mock-store'
    import promise from 'redux-promise';
    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 = [promise]
const mockStore = configureMockStore(middlewares)

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);
  });
});

i added promise as middleware

result

(node:19685) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Request failed with status code 404
(node:19685) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
 FAIL  tests/jest/actions/admin.test.js
  async actions
    ✕ FETCH_CONTENT_VIDEO_LIST (43ms)

  ● async actions › FETCH_CONTENT_VIDEO_LIST

    expect(received).toEqual(expected)

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

    Difference:

    - Expected
    + Received

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

      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',
      fetchContentVideoList: [Function: fetchContentVideoList],
      FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
      UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
      fetchContentVideoListCount: [Function: fetchContentVideoListCount],
      updateContentVideoList: [Function: updateContentVideoList] }

FIXED

added a then clause. is this correct way to do this?

    import configureMockStore from 'redux-mock-store'
import promise from 'redux-promise';
import expect from 'expect' // You can use any testing library
import axios from 'axios';
import * as actions from '../../../app/actions/admin'


const middlewares = [promise]
const mockStore = configureMockStore(middlewares)
const store = mockStore({  })

beforeEach(() => { // Runs before each test in the suite
    store.clearActions();
      });

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


  it('FETCH_CONTENT_VIDEO_LIST', () => {

    const expectedActions = [{"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}]

    store.dispatch(actions.fetchContentVideoList()).then(() => {
        expect(store.getActions()).toEqual(expectedActions);
    });
  });


  it('FETCH_CONTENT_VIDEO_LIST_COUNT', () => {

        const expectedActions = [{"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST_COUNT}]


        store.dispatch(actions.fetchContentVideoListCount()).then(() => {
            expect(store.getActions()).toEqual(expectedActions);
        });
      });

  it('UPDATE_CONTENT_VIDEO_LIST', () => {

        const expectedActions = [{"payload": {}, "type": actions.UPDATE_CONTENT_VIDEO_LIST}]


        store.dispatch(actions.updateContentVideoList()).then(() => {
            expect(store.getActions()).toEqual(expectedActions);
        });
      });

});
1

There are 1 best solutions below

3
On BEST ANSWER

fetchContentVideoList doesn't wait for the promise to be resolved or rejected, so the payload becomes the unresolved promise.

One way to fix this would be to use the async/await method:

export async function fetchContentVideoList(page, size, where, sort) {
    const request = await axios.get('url');
    return {
        type: FETCH_CONTENT_VIDEO_LIST,
        payload: request
    };
}

See async docs on MDN for more information.

Edit for Question Update

This change turns the action into an asynchronous action, which means that it needs to be handled in a slightly different way. Making the expections after the promise has resolved (as you are doing) is one good way to test the action.