Unified Gateway

Testing

Unit and integration testing strategy.

Tests are designed to be hermetic with respect to providers:

  • They do not need real credentials for OpenAI, Google, Azure, OpenRouter, etc.
  • bun run --filter @boelabs/unified-gateway test, bun run --filter @boelabs/unified-gateway test:unit, and bun run --filter @boelabs/unified-gateway test:integration import apps/gateway/tests/support/noRealFetch.ts, which blocks any real fetch.
  • If a test needs to simulate an upstream, it must use withStubbedFetch() from tests/support/fetch.ts.

Layers

LayerScriptExternal dependencies
Unit / contractbun run --filter @boelabs/unified-gateway test or bun run --filter @boelabs/unified-gateway test:unitNo real network. Lives next to the code in apps/gateway/src/**/*.test.ts.
Integrationbun run --filter @boelabs/unified-gateway test:integrationLocal Postgres/Redis if the test needs them; if they are not available, it is skipped. Lives in apps/gateway/tests/integration/**/*.ts. Never a real provider.
Allbun run --filter @boelabs/unified-gateway test:allUnit + integration.
Catalog validationbun run --filter @boelabs/unified-gateway catalog:validateNo real network; validates local JSON.

Common helpers

  • tests/support/fetch.ts: upstream stubs (withStubbedFetch, jsonResponse).
  • tests/support/app.ts: a mini Hono app for /v1/* endpoints with auth, request-id, and OpenAI-compatible errors.
  • tests/support/infra.ts: Postgres and Redis detection/teardown.
  • tests/support/integrationCleanup.ts: defensive cleanup for UUID-suffixed integration-test rows before and after each integration file.
  • tests/support/wait.ts: polling for fire-and-forget async effects (logs, cache, Redis).
  • apps/gateway/tests/support/noRealFetch.ts: global guard against real network access.

Escape hatch

For a one-off manual test against the internet:

ALLOW_TEST_NETWORK=1 bun run --filter @boelabs/unified-gateway test

Do not use it in CI or in normal tests; if a provider behavior matters, capture the minimal shape and simulate it with withStubbedFetch().

On this page