Testing in TypeScript: unit, integration, e2e from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Testing in TypeScript: from unit to e2e — a complete guide

\n

Modern web development is unthinkable without quality testing. TypeScript, as a superset of JavaScript, provides powerful typing tools but does not solve the problem of logical errors. In this article, we will cover three levels of testing: unit, integration, and e2e (end-to-end). You will learn how to set up the environment, write effective tests in TypeScript, and integrate them into a CI/CD pipeline.

\n\n

1. Unit testing: the foundation of the testing pyramid

\n

Unit tests check isolated modules (functions, classes, methods) without external dependencies. For TypeScript, the best choice is Jest — it supports TypeScript out of the box and provides a rich API for mocks and assertions.

\n\n

Setting up Jest for TypeScript

\n
npm install --save-dev jest @types/jest ts-jest\nnpx ts-jest config:init
\n

The jest.config.ts file should contain:

\n
export default {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  roots: ['<rootDir>/src'],\n  testMatch: ['**/__tests__/**/*.test.ts']\n};
\n\n

Example of a unit test for a function

\n

Suppose we have a discount calculation function:

\n
// src/utils/discount.ts\nexport function calculateDiscount(price: number, percent: number): number {\n  if (percent < 0 || percent > 100) throw new Error('Invalid percent');\n  return price - (price * percent) / 100;\n}
\n

Test for it:

\n
// src/__tests__/discount.test.ts\nimport { calculateDiscount } from '../utils/discount';\n\ndescribe('calculateDiscount', () => {\n  it('should return 80 for price 100 and discount 20%', () => {\n    expect(calculateDiscount(100, 20)).toBe(80);\n  });\n\n  it('should throw an error for an invalid percent', () => {\n    expect(() => calculateDiscount(100, 150)).toThrow('Invalid percent');\n  });\n\n  it('should return 0 for a 100% discount', () => {\n    expect(calculateDiscount(50, 100)).toBe(0);\n  });\n});
\n\n

Working with mocks

\n

Use mocks to isolate tests. Example with a service that depends on a database:

\n
// src/services/user.service.ts\nimport { db } from '../database';\n\nexport class UserService {\n  async getUser(id: number) {\n    const user = await db.findUser(id);\n    if (!user) throw new Error('User not found');\n    return user;\n  }\n}
\n
// src/__tests__/user.service.test.ts\nimport { UserService } from '../services/user.service';\nimport { db } from '../database';\n\njest.mock('../database');\n\ndescribe('UserService', () => {\n  it('should return a user', async () => {\n    const mockUser = { id: 1, name: 'Alice' };\n    (db.findUser as jest.Mock).mockResolvedValue(mockUser);\n\n    const service = new UserService();\n    const result = await service.getUser(1);\n    expect(result).toEqual(mockUser);\n  });\n});
\n\n

2. Integration testing: checking component interaction

\n

Integration tests check how modules work together: API routes, databases, external services. For TypeScript applications on Node.js, Supertest is often used together with Jest.

\n\n

Setting up an integration test for Express/NestJS

\n
npm install --save-dev supertest @types/supertest
\n

Example test for a REST API (NestJS):

\n
// src/__tests__/app.integration.test.ts\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeAll(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    a                

Blogs

Book Recommendations