# `testing/conformance` — `runSecretsConformance` harness _(no submodules)_ ## Purpose `runSecretsConformance` is the reusable Vitest suite every concrete `SecretsLike` implementation in the api-secrets family MUST pass. Stage-4 adapters (`api-secrets-env`, `api-secrets-vault`) and The `api-secrets-bun` adapter all import it, hand it a factory that returns a fresh fixture per scenario, and inherit the cross-package shape guarantees — `get` returns the value, `get` returns `undefined` on miss, `require` returns the value, `require` throws `SECRETS.SECRET_NOT_FOUND` on miss, and `list()` enumerates seeded names. Centralising the suite means an adapter cannot accidentally drift its semantics from peer adapters without a test failure showing up in its own CI. The harness is intentionally factory-based so sources that own real resources (testcontainers-backed vault, OS keystore) can seed and tear down per scenario rather than reusing a single instance across the suite. ## Features - Five canonical scenarios covering the four documented behaviours plus `list()` enumeration. - Per-scenario fixture factory with optional teardown hook. - Customisable `isNotFound` predicate so sources representing missing names differently (network adapter wrapping a transport error) can still pass. - All `it(...)` calls carry `{ timeout: 5000 }`. ## Usage: Basic ```ts import { runSecretsConformance } from "@suaveplan/api-secrets/testing"; import { createEnvSecrets } from "./env-secrets.js"; runSecretsConformance({ label: "env-secrets", factory: (seed) => { const restore = applyEnv(seed); const secrets = createEnvSecrets({ allowList: Object.keys(seed) }); return { secrets, teardown: () => restore() }; }, }); ``` ## Usage: Advanced Adapt the harness to a source whose missing-name representation differs from the canonical code: ```ts import { runSecretsConformance } from "@suaveplan/api-secrets/testing"; import { VaultTransportError } from "./vault-transport.js"; runSecretsConformance({ label: "vault-secrets", factory: async (seed) => { const container = await startVaultContainer({ seed }); return { secrets: container.secrets, teardown: () => container.stop(), }; }, // vault wraps "not found" in a transport-level 404 — recognise it as // the canonical SECRET_NOT_FOUND for the purposes of the suite. isNotFound: (err) => err instanceof VaultTransportError && err.status === 404, }); ``` ## API Reference - `function runSecretsConformance(options: RunSecretsConformanceOptions): void` — registers a Vitest `describe` block; call once at module top level. - `interface RunSecretsConformanceOptions` — `{ label, factory, isNotFound? }`. - `interface SecretsConformanceFixture` — `{ secrets, teardown? }`. ## Implementation Notes The harness deliberately uses `describe`/`it` from `@suaveplan/testing/runner` rather than importing directly from `vitest` — that runner wrapper routes to `bun:test` under Bun's runner condition, so a package whose runtime is browser-tier can still drive its conformance check from a `bun test` invocation. The default `isNotFound` matches on the canonical `SECRETS.SECRET_NOT_FOUND` code string; adapters not extending `SecretsError` directly must supply their own predicate. Note the harness does not check `dispose()` — that's intentional, because the canonical api-types `SecretsLike` shape does not require `dispose`; adapters that DO own resources should pair the conformance run with their own teardown suite.