Code Your Greens

Common Issues

Syntax gotchas

When using the module factory mocking style with jest, you need to pass the mocks themselves in as a function that calls the mock function:

hello: () => mockHello()

instead of setting them directly:

hello: mockHello

For example:

import goodbye, { hello } from './greeter'
const mockGoodbye = () => 'goodbye jest'
const mockHello = jest.fn()
jest.mock('./greeter', () => ({
__esModule: true,
default: mockGoodbye,
hello: mockHello
}))
// inside test
// TypeError: greeter_1.default is not a function
expect(goodbye()).toBeUndefined()
// TypeError: greeter_1.hello is not a function
expect(hello()).toEqual('hello jest')

Jest doesn't automock everything when using a module factory

You also need to make sure that you include an entry in the mocked module for each function your test needs to be able to call.

If you pass in the module factory parameter, jest will not automock the module and instead only set the module to the mocked definition you provide it in the factory.

Forgetting to specify the mocked function won't result in it being mocked in this case:

import goodbye, { hello } from './greeter'
jest.mock('./greeter', () => ({
__esModule: true,
default: jest.fn(),
// Omitting the definition for hello in this case won't automatically
// assign it to jest.fn():
// hello: jest.fn(),
}))
// inside test
expect(goodbye()).toBeUndefined() // correct
// TypeError: greeter_1.hello is not a function
expect(hello()).toBeUndefined()

Don't mix the module factory vs automocking strategies

Remember, when using the module factory as the second argument to jest.mock, it disables automocking for the module and the only functions that now exist for the module are what the module factory returns.

So when writing mocks using this strategy, don't try to use the

const mockHello = hello as jest.Mock<any>

strategy at the same time for mocking named exports. That strategy relies on Jest automocking everything to make it work.

const mockHello = hello as jest.Mock<any>
jest.mock('./greeter', () => ({
__esModule: true,
default: jest.fn(),
// Adding or removing this line won't fix it either:
// hello: () => mockHello
}))
// TypeError: mockHello.mockImplementation is not a function
mockHello.mockImplementation(() => 'hello jest')

Correctly using an ordinary function as a mock implementation

You can use an ordinary function as a mocked implementation, but it's more limited than using a mock created with jest.fn().

You won't be able to spy on it, or set a different mock implementation partway through your tests:

const mockHello = () => 'hello jest'
jest.mock('./greeter', () => ({
__esModule: true,
default: () => 'goodbye jest',
// This will work fine,
// if you only need the one implementation for all your tests
hello: () => mockHello()
}))
describe('using ordinary functions for mock implementations', () => {
it('should use the mock implementation', () => {
expect(hello()).toEqual('hello jest')
})
it('will not be able to set a new mock implementation', () => {
// compile error, since mockHello is not a jest mock
mockHello.mockImplementation(() => 'hi jest')
expect(hello()).toEqual('hello jest')
})
it('will not be able to spy on it', () => {
hello()
// Matcher error: received value must be a mock or spy function
expect(mockHello).toHaveBeenCalled()
})
})