Skip to main content

tsed-testing

Write unit and integration tests for Ts.ED v8 applications with Vitest (Jest as a fallback) - vitest.config with unplugin-swc, PlatformTest.create/invoke/reset from @tsed/platform-http/testing, provider mocking with {token, use}, inject() in specs, PlatformTest.createRequestContext, and PlatformTest.bootstrap(Server) with SuperTest and PlatformTest.callback(). Use when adding or fixing *.spec.ts files for services, controllers, middlewares or interceptors, when injected properties are undefined in tests, or on the error "Platform type is not specified" / a missing platform adapter.

Quellinformationen

Repository
tsedio/tsed
Letzte Quellaktivität
3. Oktober 2026 um 16:50
Erkannte Sprache von SKILL.md
Englisch
Sterne
3.089
Forks
295

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
3 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
tsed-testing
description
Write unit and integration tests for Ts.ED v8 applications with Vitest (Jest as a fallback) - vitest.config with unplugin-swc, PlatformTest.create/invoke/reset from @tsed/platform-http/testing, provider mocking with {token, use}, inject() in specs, PlatformTest.createRequestContext, and PlatformTest.bootstrap(Server) with SuperTest and PlatformTest.callback(). Use when adding or fixing *.spec.ts files for services, controllers, middlewares or interceptors, when injected properties are undefined in tests, or on the error "Platform type is not specified" / a missing platform adapter.
# Test a Ts.ED Application Build every tested class through the Ts.ED test injector. Never instantiate a DI-managed class (service, controller, middleware, interceptor, module) with `new` in a test: it bypasses injection, scopes, hooks and mocks. Read [the testing recipes](references/recipes.md) for middleware, interceptor, request-context and stubbing examples. Depth: `https://tsed.dev/docs/testing.md`, `https://tsed.dev/tutorials/vitest.md`. ## 1. Configure Vitest Install `vitest unplugin-swc @swc/core @vitest/coverage-v8` (and `supertest @types/supertest` for integration tests). A project generated by tsed-cli already has this. ```typescript // vitest.config.mts import swc from "unplugin-swc"; import {defineConfig} from "vitest/config"; export default defineConfig({ test: {globals: true, root: "./"}, plugins: [ swc.vite({ jsc: { target: "es2022", keepClassNames: true, parser: {syntax: "typescript", decorators: true}, transform: {useDefineForClassFields: false, legacyDecorator: true, decoratorMetadata: true} } }) ] }); ``` - Do not rely on Vitest's default esbuild transform: it does not emit decorator metadata, so constructor and `@Inject()` property injection resolve to `undefined`. - Do not remove `useDefineForClassFields: false`; class fields would overwrite injected properties. - Jest: use `ts-jest` per `https://tsed.dev/tutorials/jest.md`. It is unstable with ESM; prefer Vitest for new projects. ## 2. Choose the test type 1. Logic of one provider with mocked collaborators: unit test with `PlatformTest.create()` (steps 3-4). Fast, no HTTP server. 2. Routing, validation, serialization, middlewares chain, exception filters: integration test with `PlatformTest.bootstrap(Server)` + SuperTest (step 5). 3. Real database or broker: add a testcontainers package (step 6). ## 3. Unit test a provider ```typescript import {inject} from "@tsed/di"; import {PlatformTest} from "@tsed/platform-http/testing"; import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {UsersService} from "./UsersService.js"; describe("UsersService", () => { beforeEach(() => PlatformTest.create()); afterEach(() => PlatformTest.reset()); it("should return the user", async () => { const service = inject(UsersService); expect(await service.findById("1")).toEqual({id: "1"}); }); }); ``` - `PlatformTest.create(settings?)` accepts any configuration key: `PlatformTest.create({features: {beta: true}})` then read it with `constant("features.beta")`. - `PlatformTest.get(Token)` and `inject(Token)` return the shared instance. `PlatformTest.injector` is the `InjectorService`. - Import `inject` from `@tsed/di`. `@tsed/platform-http/testing` only exports `PlatformTest` and `FakeAdapter`. - For code without HTTP dependencies, `DITest` from `@tsed/di` offers the same `create`, `invoke`, `get`, `reset`. ## 4. Mock dependencies ```typescript const repository = {findById: vi.fn().mockResolvedValue({id: "1"})}; const service = await PlatformTest.invoke<UsersService>(UsersService, [{token: UsersRepository, use: repository}]); expect(await service.findById("1")).toEqual({id: "1"}); expect(repository.findById).toHaveBeenCalledWith("1"); ``` - `PlatformTest.invoke(Token, [{token, use}])` builds a fresh instance with local mocks and runs `$onInit`. Always `await` it. - Mock for the whole `describe`: `PlatformTest.create({imports: [{token: UsersRepository, use: repository}]})`, then `inject(UsersService)`. - `imports` entries accept `use`, `useClass`, `useFactory` or `useAsyncFactory`. `useValue` is ignored there. - Symbol or factory tokens are mocked the same way: `{token: DbConnection, use: fakeDb}`. - Controllers are providers: `await PlatformTest.invoke<UsersController>(UsersController, [...])` and call the handler method directly with plain arguments. - Mock only direct collaborators. Do not `vi.mock()` a class file that the injector must still register. ## 5. Integration test with SuperTest ```typescript import {PlatformTest} from "@tsed/platform-http/testing"; import SuperTest from "supertest"; import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {Server} from "../Server.js"; import {UsersController} from "./UsersController.js"; describe("UsersController", () => { beforeAll(PlatformTest.bootstrap(Server, {mount: {"/rest": [UsersController]}})); afterAll(PlatformTest.reset); it("should call GET /rest/users/:id", async () => { const request = SuperTest(PlatformTest.callback()); const response = await request.get("/rest/users/1").expect(200); expect(response.body).toEqual({id: "1"}); }); }); ``` - `PlatformTest.bootstrap()` returns a function; pass it to `beforeAll`, or call it: `await PlatformTest.bootstrap(Server)()`. - The platform adapter must be registered: import `@tsed/platform-express` (or `-koa`, `-fastify`) in `Server.ts` or in the spec, or pass `{adapter: PlatformExpress}`. - No port is opened unless `listen: true` is passed. The environment is `test` and the logger level is `off` by default. - Settings passed as second argument replace the same `@Configuration` keys (only `mount`, `scopes`, `logger` are merged). Passing `imports` drops the Server's own `imports`. - Stub after bootstrap: `vi.spyOn(PlatformTest.get(UsersService), "findById").mockResolvedValue(...)`. ## 6. Use real infrastructure sparingly Point to `@tsed/testcontainers-mongo` (`https://tsed.dev/tutorials/mongoose.md`) and the premium `@tsedio/testcontainers-*` packages (Postgres, Redis, Vault) listed in `https://tsed.dev/docs/testing.md`. Do not hand-roll container lifecycle code when a package exists. ## Pitfalls - "Platform type is not specified" (older releases) or a crash while creating the platform adapter in `PlatformTest.bootstrap`: no adapter package was imported. Add `import "@tsed/platform-express";`. - `beforeEach(PlatformTest.create)` passes Vitest's test context as settings. Write `beforeEach(() => PlatformTest.create())`. - Missing `PlatformTest.reset` leaks providers, hooks and mocks into the next file and keeps handles open. - `PlatformTest.invoke` without `await` returns a promise; assertions then run on the promise. - `PlatformTest.inject([Token], cb)` is deprecated. Use `inject()` or `PlatformTest.invoke()`. - Services reading `context()` need `runInContext(PlatformTest.createRequestContext(), () => ...)` from `@tsed/di`. - One `PlatformTest.bootstrap` per file in `beforeAll`, not `beforeEach`: bootstrapping the server per test is slow. - Do not import from `@tsed/common`; `PlatformTest` lives in `@tsed/platform-http/testing`. ## Checklist - `vitest.config` uses `unplugin-swc` with `decorators`, `legacyDecorator`, `decoratorMetadata` and `useDefineForClassFields: false`. - No `new` on a DI-managed class anywhere in the specs; instances come from `inject()`, `PlatformTest.get()` or `PlatformTest.invoke()`. - Every `PlatformTest.create`/`bootstrap` has a matching `PlatformTest.reset`. - Mocks use `{token, use}` and are asserted with `toHaveBeenCalledWith`; success and error paths are covered. - Integration specs import the platform adapter and build requests with `SuperTest(PlatformTest.callback())`. - Related skills: tsed-di (providers, scopes), tsed-configuration (settings overrides), tsed-controllers, tsed-middlewares, tsed-exceptions (error payload assertions).
Auf GitHub ansehen