Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Writing scenarios

A scenario is a Rhai script. The top level can be the whole test, or you can register several named scenarios as a suite.

Agents and call control

agent(name, #{ … }) connects a headless baresip instance and returns a handle you drive with verbs — register, dial, accept, hangup, hold, dtmf, transfer, … See Agents for the full set, the config options and the readable state (registered, state, …).

await_until

SIP is asynchronous, so assertions are polled: await_until re-runs an assert(...) until it holds or a timeout elapses. Use it instead of sleeping.

#![allow(unused)]
fn main() {
a.dial(b);
await_until(|| assert(b.state).equals(State::Ringing), "15s");
}

The matchers — equals, is_true, contains, … — are all on the assertion handle.

Suites: setup / scenario / teardown

setup() runs before each scenario and returns the context passed to it; each scenario(name, body) runs in isolation with fresh agents; teardown() runs after each (even on failure).

#![allow(unused)]
fn main() {
setup(|| {
    let caller = agent("Caller", #{
        username: env("A_USER"),
        domain: env("SIP_DOMAIN"),
        password: env("A_PASS"),
    });
    caller.register();
    await_until(|| assert(caller.registered).is_true(), "10s");
    #{ caller: caller }
});

scenario("answered call", #{ tags: ["smoke"] }, |ctx| {
    ctx.caller.dial("+49301234567");
    await_until(|| assert(ctx.caller.state).equals(State::Established), "15s");
});
}

Selecting, tagging and skipping

The scenario(name, #{ … }, body) options control which scenarios run:

  • Tags#{ tags: ["smoke"] }, then --tag smoke / --exclude-tag slow.
  • Skip#{ skip: true | "reason" } disables a scenario statically; or call skip("reason") at runtime (e.g. env-gated).
  • Focus#{ only: true } runs only the focused scenario(s), run-wide.

Skipped scenarios are reported but don’t fail the run.

More