At a glance
SDK tests
Providers are tested by driving them with the vendor’s official SDK, pinned to an exact version indevDependencies (for example "resend": "6.34.1"). startService from @deploybaseline/testing starts the plugin in process on a free port and returns its url for the SDK’s base URL option:
closeAllServices in afterAll or afterEach. createWebhookSink gives you a local receiver for webhook assertions.
Each package’s vitest.config.ts spreads providerTestConfig from @deploybaseline/testing/vitest, which sets a 10 second timeout, excludes *.dual.test.ts, points core at the cache directories the gates read, and reuses workers across test files with a per-file setup that undoes spies, stubbed globals and env, and fake timers. See How tests share the machine.
Coverage matrix
src/__tests__/coverage.ts lists every route the plugin registers as "METHOD /pattern" (or WS /pattern, or a GraphQL root field such as Query.issues), with a status:
supported: works like the real API for the flows we know aboutpartial: works, with known gaps described innotesor pinned bygapsnot_started: planned, not registered yet
supported, and entries the last full run did not hit get the note “No test yet”.
- Gate 1: matrix matches routes
- Gate 2: every route is hit
coverage.test.ts calls checkRouteCoverage(coverage, pluginRoutes(plugin)). It fails when a registered route is missing from the matrix or the matrix lists a route that is not registered. Composed services use checkModuleCoverage so each route sits under the module that registered it.Spec gate
When a vendor publishes a usable OpenAPI document, its trimmed copy lives atspec/openapi.json (see Vendored specs). During a full run, core samples JSON responses per route and status, and the gate validates each against the operation’s response schema, naming the operation and JSON path of every mismatch.
1
Turn it on in warn mode
Add
spec: { mode: "warn" } to coverageGate in coverage.setup.ts and run the full suite.2
Record the current mismatches
src/__tests__/spec-allow.ts. Existing entries keep their reason; entries that no longer match are dropped.3
Triage and switch to fail
Fix what you can, give every remaining entry a specific reason, then set
mode: "fail". In fail mode an allow entry that matches nothing also fails, so the list cannot rot.successOnly: true when the vendor spec documents only successful responses (Twilio, Resend), so undocumented error statuses are not reported; specPath when the emulator’s route pattern is spelled differently from the vendor’s path.
Pinned gaps
Pin a known difference from the real API as anit.fails test, so fixing the gap flips the test. List the test’s name in the gaps of its matrix entry and mark the entry partial. checkPinnedGaps (called from coverage.test.ts) keeps the two in sync.
Property and model tests
- Parsers get
fast-checkproperty tests:*.property.test.ts(for examplestripe/src/__tests__/form-body.property.test.ts). - State machines get a model-based test:
*.model.test.tsruns random command sequences against a small reference model (Stripe has several, such assubscriptions.model.test.ts).
State restart and persistence
- Every provider has a
state-restarttest that runs a main flow, callsrestartService(save, then start a fresh instance from the saved JSON on the same port), and checks that reads match and tokens still work. tests/contracts/persistence.jsis one shared contract for saved state: a restart keeps writes, tokens, and signing keys; astateVersionmismatch is refused and left alone; reset; and the single-writer lock. It runs frompersistence-contract.test.tsinpackages/cliagainst bothcreateEmulatorand thestartrunner. A change to how either runtime saves or loads state must keep it passing.state-fixtures.test.tsrestores the state each earlier provider version saved (packages/cli/src/__tests__/fixtures/state/<provider>/<version>.json) and checks that the same state under anotherstateVersionis refused. After bumping a provider,pnpm state-fixturesadds the new version’s fixture.
Custom consumer acceptance
scripts/custom-api-acceptance.mjs installs the packed CLI into a fresh temporary project and repeats the CLI checks there, including a hard kill and stale lock takeover. CI runs it on Linux, macOS, and Windows with Node 24, and on Linux with Node 26.
Dual mode
Dual mode runs the same SDK scenarios against the emulator and the vendor’s sandbox, then compares response shapes. It is off unlessDUAL_MODE names the provider, refuses anything that is not a sandbox credential, and tags what it creates so leftovers can be swept.
node scripts/dual-cleanup.mjs <provider> sweeps leftovers (add --dry-run to preview). The Dual mode workflow runs one provider on demand and all of them monthly from the protected dual-mode environment, uploads a comparison report, and on success opens a PR that records the date in conformance/verified.json.
Conformance report
scripts/conformance.mjs regenerates CONFORMANCE.md and docs/snippets/conformance/<name>.mdx from repository content only (matrices, gate settings, vendored specs, the lockfile, conformance/verified.json), so the output is stable and CI can diff it.
What CI enforces
Thebuild-and-test job in .github/workflows/ci.yml runs, in order:
1
Install and build
pnpm install --frozen-lockfile, then pnpm build.2
Bundle budget
node scripts/check-bundle.mjs: CLI tarball size, the code --help loads, and that the build inlines no provider (from dist/metafile-esm.json).3
Packaged notices
Every packed package carries the root
LICENSE, NOTICE, and THIRD_PARTY_NOTICES.md.4
Release plan
node scripts/release-packages.mjs plan --dry-run: which package versions a merge would publish, with a warning for any that has no changelog entry.5
Packed providers
node scripts/compatibility.mjs host --packed: the built CLI starts every provider from its packed tarball, installed into an empty project.6
Provider packages
pnpm test:third-party: the provider template, packed and served from a local registry, is refused until trusted, pinned by trust, run next to Stripe, and refused again when baseline.lock names another integrity.7
New install
pnpm test:slim-cli: the packed CLI, installed with npm into an empty project, holds no provider code; a first start with an empty cache pulls the default providers from a local registry, a second runs them from the cache, and an offline start with no cache says to run pull.8
Generated files are fresh
pnpm conformance followed by git diff --exit-code on CONFORMANCE.md and docs/snippets/conformance, and node scripts/generate-api-reference.mjs --check for the API reference.9
Static checks
pnpm lint (Biome lint and format check), pnpm type-check.10
Tests
pnpm test, with every coverage and spec gate.Docs (Mintlify) job runs mint validate and mint broken-links, and the custom-consumer matrix runs pnpm test:custom-consumer. make check runs the same set locally.