Generate a deterministic conformance test suite from a v4 "Suluk" contract — the contract's claims, made executable.
CANDIDATE tooling — not official OpenAPI. Suluk is a single-contributor candidate for OpenAPI Specification v4.0 ("Moonwalk"), unaffiliated with the OpenAPI Initiative and unable to ratify anything on the SIG's behalf.
bun add @suluk/testgen @cfworker/json-schema
@cfworker/json-schema is a peer dependency — the generated suite imports it to validate response
bodies against their declared schemas. generateMoneyTests additionally targets @suluk/stripe (the
emitted suite imports the pricing primitives from there).
generateTests(doc) walks a v4 document and emits a self-contained test file (a string) that runs
against a live deployment. It turns the x-suluk-* facets from decoration into load-bearing claims:
x-suluk-access is only the expectation — the test passes iff the wire agrees. It
never asserts over a projection and never treats the facet as if it were the enforcement (C022 inv.3).@suluk/hono envelope: title string + status matching the HTTP status).x-suluk-cost — checked statically,
never as a literal µ$ amount (which would couple tests to billing internals and go flaky).A pure function of the document: same contract in, same suite out, no network at generate-time. Each op's
tests are labelled with its provenance (x-suluk-source) so a failure points at the authoring source.
generateMoneyTests() is a separate emitter for the money path — an in-process suite over the @suluk/stripe
pricing primitives (anti-tampering, integer-cents, never-over-discount, exact proration, deterministic
idempotency). It takes no document; the invariants live in the shared primitives, not in any one contract.
Reach for it whenever you want the contract's facets to mean something — this is what makes x-suluk-*
enforced rather than aspirational. The common pattern is to expose the generated suite as a download endpoint
so any consumer can verify your deployment honours its own contract (see Usage). Add generateMoneyTests when
your app touches checkout/billing through @suluk/stripe.
This is a generator, not a runner: it produces a bun:test (or vitest) file you run yourself. It is the
testing facet of the projection model — siblings like @suluk/scalar / @suluk/swagger render the contract;
@suluk/sdk generates a client; this generates the conformance proof.
import { generateTests } from "@suluk/testgen";
import type { OpenAPIv4Document } from "@suluk/core";
const suite = generateTests(document, { baseURL: "https://api.example.com" });
// → a self-contained test-file string. Write it next to your tests and run it:
await Bun.write("api.conformance.test.ts", suite);
Run the emitted suite against a deployment — SULUK_BASE_URL wins over the baked-in baseURL:
SULUK_BASE_URL=https://api.example.com bun test api.conformance.test.ts
Optional positive-side checks (a non-public op also asserting a valid principal IS allowed through) are skipped unless you provide synthetic principal tokens — never a production credential:
SULUK_ADMIN_TOKEN=… SULUK_USER_TOKEN=… bun test api.conformance.test.ts
import { generateTests } from "@suluk/testgen";
app.get("/conformance.test.ts", (c) =>
new Response(generateTests(document, { baseURL: new URL(c.req.url).origin }), {
headers: {
"content-type": "application/typescript; charset=utf-8",
"content-disposition": 'attachment; filename="api.conformance.test.ts"',
},
}),
);
generateTests(document, {
baseURL: "https://api.example.com", // baked default; SULUK_BASE_URL overrides at run-time
framework: "vitest", // "bun" (default) | "vitest" — toggles the emitted imports
});
import { generateMoneyTests } from "@suluk/testgen";
const money = generateMoneyTests(); // imports primitives from "@suluk/stripe"
await Bun.write("money.conformance.test.ts", money);
// then: bun test money.conformance.test.ts (no network, in-process)
// configurable runner + import specifier:
generateMoneyTests({ framework: "vitest", stripeModule: "../pricing" });
| Export | What it does |
|---|---|
generateTests(doc, opts?) |
Emit a wire-conformance suite (access / status / schema / cost) from a v4 document, as a test-file string. |
generateMoneyTests(opts?) |
Emit an in-process money-correctness suite over the @suluk/stripe pricing primitives. |
TestgenOptions |
{ baseURL?: string; framework?: "bun" | "vitest" }. |
MoneyTestsOptions |
{ framework?: "bun" | "vitest"; stripeModule?: string }. |
This package generates, never hosts (L3). It is a pure string-emitter: no network at generate-time, no deployment of its own. The seams it leaves to the app:
SULUK_BASE_URL (or the baked baseURL) at run-time — the
generated suite reads it from the environment.x-suluk-access; this
never re-implements authz, and never asserts over a projection (C022 inv.3 — the server is the only boundary).SULUK_*_TOKEN), out of band.bun test); you decide where to write it and when
to run it in CI.Contributing: a new facet means a new asserted claim here — that is what keeps x-suluk-* load-bearing.
Apache-2.0.