ts-jest Configuration
ts-jest Configuration
ts-jest compiles TypeScript during the test run so tests can import TS sources directly:
// jest.config.ts
export default {
preset: "ts-jest",
testEnvironment: "node",
moduleNameMapper: { "^@app/(.*)$": "<rootDir>/src/$1" },
transform: { "^.+\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.test.json" }] },
};
Using a dedicated tsconfig.test.json lets tests include @types/jest and esModuleInterop without relaxing the app build. Diagnostics come from the same config: turn them off only for transpile-only CI runs, because a skipped diagnostic turns a compile error into a confusing runtime failure.
Mocking with Types
Mocking with Types
jest.mock is hoisted above imports, so the factory runs before the module under test:
jest.mock("../src/mailer", () => ({ send: jest.fn() }));
import { send } from "../src/mailer";
const mockedSend = jest.mocked(send);
mockedSend.mockResolvedValue({ id: "1" });
jest.mocked gives a fully typed mock — .mockResolvedValue and .mock.calls infer from the real signature. For object collaborators use jest.spyOn(svc, "fetchUser") (restores in afterEach with restoreMocks: true), and for paths that should resolve like the app, mirror every alias in moduleNameMapper — missing mappings are the most common "cannot find module" in TS test suites.
Pitfalls and Interview Angles
Pitfalls and Interview Angles
Globals versus imports. Plain describe/expect rely on @types/jest; importing from @jest/globals gives typed symbols without that package. Mixing both in one repo makes one side any.
ESM mode. Running Jest as native ESM needs --experimental-vm-modules and extensionsToTreatAsEsm; the CommonJS transform path is the default and expects jest.mock hoisting rather than vi-style static mocks.
Type-only imports. Under isolatedModules, forgetting import type emits a runtime require of a file that exports nothing.
Interview: explain hoisting (why jest.mock can reference a factory before imports), how jest.mocked preserves types, and when you would choose spyOn over a full module mock.
Quiz
1. Why does jest.mock use a hoisting transformer in ts-jest?
2. What does jest.mocked(fn) provide that fn alone does not?
3. A test compiles but fails with "Cannot find module '@app/config'". What is missing?
Flashcards
Question
ts-jest preset
Click to reveal answer
Answer
Wires a TypeScript transform so tests import .ts sources directly.
Question
jest.mock hoisting
Click to reveal answer
Answer
Factory calls are lifted above imports so the module registry is patched first.
Question
jest.mocked
Click to reveal answer
Answer
Type-preserving wrapper giving mockResolvedValue/mock.calls the real signatures.
Question
moduleNameMapper
Click to reveal answer
Answer
Jest's equivalent of tsconfig paths — required or alias imports fail at runtime.
Revision Notes
Key Takeaways
- 1. Test tsconfig stays separate from the app build config
- 2. Mirror every paths alias in moduleNameMapper
- 3. Pick one typing source: @types/jest or @jest/globals imports
Interview Tips
- • Explain hoisting with the module-evaluation-order argument, not "Jest does it"
- • Describe spy versus module mock and when each is enough
Cheat Sheet
preset ts-jest + dedicated test tsconfig; moduleNameMapper mirrors paths; jest.mocked for typed mocks; restoreMocks in afterEach; ESM needs --experimental-vm-modules.
Continue Learning
Before You Start
- No prerequisites listed.