tx291
tx291

Reputation: 1331

Testing Promise.all with Jest/Vuex

I am trying to test a Vuex action that uses Promise.all to fetch data from an API, and then commits a mutation based on the response. However, both my assertion test (expect.assertions(1)) and the test to see if the commit was called are failing.

My action is:

fetchUserProfile ({ dispatch, commit}) {
      const userAccountFetch = api.get('/user/account');
      const userProfileFetch = api.get('/user/profile');
      const userItemsFetch = api.get(`/user/purchases`);
      Promise.all([
        userAccountFetch.catch((error) => {
          console.error(error);
          return { error, };
        }), 
        userProfileFetch.catch((error) => { 
          console.error(error); 
          return { error, };
        }),
        userItemsFetch.catch((error) => {
          console.error(error);
          return { error, };
        }),
      ]).then((responses) => {
          commit('setUserAccount', {responses});
        }
      });
  }

My test is as follows:

jest.mock('@api/api.js', () => ({ get: jest.fn(), }));
const mockApi = require('@api/api.js');

test('fetchUserProfile performs commit on successful fetch', () => {
    const mockResponse = [{userAccount: ....}, {userProfile: ...}, {userItems: ....}];
    mockApi.get.mockReturnValueOnce(Promise.resolve(mockResponse[0]));
    mockApi.get.mockReturnValueOnce(Promise.resolve(mockResponse[1]));
    mockApi.get.mockReturnValueOnce(Promise.resolve(mockResponse[2]));
    expect.assertions(1);
    fetchUserProfile({ commit, state, }).then(() => expect(commit).toHaveBeenCalledTimes(1));
  });

I put console.logs throughout my action, and the test is making it down to the line where I perform my commit, but for some reason the test is not passing. I'm not sure what is wrong here. Any help would be tremendously appreciate.

Upvotes: 0

Views: 3962

Answers (1)

Estus Flask
Estus Flask

Reputation: 222989

This is a very common antipattern that a function that uses promises doesn't return a promise that could be chained. This prevents it from being efficiently used and tested.

It should be:

return Promise.all(...)

Another problem is that Jest asynchronous test doesn't return a promise. This results in uncaught rejection that doesn't affect test result.

async..await is the efficient way to maintain the order of execution; async function always returns a promise:

test('fetchUserProfile performs commit on successful fetch', async () => {
    ....
    await fetchUserProfile({ commit, state });
    expect(commit).toHaveBeenCalledTimes(1);
});

Upvotes: 1

Related Questions