E2E Test Generation
Configure e2e in nestia.config.ts and npx nestia e2e writes a starter end-to-end test for every @TypedRoute-decorated method in your project. Each test:
- Picks a random valid input from the routeβs DTO type (via
typia.random<T>()). - Calls the generated SDK function (no
fetchstrings). - Asserts that the response matches the declared return type.
Thatβs the schema-contract net: every route gets covered, on every CI run, with zero hand-written boilerplate. Your own business-logic tests live alongside them.
New to this feature? Read Tutorial β Auto E2E Tests for the friendly walkthrough. This page is the reference.
Enable
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./src/AppModule";
const config: INestiaConfig = {
input: () => NestFactory.create(AppModule),
output: "src/api",
e2e: "test", // output directory for the generated suite
};
export default config;Run:
npx nestia e2eOutput: test/features/api/<controller-path>/test_api_<route>.ts (one file per endpoint).
Anatomy of a generated test
import typia, { Primitive } from "typia";
import api from "@my-app/api";
import type { IArticle } from "@my-app/api/lib/structures/IArticle";
export const test_api_articles_create = async (
connection: api.IConnection,
): Promise<void> => {
const output: IArticle = await api.functional.articles.create(
connection,
typia.random<Primitive<IArticle.ICreate>>(),
);
typia.assert(output);
};Three lines that matter:
typia.random<Primitive<IArticle.ICreate>>()β synthesizes a schema-valid request body.api.functional.articles.create(...)β the generated SDK call againstconnection.typia.assert(output)β verifies the response matchesIArticle.
If the schema drifts (server returns a different shape), the assert fails on the next CI run.
Re-running npx nestia e2e overwrites these files. Keep them auto-generated and add your hand-written scenarios in sibling files (the runner picks up anything matching test_*).
Run the suite
@nestia/e2eβs DynamicExecutor walks the test directory, finds every test_* function, and runs them in series. A typical runner:
import { DynamicExecutor } from "@nestia/e2e";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "../src/AppModule";
const main = async () => {
const app = await NestFactory.create(AppModule);
await app.listen(0);
const port = (app.getHttpServer().address() as any).port;
const report = await DynamicExecutor.validate({
prefix: "test_",
parameters: () => [{ host: `http://localhost:${port}` }],
})(__dirname + "/features");
console.log(report);
await app.close();
};
main().catch(console.error);Run with npx ttsx test/index.ts. Exit code reflects pass/fail; plug into CI.
Mixing generated tests with hand-written ones
The convention is one directory per controller / domain, with both auto and hand-written files:
test/features/api/articles/
βββ test_api_articles_create.ts # generated β schema contract
βββ test_api_articles_list.ts # generated β schema contract
βββ test_api_articles_admin_sees_all.ts # hand-written β business rule
βββ test_api_articles_archive_idempotent.ts # hand-written β business ruleDynamicExecutor finds them all by the test_ prefix. The auto-generated tests prove the schema works; your hand-written tests prove the rules work.
Re-using the SDK for benchmarks
The same test files drive @nestia/benchmark β point it at the same directory and you get a load report:
import { NestiaBenchmarker } from "@nestia/benchmark";
const report = await NestiaBenchmarker.benchmark({
prefix: "test_",
parameters: () => [{ host: `http://localhost:${port}` }],
threads: 16,
duration: 30_000,
})(__dirname + "/../test/features");You get RPS, latency percentiles, and per-endpoint error rates as a markdown report. See E2E β Benchmark for the full configuration.
See also
- Tutorial β Auto E2E Tests β the walkthrough.
- E2E β Why E2E? β the case for e2e over unit tests when you have an SDK.
- E2E β Development β patterns for hand-written scenarios.
- E2E β Benchmark β load testing on top of the same files.