node-test-utils
v1.0.1
Published
A powerful testing toolkit for Node.js applications (NestJS & Express) - auto mocks, test data factories, module helpers, and E2E snapshot testing
Maintainers
Readme
Node Test Utils
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
📋 What This Package Does
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.
Core Capabilities:
🔹 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.
What Problems Does It Solve?
- Eliminates Boilerplate: Reduces test setup code by 70%+ by automating mock creation and test data generation
- Speeds Up Development: Write tests 50%+ faster with auto-mocks and factory patterns
- Improves Consistency: Standardizes testing patterns across your entire team
- Reduces Maintenance: Makes tests easier to update as your application evolves
- Framework Agnostic: Works with NestJS, Express, and any Node.js framework
- Type-Safe: Full TypeScript support with IntelliSense for better developer experience
Perfect For:
- Developers writing unit tests for services and controllers
- Teams building integration tests for NestJS applications
- Projects needing E2E API testing with snapshot comparison
- Anyone tired of writing repetitive mock setup code
- Teams wanting to standardize their testing approach
✨ Features
| 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 | ✅ | ✅ |
Why Use This Package?
- ⚡ 50%+ faster test development with auto-mocks and factories
- 📏 Standardized testing patterns across your entire team
- 🔧 Easy maintenance as your application grows
- 🚀 70%+ less boilerplate code
- 🎨 Universal - works with both NestJS and Express
- 📦 Zero configuration - works out of the box
- 🔒 Type-safe - full TypeScript support with IntelliSense
📦 Installation
# npm
npm install --save-dev node-test-utils
# yarn
yarn add -D node-test-utils
# pnpm
pnpm add -D node-test-utilsPeer Dependencies
This package requires minimal dependencies. Install only what you need:
For NestJS projects:
npm install --save-dev @nestjs/testing @nestjs/common @nestjs/coreFor Express projects:
npm install --save-dev expressRequired for all projects:
npm install --save-dev jestNote: All peer dependencies are optional. Install only the ones you need for your framework.
🚀 Quick Start
1️⃣ Auto Mocks
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!2️⃣ Test Data Factories
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: '[email protected]', ... }
// 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 usersAvailable 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 elements3️⃣ Module Helpers (NestJS Only)
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 maintain4️⃣ E2E Snapshot Testing
Take snapshots of API responses for regression testing. Works with both NestJS and Express!
NestJS Example
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',
});
});
});Express Example
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: '[email protected]' },
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' } },
]);📚 Complete Examples
Example 1: NestJS Full Integration Test
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,
});
});
});Example 2: Express Full Integration Test
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');
});
});📖 API Reference
Auto Mocks
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 mock
Returns: 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' })
});Test Data Factories
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 state
createTestData<T>(defaults: Partial<T>, overrides?: Partial<T>): T
Quick factory function for simple cases.
createFactory<T>(defaults: () => Partial<T>): (overrides?: Partial<T>) => T
Creates a factory function.
TestDataHelpers
Collection of helper functions for generating test data (see Quick Start section).
Module Helpers (NestJS Only)
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.
E2E Snapshot Testing
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.
🎓 Best Practices
- Use factories for all test data - Makes tests more maintainable and consistent
- Use auto-mocks for services - Saves time and reduces boilerplate significantly
- Use snapshots for API contracts - Catches breaking changes early in development
- Create factory classes - More reusable than inline factories
- Use TestDataHelpers - Ensures consistent test data across your application
- Group related overrides - Keep module overrides organized and readable
- Name snapshots meaningfully - Use descriptive
snapshotNamevalues
🔧 Troubleshooting
Issue: "Cannot find module 'jest'"
Solution: Make sure Jest is installed:
npm install --save-dev jest @types/jestIssue: "Cannot find module '@nestjs/testing'"
Solution: Install NestJS dependencies (only needed for NestJS projects):
npm install --save-dev @nestjs/testing @nestjs/common @nestjs/coreIssue: Snapshots failing with random data
Solution: Use fixed data for snapshots or update snapshots:
npm test -- -u # Update snapshotsIssue: Auto-mock not working
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 {}🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with ❤️ for the NestJS and Express communities
- Inspired by the need for better testing utilities in Node.js applications
- Thanks to all contributors and users
📊 Compatibility
| 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
