2

I have a function (a Redux action) which calls 2 functions. I can't figure how how to test this with Jest:

This is my function:

import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';

export default () => async dispatch => {
  await dispatch(doSomething());
  dispatch(doSomethingElse());
};

This is my test:

import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';

import functionToTest from 'redux/function-to-test'

describe("functionToTest", ()=>{
    jest.mock('redux/do-something');
    jest.mock('redux/do-something-else');
    const dispatch = jest.fn();

    test('my test', ()=>{
        functionToTest()(dispatch);
        console.log(dispatch.mock.calls); // This returns an anonymous function
        console.log(doSomething) // This returns undefined 
    })

})

1 Answer 1

3

It looks like you are wanting to mock the default export for do-something and do-something-else and test that they get dispatched by the code under test.

If that is the case then you can do it like this:

import functionToTest from 'redux/function-to-test'

jest.mock('redux/do-something', () =>
  () => 'do something mock'
);
jest.mock('redux/do-something-else', () =>
  () => 'do something else mock'
);

describe("functionToTest", () => {
  test('my test', async () => {  // <= async test function
    const dispatch = jest.fn();
    await functionToTest()(dispatch);  // <= await the Promise
    expect(dispatch.mock.calls[0][0]).toBe('do something mock');  // Success!
    expect(dispatch.mock.calls[1][0]).toBe('do something else mock');  // Success!
  });
});

Details

You can pass a module factory function as the second paramter to jest.mock and Jest will use the result of calling the function as what it gives back when the module is imported during the test.

jest.mock calls get hoisted by babel-jest and run before everything else in the code file. The hoisting doesn't work right when jest.mock is defined in a test function so the jest.mock calls should be moved to the top level scope of the test file.

The function under test is async so use an async test function and await the Promise to make sure it has completed before asserting.

Sign up to request clarification or add additional context in comments.

2 Comments

This works! At the risk of going off topic, does this look like an appropriate testing strategy for this type of function? For instance I don't think it would test the order in which doSomething() and doSomethingElse() were called.
Yep, this approach works fine! (note that it's testing the order of doSomething and doSomethingElse since the dispatch mock records the arguments it was called with in the order they were called in: ...mock.calls[0]... and then ...mock.calls[1]...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.