Skip to content

A unit testing framework for TypeScript backends working with inversion of control and dependency injection

License

Notifications You must be signed in to change notification settings

suites-dev/suites

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Logo

Suites

A unit testing framework for TypeScript backends working with inversion of control and dependency injection
by @omermorad

license npm downloads npm downloads Buy Me A Coffee

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

Features

  • 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.

Examples

Solitary Mode

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);
  });
}

How It Works

The test setup uses TestBed.solitary() to create an isolated testing environment:

  1. TestBed analyzes the class - Reads UserService constructor to find UserApi and Database dependencies
  2. Automatic mocks are created - Generates mock instances of UserApi and Database with all methods as stubs
  3. Dependencies are injected - Wires the mocks into UserService constructor automatically
  4. 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.

Automatic Mocking of Dependencies

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

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();
  });
}

Prerequisites

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

Installation

First, install Suites' unit package:

npm i -D @suites/unit
# or
yarn add -D @suites/unit
# or
pnpm add -D @suites/unit

Then, 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.nestjs

Note: If you're using NestJS or Inversify, you'll also need to install reflect-metadata as a runtime dependency (not a dev dependency):

npm i reflect-metadata

For complete installation instructions, see the Installation Guide.

Configuration

Type Definitions

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.

Contributing

We welcome contributions to Suites! Please see the CONTRIBUTING.md file for more information.

Share Your Suites Experience!

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!

Migrating from Automock

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.

↗️ Migrating from Automock Guide

Your support helps us continue improving Suites and developing new features!

Support the Project

Buy Me A Coffee

πŸ“œ License

Suites is licensed under the Apache License, Version 2.0.