Jest
Jest is the default and standard testing framework used in NestJS projects. It provides a test runner, an assertion library, and powerful mocking capabilities out of the box.
Overview
When you generate a new NestJS project using the CLI (nest new project), it automatically installs Jest and configures it to work with TypeScript via ts-jest.
Jest organizes tests into “suites” (describe blocks) and individual test cases (it or test blocks). It provides functions for setup/teardown (beforeEach, afterAll) and a rich API for asserting values (expect(a).toEqual(b)).
Key Concepts
- Test Runner: The engine that finds files ending in
.spec.tsor.e2e-spec.tsand executes the code inside them. - Assertions: Statements that verify a condition is true (e.g.,
expect(response.status).toBe(200)). If an assertion fails, the test fails. - Spies and Mocks: Tools provided by Jest (
jest.fn(),jest.spyOn()) to track how functions are called and to fake their return values.
Code Examples
1. Basic Jest Syntax
A standard unit test file structure in NestJS.
// calculator.spec.ts
import { Calculator } from './calculator';
describe('Calculator', () => {
let calc: Calculator;
// Runs before EVERY individual 'it' block
beforeEach(() => {
calc = new Calculator();
});
// A specific test suite for the 'add' method
describe('add()', () => {
it('should return 5 when adding 2 and 3', () => {
// Act
const result = calc.add(2, 3);
// Assert
expect(result).toBe(5);
});
it('should handle negative numbers', () => {
expect(calc.add(-2, -3)).toBe(-5);
});
});
});
2. Spying on Methods (jest.spyOn)
Sometimes you want to use the real object, but you want to verify that a specific method was called during the execution.
it('should log a warning when dividing by zero', () => {
// Spy on the global console.warn object
const warnSpy = jest.spyOn(console, 'warn');
// Act
calc.divide(10, 0);
// Assert
expect(warnSpy).toHaveBeenCalledWith('Attempted to divide by zero');
// Always restore spies so they don't affect other tests!
warnSpy.mockRestore();
});
3. Mocking Dependencies (jest.fn)
If you are testing a Service, you don’t want it to actually hit the database. You mock the database method to return a fake value.
it('should find a user', async () => {
// Create a fake repository object
const mockUserRepository = {
// Return a resolved Promise with fake data
findOne: jest.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
};
const userService = new UserService(mockUserRepository as any);
const user = await userService.getUser(1);
expect(user.name).toEqual('Alice');
// Verify the service passed the correct arguments to the repository
expect(mockUserRepository.findOne).toHaveBeenCalledWith({ where: { id: 1 } });
});
Best Practices
- Arrange, Act, Assert (AAA): Always structure your test blocks visually into three sections: Arrange (setup variables and mocks), Act (call the function being tested), and Assert (verify the results). This makes tests highly readable.
- Clear Mocks Between Tests: If Test A calls
mockRepo.save()5 times, and Test B expects it to be called 1 time, Test B might fail because Jest remembers the 5 calls from Test A. Always ensureclearMocks: trueis set in yourjest.config.js, or calljest.clearAllMocks()inbeforeEach().