fynjs API
    Preparing search index...

    Module run-verify

    run-verify

    run-verify gives tests a controlled progression. Organize actions and assertions into explicit steps, each checked before the next begins. Coordinate callbacks, promises, and events in the order your test requires, with a deadline to keep the run bounded.

    Turn an expected error into a positive outcome. When a step must fail, the expected error satisfies that step and becomes the input to the next, ready for further assertions. Unexpected success fails the test.

    fyn add --dev run-verify
    
    import assert from "node:assert/strict";
    import { verify } from "run-verify";

    await verify({ timeout: 500 })
    .step(() => 2)
    .step(value => value * 3)
    .keep.step(value => assert.equal(value, 6))
    .step(value => `count=${value}`)
    .step(label => assert.equal(label, "count=6"));

    A plain .step() replaces the current value with what it returns. An assertion usually returns undefined. Use .keep.step() when an assertion should preserve its input.

    The chain is thenable and has no terminal method. Awaiting it starts the run. A thrown error or rejected Promise rejects the run. TypeScript infers the value at each step and reports incompatible steps at compile time.

    Method Use it for
    .step(fn) Synchronous work or a Promise-returning function. The function receives the current value.
    .step(value) A value or Promise that already exists. A direct Promise has already started.
    .asyncStep(fnOrValue) Async work where an array should resolve element by element, like Promise.all.
    .callbackStep(fn) An error-first callback API. One parameter receives next. Two receive (value, next).

    Pass a function when work must wait for its turn in the chain:

    const [a, b] = await verify({ timeout: 500 }).asyncStep(() => [save("a"), save("b")]);
    

    .step() adopts a single Promise. It passes arrays through unchanged. Use .asyncStep() when an array of promises must settle before the next step.

    Callback steps make callback completion explicit:

    const record = await verify({ timeout: 500 })
    .callbackStep(next => loadRecord("record-1", next))
    .keep.step(value => assert.equal(value.id, "record-1"));

    In TypeScript, a callback result defaults to unknown. Its type cannot be inferred from an error-first callback. Provide the type when later steps need its structure:

    const id = await verify({ timeout: 500 })
    .callbackStep<{ id: string }>(next => loadRecord("record-1", next))
    .step(record => record.id);

    Add an expected-error modifier immediately before the step that must fail:

    await verify({ timeout: 500 })
    .expectErrorMatch("not found", "TASK_NOT_FOUND")
    .step(() => loadTask("missing"))
    .step(error => assert.equal(error.task, "missing"));
    Modifier Requirement
    .expectError The next step must fail. A throw or rejection counts. A callback error also counts.
    .expectErrorMatch(matcher, code?) The top-level message must contain a string matcher or match a regex. A supplied code must also match exactly.
    .expectErrorInstanceMatch(ConstructorOrArray, matcher?, code?) The failure must be an instance of the constructor or any constructor in a nonempty array. Optional message and code constraints also apply.
    .expectErrorToBe(message, code?) The top-level message must equal message. A supplied code must also match.
    .expectErrorToBe(Constructor, code?) The failure must be an instance of Constructor; the next step receives that instance type. A supplied code must also match.
    .expectErrorHas(message, code?) The top-level message must contain message. A supplied code must also match.
    .keep The next step must finish. Its input remains the chain value.

    A successful step fails an expected-error requirement. A matching failure becomes the next value, retaining its original identity. Without an instance requirement, that value has the unknown type because JavaScript can throw any value. An instance requirement infers its constructor's instance type; an array infers the union of its instance types.

    await verify({ timeout: 500 })
    .expectErrorInstanceMatch([TypeError, RangeError], /^invalid input$/, "E_BAD")
    .step(() => parseInput())
    .step(error => assert.equal(error.message, "invalid input"));

    String matchers check substrings; use an anchored regex for an exact message. Both new matching methods retain requirements from earlier calls, so every requirement must pass. Omitting code adds no code constraint and preserves earlier ones. The existing expectErrorToBe and expectErrorHas methods remain available with their current semantics.

    The positional API also exports expectErrorMatch(fn, matcher, code?) and expectErrorInstanceMatch(fn, ConstructorOrArray, matcher?, code?):

    import { asyncVerify, expectErrorInstanceMatch, expectErrorMatch } from "run-verify";

    await asyncVerify(
    expectErrorMatch(() => loadTask("missing"), "not found", "TASK_NOT_FOUND")
    );
    await asyncVerify(
    expectErrorInstanceMatch(() => parseInput(), TypeError, /^invalid input$/, "E_BAD")
    );

    Modifiers affect only the next step method. You can combine modifiers.

    Pass run-wide concerns to verify():

    let connection;

    await verify({
    timeout: 1000,
    cleanup: async () => {
    if (connection) await connection.close();
    }
    })
    .step(() => openConnection())
    .step(opened => {
    connection = opened;
    return opened.load();
    })
    .keep.step(result => assert.ok(result));
    Option Effect
    timeout Deadline in milliseconds for the whole run. There is no default.
    cleanup One function or an array. It runs after success or failure.
    signals Named external signals that must settle before the run can finish.

    Declare cleanup before fallible setup. Keep that setup inside the chain when cleanup must cover a partial setup or timeout.

    signal() represents work that finishes outside the step sequence. A declaration in config.signals makes the signal required. .awaiting() waits for its value at a deliberate point in the chain.

    import { signal, verify } from "run-verify";

    const saved = signal();
    const onSaved = record => saved.resolve(record);

    await verify({
    timeout: 500,
    signals: { saved },
    cleanup: () => store.off("saved", onSaved)
    })
    .step(() => {
    store.once("saved", onSaved);
    return store.save("record-1");
    })
    .awaiting(saved)
    .step(record => record.id)
    .step(id => assert.equal(id, "record-1"));

    Registering a signal does not block the chain. The listener can be ready before the work starts. The signal can resolve before .awaiting() is reached. Rejecting it fails the run.

    signal<T>() types the value supplied to the next step. .awaiting("saved") uses the matching key from config.signals. The signal-object form avoids string typos in JavaScript. A signal represents one occurrence. It can be awaited only once.

    verify.signal() is the same helper as the standalone signal() export.

    Chains are immutable. You can branch a prefix:

    const withStore = verify({ timeout: 500, cleanup: closeStore }).step(() => makeStore());

    const a = await withStore.step(store => store.save("a"));
    const b = await withStore.step(store => store.save("b"));

    Each branch is a separate run with its own setup and cleanup. Awaiting the same chain more than once runs it once. A chain with configured signals cannot be branched or reused. Each signal represents one occurrence. Create the signals and chain inside each test.

    See the full API reference for every verify method, option, type, and runtime rule.

    verify uses lower-level runner APIs to do the work. Those APIs are also exported. See the low-level API reference for details.

    Licensed under the Apache License, Version 2.0.

    Chain
    ChainConfig
    DeferHandlers
    DeferObject
    Signal
    VerifyFn
    WrapObject
    CheckFunction
    DoneCallback
    ErrorClass
    ErrorClasses
    ErrorCode
    ErrorMatcher
    NextCallback
    SignalMap
    StepCallback
    DEFER_EVENT
    DEFER_OBJ
    DEFER_WAIT
    IS_FINALLY
    verify
    WRAPPED_FN
    _asyncVerifyFrom
    asyncVerify
    expectError
    expectErrorHas
    expectErrorInstanceMatch
    expectErrorMatch
    expectErrorToBe
    onFailVerify
    runDefer
    runFinally
    runTimeout
    runVerify
    signal
    withCallback
    wrapAsyncVerify
    wrapCheck
    wrapFn
    wrapVerify