Skip to content

v0.6.0

Latest

Choose a tag to compare

@MustCodeAl MustCodeAl released this 23 Oct 09:41
· 339 commits to main since this release

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 --locked

Breaking

  • Downloads go to ./downloaded_files, as in Python SeleniumBase. BaseCase::get_downloads_folder,
    assert_downloaded_file, download_file and the other download helpers used the OS Downloads
    folder; they now use downloaded_files in 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_download and download.directory_upgrade,
    and the Firefox browser.download.* ones; a preference you set yourself wins), and the pure CDP
    engine sends Browser.setDownloadBehavior at launch, so Page::assert_downloaded_file finds a
    file without a folder being chosen first. downloaded_files/ is in .gitignore.
  • A reused browser keeps its cookies unless --crumbs. With --reuse-session or --rcs the
    browser handed to the next test used to have every cookie deleted; now the cookies stay (Python's
    default) and SB_CRUMBS=1 or browser::reuse::set_crumbs(true) deletes them. The other windows
    are still closed, the page's storage cleared and the page set to about: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 on about:blank, which no one wants. Without a start page (--url,
    SB_START_PAGE or the settings file) they now stop with error: 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. cdp needs 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-storage and cache-clear changed a profile that a fresh browser throws away
    at the end; they now stop with error: 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-css and throttle3g (an unrecognised
    subcommand now). Several steps in one browser are run-scenario, deferred and the MCP
    server. export-recording stays: 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-text and record stop with error: NAME opens its own URL; leave out --start-page when the command line names a start page; one that comes
    from SB_START_PAGE or the file is only a default and is ignored for them.
  • devtools, choose-file and deferred read the global options. They no longer have
    an option of their own for --headless, --user-data-dir, --proxy or --url; the
    global ones of the same names do the same work, and give the page to open (choose-file
    and deferred act on the start page, a blank upload page when choose-file has 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::breakpoint and
    common::debug_prompt.
    sb.breakpoint("message").await? pauses a test with the browser
    open and reads commands from the terminal: c goes on, s saves a screenshot and src the
    page source to latest_logs/<test id>/, u shows the address and title, js <expr> shows
    a value, q stops the test with a TestLifecycle error and h lists 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), and SB_BREAKPOINTS=0 turns
    it off, as Python's PYTHONBREAKPOINT=0 does. DebugPrompt, PromptKind, PromptOutcome,
    PromptPage and LineInput are public, for the runner's --trace, --pdb and
    --final-debug (not wired to a flag yet). BaseCase::recorder_mode says whether a
    recording window is open.

  • A command line that does not parse prints the command's page, then the error. Like
    Python's sbase, sbrs mkfile, sbrs grid-hub, sbrs get-text and sbrs plugin info
    print the usage, arguments, flags and examples of the command the words reached, a blank
    line, and last the parser's error: line and tip:, 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, --version and shell completion
    are as before.

  • Every command has an example and a help heading. sbrs <command> --help ends 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 in sbrs --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 by parse_chromium_args), with_disable_features and with_host_resolver_rules
    replace composing extra_args by hand. --incognito and --guest are 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 -private and -devtools, and
    security.csp.enable for --disable-csp; Firefox and Safari are maximized once running.

  • LocaleCode reads a language code in Python's form (ar_eg) or Chrome's (ar-EG) and
    writes Chrome's.

  • The start page: --start-page, --url and --start_page, SB_START_PAGE, and the
    start_page key of the settings file.
    Every sbrs command 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 over SB_START_PAGE, which wins over the file;
    a bare host gets https:// and a local file becomes a file:// URL. sbrs test --url X
    hands it on to the tests as SB_START_PAGE. The library side is Settings::start_page
    (which to_browser_config copies into BrowserConfig::start_page),
    SettingsOverrides::start_page and START_PAGE_ENV.

  • --save-screenshot saves a screenshot to latest_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 sbrs itself is global. sbrs get-title --headless --url https://example.com works as well as sbrs --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 with quit, 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
    Fingerprint JSON, described by the new schemas/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 a CapturedFingerprint (the fingerprint, the readings no setting holds in
    unmapped, and a ProbeInfo with the page, the time and the browser version);
    compare_fingerprint checks 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,
    mode 0600), from_json, to_json_pretty, diff (SettingDiff), compare_to
    (FingerprintComparison) and claimed_settings are 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 FILE reports the errors and warnings of a file (status 2 when
    there is an error); diff A B lists the settings where B differs from what A expects
    (status 1 when any does); presets lists the presets.

  • The global --fingerprint FILE, SB_FINGERPRINT and 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, and sbrs devtools applies it through the
    pure CDP launch options. Settings::fingerprint, load_fingerprint, check_fingerprint
    and Settings::resolve_fingerprint_file are the library side.

  • sbrs-mcp install CLIENT..., sbrs-mcp uninstall CLIENT... and sbrs-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 as seleniumbase (--server cdp, the
    default, driver or sb) and the development server as seleniumbase-dev
    (--server dev, no browser). --name renames them (NAME, NAME-dev), --only browser|dev registers just one, --output-dir sets SB_MCP_OUTPUT_DIR (default:
    sbrs-mcp in your data folder), --plugin and --plugin-opt go to the browser
    server's arguments, --scope project writes the client's file in the current folder,
    --print shows what would be written or run, and --force replaces 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 (through codex mcp add, else
    config.toml edited with toml_edit), cursor, gemini-cli, opencode, vscode and
    zed. A config file is backed up to FILE.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). Running sbrs-mcp with 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 the sbrs command 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 of BaseCase and of the pure CDP
      engine (Browser, Page, Locator, BrowserContext) and returns the type,
      the full signature, the first paragraph of the documentation, is_async and
      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=1 rewrites it).
    • parity_lookup: the status, Rust path and notes of a Python SeleniumBase 4.55.2
      name, from parity/api.toml, with close names when there is no exact match.
    • python_to_rust: the importer of sbrs import-python, with its diagnostics.
    • scaffold: the files sbrs mkfile and sbrs mkdir would create, as text; it
      writes nothing.
    • cli_help: the sbrs command 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_plugins and plugin_info: the built-in plugins of the build, or how to
      get them.
    • install_driver: downloads a driver as sbrs install does and returns its path
      and version. Not read-only, destructive (it replaces a driver of another
      version) and open-world, which a new Effect::Fetch says in the annotations.
      The downloader is a parameter (mcp::dev::host_with_installer), so tests
      install without the network.
    • explain_error: rebuilds a SeleniumBaseError from its text or category and
      returns its hint, whether it is transient, the sbrs exit status, the next steps
      and the sections of the common-problems page that apply.
    • check_config: the settings file and the SB_* variables as sbrs reads 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 of Fingerprint::validate, the same
      report validate_fingerprint gives.
    • diagnose_environment, the tool cdp and sb have, shared.
  • Settings::check and Settings::check_with read the settings like
    Settings::load_from but return every problem (SettingsCheck,
    SettingsProblem), not only the first, and name the variable of each.

  • diagnose_environment reports 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
    mobileEmulation capability 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_AGENT is public in browser::options. The pure CDP engine is not changed
    here.

  • headless1 runs chrome-headless-shell for Chrome with no program of its own named
    (downloaded when missing); the undetected mode refuses it as it refuses the shell.
    chrome-headless-shell is always headless. Chrome's locale is written ar-EG for
    --lang and the intl.accept_languages preference, 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. The Debug output of BrowserConfig leaves the
    password out of the proxy, the PAC URL and the WebDriver server URL.

  • The driver MCP server has eight debugging tools it did not have, the same
    definitions as on sb: inspect_page, suggest_selectors, diagnose_selector,
    get_console_messages, capture_debug_bundle, get_page_info,
    export_session_as_test and diagnose_environment. It is 34 tools now.
    get_failed_requests and audit_page stay with cdp and sb.

  • Profile::ALL has a fourth profile, and sbrs-mcp --server accepts dev.

  • find_api no longer returns a deprecated field: 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)
    and common::exceptions (Exception): use utilities::retry::{RetryPolicy, RateLimiter}
    and SeleniumBaseError.
  • StealthFlags: use StealthPolicy. StealthPolicy::{mask_all, all_custom}: use
    StealthPolicy::max. evasions::cdp_overrides: use safe_cdp_overrides, which leaves out
    the Proxy-Authorization header.
  • profile_payloads::{Flags, Fingerprint, ProxyConfig}: use ProfileFlags,
    ProfileFingerprint and ProfileProxy.
  • PlaywrightSession::{launch_headless, launch_with_fingerprint, launch_headless_with_fingerprint}: use launch_with_config with a BrowserConfig.
  • run_browser_test_boxed, Plugins::run_browser_test_boxed and BrowserTestFuture: pass
    an async closure, async |sb| { .. }, to run_browser_test.
  • RunSettings::{with_fast_mode, pause, message_seconds} and DEFAULT_MESSAGE_SECONDS:
    --fast has no effect here, so there is no replacement; use pause_for(PauseKind),
    message_duration() and DEFAULT_MESSAGE_DURATION.
  • BaseCase::{cdp_type_text, cdp_click_element, save_saved_cookies, load_saved_cookies, qa_report_markdown}: use cdp_insert_text, cdp_click, save_cookies, load_cookies
    and MasterQaSession::to_markdown.
  • sb_cdp::Locator::click_at: use click_with_offset(x, y, false).
  • Settings::from_toml: use Settings::from_file.
  • The assert_visible! macro: use sb_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 stays goto), so the generated test no longer loads
    every page twice; the Rust, pure CDP and Gherkin outputs and sbrs replay understand it.

  • sbrs record no 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, confirm or prompt no longer ends sbrs record or gets dismissed by it:
    RecorderSession::poll tells an open dialog from a closed browser, and
    RecorderSession::prepare_config leaves 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 a goto of the page the form led to.

  • The recorder's selectors find the element and nothing else: the id, then data-testid,
    name, aria-label, placeholder and 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 and sbrs replay read SB_RECORDED_SECRET
    from the environment, and SB_REC_KEEP_SECRETS=true keeps 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
    and sbrs mkrec --file test.rs --url URL write the Rust test of what was done directly.

  • zsh completion reaches the second level: sbrs pl<Tab> now gives sbrs plugin with
    a space, so the next Tab offers info and list, and a completed flag such as
    --url gets its space too. usage 6.12's zsh script told zsh to add no suffix to any
    word; sbrs completions zsh now 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
    info and list instead of plugin again. usage 6.12's script cut the line at the
    command's text, which leaves out the trailing space; sbrs completions powershell pads
    it instead.