Search code examples
reactjstestingreduxjestjs

store.dispatch cannot read property 'then' of undefined


I am trying to test my async action and I get this error:

store.dispatch cannot read property 'then' of undefined

I tried to use the then on the actionTypes (I am sorry, that is an actionCreator but I imported it as actionType), but it goes from undefined to:

TypeError: actionTypes.fetchGitHubDataAsync(...).then is not a function.

it('Dispatches BOOKS_SUCCESS after fetching books', () => {
   // Response body sample
   const mockData = [
   {
       "name": "javascript",
       "display_name": "JavaScript",
       "short_description": "JavaScript (JS) is a lightweight interpreted programming language with first-class functions.",
       "description": "JavaScript (JS) is a lightweight interpreted or JIT-compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat. JavaScript is a prototype-based, multi-paradigm, dynamic language, supporting object-oriented, imperative, and declarative (e.g. functional programming) styles.",
       "created_by": "Brendan Eich",
       "released": "December 4, 1995",
       "created_at": "2016-11-28T18:41:00Z",
       "updated_at": "2019-11-06T15:05:24Z",
       "featured": true,
       "curated": true,
       "score": 7954.724
   }
   ]

   fetchMock.getOnce('https://api.github.com/search/topics?q=javascript',
                { body: { results: mockData }})

   const expectedActions = [
         { type: actionTypes.FETCH_GITHUB_DATA},
   ]
   store.dispatch(actionTypes.fetchGitHubDataAsync())
             .then(() => {
                 expect(store.getActions()).toEqual(expectedActions)
   })
})

actions js file

export const fetchGitHubDataAsync = () => {
    return dispatch => {
        fetch('https://api.github.com/search/topics?q=javascript', {
            headers: {
              'Accept': 'application/vnd.github.mercy-preview+json'
            }
          })
            .then(res => res.json())
            .then(json => {console.log('json', json.items.slice(0, 5)); 
            return dispatch({type: 'FETCH_GITHUB_DATA', payload: json.items.slice(0, 5)})});
    }
}

Solution

  • Here is an unit test working example without using third-party mock library.

    action.js:

    export const fetchGitHubDataAsync = () => {
      return dispatch => {
        return fetch('https://api.github.com/search/topics?q=javascript', {
          headers: {
            Accept: 'application/vnd.github.mercy-preview+json'
          }
        })
          .then(res => res.json())
          .then(json => {
            console.log('json', json.items.slice(0, 5));
            return dispatch({ type: 'FETCH_GITHUB_DATA', payload: json.items.slice(0, 5) });
          });
      };
    };
    

    action.spec.js:

    import * as actionTypes from './action';
    import createMockStore from 'redux-mock-store';
    import thunk from 'redux-thunk';
    
    const mws = [thunk];
    const mockStore = createMockStore(mws);
    const store = mockStore({});
    
    describe('fetchGitHubDataAsync', () => {
      it('Dispatches BOOKS_SUCCESS after fetching books', () => {
        expect.assertions(2);
        const mJson = { items: [1, 2, 3, 4, 5, 6] };
        const mResponse = { json: jest.fn().mockResolvedValueOnce(mJson) };
        global.fetch = jest.fn().mockResolvedValueOnce(mResponse);
        const expectedActions = [{ type: 'FETCH_GITHUB_DATA', payload: [1, 2, 3, 4, 5] }];
        return store.dispatch(actionTypes.fetchGitHubDataAsync()).then(() => {
          expect(store.getActions()).toEqual(expectedActions);
          expect(global.fetch).toBeCalledWith('https://api.github.com/search/topics?q=javascript', {
            headers: {
              Accept: 'application/vnd.github.mercy-preview+json'
            }
          });
        });
      });
    });
    

    Unit test result with 100% coverage:

     PASS  src/stackoverflow/58803026/action.spec.js
      fetchGitHubDataAsync
        ✓ Dispatches BOOKS_SUCCESS after fetching books (16ms)
    
      console.log src/stackoverflow/58803026/action.js:239
        json [ 1, 2, 3, 4, 5 ]
    
    -----------|----------|----------|----------|----------|-------------------|
    File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    -----------|----------|----------|----------|----------|-------------------|
    All files  |      100 |      100 |      100 |      100 |                   |
     action.js |      100 |      100 |      100 |      100 |                   |
    -----------|----------|----------|----------|----------|-------------------|
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        5.329s, estimated 15s
    

    Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58803026