Nest.js applications are built from classes, decorators and dependency injection. Tests usually aren't: they are anonymous functions that fetch what they need with app.get(Component).

nestjs-mocha-decorators lets you write tests the same way you write the rest of your app. Suites and tests are plain classes and methods, and test classes are Nest providers.

@TestSuite('Demo Test Suite') export class DemoTest { @Inject() private readonly httpService!: HttpService; @Test('Get Test') async testGet(): Promise<void> { const { data } = await firstValueFrom(this.httpService.get('http://localhost:4343/demo')); expect(data).toBe('Hello, Test world !'); } } 

@TestSuite is a Mocha describe, @Test is a Mocha it, and @Inject() works as it does anywhere else in Nest.

Installation

You need Nest.js 12, Mocha 12 and Node.js ^20.19.0 or >=22.12.0. TypeScript 7 does not work with ts-node, so this setup uses TypeScript 6.0.

npm i --save-dev nestjs-mocha-decorators mocha ts-node typescript@~6.0.0 @nestjs/testing @types/mocha @types/node 

Your tsconfig.json needs these options:

{ "compilerOptions": { "module": "node20", "types": ["node", "mocha"], "experimentalDecorators": true, "emitDecoratorMetadata": true } } 

Boot the app, then run Mocha

Create test/test.entrypoint.ts. It boots your app, declares the tests and starts Mocha:

import { HttpModule } from '@nestjs/axios'; import { Test } from '@nestjs/testing'; import { run } from 'mocha'; import { MochaTestModule, MochaTestService } from 'nestjs-mocha-decorators'; import { DemoTest } from './tests/demo.test'; import { YourAppModule } from './your-app/your-app.module'; async function bootstrap(): Promise<void> { try { const testingModule = await Test.createTestingModule({ imports: [ YourAppModule, // The app to test MochaTestModule.registerTests([DemoTest], [HttpModule]), // Your tests, and the modules they need ], }).compile(); const app = testingModule.createNestApplication(); await app.listen(4343); app.get(MochaTestService).declareTests(); run(); } catch (error) { console.error(error); process.exit(1); } } bootstrap(); 

Then add the test script to your package.json:

{ "scripts": { "test": "mocha --delay --exit --require ts-node/register test/test.entrypoint.ts" } } 

--delay makes Mocha wait until run() is called, once Nest.js has started.

Share tests with inheritance

Because tests are classes, a base class can hold the tests that several suites have in common. Each subclass decorated with @TestSuite runs them, and can override a test method:

abstract class CrudTest { @Test('Lists items') async list(): Promise<void> { // ... } } @TestSuite('Users') export class UsersTest extends CrudTest {} @TestSuite('Orders') export class OrdersTest extends CrudTest {} 

Run code around every test

Hooks live in their own class, which you register like any other test class. They run around every test of every suite:

import { TestEvent, TestEventsEnum, TestEventsSuite } from 'nestjs-mocha-decorators'; @TestEventsSuite() export class Events { @TestEvent(TestEventsEnum.BEFORE_EACH) async beforeEach(): Promise<void> { // Runs before each test } @TestEvent(TestEventsEnum.AFTER_EACH) async afterEach(): Promise<void> { // Runs after each test } } 

Run a single suite or test

Pick one with an environment variable. Names must match exactly:

SUITETORUN="Demo Test Suite" npm test TESTTORUN="Get Test" npm test 

Try it

The library is MIT licensed. You can find it on npm and GitHub, where issues and suggestions are welcome.