Verification
Mountebank has no first-class “did this happen N times” assertion — you fetch
GET /imposters/{port} and inspect requests/numberOfRequests yourself. The typed DSL turns
that into one call, imposter.verify(match, count), on top of the recorded-request journal that
imposter().record() enables.
verify() and count matchers
import { imposter, onGet, okJson, times, atLeast, atMost, between, never } from '@rift-vs/rift';
const users = await engine.create(
imposter('users').record()
.stub(onGet('/api/users/1').willReturn(okJson({ id: 1 }))));
await fetch(`${users.url}/api/users/1`);
await users.verify(onGet('/api/users/1'), times(1)); // exactly 1
await users.verify(onGet('/api/users/1'), atLeast(1)); // default when count is omitted
await users.verify(onGet('/api/other'), atMost(0)); // same as never()
await users.verify(onGet('/api/users/1'), between(1, 3));
await users.verify(onGet('/api/other'), never()); // times(0)
match accepts a StubBuilder (only its predicates are used — any .willReturn(...) on it is
ignored), a raw wire.Predicate, or a wire.Predicate[]. count defaults to atLeast(1).
verify() throws RiftError up front, naming .record() as the fix, if the imposter wasn’t
created with recording enabled — there’s no journal to check against otherwise.
recorded() and clearRecorded()
const all = await users.recorded(); // RecordedRequest[]
const gets = await users.recorded({ match: onGet('/api/users/1') });
await users.clearRecorded(); // DELETE savedRequests
Each RecordedRequest is the mapped, ergonomic shape (method, path, query, headers,
body, from, timestamp), plus raw — the untouched wire object — for anything not lifted
onto the typed fields.
Live iteration: requests()
const controller = new AbortController();
for await (const req of users.requests({ signal: controller.signal, match: onGet('/api/users/1') })) {
console.log(req.method, req.path);
}
An AsyncIterableIterator<RecordedRequest> that polls the journal (default every 250ms) and
yields each newly-recorded request exactly once, in journal order. It completes cleanly (no
throw) when opts.signal aborts or the imposter is deleted mid-poll; like verify(), it throws
up front — before the first poll — if recording isn’t enabled.
Client-side predicate evaluation — what’s supported
There is no server-side verify endpoint in the engine yet, so verify()/recorded(filter)
evaluate predicates in the SDK, against the recorded requests: equals, deepEquals,
contains, startsWith, endsWith, matches, exists, and, or, not, honoring
caseSensitive (default insensitive), keyCaseSensitive, except, plus a built-in jsonpath
subset (dot + bracket + numeric index, e.g. $.a.b[0].c; filters/wildcards are unsupported).
xpath and inject predicates are not evaluable client-side. Rather than silently treating
every request as a non-match (or, worse, a match), a verify()/recorded() call whose match
includes either operator throws UnsupportedPredicateError, naming the unsupported operator. If
you need to assert on XML bodies or a custom inject predicate, express the check some other way
(e.g. assert on the raw body string from recorded() yourself).
Failure diagnostics: VerificationError
A verify() miss throws a VerificationError with a WireMock-style near-miss diff: which
recorded request came closest (the one satisfying the highest fraction of leaf predicate clauses;
ties go to the most recent), and which of its fields matched or didn’t.
Verification failed for imposter "users" (port 55123)
Expected GET /api/users/1 times(1)
Actual 0 of 3 recorded requests matched
Closest non-match — request #2 at 2026-07-09T10:12:03Z from 127.0.0.1:52114:
method GET ✓
path /api/users/2 ✗ expected equals "/api/users/1"
header accept: application/json ✓
The error carries machine-readable fields too: error.expected (the predicates), error.count
({ matched, total, matcher }), error.recorded (everything on the journal), and
error.closest. The testkit’s assertReceived reuses this same renderer.
See Migrating from Mountebank §Verification for the Mountebank-side comparison, and the API reference §6 for the exact types.