My Jest mock cheatsheet for TypeScript
I find myself looking up past projects to remember how to mock various things with Jest in TypeScript, so I’ve started writing up notes on this page to gather them in one place.
Mock a function without early referencing
Because of the way Jest hoists mocks, it’s easy to trigger a footgun where Jest complains about referencing something before initialisation.
You can usually avoid that by wrapping the reference in an outer function call, so that it’s not immediately referenced:
const fooServiceFooFunction = jest.fn()
jest.mock("@foo-provider/some-library", () => ({
fooService: () => ({
foobar: async () => fooServiceFooFunction(),
}),
}));
You can’t just do ({ foobar: fooServiceFooFunction })
inside the mock, as that
would be referencing the fooServiceFooFunction
before it’s initialised.
If you do that, you’ll get an error message like this:
ReferenceError: Cannot access '...' before initialization
.
This happens because Jest hoists mocks to the top, leaving things like function initialisations behind. If you only reference the function at call-time from another function, that’s OK as by that time the function is initialised.
Mock a function using ts-jest/utils mocked()
A lot of TypeScript projects use the ts-jest/utils
package, which provides a
typed mocked()
function which lets you access the Jest mock of some function.
You mock the module like Jest as normal, and also import the mocked item from the mocked module. Remember that Jest hoists the mock, so the import is guaranteed to happen after the mock has been applied.
import { mocked } from 'ts-jest/utils';
import { someFunction } from '../foobar';
jest.mock('../foobar');
const mockedSomeFunction = mocked(someFunction);
This is quite nice as it gets the type correct for the TypeScript compiler.
Mock a class in a module
It’s common to need to mock out a class in a module, but I can never remember the exact syntax to do it. It looks like this:
jest.mock("@some-provider/foobar", () => ({
CoolThing: class {
doSomethingCool() {
return "foo";
}
},
}));
You can combine this with the mocked()
function described above to be able to
access the mocked class in the tests.
Mock Firebase *
This is specific to use of the ts-firebase-driver-testing library.
As a general example:
const inProcessFirebase = new InProcessFirebaseDriver();
const authGetUserByEmail = jest.fn();
const authCreateUser = jest.fn();
const authGetUser = jest.fn();
jest.mock("firebase-admin", () => {
return {
firestore: () => inProcessFirebase.firestore(),
auth: () => ({
getUserByEmail: async () => authGetUserByEmail(),
createUser: async () => authCreateUser(),
getUser: async () => authGetUser(),
}),
};
});
jest.mock("firebase-functions", () => {
return {
region: () => inProcessFirebase.runWith().region(),
config: () => ({
foobar: {
foo: "bar",
},
}),
logger: {
info: jest.fn(),
error: jest.fn(),
}
};
});
More info here: Simple way to use ts-firebase-driver-testing with a Jest mock.
By the way, you can hire me as a freelance TypeScript developer to assist with your business.