Skip to main content

seleniumbase-rs does not ship its own test runner. Instead, it integrates with standard Rust tooling: #[tokio::test], cargo test, cargo nextest run, and the run_browser_test lifecycle helper. This keeps tests idiomatic and lets you use the full Rust testing ecosystem.

This page maps common testing concepts from Python and JavaScript to Rust, shows the recommended test shape, and explains how to organize a growing suite.

Concept mapping#

Python or JavaScript conceptRust equivalent
pytest async plugin#[tokio::test]
SeleniumBase setUp / tearDownrun_browser_test
Test selection by namecargo test name or nextest filters
Parallel test executioncargo nextest run
Feature-specific suitesCargo features
Environment configurationBrowserConfig, sbase_config.toml, SB_* env vars
Parameterized test casesA loop, helper function, or parameterized-test crate

Use run_browser_test to guarantee cleanup. It creates a BaseCase, runs your async test body, and then calls quit even when the body fails:

The test is an async closure, async |sb| { .. } (or an async fn that takes &mut BaseCase). It receives &mut BaseCase and returns Result<()>, that is Result<(), SeleniumBaseError>, so ? converts any error with a From impl into it. The browser is closed when the test panics too, and the panic is then raised again. Code written for older versions used |sb| Box::pin(async move { .. }); drop the Box::pin and write async |sb| { .. }. To test a page with the Pure CDP engine instead, use run_cdp_test(LaunchOptions::default(), async |page| { .. }).

Run the test:

Running the full suite#

For small suites, the default test runner is fine. For larger suites, install and use cargo-nextest:

Note

Nextest runs each test as a separate process, which isolates browser failures and makes parallel execution safer. The repository profile intentionally does not retry failed tests, so flaky behavior is not hidden.

Sharing helpers#

As your suite grows, extract reusable helpers into modules or crates:

BaseCase::find_element is still there when you want the thirtyfour::WebElement handle.

Use the capability traits (BrowserApi, ElementApi, AssertionApi, ScreenshotApi) when you want helpers to work with any type that exposes the same behavior:

Both BaseCase (WebDriver) and sb_cdp::Page (Pure CDP) implement the traits, so the same helper runs on either. ElementApi no longer has find_element, because its thirtyfour::WebElement return type tied the trait to WebDriver.

Parameterized tests#

Rust does not have built-in parameterized tests, but you can achieve the same result with a loop inside a single test or with a parameterized-test crate:

Test organization#

A typical project layout looks like this:

my_project
Cargo.toml
sbase_config.tomlglobal defaults for every test
src
main.rs
testsintegration tests, each compiled as a separate binary
helpersshared helpers
mod.rs
login.rs
checkout.rs

Integration tests in tests/ are compiled as separate binaries, which gives each test its own browser process and reduces shared-state bugs.

Configuration per test#

For tests that need special configuration, build a BrowserConfig directly:

For global defaults, use sbase_config.toml or SB_* environment variables. See Settings and Configuration for details.

Macros for shorter tests#

The sb_test! macro generates a #[tokio::test] wrapper and the run_browser_test boilerplate:

This expands to the same shape as the manual example above. It is optional but useful for linear tests where the reduced noise improves readability.

See Macros for the full macro catalog.

Common pitfalls#

Using the old Box::pin closure

run_browser_test takes an async closure now, so |sb| Box::pin(async move { .. }) does not compile (“implementation of AsyncFnOnce is not general enough”). Write async |sb| { .. }, or call run_browser_test_boxed while you migrate.

Mixing sync and async cleanup

BaseCase::quit is async. Do not rely on Drop for cleanup; use run_browser_test or call quit explicitly.

Heavy setup in every test

If every test logs in, consider a helper or a shared session strategy, but be aware that shared browsers can leak state.

Too much parallelism

Browsers are expensive. Start with low concurrency and increase only after measuring.

Testing checklist#

  • Tests use run_browser_test or sb_test! for automatic cleanup.
  • Helpers are extracted into tests/helpers/ or a shared crate.
  • Configuration is externalized for environment differences.
  • The suite is run with cargo test or cargo nextest run.
  • Tests capture screenshots or page source on failure.