Rust guide

From Cargo test to browser WebAssembly.

Write one ordinary Rust unit-test inventory, run it natively with full diagnostics, then compile that same inventory into a deployable browser harness.

1. Install

Use Rust 1.85 or newer and add the zero-dependency crate:

cargo add vanilla-test
Check the terminal.

A successful Cargo command exits with status 0 and records the crate in Cargo.toml.

2. Write the native suite

Put the lifecycle inside an ordinary Rust #[test]. Use the final report as the assertion message so failures retain the complete suite context.

#[cfg(test)]
mod tests {
    use vanilla_test::VanillaTest;

    #[test]
    fn basic_suite() {
        let mut test = VanillaTest::new();

        test.expects("uppercase preserves the word").unwrap();
        if "rust".to_uppercase() == "RUST" {
            test.pass().unwrap();
        } else {
            test.fail().unwrap();
        }
        test.done().unwrap();

        let result = test.report().unwrap();
        assert!(result.ok, "{}", result.report);
    }
}

3. Run natively

cargo test

Cargo remains the detailed diagnostic host: it prints each Rust test name, assertion failure, panic, and doctest result.

4. Build the browser test

Install Rust's minimal WebAssembly target and the Cargo subcommand once, then build the current package's existing library-test inventory:

rustup target add wasm32-unknown-unknown
cargo install vanilla-test --version 2.1.0
cargo vanilla-test --browser

The output directory is dist/vanilla-test/ and contains index.html, browser.js, and vanilla-test-tests.wasm. Serve the directory over HTTP with the WASM MIME type application/wasm.

5. Add passive rendered-text checks

Start from the built-in runner, keep its result hooks and ./browser.js module, then mark visible text with a named check:

<h1
  data-rust-browser-site-check="dashboard heading is visible"
  data-rust-browser-expected="Dashboard"
>Dashboard</h1>
cargo vanilla-test --browser --page tests/browser.html

--page copies the HTML bytes without parsing or validation; it does not copy assets or wait for dynamic content. The host adapter takes one snapshot when it starts and checks connected, visible, nonempty rendered text plus the optional exact expected text. It does not click, type, focus, navigate, wait, retry, or call JavaScript from Rust. A page-check failure does not suppress the same Rust harness, which still runs once.

6. Deploy the static result

Deploy the generated directory and any same-origin assets referenced by the custom page. The browser uses native fetch and WebAssembly.instantiateStreaming; there is no framework, generated glue, or runtime dependency.

Interpret the browser boundary honestly.

The zero-import Rust module cannot call JavaScript, the DOM, or the browser console. Test JavaScript functions in the JavaScript lane; this host adapter can only observe text they rendered before it started. Native Cargo remains the detailed path when one of the same seven Rust #[test] functions fails.