Repository navigation
Prebuilt binaries are for macOS on Apple Silicon only (GitHub Actions cannot run for this repository right now). Everywhere else:
brew install MustCodeAl/tap/sbrs
# or
cargo install --git https://github.com/MustCodeAl/seleniumbase-rs --tag v0.6.0 seleniumbase-rs-cli --lockedBreaking
- Downloads go to
./downloaded_files, as in Python SeleniumBase.BaseCase::get_downloads_folder,
assert_downloaded_file,download_fileand the other download helpers used the OS Downloads
folder; they now usedownloaded_filesin the working directory
(browser::downloads::downloads_dir), and a browser the library launches is told to save
there: WebDriver sessions ask for it in their capabilities (the Chrome and Edge preferences
download.default_directory,download.prompt_for_downloadanddownload.directory_upgrade,
and the Firefoxbrowser.download.*ones; a preference you set yourself wins), and the pure CDP
engine sendsBrowser.setDownloadBehaviorat launch, soPage::assert_downloaded_filefinds a
file without a folder being chosen first.downloaded_files/is in.gitignore. - A reused browser keeps its cookies unless
--crumbs. With--reuse-sessionor--rcsthe
browser handed to the next test used to have every cookie deleted; now the cookies stay (Python's
default) andSB_CRUMBS=1orbrowser::reuse::set_crumbs(true)deletes them. The other windows
are still closed, the page's storage cleared and the page set toabout:blank. - A page command needs a page.
get-text,get-title,get-attribute,screenshot,
assert-element,hover,send-keys, the alert commands and the other commands that act
on a page used to act onabout:blank, which no one wants. Without a start page (--url,
SB_START_PAGEor the settings file) they now stop witherror: NAME acts on a page, and every sbrs command starts a fresh browser; give the page: sbrs --url https://example.com NAME ...and status 2, before any browser starts.cdpneeds no page. - A command that changes the profile needs
--user-data-dir.clear-cookies,
load-cookies,set-local-storage-item,remove-local-storage-item,
clear-local-storageandcache-clearchanged a profile that a fresh browser throws away
at the end; they now stop witherror: NAME changes the profile, which a fresh browser throws away; add --user-data-dir DIR(status 2) unless the folder is named. - Fifteen commands are removed because they have no observable effect in a one-shot
browser:go-back,go-forward,refresh,switch-to-window,switch-to-frame,
switch-to-default-content,switch-to-parent-frame,switch-to-newest-window,
switch-to-default-window,open-new-window,open-new-tab,close-window,
set-window-position,get-active-element-cssandthrottle3g(an unrecognised
subcommand now). Several steps in one browser arerun-scenario,deferredand the MCP
server.export-recordingstays: it writes a test from an action file and starts no browser. - A command with a URL of its own refuses
--url.open,smoke,download-file,
print-pdf,pdf-text,assert-pdf-textandrecordstop witherror: NAME opens its own URL; leave out --start-pagewhen the command line names a start page; one that comes
fromSB_START_PAGEor the file is only a default and is ignored for them. devtools,choose-fileanddeferredread the global options. They no longer have
an option of their own for--headless,--user-data-dir,--proxyor--url; the
global ones of the same names do the same work, and give the page to open (choose-file
anddeferredact on the start page, a blank upload page whenchoose-filehas none).
The same global option on both sides of the command is a repeat and is refused.
Added
-
A debug prompt:
BaseCase::breakpoint,sb_cdp::Page::breakpointand
common::debug_prompt.sb.breakpoint("message").await?pauses a test with the browser
open and reads commands from the terminal:cgoes on,ssaves a screenshot andsrcthe
page source tolatest_logs/<test id>/,ushows the address and title,js <expr>shows
a value,qstops the test with aTestLifecycleerror andhlists the commands. The time
spent at the prompt is added to the time limit. The pause is skipped, with a warning in the
log, when standard input is not a terminal (CI,cargo nextest), andSB_BREAKPOINTS=0turns
it off, as Python'sPYTHONBREAKPOINT=0does.DebugPrompt,PromptKind,PromptOutcome,
PromptPageandLineInputare public, for the runner's--trace,--pdband
--final-debug(not wired to a flag yet).BaseCase::recorder_modesays whether a
recording window is open. -
A command line that does not parse prints the command's page, then the error. Like
Python'ssbase,sbrs mkfile,sbrs grid-hub,sbrs get-textandsbrs plugin info
print the usage, arguments, flags and examples of the command the words reached, a blank
line, and last the parser'serror:line andtip:, on standard error with status 2. A
mistake found after parsing (a page command with no page, a start page for a command with a
URL of its own) prints the same way. An unknown command, or none, prints the commands by
group, names only, instead of the 112-line help.--help,--versionand shell completion
are as before. -
Every command has an example and a help heading.
sbrs <command> --helpends with an
Examples:section (sbrs --url https://example.com get-text --css h1), the commands are
grouped as Page commands, Files and generators, Record and replay, Tests, Drivers, grid and
servers, Import and convert, Security, and Info and setup insbrs --help, and a test
proves that every example parses. The examples are in the usage spec and in
docs/help/cli_reference.md. -
The Chromium switches are typed.
BrowserConfig::with_dark_mode,with_guest_mode,
with_incognito,with_devtools,with_disable_ws/with_enable_ws,with_swiftshader,
with_enable_3d_apis,with_maximize,with_no_sandbox,with_disable_gpu,
with_headless1/with_headless2,with_xvfb,with_chromium_arg(Python's comma list,
read byparse_chromium_args),with_disable_featuresandwith_host_resolver_rules
replace composingextra_argsby hand.--incognitoand--guestare left out, with a
warning, when the session loads an extension. A headless session may keep its GPU
(with_enable_3d_apis,with_swiftshader). Firefox gets-privateand-devtools, and
security.csp.enablefor--disable-csp; Firefox and Safari are maximized once running. -
LocaleCodereads a language code in Python's form (ar_eg) or Chrome's (ar-EG) and
writes Chrome's. -
The start page:
--start-page,--urland--start_page,SB_START_PAGE, and the
start_pagekey of the settings file. Everysbrscommand starts a fresh browser, so
a command that acts on a page now acts on this one:sbrs --url https://example.com get-text --css h1. The command line wins overSB_START_PAGE, which wins over the file;
a bare host getshttps://and a local file becomes afile://URL.sbrs test --url X
hands it on to the tests asSB_START_PAGE. The library side isSettings::start_page
(whichto_browser_configcopies intoBrowserConfig::start_page),
SettingsOverrides::start_pageandSTART_PAGE_ENV. -
--save-screenshotsaves a screenshot tolatest_logs/just before a browser command
quits and prints its path (Saved screenshot: PATH). A command that changes the page
(click-partial-link-text,hover,human-click,add-text, ...) also prints where the
browser ended up,Now at: URL (TITLE), so a click that navigates shows where it went. -
Every option of
sbrsitself is global.sbrs get-title --headless --url https://example.comworks as well assbrs --headless --url https://example.com get-title; the same option on both sides of the command is refused as a repeat (status 2).
Every page command now ends withquit, where some left the browser to the drop-time
cleanup. -
Fingerprint capture, export and import. A browser's fingerprint can now be read from
a real browser and handed back to any launch path, as one file format everywhere: the v2
FingerprintJSON, described by the newschemas/fingerprint.schema.json(a test fails
when the schema is stale).Page::capture_fingerprint(pure CDP) and
BaseCase::capture_fingerprint(WebDriver) read what a page can see of the browser and
return aCapturedFingerprint(the fingerprint, the readings no setting holds in
unmapped, and aProbeInfowith the page, the time and the browser version);
compare_fingerprintchecks that a live page presents a fingerprint and lists what no page
can read as unverifiable instead of as a match.Fingerprint::load,save(atomic,
mode0600),from_json,to_json_pretty,diff(SettingDiff),compare_to
(FingerprintComparison) andclaimed_settingsare public. -
sbrs fingerprint capture|export|check|diff|presets.capture [URL] [-o FILE] [--readings FILE]prints or writes the fingerprint of the browser the global options
start;export (--preset NAME | --random [--seed N] [--os OS])writes a preset or a seeded
random identity;check FILEreports the errors and warnings of a file (status 2 when
there is an error);diff A Blists the settings whereBdiffers from whatAexpects
(status 1 when any does);presetslists the presets. -
The global
--fingerprint FILE,SB_FINGERPRINTand a[fingerprint]table (file = "...") in the settings file make every browser a command starts present a fingerprint
file. The command line wins over the variable, which wins over the file; a file that
cannot be read stops the command before a browser starts. A Chromium browser runs in the
CDP mode for it when no mode was asked for, andsbrs devtoolsapplies it through the
pure CDP launch options.Settings::fingerprint,load_fingerprint,check_fingerprint
andSettings::resolve_fingerprint_fileare the library side. -
sbrs-mcp install CLIENT...,sbrs-mcp uninstall CLIENT...andsbrs-mcp clients
register the server with MCP clients, remove the registration, and list the clients
with where each keeps its config and whether its config and program were found.
One install registers two servers, so an assistant gets the browser and the
development tools at once: the browser server asseleniumbase(--server cdp, the
default,driverorsb) and the development server asseleniumbase-dev
(--server dev, no browser).--namerenames them (NAME,NAME-dev),--only browser|devregisters just one,--output-dirsetsSB_MCP_OUTPUT_DIR(default:
sbrs-mcpin your data folder),--pluginand--plugin-optgo to the browser
server's arguments,--scope projectwrites the client's file in the current folder,
--printshows what would be written or run, and--forcereplaces a different entry
of the same name (without it the entry is left alone: exit status 2). The command
registered is the absolute path of the running binary. Clients:claude-code(through
claude mcp add-json),claude-desktop,codex(throughcodex mcp add, else
config.tomledited withtoml_edit),cursor,gemini-cli,opencode,vscodeand
zed. A config file is backed up toFILE.bak-sbrs-mcp, changed only in the entries
concerned and replaced atomically, and a file with comments is not rewritten (the
snippet to add by hand is printed). Runningsbrs-mcpwith no command still serves.
See the MCP server tutorial. -
A fourth MCP server,
dev(sbrs-mcp --server dev,mcp::Profile::Dev,
mcp::dev::host). It starts no browser and helps with developing with the
library, using thesbrscommand line and diagnosing problems, in twelve tools.
Load it next to one browser server; the tools are not added to the browser
servers, because every tool costs context in every session that loads one.find_api: searches the public methods ofBaseCaseand of the pure CDP
engine (Browser,Page,Locator,BrowserContext) and returns the type,
the full signature, the first paragraph of the documentation,is_asyncand
deprecated. The index is generated from the source by a test, committed as
src/mcp/dev/api_index.json, and checked by a second test
(SB_UPDATE_API_INDEX=1rewrites it).parity_lookup: the status, Rust path and notes of a Python SeleniumBase 4.55.2
name, fromparity/api.toml, with close names when there is no exact match.python_to_rust: the importer ofsbrs import-python, with its diagnostics.scaffold: the filessbrs mkfileandsbrs mkdirwould create, as text; it
writes nothing.cli_help: thesbrscommand line from its usage spec
(completions/sbrs.usage.kdl), embedded and read by a small KDL reader in the
library: commands, flags, defaults, choices and aliases.list_pluginsandplugin_info: the built-in plugins of the build, or how to
get them.install_driver: downloads a driver assbrs installdoes and returns its path
and version. Not read-only, destructive (it replaces a driver of another
version) and open-world, which a newEffect::Fetchsays in the annotations.
The downloader is a parameter (mcp::dev::host_with_installer), so tests
install without the network.explain_error: rebuilds aSeleniumBaseErrorfrom its text or category and
returns its hint, whether it is transient, thesbrsexit status, the next steps
and the sections of the common-problems page that apply.check_config: the settings file and theSB_*variables assbrsreads them,
every problem at once, a redacted summary of what would be launched, and the
plugin selection. It starts nothing.check_fingerprint: parses a fingerprint or an anti-detect-browser profile
payload and returns the coherence report ofFingerprint::validate, the same
reportvalidate_fingerprintgives.diagnose_environment, the toolcdpandsbhave, shared.
-
Settings::checkandSettings::check_withread the settings like
Settings::load_frombut return every problem (SettingsCheck,
SettingsProblem), not only the first, and name the variable of each. -
diagnose_environmentreports the driver cache folder and what is in it, the cargo
features the build has and lacks, and judges an output folder that does not exist
yet by the nearest folder above it.
Changed
-
Mobile mode is a whole phone.
with_mobile(true)without metrics now sends the
mobileEmulationcapability with the default screen, which is 390 by 715 at a ratio of 3
(it was 411 by 731, and only a window size and a user agent). The undetected mode drops the
capability, which a page can see, and sends the same phone over DevTools to every window
(BrowserSession::apply_mobile_emulation: device metrics, five touch points and the user
agent). Firefox, Safari and Internet Explorer log a warning and start as desktop browsers.
MOBILE_USER_AGENTis public inbrowser::options. The pure CDP engine is not changed
here. -
headless1runschrome-headless-shellfor Chrome with no program of its own named
(downloaded when missing); the undetected mode refuses it as it refuses the shell.
chrome-headless-shellis always headless.Chrome's locale is writtenar-EGfor
--langand theintl.accept_languagespreference, whichever way (ar_eg) it was given.
A virtual display smaller than 1024 by 768 is raised to that size, as Python does. -
{config:?}hides credentials. TheDebugoutput ofBrowserConfigleaves the
password out of the proxy, the PAC URL and the WebDriver server URL. -
The
driverMCP server has eight debugging tools it did not have, the same
definitions as onsb:inspect_page,suggest_selectors,diagnose_selector,
get_console_messages,capture_debug_bundle,get_page_info,
export_session_as_testanddiagnose_environment. It is 34 tools now.
get_failed_requestsandaudit_pagestay withcdpandsb. -
Profile::ALLhas a fourth profile, andsbrs-mcp --serveracceptsdev. -
find_apino longer returns adeprecatedfield: no method can carry one now.
Removed
Every deprecated item is gone, with no shim, and nothing in src/ is marked
#[deprecated] (tests/no_deprecated.rs keeps it so). Each one had a replacement since
0.5.0, or 0.1.0 for the common modules.
common::decorators(retry_on_exception,retry_on_exception_async,rate_limited)
andcommon::exceptions(Exception): useutilities::retry::{RetryPolicy, RateLimiter}
andSeleniumBaseError.StealthFlags: useStealthPolicy.StealthPolicy::{mask_all, all_custom}: use
StealthPolicy::max.evasions::cdp_overrides: usesafe_cdp_overrides, which leaves out
theProxy-Authorizationheader.profile_payloads::{Flags, Fingerprint, ProxyConfig}: useProfileFlags,
ProfileFingerprintandProfileProxy.PlaywrightSession::{launch_headless, launch_with_fingerprint, launch_headless_with_fingerprint}: uselaunch_with_configwith aBrowserConfig.run_browser_test_boxed,Plugins::run_browser_test_boxedandBrowserTestFuture: pass
an async closure,async |sb| { .. }, torun_browser_test.RunSettings::{with_fast_mode, pause, message_seconds}andDEFAULT_MESSAGE_SECONDS:
--fasthas no effect here, so there is no replacement; usepause_for(PauseKind),
message_duration()andDEFAULT_MESSAGE_DURATION.BaseCase::{cdp_type_text, cdp_click_element, save_saved_cookies, load_saved_cookies, qa_report_markdown}: usecdp_insert_text,cdp_click,save_cookies,load_cookies
andMasterQaSession::to_markdown.sb_cdp::Locator::click_at: useclick_with_offset(x, y, false).Settings::from_toml: useSettings::from_file.- The
assert_visible!macro: usesb_assert_visible!.
Fixed
-
The recorder writes a test that runs. A page reached by a click or a key is recorded as
goto_if_not_url(the first page staysgoto), so the generated test no longer loads
every page twice; the Rust, pure CDP and Gherkin outputs andsbrs replayunderstand it. -
sbrs recordno longer loses what is done right after a page loads: it runs in a session
with a DevTools connection, which installs the listeners in every page from its first
moment, and looks at the page every 300 ms. -
An
alert,confirmorpromptno longer endssbrs recordor gets dismissed by it:
RecorderSession::polltells an open dialog from a closed browser, and
RecorderSession::prepare_configleaves dialogs open for the person. -
A click on the label of a checkbox is recorded once, not twice (the replay used to
toggle the box twice); a click on a<select>is no longer recorded before its change. -
Enter in a field is recorded with the text (
type_text("#q", "text\n")), so the replay
sends the form again, instead of a typing and agotoof the page the form led to. -
The recorder's selectors find the element and nothing else: the id, then
data-testid,
name,aria-label,placeholderand the like, then the shortest path up from the
element that is unique. A path cut after six levels used to fit other elements too. -
A password typed while recording is no longer written to the file in clear text: it is
{{SB_RECORDED_SECRET}}, the generated test andsbrs replayreadSB_RECORDED_SECRET
from the environment, andSB_REC_KEEP_SECRETS=truekeeps the typed text. -
sbrs export-recording ACTIONS.json [-o TEST.rs]writes a Rust test from an action file
(it used to start a browser and export an empty recording).sbrs record URL -o test.rs
andsbrs mkrec --file test.rs --url URLwrite the Rust test of what was done directly. -
zsh completion reaches the second level:
sbrs pl<Tab>now givessbrs pluginwith
a space, so the next Tab offersinfoandlist, and a completed flag such as
--urlgets its space too. usage 6.12's zsh script told zsh to add no suffix to any
word;sbrs completions zshnow adds complete words with zsh's own space and keeps no
suffix only for words that go on (--flag=, a folder/,key:). Shells installed
from Homebrew pick it up with the next release. -
PowerShell completion after a space offers the next level:
sbrs plugin <Tab>gives
infoandlistinstead ofpluginagain. usage 6.12's script cut the line at the
command's text, which leaves out the trailing space;sbrs completions powershellpads
it instead.