Test without API keys
Exercise your application's failure paths with deterministic mock outcomes.
On this page
Assert fallback behavior
import assert from 'node:assert/strict';
import { createSearch } from '@belweave/search-sdk';
import { createMockProvider } from '@belweave/search-sdk/testing';
const primary = createMockProvider({
id: 'primary',
outcomes: [{ type: 'error', code: 'rate_limit', retryAfterMs: 2_000 }],
});
const backup = createMockProvider({ id: 'backup' });
const client = createSearch({ provider: primary, fallback: [backup] });
const response = await client.web.search({ query: 'search interfaces' });
assert.equal(response.provider, 'backup');
assert.equal(response.attempts.length, 2);
assert.equal(response.warnings[0]?.code, 'fallback_used');
assert.equal(primary.calls.length, 1);
assert.equal(backup.calls.length, 1);Each mock has an independent outcome queue and call history. Outcomes are reserved in invocation order, even if concurrent calls complete in a different order. An exhausted explicit queue returns configuration.
Understand fixture behavior
- Without an outcome queue, the default success fixture repeats.
- A success outcome accepts
results,usage, anddelayMs. Omit provenance; the mock adds it. - An error outcome accepts
code, optionalstatus,retryAfterMs, anddelayMs. - The mock implements hostname filtering and output limits. Timestamps reflect the actual test clock.
Keep evidence levels separate
| Check | What it can establish |
|---|---|
| Application mock | Your consumer's state and error handling. |
| Injected HTTP fixture | Expected request mapping and response validation. |
| Authenticated live request | Behavior of a particular provider request at a particular time. |
| Quality evaluation | Usefulness against a dated query set and explicit rubric. |
Passing fixture tests does not establish live key validity, production availability, billing correctness, or a provider quality ranking.