Skip to content

Part 4.1 — Setting Up Jest, Test Environment & Prisma Test DB

Site Console Site Console
4 min read Updated Dec 8, 2025 Backend Development 0 comments

Testing a backend requires more than installing Jest and writing a few assertions.
Your tests need:

  • a dedicated test database, isolated from development

  • a repeatable schema reset workflow

  • testing modules that bootstrap NestJS correctly

  • integration with Supertest

  • a structure that scales as your backend grows

In this post, you'll set up all the essential machinery that makes backend testing predictable and safe.


1. Install Testing Dependencies

NestJS comes with basic Jest config, but you need a bit more for backend testing:

pnpm add -D @nestjs/testing jest ts-jest supertest @types/supertest

Initialize Jest (if not already created):

pnpm ts-jest config:init

You now have a jest.config.js.


2. Create a Dedicated Test Database (PostgreSQL)

You must never run tests against your dev or production DB.

Add a separate Postgres service for tests:

# docker-compose.yml
services:
  db:
    image: postgres:15
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: fullstack_db

  db_test:
    image: postgres:15
    ports:
      - "5433:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: fullstack_test_db

Start it:

docker compose up -d db_test

Your test DB is now available on port 5433.


3. Create a .env.test Environment File

At the root of your backend:

DATABASE_URL="postgresql://postgres:password@localhost:5433/fullstack_test_db"
NODE_ENV=test
PORT=4000

This ensures tests run fully isolated.


4. Configure Jest to Use .env.test

Update jest.config.js:

process.env.NODE_ENV = 'test';
require('dotenv').config({ path: '.env.test' });

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleFileExtensions: ['js', 'json', 'ts'],
  rootDir: '.',
  testRegex: '.*\\.spec\\.ts$',
  coverageDirectory: './coverage',
};

Now Jest always loads the correct DB URL.


5. Generate a Testing Module for NestJS

Whenever you test anything involving NestJS, create a module:

import { Test } from '@nestjs/testing';
import { AppModule } from '../src/app.module';

describe('AppModule', () => {
  it('initializes correctly', async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    const app = module.createNestApplication();
    await app.init();

    expect(app).toBeDefined();
  });
});

This ensures:

  • pipes

  • filters

  • interceptors

  • providers

are all wired correctly.


6. Ensure Prisma Works in Testing Context

You need a clean test database before each test suite.

Create a utility: test/utils/prisma-test.ts

import { PrismaClient } from '@prisma/client';

export const prisma = new PrismaClient();

export async function resetDb() {
  await prisma.$transaction([
    prisma.post.deleteMany(),
    prisma.user.deleteMany(),
  ]);
}

This is fine for small projects.
For larger suites, you’ll use transactions (covered in Part 4.5).


7. Run Prisma Migrations on the Test DB

Before tests boot:

pnpm prisma migrate deploy --schema=prisma/schema.prisma

You can automate this in Jest’s global setup:

Create: jest.global-setup.ts

import { execSync } from 'child_process';

module.exports = async () => {
  execSync('pnpm prisma migrate deploy', { stdio: 'inherit' });
};

Add to config:

globalSetup: './jest.global-setup.ts',

Now every test suite runs against a pristine schema.


8. Using Supertest for Integration Requests

Install Supertest (already done), then test your controllers:

import request from 'supertest';
import { Test } from '@nestjs/testing';
import { AppModule } from '../src/app.module';

describe('Users (e2e)', () => {
  let app;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = module.createNestApplication();
    await app.init();
  });

  it('creates a user', async () => {
    const res = await request(app.getHttpServer())
      .post('/users')
      .send({ name: 'Bob', email: 'bob@example.com' })
      .expect(201);

    expect(res.body.email).toBe('bob@example.com');
  });
});

This test touches:

  • NestJS controller

  • DTO validation

  • pipes

  • Prisma

  • test database

  • global interceptors

  • error filters

True integration testing.


9. Ensure Test Cleanup

After running tests, shut down Prisma:

afterAll(async () => {
  const { prisma } = await import('./test/utils/prisma-test');
  await prisma.$disconnect();
});

Without this, Jest may hang.


10. Add test Script to package.json

"scripts": {
  "test": "jest",
  "test:watch": "jest --watch",
  "test:ci": "jest --runInBand"
}

Note:
--runInBand ensures predictable behavior in CI environments.


11. Summary

You now have:

  • A dedicated PostgreSQL test database

  • .env.test environment

  • Jest test configuration

  • Global setup for Prisma migrations

  • Testing modules for Nest

  • Supertest for full-stack endpoint testing

  • Repeatable DB reset utilities

  • Clean test lifecycle management

Related

Leave a comment

Sign in to leave a comment.

Comments