Suites
A unit testing framework for TypeScript backends working with inversion of control and dependency injection
Works with projects using
- With Suites
- Without Suites
import { TestBed, type Mocked } from '@suites/unit';
describe('User Service', () => {
let userService: UserService; // The unit we are testing
let userApi: Mocked<UserApi>; // The dependencies we are mocking
let database: Mocked<Database>;
beforeAll(async () => {
// Create an isolated test env for the unit
const { unit, unitRef } = await TestBed.solitary(UserService).compile();
userService = unit;
// Retrieve the unit's dependency mocks - automatically generated
userApi = unitRef.get(UserApi);
database = unitRef.get(Database);
});
// ✅ Test test test
it('should generate a random user and save to the database', async () => {
userApi.getRandom.mockResolvedValue({id: 1, name: 'John'} as User);
await userService.generateRandomUser();
expect(database.saveUser).toHaveBeenCalledWith(userFixture);
});
});
// THE MANUAL WAY
// (Similar complexity exists in NestJS, InversifyJS, etc.)
import { UserService } from './user-service';
import { UserApi } from './user-api';
import { Database } from './database';
describe('User Service', () => {
let userService: UserService;
let userApi: any; // ❌ Lost type safety!
let database: any;
beforeAll(async () => {
// 🔧 Manually create mocks for each dependency
userApi = {
getRandom: jest.fn(),
// Missing methods? Who knows? No compile-time checks!
};
database = {
saveUser: jest.fn(),
// What other methods exist? ¯\_(ツ)_/¯
};
// Manual wiring - boilerplate for every test
userService = new UserService(userApi, database);
});
it('should generate a random user and save to the database', async () => {
userApi.getRandom.mockResolvedValue({id: 1, name: 'John'} as User);
await userService.generateRandomUser();
expect(database.saveUser).toHaveBeenCalledWith(userFixture);
});
}
Declarative
Suites' declarative API creates fully-typed, isolated test environments with a single declaration. Suites auto-generates all mocks and wires dependencies automatically.
Type-Safe
Generate type-safe mocks bound to implementations. Eliminate broken tests after refactors, silent runtime failures, and manual type casting.
Refactoring Confidence
Change constructors, add dependencies, refactor classes - tests adapt automatically. Skip manual mock updates. Catch breaking changes at compile time, not runtime.
AI Ready
One canonical pattern teaches AI agents the entire API. Coding agents like Claude Code and Cursor write correct tests in a single pass with 95% less context consumption compared to manual mocking patterns.
Used by
Standardized Testing Across Teams
Stop relearning test patterns on every project. Suites provides a consistent, standardized approach that works identically across NestJS, InversifyJS, and any DI framework, giving teams a unified testing experience.
See Framework Support →// Same pattern works everywhere
// NestJS, InversifyJS, TSyringe...
TestBed.solitary(OrderService).compile();
// Or test with real dependencies
TestBed.sociable(OrderService)
.expose(PaymentProcessor)
.compile();
Tests That Reveal Intent, Not Boilerplate
Suites' declarative API removes 90% of test setup code. No more scrolling through mock wiring, logic is front and center. New team members write tests on day one, not day ten.
See Quick Start →// One line creates the entire test environment
const { unit, unitRef } = await TestBed
.solitary(UserService)
.compile();
// Just test the logic
const userApi = unitRef.get(UserApi);
userApi.getRandom.mockResolvedValue(user);
await unit.generateRandomUser();
Type-Safe, Automatic Mocking
No more debugging broken mocks. Suites automatically generates fully-typed mocks bound to implementation. Catch errors at compile time, not runtime. Refactor with confidence while mocks stay valid when dependencies change.
Learn about Mocking →// No manual mocks needed!
const { unit, unitRef } = await TestBed
.solitary(UserService)
.compile();
// Fully-typed mocks, automatically generated
const userApi = unitRef.get(UserApi);
userApi.get.mockResolvedValue({ name: 'John' });
Built for AI-First Development
Manual mocking forces AI agents to hold 40+ lines of boilerplate per test in context. Suites provides one canonical pattern that reduces token consumption by 95%. AI coding assistants like Claude Code, Cursor, and GitHub Copilot generate accurate tests in a single pass without burning tokens on repetitive setup code.
Suites and AI →// Manual: 40+ lines per test in AI context
// class MockUserApi { getRandom = jest.fn(); ... }
// class MockDatabase { saveUser = jest.fn(); ... }
// const userService = new UserService(mockUserApi, mockDb);
// Suites: Single canonical pattern
const { unit, unitRef } = await TestBed
.solitary(UserService)
.compile();
// AI agents learn the entire API from one example




