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.
Top comments (0)