Fixture API
The routes a product exposes so each test run can create its test data in any environment, production included, and delete it when the run ends.
A test run creates the data its tests need, such as a verified user with a role, in every
environment it tests, production included, and deletes all of it when it ends. The product does
this through its Fixture API: a few locked-down routes in the product, written in its own
stack. Clanker Ship defines the protocol and signs a fixture token for each run, the only
credential a Fixture API accepts. A deployment's fixtureUrl says where its Fixture API is. The
set-up-testing skill builds one from your fixtures
clanker instructions.
Routes
Paths are relative to the fixture URL. Every request sends Authorization: Bearer <fixture token>.
| Route | What it does |
|---|---|
GET /manifest | Lists the fixtures and jobs the Fixture API offers |
POST /scopes/{scope}/fixtures/{name} | Creates one fixture in the scope from the JSON body and returns what it made: IDs, emails, passwords, session cookies and keys |
GET /scopes/{scope}/outbox | Returns the messages the product would have sent to the scope's test users |
POST /scopes/{scope}/jobs/{name} | Runs one scheduled job now, for the scope's tenants only |
GET /scopes/{scope} | Returns { scope, counts, expiresAt }, with the scope's records counted by kind |
DELETE /scopes/{scope} | Deletes the scope and returns { deleted, remaining }, then deletes other scopes past their expiry |
The manifest names each fixture with a JSON Schema for its body (params) and a body that creates
it (example). outbox says whether the outbox route is there.
{ "protocol": 1, "fixtures": [ { "name": "user", "description": "A verified user with a role in a new tenant.", "params": { "type": "object", "properties": { "role": { "type": "string" } } }, "example": { "role": "admin" } } ], "jobs": [{ "name": "send-digests", "description": "Sends the daily digest emails." }], "outbox": true }
- Create through the product's own services, never raw SQL. Take times in the past, such as an expired invite, as parameters.
- Give each root, a record that belongs to no other such as a user or a tenant, the scope and its expiry. Delete every other record with its root, so deleting the roots deletes the scope.
- A fixture call may send an
Idempotency-Keyheader. Keep the first answer for each key and return it when the call comes again with that key, without making anything new. deletedcounts records by kind, such as{ "users": 4, "tenants": 1 }, andremainingis how many records are left. Anything left fails the run.- Delete expired scopes after answering, so the teardown stays fast.
Fixture tokens
Starting a run, a shard or a retry returns fixture: { scope, token, url, expiresAt } when the
deployment has a fixture URL. Create a fixture token returns the same
without a run, lasting from 5 seconds to six hours; anyone who can publish test runs can create
one. A scope is scp_ and 12 lowercase letters or digits, such as scp_7h2k9q2m4x1a, so it fits in
an email address or a hostname. It expires with its token, six hours after it starts at most.
| Claim | Value |
|---|---|
iss | The Clanker Ship API that signed it: https://api.clankership.com |
sub | The Clanker Ship workspace's ID |
aud | The fixture URL |
env | The environment's slug |
class | production or non-production |
kind | fixture |
scope | The scope |
run | The run's number, or null for a token without a run |
iat | When it was issued, in seconds |
exp | When it expires, in seconds; the scope expires then too |
A Fixture API accepts a token only when all of these hold:
- Its signature checks out against
GET {iss}/.well-known/jwks.json: Ed25519 keys,alg: EdDSA, matched bykid. iss,subandenvare the issuer, workspace and environment the deployment trusts.audis the Fixture API's own URL, so a token for staging fails on production.expis in the future, and the scope in the path is the token'sscope.
Run context
clanker run and clanker retry hand Playwright the run context as use.clanker. Specs read it
through a fixture and never from environment variables.
| Field | Value |
|---|---|
environment | { slug, class } of the environment tested, or null without one |
local | True when the site under test is on this machine |
deployments | Each product's base URL in that environment, by product slug |
fixture | The scope, token, Fixture API URL and expiry, or null without a Fixture API |
semaphores | Where the run takes semaphore leases, and its run token; null for an unpublished run |
Check a Fixture API
clanker fixtures check --environment stagingIt asks for a ten-minute token, reads the manifest, creates every fixture from its example and
deletes the scope. It exits 1 when a step fails or anything is left. --fixture-url checks another
Fixture API, such as a local server. See Test runs for
how a run cleans up and reports it.