Integration Testing JavaScript with Docker: Advanced Techniques

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 JavaScript with Docker: From Theory to Advanced Practice

\n\n

Integration testing is a critically important development stage that checks the interaction between various modules and external services. For JavaScript applications on Node.js, Docker becomes an indispensable tool, allowing you to create isolated, reproducible environments for testing. In this article, we will look at advanced techniques for setting up integration tests with Docker, including working with databases, queues, and optimization for CI/CD.

\n\n

Why Docker for Integration Tests?

\n\n

Traditional approaches to integration testing (mocks, stubs) do not always reflect the real behavior of the system. Docker solves this problem by providing:

\n\n
    \n
  • Isolation: each test runs in a clean container without affecting other tests or the local environment.
  • \n
  • Reproducibility: identical execution conditions on the developer's machine and in CI/CD.
  • \n
  • Scalability: the ability to run tests in parallel with different versions of dependencies (PostgreSQL, Redis, Elasticsearch).
  • \n
  • Fast Recovery: recreating containers takes seconds, not hours of setup.
  • \n
\n\n

Setting Up an Advanced Test Environment

\n\n

Let's consider a typical Node.js application that uses PostgreSQL and Redis. Instead of a simple docker-compose.yml, we will create a flexible configuration with support for parallel tests and health checks.

\n\n

Step 1: Docker Compose with Dynamic Ports

\n\n

To avoid port conflicts during parallel execution, we use dynamic allocation:

\n\n
# docker-compose.test.yml\nversion: '3.8'\nservices:\n  postgres_test:\n    image: postgres:15-alpine\n    environment:\n      POSTGRES_DB: test_db\n      POSTGRES_USER: test_user\n      POSTGRES_PASSWORD: test_pass\n    ports:\n      - "0:5432"  # Dynamic port\n    healthcheck:\n      test: ["CMD-SHELL", "pg_isready -U test_user -d test_db"]\n      interval: 2s\n      timeout: 5s\n      retries: 10\n    tmpfs: /var/lib/postgresql/data  # Data in RAM for speed\n\n  redis_test:\n    image: redis:7-alpine\n    ports:\n      - "0:6379"\n    healthcheck:\n      test: ["CMD", "redis-cli", "ping"]\n      interval: 2s\n      timeout: 5s\n      retries: 10
\n\n

Step 2: Utilities for Running Tests with Docker

\n\n

Let's create a helper class that automatically finds dynamic ports and waits for services to be ready:

\n\n
// test/setup/docker-manager.js\nconst { DockerComposeEnvironment, Wait } = require('testcontainers');\nconst { Client } = require('pg');\nconst Redis = require('ioredis');\n\nclass DockerTestManager {\n    constructor() {\n        this.environment = null;\n        this.config = {\n            pgPort: null,\n            redisPort: null\n        };\n    }\n\n    async start() {\n        this.environment = await new DockerComposeEnvironment(\n            '.', \n            'docker-compose.test.yml'\n        ).withWaitStrategy('postgres_test', Wait.forHealthCheck())\n         .withWaitStrategy('redis_test', Wait.forHealthCheck())\n         .up();\n\n        // Extract port mapping\n        const pgContainer = this.environment.getContainer('postgres_test');\n        const redisContainer = this.environment.getContainer('redis_test');\n        \n        this.config.pgPort = pgContainer.getMappedPort(5432);\n        this.config.redisPort = redisContainer.getMappedPort(6379);\n        \n        return this.config;\n    }\n\n    async stop() {\n        if (this.environment) {\n            await this.environment.down();\n        }\n    }\n}\n\nmodule.exports = DockerTestManager;
\n\n

Advanced Integration Testing Scenarios

\n\n

Now let's move on to specific tests that check the real interaction of components.

\n

Blogs

Book Recommendations