Search code examples
reactjstypescriptunit-testingjestjsts-jest

Wrap jest mocks in a function for use in multiple tests


I'm trying to wrap a jest.mock into a function so I can reuse it in multiple files. My use case is for react hooks, and I am using typescript. Currently my test files looks something like this:

test.tsx

//some imports

jest.mock('../path/to/hoook/whatever', () => ({
    useWhatever: jest.fn()
}))


const mockResult = () => {
    return ({
        some stuff
    };
};


describe('Component', () => {
let wrapper;

    beforeEach(() => {
        mocked(useWhatever).mockClear();

        mocked(useWhatever).mockImplementation(() => mockResult);

        wrapper = shallow(
            <Component />
        );
    });

    //tests below
});

This works just fine, but this whatever hook gets used by other components and I'm trying to wrap up the jest.mock for reuse in other tests. What i'm trying to do looks something like this:

mocks.ts

export const mockWhatever = () => jest.mock('../path/to/hoook/whatever', () => ({
    useWhatever: jest.fn()
}))


export const mockResult = () => {
    return ({
        some stuff
    };
};

test.tsx

//some imports
mockWhatever();

describe('Component', () => {
let wrapper;

    beforeEach(() => {
        mocked(useWhatever).mockClear();

        mocked(useWhatever).mockImplementation(() => mockResult);

        wrapper = shallow(
            <Component />
        );
    });

    //tests below
});

When doing it this way, I get errors like "TypeError: utils_1.mocked(...).mockClear is not a function" when running the test. Is it possible to wrap mocks like this? And if so, what might I be doing wrong or missing?

Thanks


Solution

  • jest.mock is hoisted above imports with Babel transform, this is the reason why this works as intended:

    import ... from 'whatever';
    jest.mock('whatever', ...);
    

    It's impossible to achieve the same thing for mockWhatever without custom Babel transform, therefore modules are imported before they are mocked. import needs to be replaced with require and in order for a mock to take effect, import..require syntax can be used for TypeScript type safety.

    __mocks__ is a way to reuse module mocks that Jest provides. Considering that there's __mocks__/whatever.js mocked module, it's used as a mock with jest.mock('whatever').