Setup your local environment for GraphQL E2E Tests - NestJS / Docker

Setup your local environment for GraphQL E2E Tests - NestJS / Docker

Using docker to and setup Jest to run E2E tests locally without affecting the main database during development

In the dynamic landscape of web development, end-to-end (E2E) testing is a crucial step to ensure the seamless functionality of applications. When it comes to GraphQL-powered applications built with NestJS, setting up a local environment for E2E tests becomes paramount for efficient development. This article will guide you through the process of configuring your local environment for E2E tests in a GraphQL-NestJS project using Docker. Emphasizing the significance of using Docker to maintain isolation and the integration of Jest for local E2E test execution, we'll explore a comprehensive approach that allows developers to rigorously test their applications without affecting the primary database during the crucial development phase. Let's dive into the world of streamlined E2E testing and enhance your GraphQL-NestJS development experience.

Folder structure

.
├── node_modules
├── src
├── test/
│   ├── docker-compose-test.yaml
│   ├── jest-e2e.json
│   ├── test.env
│   ├── transformer.js
│   ├── app.e2e.spec.ts
│   ├── other-module.e2e.spec.ts
│   └── ..
├── .env
└── package.json

docker-compose-test.yaml:

version: '3.8'

services:
  redis:
    image: redis:7.2.0-alpine
    ports:
      - '${REDIS_PORT}:6379'
    restart: always

  database:
    image: postgres:15.2-alpine
    restart: always
    ports:
      - '${POSTGRES_PORT}:5432'
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DATABASE}

This configuration file orchestrates Docker containers for essential services required during E2E testing. It includes services for Redis and PostgreSQL databases, each encapsulated in its own container. Notably, Docker ensures isolation and reproducibility of your testing environment.

jest-e2e.json:

{
  "moduleFileExtensions": [
    "js",
    "json",
    "ts"
  ],
  "rootDir": ".",
  "testEnvironment": "node",
  "testRegex": ".e2e-spec.ts$",
  "transform": {
    "^.+\\.(t|j)s$": [
      "ts-jest",
      {
        "astTransformers": {
          "before": [
            "test/transformer.js"
          ]
        }
      }
    ]
  },
  "moduleNameMapper": {
    "^src/(.*)": "<rootDir>/../src/$1"
  },
  "globalSetup": "../test/setup.ts",
  "globalTeardown": "../test/teardown.ts",
  "reporters": [
    "default",
    "jest-junit"
  ]
}

Jest is a powerful testing framework, and this configuration file tailors its settings for E2E testing. It specifies the file extensions, test environment, and test regex pattern for E2E test files. Additionally, Jest's ability to transform TypeScript files is utilized through the ts-jest transformer. The global setup and teardown scripts (setup.ts and teardown.ts) orchestrate the Docker environment and handle necessary cleanup after tests.

setup.ts and teardown.ts:

//setup.ts
import { exec } from 'child_process';
require('dotenv').config({ path: 'test/test.env' })

export default async function (
  _globalConfig: unknown,
  _projectConfig: unknown,
) {
  await runCliCommand(`docker compose -f test/docker-compose-test.yaml -p ${TESTING_DOCKER_NAME} --env-file test/test.env up -d`);
  await new Promise(f => setTimeout(f, 2000));//await for db port
  await runCliCommand(`yarn prisma generate`);
  await runCliCommand(`yarn prisma migrate deploy`);
  await runCliCommand(`yarn seed`); //if you have a seed script and want to test against dummy data
}
export function runCliCommand(command: string) {
  console.log(`Running command: ${command}`);
  return new Promise((resolve, reject) => {
    exec(command, (error, stdout, stderr) => {
      if (error) {
        console.error(error);
        reject(error);
      }
      if (stderr) {
        //reject(stderr);
      }
      console.log(stdout);
      resolve(stdout);
    });
  });
}

export const TESTING_DOCKER_NAME = 'app_e2e_test';
//teardown.ts
import {
  TESTING_DOCKER_NAME,
  runCliCommand,
} from './setup';

module.exports = async function (
  globalConfig: unknown,
  projectConfig: unknown,
) {
  await runCliCommand(`docker compose -f test/docker-compose-test.yaml -p ${TESTING_DOCKER_NAME} down -v`);
};

These scripts serve as global setup and teardown procedures for the Jest E2E testing environment. In setup.ts, Docker containers are started, Prisma artifacts are generated, migrations are deployed, and any necessary seed scripts are executed. Conversely, teardown.ts ensures the graceful shutdown of Docker containers, cleaning up the testing environment after the test suite completes.

test.env:

TESTING_PROJECT_NAME='app_e2e_test'
POSTGRES_USER=postgres_test
POSTGRES_PASSWORD=password
POSTGRES_DATABASE=demo1_test
POSTGRES_PORT=5433
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DATABASE}?schema=public"
JWT_SECRET="top_secret_value"
REDIS_PORT=6380
REDIS_HOST=localhost
APP_PORT=3002

This file encapsulates environment variables specific to the testing environment, such as database credentials, ports, and URLs. By isolating these values, potential conflicts with the development environment are avoided, ensuring a dedicated and controlled setting for E2E testing.

transformer.js

//transformer.js
const transformer = require('@nestjs/graphql/plugin');

module.exports.name = 'nestjs-graphql-transformer';
// you should change the version number anytime you change the configuration below - otherwise, jest will not detect changes
module.exports.version = 1;

module.exports.factory = (cs) => {
  return transformer.before(
    {
      // @nestjs/graphql/plugin options (can be empty)
    },
    cs.program, // "cs.tsCompiler.program" for older versions of Jest (<= v27)
  );
};

This file leverages the @nestjs/graphql/plugin to transform TypeScript files before they are processed by Jest. It ensures that the GraphQL schema is appropriately handled during E2E testing, providing compatibility between the testing environment and the NestJS application.

package.json:

{
  "name": "your-project-name",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test:e2e": "jest --config ./test/jest-e2e.json"
    // Other scripts in your package.json...
  },
  "dependencies": {
    // Your project dependencies...
  },
  "devDependencies": {
    // Your project devDependencies...
  },
  "jest": {
    // Jest configuration for non-E2E tests...
  }
}

With this configuration, you can execute your E2E tests by running the following command in your terminal:

npm run test:e2e

This comprehensive approach to setting up a local environment for E2E tests in a GraphQL-NestJS project using Docker not only streamlines the testing process but also guarantees the integrity of your application by isolating test-specific configurations. By following these steps, developers can confidently run E2E tests locally without impacting the main database during the crucial development phase, fostering a robust and efficient development cycle.