A unit testing framework for TypeScript backends working with inversion of control and dependency injection
by @omermorad
Docs Β Β β’Β Β Getting Started Β Β β’Β Β Why Suites Β Β β’Β Β Guides
Dependency Injection Frameworks: NestJS (official), InversifyJS (official)
Testing Libraries: Jest, Vitest, Sinon
Using Suites? Share your experience, and help us shape the future of Suites
-
Declarative - Provides a declarative API for defining fully-typed, isolated test environments from a single specification, including automatic mock generation and dependency wiring based on constructor metadata.
-
Type-Safe Refactoring - Binds mocks to concrete TypeScript implementations so that changes to constructors, injected dependencies, and method signatures are validated at compile time, enabling confident refactors with less failing tests.
-
Standardized Testing Across Teams - Exposes a uniform testing surface across NestJS, InversifyJS, and other DI setups, enabling consistent test structure and patterns regardless of the underlying framework.
-
AI Ready - Provides a concise and strict test API that minimizes context requirements for LLM-based coding agents, enabling higher-quality generated tests, clearer and more actionable error messages that guide automatic self-correction, and a higher likelihood of completing test authoring in a single pass.
Solitary mode tests a single unit in complete isolation - all dependencies are automatically mocked. Use this when you want to test your unit's logic without any real dependencies.
Learn more about Solitary Tests
import { TestBed, type Mocked } from '@suites/unit';
describe('User Service', () => {
let userService: UserService; // Class under test
let userApi: Mocked<UserApi>; // Mock instance
let database: Mocked<Database>; // Mock instance
beforeAll(async () => {
// Create the test environment with automatic mocking
const testBed = await TestBed.solitary(UserService).compile();
userService = testBed.unit;
// Retrieve the mock instances
userApi = testBed.unitRef.get(UserApi);
database = testBed.unitRef.get(Database);
});
it('should generate a random user and save to the database', async () => {
const mockUser = { id: 1, name: 'John' } as User;
userApi.getRandom.mockResolvedValue(mockUser);
await userService.generateRandomUser();
expect(database.saveUser).toHaveBeenCalledWith(mockUser);
});
}The test setup uses TestBed.solitary() to create an isolated testing environment:
- TestBed analyzes the class - Reads
UserServiceconstructor to findUserApiandDatabasedependencies - Automatic mocks are created - Generates mock instances of
UserApiandDatabasewith all methods as stubs - Dependencies are injected - Wires the mocks into
UserServiceconstructor automatically - Type-safe access - Use
unitRef.get()to retrieve mocks with full TypeScript support
No manual mock creation needed. TestBed handles dependency discovery, mock generation, and wiring automatically.
When using TestBed.solitary(), all dependencies are automatically mocked. Each method becomes a stub with no predefined responses. Configure stub responses in tests as needed.
// These stubs start with no return values
userApi.getRandom // Returns undefined by default
database.saveUser // Returns undefined by default
// Configure them in your tests
userApi.getRandom.mockResolvedValue({ id: 1, name: 'John' });
database.saveUser.mockResolvedValue(42);Sociable mode tests how components work together. You choose which dependencies to keep real (using .expose()) while external I/O remains mocked. Use this when you want to test integration between multiple units.
Learn more about Sociable Tests
import { TestBed, type Mocked } from '@suites/unit';
describe('User Service', () => {
let userService: UserService; // Class under test
let database: Mocked<Database>; // Mock instance
beforeAll(async () => {
// Create test environment with real UserApi
const testBed = await TestBed.sociable(UserService)
.expose(UserApi) // Use real UserApi implementation
.compile();
userService = testBed.unit;
database = testBed.unitRef.get(Database);
});
it('should generate a random user and save to the database', async () => {
await userService.generateRandomUser();
expect(database.saveUser).toHaveBeenCalled();
});
}Before installing Suites, ensure your project meets these requirements:
- Dependency Injection Framework: NestJS, InversifyJS, or plain TypeScript classes with constructor injection
- Testing Library: Jest, Vitest, or Sinon
First, install Suites' unit package:
npm i -D @suites/unit
# or
yarn add -D @suites/unit
# or
pnpm add -D @suites/unitThen, install ONE adapter for your DI framework and ONE adapter for your testing library:
DI Framework Adapters:
- NestJS -
@suites/di.nestjs - InversifyJS -
@suites/di.inversify
Testing Library Adapters:
- Jest -
@suites/doubles.jest - Vitest -
@suites/doubles.vitest - Sinon -
@suites/doubles.sinon
Example for NestJS + Jest:
npm i -D @suites/doubles.jest @suites/di.nestjs
# or
yarn add -D @suites/doubles.jest @suites/di.nestjs
# or
pnpm add -D @suites/doubles.jest @suites/di.nestjsNote: If you're using NestJS or Inversify, you'll also need to install
reflect-metadataas a runtime dependency (not a dev dependency):npm i reflect-metadata
For complete installation instructions, see the Installation Guide.
Create a global.d.ts file in your project root (or in your test directory) to enable proper TypeScript support:
/// <reference types='@suites/doubles.jest/unit' />
/// <reference types='@suites/di.nestjs/metadata' />Replace @suites/doubles.jest and @suites/di.nestjs with your chosen adapters.
For detailed configuration instructions, see the Installation Guide.
We welcome contributions to Suites! Please see the CONTRIBUTING.md file for more information.
Are you using Suites in your projects? We've created a community discussion where teams and companies can share how they're using Suites in production.
π Join the discussion and tell us more :)
Your contributions help others discover best practices and see real-world applications of Suites!
If you're currently using Automock, we've created a comprehensive migration guide to help you transition to Suites. The guide covers all the changes and improvements, making the upgrade process smooth and straightforward.
Your support helps us continue improving Suites and developing new features!
Suites is licensed under the Apache License, Version 2.0.

