Skip to content

Operations API Tests — Goal

Build a strongly-typed, self-contained API-test suite for the operations component that exercises its HTTP API from the outside, and do so as a reusable pattern — a structure any Arda backend component (accounts, a future system-api-tests) can replicate with minimal change. operations is the reference instance; this document scopes the pattern and its first application.

The suite reaches parity with the existing Bruno api-test coverage for operations (item, kanban, business-affiliate, configuration/probe) and is structured to extend beyond it. The specific assertions are secondary to the structure: the value of this project is a template that is correct-by-layering, contract-accurate, and cheap to run in every phase of the development cycle.

Drawn from the founding discussion (technology, needs, options):

  1. Strongly-typed TypeScript. The wire is type-checked against the component’s own OpenAPI, so a contract change is a compile error, not a runtime surprise. TypeScript is chosen for closeness to the frontend stack (arda-frontend-app): the suite can double as client API-usage examples, and infrastructure and utilities can be shared with frontend development. A full programming language (vs a test-oriented framework) also gives full control of control flow and concurrency, first-class composition of reusable elements, and a low learning curve for engineers already working in TypeScript.
  2. Runs locally and in CI. The same suite runs from a developer shell against a local cluster and, later, from GitHub Actions against a deployed environment.
  3. Dual authentication. Exercises the API over both the static API key and OAuth2/JWT (Cognito access token on AWS; a self-minted RS256 JWT locally), with any test runnable under either auth without code changes.
  4. Multiple SUTs. One typed registry describes every deployment target (local + the four AWS partitions), each with declared capabilities that gate tests.
  5. Secrets never in the repo. All credentials are 1Password references resolved at run time; the tree holds op:// pointers only.
  6. Selectable scope. Tests carry a category (probe ⊆ sanity ⊆ acceptance ⊆ all, plus functional/stress/bug/extra) so a run loads exactly the intended slice.
  7. Governed flakiness. A quarantine mechanism with a compile-required ticket, an expiry, and a failure budget keeps known-bad tests visible without blocking.
  8. Reusable and extensible. The real goal is that the structure yields reusable elements that can be published and shared — across components and at the system level — and extended with new modules and scenarios. Packaging each non-test layer as a standalone unit is the mechanism that makes sharing a move-and-publish rather than a rewrite; it is not the goal itself.
  • Isolation. The subproject must stay isolated from the rest of the operations repo — never touching the Gradle build, the Helm chart, or the deployable — so it can be separated out (into a shared library or its own repo) at any time.
  • No hardcoded local port. The local NodePort is dynamic; the base URL is discovered at run time.
  • Direct-edit CHANGELOG. Every PR carries an entry (suite changes are usually Fixed); the single per-repo version means a deployed tag identifies the exact suite revision that matches it.
  • en-US for all content and identifiers.
  • Each component serves its per-module OpenAPI publicly at /v1/<module>/docs/openApi.json (no auth) — enough to generate the typed proxies.
  • operations accepts either a static API key or a Cognito access token as the bearer (the id token is rejected).
  • Local deployments validate JWTs against a Caddy-served static JWKS (iss: http://caddy/), so a self-minted token needs no Cognito.
  • The SUT under test is reachable whenever tests or proxy generation run — an accepted, deliberate coupling (see the design contract check).

These three workflows are the foundation the design serves. In all three, generate → compile → test is the spine, and compilation after generation is a cheap contract / backwards-compatibility check.

1. Local development — inner loop against a local cluster.

  1. Deploy the component to the local cluster.
  2. Run the suite with SUT=local: generate the proxies from the locally published OpenAPI.
  3. If it compiles, run the tests.
  4. On a compile or test failure, change the tests or the component (adding unit tests as needed) and loop from step 1 until development is complete.

2. Local verification — pre-merge check against dev (which runs origin/main by construction; dev is shorthand for the current dev partition, the alpha002-dev SUT key).

  1. Run the suite with SUT=dev: generate from dev’s OpenAPI, compile, test.
  2. If it fails, and the break is intended, record the intent in the CHANGELOG: a break in a pre-existing route → a major bump; an addition on a new route → a minor bump.
  3. Otherwise, fix the code or the tests until the run is clean (or the CHANGELOG decision converges).

3. CI run — automated gate after merge.

  1. A PR merges and the component deploys to dev.
  2. The suite is triggered with SUT=dev: generate, compile, test.
  3. On failure the deployment pipeline fails; the developer takes corrective action in a new PR.
  1. A self-contained TypeScript suite in operations/api-tests, at parity with the operations Bruno coverage, green against both local and dev.
  2. A single command (make verify SUT=<name>) runs the full spine for any SUT, discovering the local base URL automatically.
  3. Any test runs under api-key or OAuth with no code change; auth-specific tests gate themselves.
  4. The typed wire is generated from the SUT’s live OpenAPI and not committed, so a contract drift surfaces as a compile failure.
  5. The four package layers are a DAG enforced by the build, and each is structured for reuse — promotable to a shared library across components and at the system level.
  6. No secret values in the repository; capabilities and quarantine govern selection and flakiness.

See the design for how the parts realize these, and verification for how each is confirmed.


Copyright: (c) Arda Systems 2025-2026, All rights reserved