Jest

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

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.ts or .e2e-spec.ts and 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 ensure clearMocks: true is set in your jest.config.js, or call jest.clearAllMocks() in beforeEach().