SUITES / TYPESCRIPT UNIT TESTING
Project Suites.
A unit testing framework for TypeScript backends working with inversion of control and dependency injection
Open source. Built for dependency injection.
import { TestBed } from '@suites/unit';import { UserService } from './user.service';import { UserRepository } from './user.repository';
const { unit, unitRef } = await TestBed .solitary(UserService) .compile();
const repository = unitRef.get(UserRepository);repository.getUserById.mockResolvedValue(user);
expect(await unit.getUserName(user.id)) .toBe(user.name);FITS YOUR STACK
One testing pattern.
The tools you already use.
Dependency injection
- NestJS
- InversifyJS
- InjectionJS
Test runners
- Jest
- Vitest
LESS WIRING. MORE TESTING.
Suites compared with manual mocking
Keep the test.
Let Suites handle the setup.
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); });}A SMALL API. A CLEARER TEST.
Make room for the behavior
that matters.
Standardized Testing Across Teams
Stop relearning test patterns on every project. Suites provides a consistent, standardized approach that works identically across NestJS, InversifyJS, and InjectionJS, with Jest or Vitest as your test runner.
See framework support// Same pattern works everywhere// NestJS, InversifyJS, InjectionJS
TestBed.solitary(OrderService).compile();
// Or test with real dependenciesTestBed.sociable(OrderService) .expose(PaymentProcessor) .compile();Tests That Reveal Intent, Not Boilerplate
Create the unit and its dependency mocks in one step. Keep setup short so the behavior you arrange, run, and assert is easy to find.
See quick start// One line creates the entire test environmentconst { unit, unitRef } = await TestBed .solitary(UserService) .compile();
// Just test the logicconst 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 generatedconst userApi = unitRef.get(UserApi);
userApi.get.mockResolvedValue({ name: 'John' });Built for AI-First Development
A consistent TestBed pattern gives coding assistants a small, repeatable example to follow. Spend your review on test behavior instead of generated mock classes and constructor wiring.
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 patternconst { unit, unitRef } = await TestBed .solitary(UserService) .compile();
// AI agents learn the entire API from one exampleSTART WITH ONE CLASS
Write your first Suites test.
Choose your framework and runner. Follow the same simple pattern.