Mocking classes in Jest / Typescript

bmitchinson

Ben Mitchinson

Posted on October 18, 2021

Mocking classes in Jest / Typescript

Cross posted on my website mitchinson.dev

TL;DR

Example Test

GetANumber.test.ts mocks a class, and further customizes a class method on that mocked class for a single test.

Purpose

It was surprisingly hard to find a recently written article about the fastest way to setup Jest with some simple class mocks in Typescript. The following example demonstrates mocking a class and modifying methods of that mocked class within a single test.

Libraries like jest-ts-auto-mock are not used, cause I was unable to find a way to get them to work. Could have just been using them wrong but who knows.

I used the following methods to mock classes in an Express app while coding in test driven development.

Explanation

Comments are all over in this Example Repo, but some highlights are:

  • jest.mock ends up at the top of the file when it's transpiled.
    • Even if you put it under other things, it gets pulled to the top.
///////////////////
jest.mock("./Class", mockOne);

it("does a thing", () => {
  expect(class).toBe(one)
})

it("does another thing", () => {
  jest.mock("./Class", mockTwo);
  expect(class).toBe(two)
})
///////////////////

// is really

///////////////////
jest.mock("./Class", mockOne); // this mock is useless
jest.mock("./Class", mockTwo); // as it's immediately replaced

it("does a thing", () => {
  expect(class).toBe(one)
})

it("does another thing", () => {
  expect(class).toBe(two)
})
///////////////////

// You might as well always write `.mock` calls at the top of your file.
Enter fullscreen mode Exit fullscreen mode
  • The example mocks a class that's a default export. Named exports can also be mocked by nesting the class mockImplementation one layer deeper.
  • jest.mock('{path_to_custom_class}') will replace that paths default export in the runtime with the defined mock in __mocks__ dir defined at the same level.
  • If you'd like to modify a mock / assert things that happened to a mock, you need to import them from the "real" class.
    • Never manually import from __mocks__, get the exports of __mocks__ "through" a normal import.
import * as MockNumberGen from "./__mocks__/NumberGen";
import * as NumberGen from "./NumberGen"; // __mocks__/CVEPathData

// Give me the mock class i've defined in __mocks__/{classname} and let me
//    name it mock{ClassName}Constructor
// Give me the mock function i've defined in __mocks__/{classname}
const { default: mockNumberGenConstructor, mockGetOne } =
  // Get these things from the NumberGen class, because I know that jest
  //     has secretly replaced it with the contents of MockNumberGen
  NumberGen as unknown as typeof MockNumberGen;
// Tell typescript that these things are really coming from MockNumberGen,
//     so it should type them as such
Enter fullscreen mode Exit fullscreen mode

The full test is available here

💖 💪 🙅 🚩
bmitchinson
Ben Mitchinson

Posted on October 18, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Mocking classes in Jest / Typescript
typescript Mocking classes in Jest / Typescript

October 18, 2021