Expand description
§vanilla-test for Rust
Project overview · Rust documentation · Guide · Examples · API · Coverage · docs.rs · crates.io · Live browser WASM test
A small, dependency-free, unsafe-free Rust implementation of the Vanilla Test lifecycle. It runs natively with Cargo and compiles the same Rust unit tests into browser WebAssembly without wasm-bindgen, generated glue, or a wrapper crate.
§Install
cargo add vanilla-testRust 1.85 or newer is supported. The crate has no dependencies and forbids unsafe code.
§Use
use vanilla_test::VanillaTest;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut test = VanillaTest::new();
test.expects("addition preserves the total")?;
if 1 + 2 == 3 {
test.pass()?;
} else {
test.fail()?;
}
test.done()?;
let result = test.report()?;
assert!(result.ok);
assert_eq!(result.total, 1);
Ok(())
}The suite is sequential. One VanillaTest instance owns one active case; create separate instances for independent concurrent work.
§Lifecycle
expects(description)starts one uniquely named case.pass()orfail()records the first decision.done()closes the case; no decision means failure.- Repeat as needed.
report()seals the suite and returns its cached immutable result.
An empty suite passes. Exact, case-sensitive descriptions are unique within one suite. Reporting while a case is active is an error, and a reported suite cannot start another case.
§API
| Item | Contract |
|---|---|
VanillaTest::new() | Creates an empty isolated suite. |
expects(&str) | Starts one uniquely described case. |
pass() | Records the first decision as passed. |
fail() | Records the first decision as failed. |
done() | Completes the case, defaulting an undecided case to failed. |
report() | Seals the suite and returns the same borrowed TestResult thereafter. |
TestResult | Owns passed/failed descriptions, totals, ok, and the plain-text report. |
TestError | A typed lifecycle error that leaves the suite unchanged. |
TestError distinguishes SuiteAlreadyReported, TestAlreadyActive, DuplicateDescription, NoActiveTest, and ActiveTestNotDone.
Rust intentionally does not copy JavaScript-only runtime validators, completion events, ANSI rendering, busy-loop helpers, or process behavior. The shared value is the lifecycle; the API remains native Rust.
§Native tests
cargo fmt --check
RUSTFLAGS="-D warnings" cargo test
cargo packageNative Cargo is the canonical detailed diagnostic path. Focused unit tests and this README’s doctest verify the native contract.
§Native source coverage
CI instruments the nine native unit tests with rustc -C instrument-coverage, merges their profiles once with Rust’s bundled llvm-profdata, and publishes region, executable-line, and function results through llvm-cov. The artifact includes LLVM summary JSON, LCOV, and detailed source HTML without a coverage crate or Cargo plugin.
The Rust coverage page displays the latest successful main result. Browser WebAssembly stays a separate pass/fail gate because native source coverage and browser delivery answer different questions.
§Browser WebAssembly
Cargo can compile the existing #[test] inventory into a browser-loadable libtest harness:
rustup target add wasm32-unknown-unknown
cargo install vanilla-test --version 2.1.0
cargo vanilla-test --browsercargo vanilla-test --browser compiles the selected package’s existing library tests and emits a deployable dist/vanilla-test/ directory containing index.html, browser.js, and vanilla-test-tests.wasm. Use --out-dir PATH to change the destination or --manifest-path crates/name/Cargo.toml to select a workspace member. The generated page is a working example: it verifies visible document text (including the canonical target label), result hooks, artifact response, WASM MIME type, streaming instantiation, and main() export, then runs the Rust harness. The same lines are written to the page and the browser console.
Use a compatible custom page when the browser site itself is part of the test:
cargo vanilla-test --browser --page tests/browser.html--page validates and copies that file into the deployable directory as index.html. Start from the built-in runner, keep its result hooks and ./browser.js module, then mark any visible text that the page should verify:
<h1
data-rust-browser-site-check="browser site renders its heading"
data-rust-browser-expected="Dashboard"
>Dashboard</h1>Each marked element becomes one named browser check without another library or JavaScript test wrapper. Site-check failures are reported but do not suppress the Rust harness; a failed WASM delivery step skips only the browser steps that depend on it.
Under the hood, the dependency-free Cargo subcommand runs:
cargo test --release --lib --target wasm32-unknown-unknown --no-runThat standard Cargo command compiles the tests but does not execute them. The generated harness exports a safe main(); the emitted page needs only the native WebAssembly API:
const { instance } = await WebAssembly.instantiateStreaming(
fetch('./vanilla-test-tests.wasm')
);
const exitCode = instance.exports.main();
if (exitCode !== 0) throw new Error(`Rust tests exited with ${exitCode}`);The repository’s deploy workflow resolves that generated artifact, runs it in real Chrome, verifies the visible checks, and publishes it at the live Rust browser path. That page also contains a copy-ready basic Rust suite. The Rust test logic appears once in src/lib.rs; native Cargo and browser WASM execute that same unit-test inventory.
The exact target name is wasm32-unknown-unknown. It is intentionally minimal and provides no browser DOM or console host API; standard output is inert, so the generated libtest harness exposes aggregate status rather than per-test console lines. The adapter does not copy or pretend to recover Rust test names: it reports its browser-side checks and the real Rust harness status. Native Cargo remains responsible for individual Rust test names, full libtest diagnostics, and doctests. This crate’s String, Vec, HashSet, Arc, formatting, and result paths are supported; a panic traps the WASM run, and operating-system or thread-dependent tests do not belong in this browser lane. See Rust’s wasm32-unknown-unknown target documentation.
Deploy the output directory and any assets referenced by a custom page to the same static HTTP host. Serve .wasm with application/wasm so the browser can compile it while streaming.
§Benchmark
cargo bench --bench lifecycle -- 100000 5The dependency-free harness performs one warmup, records and prints five optimized samples, times suite construction plus unique-description formatting and expects() → pass() → done(), then validates the sealed report outside the timed boundary. Shared results and methodology live in the project README.
§Versions and releases
Rust follows the project’s shared major/minor line while retaining language-specific patch versions. Every GitHub release contains the current package for every supported language. See the canonical multi-language release policy.
Structs§
- Test
Result - An immutable summary produced by
VanillaTest::report. - Vanilla
Test - A single-use, sequential test suite.
Enums§
- Test
Error - A lifecycle error that leaves the suite unchanged.