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 concept | Rust equivalent |
|---|---|
pytest async plugin | #[tokio::test] |
SeleniumBase setUp / tearDown | run_browser_test |
| Test selection by name | cargo test name or nextest filters |
| Parallel test execution | cargo nextest run |
| Feature-specific suites | Cargo features |
| Environment configuration | BrowserConfig, sbase_config.toml, SB_* env vars |
| Parameterized test cases | A loop, helper function, or parameterized-test crate |
Recommended test shape#
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:
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
src
testsintegration tests, each compiled as a separate binary
helpersshared helpers
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_testorsb_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 testorcargo nextest run. - Tests capture screenshots or page source on failure.