
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
node-test-utils
Advanced tools
A powerful testing toolkit for Node.js applications (NestJS & Express) - auto mocks, test data factories, module helpers, and E2E snapshot testing
A powerful, reusable testing toolkit for Node.js applications. Works seamlessly with NestJS, Express, and any Node.js framework.
Features • Installation • Quick Start • Documentation • Examples
Node Test Utils is a comprehensive testing toolkit designed to dramatically reduce the time and effort required to write, maintain, and scale tests for Node.js applications. Whether you're building with NestJS, Express, or any other Node.js framework, this package provides essential utilities that eliminate repetitive boilerplate code and standardize your testing approach.
🔹 Auto Mocks - Automatically generates Jest mocks for all methods in your services, controllers, and classes. No more manually creating mock objects for every method - just call createAutoMock(YourService) and all methods are instantly mocked and ready to use.
🔹 Test Data Factories - Create realistic, consistent test data with a fluent builder pattern. Define factory classes once, then generate test data on-demand with customizable overrides. Perfect for creating users, entities, or any complex data structures needed in your tests.
🔹 Module Helpers (NestJS) - Simplify NestJS module testing with easy provider overrides and dependency injection setup. Create test modules with mocked dependencies in a single, clean function call instead of chaining multiple override methods.
🔹 E2E Snapshot Testing - Automatically capture and compare API responses for regression testing. Works with both NestJS and Express applications, helping you catch breaking API changes before they reach production.
| Feature | Description | NestJS | Express |
|---|---|---|---|
| 🔹 Auto Mocks | Automatically create mocks for services and controllers | ✅ | ✅ |
| 🔹 Test Data Factories | Generate fake test data with a fluent builder pattern | ✅ | ✅ |
| 🔹 Module Helpers | Bootstrap NestJS modules in tests with overrides | ✅ | ❌ |
| 🔹 E2E Snapshot Testing | Run E2E snapshot tests for APIs | ✅ | ✅ |
# npm
npm install --save-dev node-test-utils
# yarn
yarn add -D node-test-utils
# pnpm
pnpm add -D node-test-utils
This package requires minimal dependencies. Install only what you need:
For NestJS projects:
npm install --save-dev @nestjs/testing @nestjs/common @nestjs/core
For Express projects:
npm install --save-dev express
Required for all projects:
npm install --save-dev jest
Note: All peer dependencies are optional. Install only the ones you need for your framework.
Automatically mock all methods of a class - no manual setup required!
import { createAutoMock } from 'node-test-utils';
class UserService {
async findOne(id: string) { return {}; }
async create(data: any) { return {}; }
}
// ✨ All methods automatically mocked!
const mockService = createAutoMock(UserService);
// Set return values
mockService.findOne.mockResolvedValue({ id: '1', name: 'John' });
mockService.create.mockResolvedValue({ id: '2', name: 'Jane' });
// Use in tests
expect(mockService.findOne).toHaveBeenCalledWith('1');
Before (without node-test-utils):
const mockService = {
findOne: jest.fn(),
create: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
// ... manually mock every method
};
After (with node-test-utils):
const mockService = createAutoMock(UserService);
// ✅ All methods automatically mocked!
Create realistic test data with a fluent, chainable API.
import { TestFactory, TestDataHelpers } from 'node-test-utils';
interface User {
id: string;
name: string;
email: string;
age: number;
createdAt: Date;
}
// Create a factory
class UserFactory extends TestFactory<User> {
protected default(): Partial<User> {
return {
id: TestDataHelpers.uuid(),
name: TestDataHelpers.fullName(),
email: TestDataHelpers.email(),
age: TestDataHelpers.int(18, 80),
createdAt: TestDataHelpers.pastDate(),
};
}
}
// Use the factory
const user = new UserFactory().create();
// ✅ Creates: { id: 'abc-123', name: 'John Smith', email: 'john@example.com', ... }
// Override specific fields
const customUser = new UserFactory()
.with({ name: 'Jane Doe', age: 25 })
.create();
// ✅ Creates: { id: 'xyz-789', name: 'Jane Doe', age: 25, ... }
// Create multiple users
const users = new UserFactory().createMany(5);
// ✅ Creates array of 5 unique users
Available Helpers:
TestDataHelpers.uuid() // Random UUID
TestDataHelpers.email() // Random email
TestDataHelpers.fullName() // Random full name
TestDataHelpers.pastDate() // Random past date
TestDataHelpers.futureDate() // Random future date
TestDataHelpers.int(1, 100) // Random integer
TestDataHelpers.float(0, 100) // Random float
TestDataHelpers.string(10) // Random string
TestDataHelpers.boolean() // Random boolean
TestDataHelpers.pickOne([1,2,3]) // Pick random element
TestDataHelpers.pickMany([1,2,3], 2) // Pick random elements
Easily create test modules with provider overrides.
import { createTestModule, createMockProvider, createAutoMock } from 'node-test-utils';
class UserService {
async findOne(id: string) { return {}; }
}
// Create mock
const mockService = createAutoMock(UserService);
mockService.findOne.mockResolvedValue({ id: '1', name: 'Test' });
// Create test module with overrides
const module = await createTestModule({
module: AppModule,
overrides: [
createMockProvider(UserService, mockService),
{ provide: ConfigService, useValue: { get: () => 'test' } },
],
});
// Get the application
const app = module.createNestApplication();
await app.init();
// Or get a specific provider
const userService = module.get(UserService);
Before (without node-test-utils):
const module = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(UserService)
.useValue(mockService)
.overrideProvider(ConfigService)
.useValue({ get: () => 'test' })
.compile();
After (with node-test-utils):
const module = await createTestModule({
module: AppModule,
overrides: [
createMockProvider(UserService, mockService),
{ provide: ConfigService, useValue: { get: () => 'test' } },
],
});
// ✅ Cleaner, more readable, easier to maintain
Take snapshots of API responses for regression testing. Works with both NestJS and Express!
import { snapshotApi, createTestApp } from 'node-test-utils';
describe('User API', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await createTestModule({
module: AppModule,
overrides: [createMockProvider(UserService, mockService)],
});
app = module.createNestApplication();
await app.init();
});
it('should get user by id', async () => {
await snapshotApi(app, '/api/users/1', {
snapshotName: 'get-user-by-id',
});
});
});
import express from 'express';
import { snapshotApi } from 'node-test-utils';
const app = express();
app.get('/api/users/:id', (req, res) => {
res.json({ id: req.params.id, name: 'John Doe' });
});
describe('User API', () => {
it('should get user by id', async () => {
await snapshotApi(app, '/api/users/1', {
snapshotName: 'get-user-by-id',
});
});
});
Advanced Options:
// POST request with body
await snapshotApi(app, '/api/users', {
method: 'POST',
body: { name: 'John', email: 'john@example.com' },
expectedStatus: 201,
snapshotName: 'create-user',
});
// With query parameters and headers
await snapshotApi(app, '/api/users', {
query: { page: 1, limit: 10 },
headers: { 'Authorization': 'Bearer token123' },
});
// Snapshot full response (status, headers, body)
await snapshotApi(app, '/api/users', {
snapshotFullResponse: true,
});
// Snapshot multiple endpoints
await snapshotMultipleApis(app, [
{ url: '/api/users', method: 'GET' },
{ url: '/api/users/1', method: 'GET' },
{ url: '/api/users', method: 'POST', body: { name: 'John' } },
]);
import { INestApplication } from '@nestjs/common';
import {
createAutoMock,
createMockProvider,
TestFactory,
TestDataHelpers,
createTestModule,
snapshotApi,
} from 'node-test-utils';
// 1. Define entity
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
// 2. Create factory
class UserFactory extends TestFactory<User> {
protected default(): Partial<User> {
return {
id: TestDataHelpers.uuid(),
name: TestDataHelpers.fullName(),
email: TestDataHelpers.email(),
createdAt: TestDataHelpers.pastDate(),
};
}
}
// 3. Service
class UserService {
async findOne(id: string): Promise<User> { return {} as User; }
async create(data: Partial<User>): Promise<User> { return {} as User; }
}
// 4. Controller
@Controller('users')
class UserController {
constructor(private userService: UserService) {}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
@Post()
async create(@Body() data: Partial<User>) {
return this.userService.create(data);
}
}
// 5. Test
describe('UserController', () => {
let app: INestApplication;
let userService: jest.Mocked<UserService>;
beforeEach(async () => {
const mockUserService = createAutoMock(UserService);
mockUserService.findOne.mockResolvedValue(
new UserFactory().with({ id: '1' }).create()
);
const module = await createTestModule({
module: AppModule,
overrides: [createMockProvider(UserService, mockUserService)],
});
app = module.createNestApplication();
await app.init();
userService = module.get(UserService);
});
afterEach(async () => {
await app.close();
});
it('should get user by id', async () => {
const user = new UserFactory().with({ id: '1', name: 'John' }).create();
userService.findOne.mockResolvedValue(user);
await snapshotApi(app, '/users/1', {
snapshotName: 'get-user-by-id',
});
});
it('should create user', async () => {
const userData = new UserFactory().create();
userService.create.mockResolvedValue(userData);
await snapshotApi(app, '/users', {
method: 'POST',
body: { name: userData.name, email: userData.email },
expectedStatus: 201,
});
});
});
import express from 'express';
import {
createAutoMock,
TestFactory,
TestDataHelpers,
snapshotApi,
createApiHelper,
} from 'node-test-utils';
// 1. Service
class UserService {
async findOne(id: string) { return {}; }
async create(data: any) { return {}; }
}
// 2. Factory
class UserFactory extends TestFactory<User> {
protected default(): Partial<User> {
return {
id: TestDataHelpers.uuid(),
name: TestDataHelpers.fullName(),
email: TestDataHelpers.email(),
};
}
}
// 3. Express app
const app = express();
app.use(express.json());
app.get('/api/users/:id', async (req, res) => {
const user = await userService.findOne(req.params.id);
res.json(user);
});
app.post('/api/users', async (req, res) => {
const user = await userService.create(req.body);
res.status(201).json(user);
});
// 4. Test
describe('User API (Express)', () => {
it('should get user by id', async () => {
const user = new UserFactory().with({ id: '1' }).create();
mockUserService.findOne.mockResolvedValue(user);
await snapshotApi(app, '/api/users/1', {
snapshotName: 'express-get-user',
});
});
it('should use API helper', async () => {
const api = createApiHelper(app);
const response = await api.get('/api/users/1').expect(200);
expect(response.body).toHaveProperty('id');
});
});
createAutoMock<T>(target: Type<T>): Mocked<T>Creates an automatically mocked version of a class with all methods mocked.
Parameters:
target - The class constructor to mockReturns: A fully mocked instance with all methods as Jest mocks
Example:
const mock = createAutoMock(UserService);
mock.findOne.mockResolvedValue({ id: '1' });
createPartialMock<T>(target: Type<T>, mockMethods: (keyof T)[]): Partial<Mocked<T>>Creates a partial mock where only specified methods are mocked.
Example:
const mock = createPartialMock(UserService, ['findOne']);
createMockProvider<T>(target: Type<T>, customMocks?: Partial<Mocked<T>>)Creates a NestJS provider configuration with mocks.
Example:
const provider = createMockProvider(UserService, {
findOne: jest.fn().mockResolvedValue({ id: '1' })
});
TestFactory<T>Abstract base class for creating test data factories.
Methods:
with(overrides: Partial<T>): this - Set custom values (chainable)create(): T - Create a single instancecreateMany(count: number): T[] - Create multiple instancesreset(): this - Reset to default statecreateTestData<T>(defaults: Partial<T>, overrides?: Partial<T>): TQuick factory function for simple cases.
createFactory<T>(defaults: () => Partial<T>): (overrides?: Partial<T>) => TCreates a factory function.
TestDataHelpersCollection of helper functions for generating test data (see Quick Start section).
createTestModule(options: CreateTestModuleOptions): Promise<TestingModule>Creates a NestJS testing module with optional overrides.
Options:
{
module: Type<any>; // The module class to test
imports?: Type<any>[]; // Additional imports
providers?: Provider[]; // Additional providers
controllers?: Type<any>[]; // Additional controllers
overrides?: ModuleOverride[]; // Provider overrides
}
getTestProvider<T>(options: CreateTestModuleOptions, provider: Type<T>): Promise<T>Gets a specific provider from a test module.
createTestApp(options: CreateTestModuleOptions): Promise<INestApplication>Creates a full NestJS application for E2E tests.
snapshotApi(app: INestApplication | Express, url: string, options?: SnapshotApiOptions): Promise<Response>Takes a snapshot of an API endpoint response. Works with both NestJS and Express!
Options:
{
expectedStatus?: number; // Expected HTTP status (default: 200)
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; // HTTP method (default: 'GET')
body?: any; // Request body
query?: Record<string, any>; // Query parameters
headers?: Record<string, string>; // Request headers
snapshotName?: string; // Custom snapshot name
snapshotFullResponse?: boolean; // Snapshot full response or just body
}
snapshotMultipleApis(app: INestApplication | Express, endpoints: Array<{ url: string } & SnapshotApiOptions>): Promise<Response[]>Takes snapshots of multiple API endpoints in sequence.
createApiHelper(app: INestApplication | Express): ReturnType<typeof request>Creates a supertest helper for making API requests.
snapshotName valuesSolution: Make sure Jest is installed:
npm install --save-dev jest @types/jest
Solution: Install NestJS dependencies (only needed for NestJS projects):
npm install --save-dev @nestjs/testing @nestjs/common @nestjs/core
Solution: Use fixed data for snapshots or update snapshots:
npm test -- -u # Update snapshots
Solution: Make sure you're using Jest and the class has methods:
// ✅ Works
class Service {
method() {}
}
// ❌ Doesn't work (no methods to mock)
class Service {}
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
| Package | Version | Status |
|---|---|---|
| NestJS | ^10.0.0 | ^11.0.0 | ✅ Supported |
| Express | ^4.0.0 | ✅ Supported |
| Jest | ^27.0.0 | ^28.0.0 | ^29.0.0 | ^30.0.0 | ✅ Supported |
| TypeScript | ^4.0.0 | ^5.0.0 | ✅ Supported |
Made with ❤️ by developers, for developers
⭐ Star on GitHub • 📦 View on npm • 🐛 Report Bug • 💡 Request Feature
FAQs
A powerful testing toolkit for Node.js applications (NestJS & Express) - auto mocks, test data factories, module helpers, and E2E snapshot testing
We found that node-test-utils demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.