Integration Testing TypeScript with Docker: A Complete Guide

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

Integration Testing TypeScript with Docker: From A to Z

\n\n

Modern TypeScript development requires not only high-quality unit testing but also verification of component interaction in real-world conditions. Integration testing using Docker allows you to spin up isolated environments with databases, caches, and other services, making tests as close to production as possible. In this article, we will walk through how to set up integration testing for a TypeScript application using Docker, write tests for a REST API, and review best practices.

\n\n

Why Docker for Integration Testing?

\n\n

Docker solves one of the main problems of integration tests — dependency on external services. Instead of using a shared database or Redis that might be occupied by other developers, we spin up isolated containers for each test run. This guarantees:

\n\n
    \n
  • Test cleanliness: each run starts from a clean state
  • \n
  • Repeatability: tests work the same way on any machine
  • \n
  • Isolation: tests do not affect each other or production data
  • \n
  • Speed: containers spin up in seconds
  • \n
\n\n

Project Setup and Docker Compose

\n\n

Let's create a simple TypeScript project with Express and PostgreSQL. Our goal is to test a user creation endpoint. We'll start with the docker-compose.test.yml file:

\n\n
version: '3.8'\nservices:\n  db_test:\n    image: postgres:15-alpine\n    environment:\n      POSTGRES_DB: testdb\n      POSTGRES_USER: testuser\n      POSTGRES_PASSWORD: testpass\n    ports:\n      - "5433:5432"\n    healthcheck:\n      test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n\n  app_test:\n    build:\n      context: .\n      dockerfile: Dockerfile.test\n    environment:\n      DATABASE_URL: postgres://testuser:testpass@db_test:5432/testdb\n      NODE_ENV: test\n    ports:\n      - "3001:3000"\n    depends_on:\n      db_test:\n        condition: service_healthy
\n\n

Now let's create a Dockerfile.test to build the TypeScript application:

\n\n
FROM node:18-alpine\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --only=production\nCOPY . .\nRUN npm run build\nCMD ["node", "dist/index.js"]
\n\n

Writing Integration Tests with Jest and Supertest

\n\n

Install the necessary packages:

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

Create a Jest configuration (jest.config.ts):

\n\n
export default {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  testMatch: ['**/__tests__/**/*.test.ts'],\n  setupFilesAfterSetup: ['./jest.setup.ts'],\n  testTimeout: 30000,\n};
\n\n

The jest.setup.ts file will handle starting and stopping Docker containers:

\n\n
import { execSync, spawn } from 'child_process';\nimport path from 'path';\n\nconst composeFile = path.resolve(__dirname, '../docker-compose.test.yml');\n\nbeforeAll(async () => {\n  // Spin up containers\n  execSync(`docker-compose -f ${composeFile} up -d --build`, { stdio: 'inherit' });\n  \n  // Wait for the application to become available\n  await new Promise((resolve) => setTimeout(resolve, 5000));\n});\n\nafterAll(async () => {\n  // Stop and remove containers\n  execSync(`docker-compose -f ${composeFile} down -v`, { stdio: 'inherit' });\n});
\n\n

Now let's write the actual test. Create a file __tests__/users.test.ts:

\n\n
import request from 'supertest';\n\nconst BASE_URL = 'http://localhost:3001/api';\n\ndescribe('Users API Integration Tests', () => {\n  const testUser = {\n    name: 'Ivan Ivanov',\n    email: 'ivan@example.com',\n    password: 'securePass123'\n  };\n\n                

Blogs

Book Recommendations