Test TypeScript services
The TypeScript template uses Jest. Generated entity directories include service and controller specs, and the repository supports separate end-to-end and integration configurations.
Commands
npm test # Unit tests
npm run test:watch # Unit tests in watch mode
npm run test:cov # Coverage report
npm run test:e2e # End-to-end suite
npm run test:integration # Integration suite
npm run build # Type-check and compile the serviceRun npm test and npm run build after apso generate. Generated type changes can affect custom modules even when a generated smoke test still passes.
Generated tests
For an entity named Project, generated tests live beside the generated files:
src/autogen/Project/
|-- Project.service.spec.ts
|-- Project.controller.spec.ts
|-- Project.service.ts
`-- Project.controller.tsThe service spec supplies a mocked TypeORM repository. The controller spec supplies a mocked generated service. These tests confirm that NestJS can construct the generated classes and that controller methods delegate to the service.
Generated specs can be replaced when you regenerate. Keep product-specific tests with your custom modules or under test/.
Test a custom workflow
This unit test covers the archive workflow from the extensions guide. It verifies both the state change and the missing-record behavior.
import { NotFoundException } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Project } from '../autogen/Project/Project.entity';
import { ProjectWorkflowService } from './project-workflow.service';
describe('ProjectWorkflowService', () => {
const projects = {
findOne: jest.fn(),
save: jest.fn(),
};
let service: ProjectWorkflowService;
beforeEach(async () => {
jest.resetAllMocks();
const moduleRef = await Test.createTestingModule({
providers: [
ProjectWorkflowService,
{
provide: getRepositoryToken(Project),
useValue: projects,
},
],
}).compile();
service = moduleRef.get(ProjectWorkflowService);
});
it('archives an existing project', async () => {
const project = { id: 'project-1', name: 'Docs', status: 'Active' };
projects.findOne.mockResolvedValue(project);
projects.save.mockImplementation(async (value) => value);
await expect(service.archive('project-1')).resolves.toMatchObject({
id: 'project-1',
status: 'Archived',
});
expect(projects.save).toHaveBeenCalledWith(project);
});
it('rejects an unknown project', async () => {
projects.findOne.mockResolvedValue(null);
await expect(service.archive('missing')).rejects.toBeInstanceOf(
NotFoundException,
);
});
});Test the HTTP contract
Use supertest when behavior depends on NestJS routing, guards, interceptors, or database wiring.
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import request from 'supertest';
import { AppModule } from '../src/app.module.rest';
import { configureNestApp } from '../src/config/nest-app.config';
describe('Projects API', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleRef.createNestApplication();
await configureNestApp(app);
await app.init();
});
afterAll(() => app.close());
it('lists projects', async () => {
const response = await request(app.getHttpServer())
.get('/Projects')
.expect(200);
expect(response.body).toHaveProperty('data');
});
});Use an isolated test database for an end-to-end suite. Never run a test that truncates or synchronizes schema against a shared development or production database.
Cover the risks that matter
For a generated CRUD resource, add tests for the behavior your product depends on:
- Required and allowed field values
- Authentication failure and success
- Cross-tenant access denial
- Relationship creation and deletion
- Pagination and filters used by the client
- Custom workflows and third-party failures
- Migration behavior for existing records
Test one complete client journey after deployment as well. A useful minimum is create, read, update, and delete through the same API key and route shape the application uses.