{"id":13469505,"url":"https://github.com/suites-dev/suites","last_synced_at":"2026-01-19T08:00:43.071Z","repository":{"id":42658064,"uuid":"429476841","full_name":"suites-dev/suites","owner":"suites-dev","description":"A unit testing framework for TypeScript backends working with inversion of control and dependency injection","archived":false,"fork":false,"pushed_at":"2025-12-03T20:46:25.000Z","size":4965,"stargazers_count":503,"open_issues_count":9,"forks_count":21,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-12-04T03:23:25.299Z","etag":null,"topics":["dependency-injection","inversifyjs","inversion-of-control","ioc","ioc-container","jest","mock","mocking","nestjs","sinon","sinonjs","spec","tdd","testing","typescript","unit-test","unit-testing","unit-testing-nodejs","vitest"],"latest_commit_sha":null,"homepage":"https://suites.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/suites-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"buy_me_a_coffee":"omermoradd"}},"created_at":"2021-11-18T15:13:37.000Z","updated_at":"2025-12-03T20:12:20.000Z","dependencies_parsed_at":"2023-12-15T10:01:56.062Z","dependency_job_id":"bf02596b-db24-4bc9-95ad-2c0dfd44752d","html_url":"https://github.com/suites-dev/suites","commit_stats":{"total_commits":275,"total_committers":3,"mean_commits":91.66666666666667,"dds":"0.010909090909090868","last_synced_commit":"9dd0ce0c9e038951aa3aa183df0424007c05b065"},"previous_names":["omermorad/automock","suites-dev/suites","automock/automock"],"tags_count":128,"template":false,"template_full_name":null,"purl":"pkg:github/suites-dev/suites","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suites-dev%2Fsuites","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suites-dev%2Fsuites/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suites-dev%2Fsuites/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suites-dev%2Fsuites/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/suites-dev","download_url":"https://codeload.github.com/suites-dev/suites/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suites-dev%2Fsuites/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28563198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T03:31:16.861Z","status":"ssl_error","status_checked_at":"2026-01-19T03:31:15.069Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","inversifyjs","inversion-of-control","ioc","ioc-container","jest","mock","mocking","nestjs","sinon","sinonjs","spec","tdd","testing","typescript","unit-test","unit-testing","unit-testing-nodejs","vitest"],"created_at":"2024-07-31T15:01:42.719Z","updated_at":"2026-01-19T08:00:43.042Z","avatar_url":"https://github.com/suites-dev.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg width=\"150\" src=\"https://raw.githubusercontent.com/suites-dev/suites/master/logo.png\" alt=\"Logo\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eSuites\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\nA unit testing framework for TypeScript backends working with inversion of control and dependency injection\n\u003cbr /\u003e\nby \u003ca href=\"https://github.com/omermorad\"\u003e\u003cstrong\u003e@omermorad\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://opensource.org/licenses/Apache-2.0\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache_2.0-blue.svg\" alt=\"license\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/suites-dev/suites/blob/master/CONTRIBUTING.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/@suites/unit\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/@suites/unit.svg?label=%40suites%2Funit\" alt=\"npm downloads\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/@automock/jest\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/@automock/jest.svg?label=%40automock%2Fjest\" alt=\"npm downloads\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://buymeacoffee.com/omermoradd\"\u003e\u003cimg src=\"https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee\" alt=\"Buy Me A Coffee\" /\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003ch3 align=\"center\"\u003e\n  \u003ca href=\"https://suites.dev\"\u003eDocs\u003c/a\u003e\n  \u003cspan\u003e\u0026nbsp;\u0026nbsp;•\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"https://suites.dev/docs/get-started/quickstart\"\u003eGetting Started\u003c/a\u003e\n  \u003cspan\u003e\u0026nbsp;\u0026nbsp;•\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"https://suites.dev/docs/get-started/why-suites\"\u003eWhy Suites\u003c/a\u003e\n  \u003cspan\u003e\u0026nbsp;\u0026nbsp;•\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"https://suites.dev/docs/guides\"\u003eGuides\u003c/a\u003e\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cstrong\u003eDependency Injection Frameworks:\u003c/strong\u003e \u003ca href=\"https://nestjs.com\"\u003eNestJS\u003c/a\u003e (\u003ca href=\"https://docs.nestjs.com/recipes/suites\"\u003eofficial\u003c/a\u003e), \u003ca href=\"https://inversify.io/\"\u003eInversifyJS\u003c/a\u003e (\u003ca href=\"https://inversify.io/docs/ecosystem/suites/\"\u003eofficial\u003c/a\u003e)\u003c/a\u003e\u003cbr/\u003e\n\u003cstrong\u003eTesting Libraries:\u003c/strong\u003e \u003ca href=\"https://jestjs.io\"\u003eJest\u003c/a\u003e, \u003ca href=\"https://vitest.dev\"\u003eVitest\u003c/a\u003e, \u003ca href=\"https://sinonjs.org\"\u003eSinon\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\nUsing Suites? \u003ca href=\"https://github.com/suites-dev/suites/discussions/655\"\u003eShare your experience\u003c/a\u003e, and help us shape the future of Suites\n\u003c/p\u003e\n\n## Features\n\n- **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.\n\n- **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.\n\n- **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.\n\n- **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.\n\n## Examples\n\n### Solitary Mode\n\n**Solitary mode** tests a single unit in complete isolation - all dependencies are automatically mocked. Use this when\nyou want to test your unit's logic without any real dependencies.\n\n[Learn more about Solitary Tests](https://suites.dev/docs/guides/solitary)\n\n```typescript\nimport { TestBed, type Mocked } from '@suites/unit';\n\ndescribe('User Service', () =\u003e {\n  let userService: UserService; // Class under test\n  let userApi: Mocked\u003cUserApi\u003e; // Mock instance\n  let database: Mocked\u003cDatabase\u003e; // Mock instance\n\n  beforeAll(async () =\u003e {\n    // Create the test environment with automatic mocking\n    const testBed = await TestBed.solitary(UserService).compile();\n\n    userService = testBed.unit;\n    // Retrieve the mock instances\n    userApi = testBed.unitRef.get(UserApi);\n    database = testBed.unitRef.get(Database);\n  });\n\n  it('should generate a random user and save to the database', async () =\u003e {\n    const mockUser = { id: 1, name: 'John' } as User;\n    userApi.getRandom.mockResolvedValue(mockUser);\n\n    await userService.generateRandomUser();\n\n    expect(database.saveUser).toHaveBeenCalledWith(mockUser);\n  });\n}\n```\n\n### How It Works\n\nThe test setup uses `TestBed.solitary()` to create an isolated testing environment:\n\n1. **TestBed analyzes the class** - Reads `UserService` constructor to find `UserApi` and `Database` dependencies\n2. **Automatic mocks are created** - Generates mock instances of `UserApi` and `Database` with all methods as stubs\n3. **Dependencies are injected** - Wires the mocks into `UserService` constructor automatically\n4. **Type-safe access** - Use `unitRef.get()` to retrieve mocks with full TypeScript support\n\nNo manual mock creation needed. `TestBed` handles dependency discovery, mock generation, and wiring automatically.\n\n### Automatic Mocking of Dependencies\n\nWhen using `TestBed.solitary()`, all dependencies are automatically mocked. Each method becomes a stub with no predefined responses. Configure stub responses in tests as needed.\n\n```typescript\n// These stubs start with no return values\nuserApi.getRandom  // Returns undefined by default\ndatabase.saveUser  // Returns undefined by default\n\n// Configure them in your tests\nuserApi.getRandom.mockResolvedValue({ id: 1, name: 'John' });\ndatabase.saveUser.mockResolvedValue(42);\n```\n\n### Sociable Mode\n\n**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.\n\n[Learn more about Sociable Tests](https://suites.dev/docs/guides/sociable)\n\n```typescript\nimport { TestBed, type Mocked } from '@suites/unit';\n\ndescribe('User Service', () =\u003e {\n  let userService: UserService; // Class under test\n  let database: Mocked\u003cDatabase\u003e; // Mock instance\n\n  beforeAll(async () =\u003e {\n    // Create test environment with real UserApi\n    const testBed = await TestBed.sociable(UserService)\n      .expose(UserApi) // Use real UserApi implementation\n      .compile();\n\n    userService = testBed.unit;\n    database = testBed.unitRef.get(Database);\n  });\n\n  it('should generate a random user and save to the database', async () =\u003e {\n    await userService.generateRandomUser();\n\n    expect(database.saveUser).toHaveBeenCalled();\n  });\n}\n```\n\n## Prerequisites\n\nBefore installing Suites, ensure your project meets these requirements:\n\n- **Dependency Injection Framework**: NestJS, InversifyJS, or plain TypeScript classes with constructor injection\n- **Testing Library**: Jest, Vitest, or Sinon\n\n## Installation\n\nFirst, install Suites' unit package:\n\n```bash\nnpm i -D @suites/unit\n# or\nyarn add -D @suites/unit\n# or\npnpm add -D @suites/unit\n```\n\nThen, install **ONE** adapter for your DI framework and **ONE** adapter for your testing library:\n\n**DI Framework Adapters:**\n- **NestJS** - `@suites/di.nestjs`\n- **InversifyJS** - `@suites/di.inversify`\n\n**Testing Library Adapters:**\n- **Jest** - `@suites/doubles.jest`\n- **Vitest** - `@suites/doubles.vitest`\n- **Sinon** - `@suites/doubles.sinon`\n\n**Example for NestJS + Jest:**\n```bash\nnpm i -D @suites/doubles.jest @suites/di.nestjs\n# or\nyarn add -D @suites/doubles.jest @suites/di.nestjs\n# or\npnpm add -D @suites/doubles.jest @suites/di.nestjs\n```\n\n\u003e **Note:** If you're using NestJS or Inversify, you'll also need to install `reflect-metadata` as a runtime dependency (not a dev dependency):\n\u003e ```bash\n\u003e npm i reflect-metadata\n\u003e ```\n\nFor complete installation instructions, see the [Installation Guide](https://suites.dev/docs/get-started/installation).\n\n## Configuration\n\n### Type Definitions\n\nCreate a `global.d.ts` file in your project root (or in your test directory) to enable proper TypeScript support:\n\n```typescript\n/// \u003creference types='@suites/doubles.jest/unit' /\u003e\n/// \u003creference types='@suites/di.nestjs/metadata' /\u003e\n```\n\nReplace `@suites/doubles.jest` and `@suites/di.nestjs` with your chosen adapters.\n\nFor detailed configuration instructions, see the [Installation Guide](https://suites.dev/docs/get-started/installation).\n\n### Contributing\n\nWe welcome contributions to Suites! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information.\n\n## Share Your Suites Experience!\n\n**Are you using Suites in your projects?** We've created a [community discussion](https://github.com/suites-dev/suites/discussions/categories/q-a) where teams and companies can share how they're using Suites in production.\n\n👉 **[Join the discussion](https://github.com/suites-dev/suites/discussions/categories/q-a)** and tell us more :)\n\nYour contributions help others discover best practices and see real-world applications of Suites!\n\n## Migrating from Automock\n\nIf you're currently using Automock, we've created a comprehensive migration guide to help you transition to Suites. The\nguide covers all the changes and improvements, making the upgrade process smooth and straightforward.\n\n[↗️ Migrating from Automock Guide](https://suites.dev/docs/migration-guides/from-automock)\n\nYour support helps us continue improving Suites and developing new features!\n\n## Support the Project\n\n\u003ca href=\"https://buymeacoffee.com/omermoradd\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" \u003e\u003c/a\u003e\n\n## 📜 License\n\nSuites is licensed under the [Apache License, Version 2.0](LICENSE).\n","funding_links":["https://buymeacoffee.com/omermoradd"],"categories":["TypeScript","Packages","Built with TypeScript"],"sub_categories":["Mocks","Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuites-dev%2Fsuites","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuites-dev%2Fsuites","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuites-dev%2Fsuites/lists"}