Search code examples
javascriptreact-reduxjestjses6-promise

React-Redux: Jest failing to test async action (Always pass)


I'm implementing unit tests for some Redux actions using Jest.

However, for some reason, this test case never fails.

A summarized version of the action looks like this:

export function attachFile(file) {
  return (dispatch, getState) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => {
        dispatch({
          type: actionTypes.ATTACH_FILE_DONE,
          file: {
            content: reader.result,
            size: file.size,
            mimeType: file.type,
            name: file.name,
          },
        });
        resolve();
      };
      reader.onerror = (error) => {
        const errorMessage = `Error reading file: ${file.name}: ${error}`;
        dispatch({
          type: actionTypes.ATTACH_FILE_FAIL,
          errorMessage,
        });
        reject(errorMessage);
      };
      reader.readAsDataURL(file);
    });
  };
}

The jest code testing it:

store.dispatch(attachFile(file)).then(() => {
  console.log('ACTUAL ACTIONS:', store.getActions());
  console.log('EXPECTED ACTIONS:', expectedActions);
  expect(store.getActions()).toEqual(expectedActions);
})

Logging the information shows me that the values are not equal, however, Jest always pass this test. I have even trying adding

fail('Just fail')

But the tests still pass, even with the data being totally different or forcing fail.

I have looked around to see similar codes, but I can't see any meaningful difference to my code, like this one

I also have commented out all the code inside the Promise and forced it to fail on the test code... still pass.

Any idea what might be wrong?


Solution

  • The tests are considered done as soon as your code finish executing.

    You will need to tell Jest to wait until your promise is fulfilled.

    You can do this by passing an argument (let's call it done) to your test|it function, this way, Jest will wait until done is called.

    So basically something like this :

    test('the data is peanut butter', done => {
      function callback(data) {
        expect(data).toBe('peanut butter');
        done();
      }
    
      fetchData(callback);
    });
    

    For your example, call done after your except :

    {
        ...
        expect(store.getActions()).toEqual(expectedActions);
        done();
    }
    

    source