The sbrs binary provides quick commands for common tasks: opening pages,
running smoke tests, executing CDP commands, patching binaries, generating
files, and more. This page covers the most common workflows.
What you will learn
- How to build and invoke the CLI.
- How to run smoke tests and assertions from the command line.
- How to execute CDP commands and JSON scenarios.
- How to patch binaries and diagnose the environment.
- How to show the installed Chrome and its driver in your shell prompt.
- How to turn on the built-in browser plugins.
Build the CLI#
The binary is built by the workspace package seleniumbase-rs-cli (crates/cli);
the library seleniumbase-rs at the repository root carries no command-line code.
To install it: cargo install --path crates/cli.
A justfile and Makefile provide common shortcuts such as just lint,
just test-all, just docs, and just completions.
Help and version#
Every top-level option and subcommand argument includes a description, so
--help shows what each flag does. --version prints the crate name and
version.
Open a page#
Run a smoke test with UC mode#
Execute a raw CDP command#
Share a browser with DevTools MCP servers#
Launches Chrome with its DevTools endpoint open, prints the endpoint and configs
for Google’s chrome-devtools-mcp and Microsoft’s Playwright MCP, and runs until
Ctrl+C, which closes the browser. See DevTools MCP servers.
Run built-in plugins#
--plugin NAME and --plugin-opt NAME.KEY=VALUE (a TOML value, so quote a
string) go before the command, repeat, and add to the [plugins] table of the
settings file and SB_PLUGINS; the command line wins over the variable, which
wins over the file. They apply to every command that starts a browser and to
sbrs devtools. A mistake stops the command with exit status 2 before a browser
starts. See Choosing plugins.
Save artifacts#
Assertions and waits#
Patch chromedriver#
Patch Chrome binary#
Diagnostic check#
doctor prints the active SB_* environment variables, the detected Chrome
binary, and the patched-binary cache path. For chromedriver it looks, in order,
at the file named by CHROMEDRIVER_PATH, at downloaded_drivers/ (where
sbrs install puts it), and on PATH; a CHROMEDRIVER_PATH that names no
file is reported rather than skipped. It also prints the driver’s major version
next to Chrome’s, because a chromedriver only drives the Chrome of its own major
version:
Install a driver#
sbrs get is another name for sbrs install, as in Python SeleniumBase. The
driver is chromedriver (the default), geckodriver (or firefoxdriver) or
edgedriver (or msedgedriver); the version is latest, a major version or a
full build, and for geckodriver a release such as 0.36.0. The driver goes to
./downloaded_drivers/ and its path is printed.
Without a version, chromedriver is the one that matches the installed Chrome,
from Chrome for Testing (the latest stable one when Chrome is not found or no
driver is listed for its version), msedgedriver the one for the installed
Edge’s major version from msedgedriver.microsoft.com, and geckodriver the
newest GitHub release. It needs network access and fetches only the driver: the
Pure CDP engine needs none. Starting a WebDriver session finds or
fetches the driver by itself, so run install ahead of time only to prepare an
offline machine or a container. Python’s --path (copy the driver to a folder
on the PATH) is not supported.
Show the browser in your shell prompt#
sbrs prompt prints one short line for a shell prompt: the major version of
the installed Chrome (or Chromium) and whether a chromedriver of that version
is already at hand. The chromedriver is looked for as doctor does: the file
CHROMEDRIVER_PATH names, downloaded_drivers/ in the current folder, then the
PATH. ✓driver means it matches, ✗driver that it is missing or of another
major version (sbrs install fetches the right one), and ?driver that its
version could not be read. --ascii writes +, - and ? instead, for
terminals and fonts without check marks.
When no browser is found it prints nothing and exits with 0, so the prompt
simply leaves the segment out; --verbose says on standard error what it
looked at. The browser is the one --browser-path names, else SB_CHROME_BIN,
else the installed Chrome or Chromium (CHROME_BIN, CHROMIUM_BIN, the usual
install folders, the PATH). A path that is given but holds no file counts as
no browser; it is never replaced by another one.
A prompt runs it before every command line, so it starts no browser and uses no network:
- The browser’s version is read from files: the app’s
Info.pliston macOS, the version folder besidechrome.exeon Windows. - A version that only running the program tells (
chromedriver --version, and Chrome on Linux) is cached for ten minutes inseleniumbase-rs/prompt-versions.jsonin the user cache folder (~/Library/Cacheson macOS,$XDG_CACHE_HOMEor~/.cacheon Linux,%LOCALAPPDATA%on Windows), together with the program’s size and modification time, so a new download or a browser update shows at once.--no-cacheasks the programs every time. A program that has not answered within two seconds is given up on: a chromedriver shows as?driver, a browser leaves the line out.
Measured with hyperfine on an Apple M1 (a debug build), a warm sbrs prompt
takes about 9 ms, as long as sbrs version takes to start; with --no-cache,
which runs chromedriver --version, about 23 ms. Asking Chrome itself with
--version would take about 45 ms.
| Placeholder | Becomes |
|---|---|
{browser} | chrome or chromium |
{major} | The browser’s major version, such as 155 |
{driver} | The mark and the word driver: ✓driver, ✗driver or ?driver |
{mark} | The mark alone |
{driver_major} | The chromedriver’s major version; empty when it is missing or unknown |
The default is --format '{browser} {major} {driver}'. {{ and }} print a
brace. An unknown placeholder is refused with exit status 2, so a typo shows
when you set the prompt up, not as a segment that never appears.
The single quotes keep $(...) for later: Bash runs it each time it draws the
prompt (the promptvars option, on by default).
For the right-hand side instead, set RPROMPT='$(sbrs prompt 2>/dev/null)'.
With PROMPT_SUBST the line goes through prompt expansion, so a % in your own
--format has to be written %%.
Fish draws the right prompt beside your own fish_prompt and runs the function
every time; this file replaces a right prompt you already have.
PowerShell decodes a program’s output with the console’s code page, which in
Windows PowerShell 5.1 turns ✓ into other characters; hence --ascii. In
PowerShell 7 with [Console]::OutputEncoding = [Text.Encoding]::UTF8 in the
profile, the marks show and --ascii can go.
A custom module shows only when when holds (or one of its detect_* lists
matches), so when = true shows it everywhere; detect_folders = ["downloaded_drivers"] in its place shows it only in projects that have
downloaded a driver. The parentheses make a conditional group, which leaves
out the space too when sbrs prompt prints nothing. The module comes where
$all is in your format (the default), or where you put ${custom.sbrs}.
Starship gives a command 500 ms (command_timeout), far more than it needs.
Warp draws its own prompt by default (the Warp prompt, made of its context
chips), which does not show your shell’s PS1. To see the segment, open
Settings > Appearance and, under Input, choose the Shell prompt (PS1)
as the prompt type (the menu labels it Shell (PS1)). Warp then draws the
prompt your shell configuration builds: the Bash or Zsh PS1 above, or the
Starship module, which Warp’s documentation lists as working in Bash, Zsh, Fish
and PowerShell. Warp shows a right-hand prompt (RPROMPT, fish_right_prompt)
in Zsh and Fish but not in Bash.
The repository’s Warp Workflow .warp/workflows/sbrs-prompt.yaml runs
sbrs prompt --verbose, to see what the segment says and why.
Run your tests#
sbrs test runs cargo test (or one example) and carries the global options
into the tests as SB_* environment variables, the way Python SeleniumBase’s
pytest options reach its tests:
Only options you actually pass are exported (SB_HEADLESS, SB_BROWSER,
SB_MODE, SB_PROXY, …), so the config file and your own SB_* variables
still apply to everything else. A test sees them when it loads its settings
with Settings::load(). -n becomes --test-threads, and the exit status
is Cargo’s.
Proxies from a list#
--proxy-list FILE reads a list of proxies, one per line, optionally named
(the Rust counterpart of Python’s PROXY_LIST):
Each line is checked when the file is read, and an error names the line number
(never the password). The same type, ProxyList, hands proxies out in turn or
at random to Rust code; see seleniumbase_rs::config::proxy_list.
Encrypt and decrypt secrets#
Keep a password out of a test file by storing it encrypted.
The passphrase comes from the environment, never from an argument, so it stays out of shell history and process listings.
Tokens use AES-256-GCM with a key derived from the passphrase (PBKDF2-HMAC-SHA256,
600,000 iterations, a fresh random salt each time). A wrong passphrase or a
modified token fails to decrypt. They are not interchangeable with Python
SeleniumBase’s sbrs encrypt, which is a reversible obfuscation with a fixed
key.
Read a results database#
With the turso feature (cargo build --features turso), sbrs report reads
the database a ResultStore writes. See
Results Database and Encrypted Profiles.
The path can also come from SB_REPORT_DB. A path that does not exist is an
error; report never creates a database.
Run a JSON scenario#
Example scenario.json:
Generate files#
The generated Rust uses run_browser_test (see Writing Browser Tests),
and a test in tests/ runs with cargo test --test login. A folder sitting
directly inside tests/ is one test target; tests/ui/README.md says how to
register a folder anywhere else.
The generators are careful with what they write:
- A name is relative to the current directory and may contain letters, digits,
_,-and., with/between folders..., absolute paths, backslashes and other characters are rejected before anything is created, and a link that leads out of the directory is not followed. - An existing file is never overwritten.
mkdirchecks every file first and creates none of them if one exists. Pass--forceto replace regular files. - They need no browser and ignore
sbase_config.toml, so they work in an empty folder.
Terminal apps#
Feature: tuiThree commands are full-screen terminal apps. They are part of the opt-in tui
feature:
An sbrs built without the tui feature prints a hint and exits with status 2.
caseplans (alias case-plans) and behave-gui (alias gui-behave) are the
Python Case Plans Generator and Behave Commander, which open Tkinter windows
there. Each takes an optional folder or file; see Case Plans
Generator and Behave Commander.
sbrs caseplans --starter and sbrs behave-gui --new are the earlier
commands that only write a file (a checklist, a new feature); they need no
feature.
Import Python tests#
Convert a SeleniumBase or Selenium WebDriver Python file:
Use --source selenium-base or --source selenium to override automatic
detection. Use --test-name user_can_log_in to choose the generated function
name. Unsupported statements are retained as TODO comments and diagnostics.
Review generated code before compiling or running it.
Import Playwright and Puppeteer tests#
Convert Playwright tests or scripts (JavaScript, TypeScript or Python) and
Puppeteer scripts or tests (JavaScript or TypeScript, or a Chrome DevTools
Recorder .json export) into Rust tests for the pure CDP engine:
import-pw and import-pptr are short names for the two commands. The
language comes from the file extension (.js, .mjs, .cjs, .ts, .mts,
.py, .json), else from the content; --language js|ts|python (Puppeteer:
js|ts|json) overrides it. Each test()/it() becomes one #[tokio::test]
named after its describe and test titles; a script without titles (codegen
output, a plain script) becomes one test named after the file, or after
--test-name. Without --output the Rust goes to standard output; one line
per statement that became a TODO(playwright) or TODO(puppeteer) comment
goes to standard error. As with import-python, the exit status tells what
happened:
| Case | Exit status |
|---|---|
A gap, a statement that became a TODO comment: a warning | 0 |
| A statement the importer could not read: an error | 1 |
| A file it cannot read | 6 |
A source it refuses (over 2 MB, or a Recorder export given to import-playwright) | 2 |
Run the generated tests headless with SB_HEADLESS=true cargo test. See
Migrate Playwright Tests and
Migrate Puppeteer Tests for every mapping.
Install shell completions#
The supported values are bash, elvish, fish, powershell, zsh, fig (a Fig spec) and usage (a usage spec), see below.
The shell scripts are short: each time you press the completion key they ask
sbrs itself for the candidates, so sbrs has to be on PATH, and the
candidates are exactly the commands, aliases, flags and values the command line
accepts. Every command and flag is listed in the
CLI reference.
Ensure the destination directory exists. For Zsh, add $HOME/.zfunc to
fpath before running compinit.
usage and mise#
sbrs completions usage prints a usage spec (KDL),
the same file as completions/sbrs.usage.kdl in the repository. The usage CLI
turns it into completions for more shells, Markdown and man pages:
Warp, inshellisense and Amazon Q#
Warp uses your shell’s own completions for commands it has no built-in spec
for (the “native shell completions” setting, on by default), so once the Bash,
Zsh or Fish completion above is installed, sbrs completes in Warp too.
Warp’s built-in specs, inshellisense
and Amazon Q read Fig completion specs
(withfig/autocomplete).
sbrs completions fig writes one:
The spec is not in withfig/autocomplete yet, so these tools do not know sbrs
until it is. How the repository’s copy is made and how to submit it is in
Submit the Fig spec.
Warp Workflows: the repository has ready-made sbrs commands in
.warp/workflows/ (smoke test, install a driver, doctor, explain the prompt
segment, record, import Playwright or Puppeteer tests, create a test folder). Warp shows them in the
command palette when you are inside the repository; copy them to
~/.warp/workflows/ to have them everywhere.
Common global flags#
Enable UC (undetected) mode.
Enable CDP mode.
Run browser headlessly.
Select browser (chrome, chromium, edge, firefox). Without it the config file’s browser, else Chrome.
Route traffic through a proxy (host:port, or a name from --proxy-list).
Choose the proxy from a list of proxies.
Number of parallel tests for sbrs test.
Troubleshooting#
sbrs: command not found
Likely cause. Binary not on PATH.
Fix. Use ./target/debug/sbrs or install with cargo install --path crates/cli.
Global flag rejected
Likely cause. Flag placed after the subcommand.
Fix. Put global flags before the subcommand: sbrs --headless open URL.
CDP command fails
Likely cause. Not in CDP mode.
Fix. Add --cdp or use a CDP-enabled config.
doctor shows missing Chrome
Likely cause. Chrome not installed or not on PATH.
Fix. Set SB_CHROME_BIN to the full path.
The sbrs prompt segment does not appear
Likely cause. No browser found, or SB_CHROME_BIN names no file.
Fix. Run sbrs prompt --verbose.