Skip to content

First Story (Rust)

Create a test file such as tests/login.rs:

use executable_stories::{write_results, Story};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn user_logs_in_successfully() {
let mut s = Story::new("user logs in successfully");
s.given("the user is on the login page");
let email = "[email protected]";
let password = "secret";
s.when("the user submits valid credentials");
let authenticated = email == "[email protected]" && password == "secret";
s.then("the user should see the dashboard");
assert!(authenticated);
s.pass();
}
#[test]
fn write_report() {
write_results();
}
}

Call .pass() at the end of each test that succeeds. If .pass() is not called before the Story is dropped, the scenario is recorded as failed.

Use tags, tickets, and doc entries to add context to your scenarios:

use executable_stories::{write_results, Story};
use serde_json::json;
#[test]
fn password_rules_enforced() {
let mut s = Story::new("password rules are enforced")
.with_tags(&["auth", "security"])
.with_tickets(&["AUTH-42"]);
s.given("the user is registering a new account");
s.note("Password policy: min 12 chars, one uppercase, one digit, one symbol");
s.when("the user submits a password that is too short");
let password = "short";
let valid = password.len() >= 12;
s.then("the registration should be rejected");
s.json("validation result", &json!({ "valid": valid, "reason": "too short" }));
s.code(
"password policy",
"min_length: 12\nrequire_uppercase: true\nrequire_digit: true",
Some("yaml"),
);
s.table(
"rule summary",
&["Rule", "Required", "Met"],
&[
vec!["min length 12", "yes", "no"],
vec!["uppercase letter", "yes", "yes"],
vec!["digit", "yes", "no"],
],
);
assert!(!valid);
s.pass();
}
Method Renders as
s.given(label) Given / And
s.when(label) When / And
s.then(label) Then / And
s.and(label) And
s.but(label) But

All step methods return &mut Self so they can be chained.

Terminal window
cargo test
Terminal window
npx --package executable-stories-formatters executable-stories format --format html

Run your reporter with --format html and your stories render into an interactive report:

Report Outputwhat this code generatesOpen live report ↗
The generated HTML report with Given/When/Then steps, a run summary, and search and status filters
Every framework adapter produces this same report. Click to open the live one.

Rust story & doc API — full steps, docs, and adapter options.

Other adapters — the rest of the non-JS adapters.