تخطَّ إلى المحتوى

Testing

هذا المحتوى غير متوفر بلغتك بعد.

What is tested, how endpoint tests run against real infrastructure, and the helpers the framework provides.

Terminal window
bun run db:up # PostgreSQL :54329 + Redis :63799 (compose)
cp .env.test.example .env.test # TEST_DATABASE_URL=postgres://… (a server-level admin URL)

TEST_DATABASE_URL must point at a dedicated test server/admin URL — never the application’s DATABASE_URL; the testing package refuses to create test databases on the application target or in APP_ENV=production.

Every database test gets its own database (fw_test_<random>), created from TEST_DATABASE_URL, migrated from the app’s database/migrations, and dropped in success and failure paths. Nothing leaks between runs.

Application-level tests use the generated tests/support.ts:

const ctx = await createTestContext(); // boots the full app on a fresh migrated DB
const response = await ctx.client.request('/api/v1/products', jsonInit('POST', { name: 'x', price: '1' }));
await ctx.close(); // stops server, shuts down, drops the DB

TEST_MODE=network swaps in-process http.request for a real loopback listener (same assertions, real transport). The generated endpoint suites run identically in both modes — make:crud --verify --test-mode network proves routes over the wire.

Each make:crud module ships tests/<resource>.crud.api.test.ts, which calls the registered Hono application (never a mocked controller):

  • happy path: create → list → read → update → re-read → delete → 404
  • public allowlist exposure (secret fields never serialized)
  • deterministic, bounded listing; pagination bounds (422)
  • malformed JSON (400), malformed ids (422), unknown ids (404)
  • invalid payloads: missing / mistyped / refinement-violating / forbidden fields
  • empty updates, immutable fields (createdAt)

make:crud --verify runs this suite plus a typecheck after every generation and reports each route, pass/fail counts and database cleanup in the result (JSON with --json).

Package tests (packages/*/tests) exercise real adapters where it matters: CRUD mixins, auditing, transactions and pagination run on real PostgreSQL; queues run on real Redis; events tests cover both buses. Pattern:

const database = await createTestDatabase({ adminUrl: requireTestDatabaseUrl() });
const connection = createConnection({ url: database.url, maxConnections: 4 });
await connection.sql`create table …`;
// … assertions …
await connection.close();
await database.drop();

MemoryEventBus stands in for Redis in unit tests; the testing package provides isolated databases instead of a fake query layer. Fakes prove wiring, never infrastructure behavior — retry, duplicate delivery and failure semantics are only proven by the real-adapter suites.

  • packages/cli/tests/generated-app.test.ts — make:crud end to end on new and existing tables, route collisions, --dry-run writing nothing, and the generated application’s full suite.
  • packages/cli/tests/create-app.test.ts — the create release gate: the generated application typechecks, passes its suite, migrates the audit table, accepts make:crud --verify, and create --with-demo produces a working products module whose endpoint tests pass as-is.
  • apps/playground/tests/contract.test.ts — OpenAPI drift check and a typed Hono RPC client against the composed application.

Run everything from the workspace root:

Terminal window
bun test # or: bun run test
  • No skipped-if-missing tests: missing TEST_DATABASE_URL fails with setup instructions instead of silently passing.
  • Tests never auto-migrate the application database; they only migrate their own isolated database.
  • Ephemeral network servers bind 127.0.0.1:0 and always close.