> ## Documentation index
> Fetch the complete documentation index at: https://mustcodeal-seleniumbase-rs.docs7.io/llms.txt
> Ask it with GET https://mustcodeal-seleniumbase-rs.docs7.io/ask?q=<keywords or question>. Short keywords rank best.
> Use these to discover all available pages before exploring further.
> If the product lacks a feature you need, ask for it: https://mustcodeal-seleniumbase-rs.docs7.io/feature-requests.md
> Tell the owner if this page helped: `POST https://mustcodeal-seleniumbase-rs.docs7.io/_docs7/analytics/feedback` with `Content-Type: application/json` and `{ "path": "/parity", "helpful": true, "comment": "…" }`. `helpful` is true or false. `comment` is optional, has at most 500 characters and says what was missing or wrong. Do not send code, secrets or personal data.

# API parity with Python SeleniumBase

*Generated by `tools/parity/render_docs.py` from `parity/api.toml`; do not edit by hand.*

This crate tracks SeleniumBase **4.55.2** (`5fc0c4bd5c`) and seleniumbase-mcp (`cecbdc68f8`), synced 2026-10-08.

| Status | Meaning |
| --- | --- |
| implemented | A Rust item with the same name exists. |
| composed | Rust does it with a different item or a composition. |
| not-applicable | Nothing to port; the reason is given. |
| planned | Not done yet. |

## Summary

| Surface | Total | implemented | composed | not-applicable | planned |
| --- | ---: | ---: | ---: | ---: | ---: |
| [BaseCase methods](#basecase-methods) | 453 | 440 | 3 | 10 | 0 |
| [Driver methods](#driver-methods) | 79 | 77 | 2 | 0 | 0 |
| [CDP Mode methods](#cdp-mode-methods) | 215 | 15 | 186 | 14 | 0 |
| [Command-line commands](#command-line-commands) | 36 | 21 | 7 | 8 | 0 |
| [pytest options](#pytest-options) | 263 | 112 | 105 | 46 | 0 |
| [`SB()` arguments](#sb()-arguments) | 107 | 50 | 40 | 17 | 0 |
| [`Driver()` arguments](#driver()-arguments) | 74 | 40 | 31 | 3 | 0 |
| [MCP: CDP server](#mcp-cdp-server) | 24 | 24 | 0 | 0 | 0 |
| [MCP: Driver server](#mcp-driver-server) | 26 | 26 | 0 | 0 | 0 |
| [MCP: SB server](#mcp-sb-server) | 88 | 88 | 0 | 0 | 0 |

## BaseCase methods

`BaseCase` (Python `BaseCase`).

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `accept_alert` | implemented | `BaseCase::accept_alert` |  |
| `activate_cdp_mode` | implemented | `BaseCase::activate_cdp_mode` |  |
| `activate_demo_mode` | implemented | `BaseCase::activate_demo_mode` |  |
| `activate_design_mode` | implemented | `BaseCase::activate_design_mode` |  |
| `activate_jquery` | implemented | `BaseCase::activate_jquery` |  |
| `activate_jquery_confirm` | implemented | `BaseCase::activate_jquery_confirm` |  |
| `activate_messenger` | implemented | `BaseCase::activate_messenger` |  |
| `activate_recorder` | implemented | `BaseCase::activate_recorder` |  |
| `ad_block` | implemented | `BaseCase::ad_block` |  |
| `add_cookie` | implemented | `BaseCase::add_cookie` |  |
| `add_cookies` | implemented | `BaseCase::add_cookies` |  |
| `add_css_link` | implemented | `BaseCase::add_css_link` |  |
| `add_css_style` | implemented | `BaseCase::add_css_style` |  |
| `add_data_point` | implemented | `BaseCase::add_data_point` |  |
| `add_js_code` | implemented | `BaseCase::add_js_code` |  |
| `add_js_code_from_link` | implemented | `BaseCase::add_js_code_from_link` |  |
| `add_js_link` | implemented | `BaseCase::add_js_link` |  |
| `add_meta_tag` | implemented | `BaseCase::add_meta_tag` |  |
| `add_series_to_chart` | implemented | `BaseCase::add_series_to_chart` |  |
| `add_slide` | implemented | `BaseCase::add_slide` |  |
| `add_text` | implemented | `BaseCase::add_text` |  |
| `add_tour_step` | implemented | `BaseCase::add_tour_step` |  |
| `append_data_to_file` | implemented | `BaseCase::append_data_to_file` |  |
| `append_data_to_logs` | implemented | `BaseCase::append_data_to_logs` |  |
| `assert_any_of_elements_present` | implemented | `BaseCase::assert_any_of_elements_present` |  |
| `assert_any_of_elements_visible` | implemented | `BaseCase::assert_any_of_elements_visible` |  |
| `assert_attribute` | implemented | `BaseCase::assert_attribute` |  |
| `assert_attribute_not_present` | implemented | `BaseCase::assert_attribute_not_present` |  |
| `assert_data_in_downloaded_file` | implemented | `BaseCase::assert_data_in_downloaded_file` |  |
| `assert_downloaded_file` | implemented | `BaseCase::assert_downloaded_file` | Differs: Waits for the default timeout (set_timeout), not a per-call one, and looks only in the OS downloads folder; Python's browser flag and its downloaded_files folder are not used. |
| `assert_downloaded_file_regex` | implemented | `BaseCase::assert_downloaded_file_regex` |  |
| `assert_element` | implemented | `BaseCase::assert_element` |  |
| `assert_element_absent` | implemented | `BaseCase::assert_element_absent` |  |
| `assert_element_not_present` | implemented | `BaseCase::assert_element_not_present` |  |
| `assert_element_not_visible` | implemented | `BaseCase::assert_element_not_visible` |  |
| `assert_element_present` | implemented | `BaseCase::assert_element_present` |  |
| `assert_element_visible` | implemented | `BaseCase::assert_element_visible` |  |
| `assert_elements` | implemented | `BaseCase::assert_elements` |  |
| `assert_elements_present` | implemented | `BaseCase::assert_elements_present` |  |
| `assert_elements_visible` | implemented | `BaseCase::assert_elements_visible` |  |
| `assert_equal` | implemented | `BaseCase::assert_equal` |  |
| `assert_exact_text` | implemented | `BaseCase::assert_exact_text` | Differs: Waits up to the default timeout (set_timeout, 10 seconds unless changed), where Python uses SMALL_TIMEOUT (6 seconds); has no timeout or by arguments (use set_timeout, or wait_for_exact_text for a timeout of its own). |
| `assert_exact_text_not_visible` | implemented | `BaseCase::assert_exact_text_not_visible` | Differs: Waits up to the default timeout (set_timeout, 10 seconds unless changed), where Python uses SMALL_TIMEOUT (6 seconds); has no timeout or by arguments (use set_timeout, or wait_for_exact_text_not_visible for a timeout of its own). |
| `assert_false` | implemented | `BaseCase::assert_false` |  |
| `assert_in` | implemented | `BaseCase::assert_in` |  |
| `assert_link` | implemented | `BaseCase::assert_link` |  |
| `assert_link_status_code_is_not_404` | implemented | `BaseCase::assert_link_status_code_is_not_404` |  |
| `assert_link_text` | implemented | `BaseCase::assert_link_text` |  |
| `assert_no_404_errors` | implemented | `BaseCase::assert_no_404_errors` |  |
| `assert_no_broken_links` | implemented | `BaseCase::assert_no_broken_links` |  |
| `assert_no_js_errors` | implemented | `BaseCase::assert_no_js_errors` |  |
| `assert_non_empty_text` | implemented | `BaseCase::assert_non_empty_text` |  |
| `assert_not_equal` | implemented | `BaseCase::assert_not_equal` |  |
| `assert_not_in` | implemented | `BaseCase::assert_not_in` |  |
| `assert_partial_link_text` | implemented | `BaseCase::assert_partial_link_text` |  |
| `assert_pdf_text` | implemented | `BaseCase::assert_pdf_text` |  |
| `assert_raises` | implemented | `BaseCase::assert_raises` |  |
| `assert_text` | implemented | `BaseCase::assert_text` | Differs: Waits up to the default timeout (set_timeout, 10 seconds unless changed), where Python uses SMALL_TIMEOUT (6 seconds); has no timeout or by arguments (use set_timeout, or wait_for_text for a timeout of its own). |
| `assert_text_not_visible` | implemented | `BaseCase::assert_text_not_visible` | Differs: Waits up to the default timeout (set_timeout, 10 seconds unless changed), where Python uses SMALL_TIMEOUT (6 seconds); has no timeout or by arguments (use set_timeout, or wait_for_text_not_visible for a timeout of its own). |
| `assert_text_visible` | implemented | `BaseCase::assert_text_visible` | Differs: Waits up to the default timeout (set_timeout, 10 seconds unless changed), where Python uses SMALL_TIMEOUT (6 seconds); has no timeout or by arguments (use set_timeout, or wait_for_text_visible for a timeout of its own). |
| `assert_title` | implemented | `BaseCase::assert_title` |  |
| `assert_title_contains` | implemented | `BaseCase::assert_title_contains` |  |
| `assert_true` | implemented | `BaseCase::assert_true` |  |
| `assert_url` | implemented | `BaseCase::assert_url` |  |
| `assert_url_contains` | implemented | `BaseCase::assert_url_contains` |  |
| `begin_presentation` | implemented | `BaseCase::begin_presentation` |  |
| `block_ads` | implemented | `BaseCase::block_ads` |  |
| `bring_active_window_to_front` | implemented | `BaseCase::bring_active_window_to_front` |  |
| `bring_to_front` | implemented | `BaseCase::bring_to_front` |  |
| `check_if_unchecked` | implemented | `BaseCase::check_if_unchecked` |  |
| `check_window` | implemented | `BaseCase::check_window` | Differs: Saves and compares the page's tag structure as Python does: visual_baseline/&lt;test&gt;/&lt;name&gt; holds page_url.txt, baseline.png and tags_level_1.txt to tags_level_3.txt, with one entry for each tag below &lt;body&gt; (the tag names, then the sorted attribute names, then the attribute values), a level of 0 is a dry run, and a page on another domain fails. Differs: Rust has no test id, so &lt;test&gt; is the name given with BaseCase::with_test_name (sb_test! does) or else the name of the running thread (the test's name under cargo test); the screenshot is of the window, not of &lt;body&gt;, and is not compared; the page source is parsed by the scraper crate, not html.parser; the baseline, check_domain and full_diff arguments are not ported, nor is the side-by-side report Python writes for a level-0 difference; level is a u8 and anything but 0, 1, 2 or 3 is an InvalidConfig error. |
| `choose_file` | implemented | `BaseCase::choose_file` |  |
| `clear` | implemented | `BaseCase::clear` |  |
| `clear_all_cookies` | implemented | `BaseCase::clear_all_cookies` |  |
| `clear_local_storage` | implemented | `BaseCase::clear_local_storage` |  |
| `clear_session_storage` | implemented | `BaseCase::clear_session_storage` |  |
| `click` | implemented | `BaseCase::click` | Differs: Takes CSS or XPath; there is no per-call timeout argument (use set_timeout). |
| `click_active_element` | implemented | `BaseCase::click_active_element` |  |
| `click_chain` | implemented | `BaseCase::click_chain` |  |
| `click_if_visible` | implemented | `BaseCase::click_if_visible` | Differs: Looks once, like Python's default `timeout=0`; `click_if_visible_with_timeout(selector, Duration)` waits for the element. There is no `scroll` argument. |
| `click_link` | implemented | `BaseCase::click_link` |  |
| `click_link_text` | implemented | `BaseCase::click_link_text` |  |
| `click_nth_visible_element` | implemented | `BaseCase::click_nth_visible_element` | Differs: Counts from 0; Python counts from 1. |
| `click_partial_link` | implemented | `BaseCase::click_partial_link` |  |
| `click_partial_link_text` | implemented | `BaseCase::click_partial_link_text` |  |
| `click_visible_elements` | implemented | `BaseCase::click_visible_elements` |  |
| `click_with_offset` | implemented | `BaseCase::click_with_offset` | The offset is from the element's top-left corner, or from its centre when `center` is true, as in Python. Differs: Takes whole-pixel offsets (Python takes numbers), and no `mark`, `timeout` or `scroll` arguments; it waits for the element to be displayed for the default timeout. In demo mode it outlines the element but draws no dot. |
| `click_xpath` | implemented | `BaseCase::click_xpath` |  |
| `console_log_script` | implemented | `BaseCase::console_log_script` |  |
| `console_log_string` | implemented | `BaseCase::console_log_string` |  |
| `context_click` | implemented | `BaseCase::context_click` |  |
| `convert_css_to_xpath` | implemented | `BaseCase::convert_css_to_xpath` |  |
| `convert_to_css_selector` | implemented | `BaseCase::convert_to_css_selector` | Differs: Takes no by argument: the strategy is read from the selector, as the other methods do. Link text, which Python turns into a :contains() pseudo-class that is not CSS, is an InvalidSelector error. |
| `convert_xpath_to_css` | implemented | `BaseCase::convert_xpath_to_css` | Differs: Converts the forms that have an exact CSS equivalent: paths (//a/b, //a//b, /html/body), a position that is the first test of its step, contains(@a,'v'), starts-with(@a,'v') (Python has none), id('x') and or (a comma list). Returns an InvalidSelector error for text(), contains(.,...), parent:: and a position after another test, where Python writes a :contains() pseudo-class that is not CSS or a selector that matches other elements. The CSS is spelled [id='x'] and [class='x'] where Python writes #x and .x. |
| `create_area_chart` | implemented | `BaseCase::create_area_chart` |  |
| `create_bar_chart` | implemented | `BaseCase::create_bar_chart` |  |
| `create_bootstrap_tour` | implemented | `BaseCase::create_bootstrap_tour` |  |
| `create_column_chart` | implemented | `BaseCase::create_column_chart` |  |
| `create_driverjs_tour` | implemented | `BaseCase::create_driverjs_tour` |  |
| `create_folder` | implemented | `BaseCase::create_folder` |  |
| `create_hopscotch_tour` | implemented | `BaseCase::create_hopscotch_tour` |  |
| `create_introjs_tour` | implemented | `BaseCase::create_introjs_tour` |  |
| `create_line_chart` | implemented | `BaseCase::create_line_chart` |  |
| `create_pie_chart` | implemented | `BaseCase::create_pie_chart` |  |
| `create_presentation` | implemented | `BaseCase::create_presentation` |  |
| `create_shepherd_tour` | implemented | `BaseCase::create_shepherd_tour` |  |
| `create_tour` | implemented | `BaseCase::create_tour` |  |
| `deactivate_demo_mode` | implemented | `BaseCase::deactivate_demo_mode` |  |
| `deactivate_design_mode` | implemented | `BaseCase::deactivate_design_mode` |  |
| `deferred_assert_element` | implemented | `BaseCase::deferred_assert_element` | Differs: Checks at once and records a failure for process_deferred_asserts, as Python does; returns Ok(()) instead of True or False, and has no timeout or fs arguments (a failure screenshot is not taken). |
| `deferred_assert_element_present` | implemented | `BaseCase::deferred_assert_element_present` | Differs: Checks at once and records a failure for process_deferred_asserts, as Python does; returns Ok(()) instead of True or False, and has no timeout or fs arguments (a failure screenshot is not taken). |
| `deferred_assert_exact_text` | implemented | `BaseCase::deferred_assert_exact_text` | Differs: Checks at once and records a failure for process_deferred_asserts, as Python does; returns Ok(()) instead of True or False, and has no timeout or fs arguments (a failure screenshot is not taken). |
| `deferred_assert_non_empty_text` | implemented | `BaseCase::deferred_assert_non_empty_text` | Differs: Checks at once and records a failure for process_deferred_asserts, as Python does; returns Ok(()) instead of True or False, and has no timeout or fs arguments (a failure screenshot is not taken). |
| `deferred_assert_text` | implemented | `BaseCase::deferred_assert_text` | Differs: Checks at once and records a failure for process_deferred_asserts, as Python does; returns Ok(()) instead of True or False, and has no timeout or fs arguments (a failure screenshot is not taken). |
| `deferred_check_window` | implemented | `BaseCase::deferred_check_window` | Differs: Takes the name and level; the failure is recorded, with the page's URL, for process_deferred_asserts. Same differences as check_window. |
| `delayed_assert_element` | implemented | `BaseCase::delayed_assert_element` |  |
| `delayed_assert_element_present` | implemented | `BaseCase::delayed_assert_element_present` |  |
| `delayed_assert_exact_text` | implemented | `BaseCase::delayed_assert_exact_text` |  |
| `delayed_assert_non_empty_text` | implemented | `BaseCase::delayed_assert_non_empty_text` |  |
| `delayed_assert_text` | implemented | `BaseCase::delayed_assert_text` |  |
| `delayed_check_window` | implemented | `BaseCase::delayed_check_window` |  |
| `delete_all_cookies` | implemented | `BaseCase::delete_all_cookies` |  |
| `delete_downloaded_file` | implemented | `BaseCase::delete_downloaded_file` |  |
| `delete_downloaded_file_if_present` | implemented | `BaseCase::delete_downloaded_file_if_present` |  |
| `delete_local_storage` | implemented | `BaseCase::delete_local_storage` |  |
| `delete_saved_cookies` | implemented | `BaseCase::delete_saved_cookies` |  |
| `delete_session_storage` | implemented | `BaseCase::delete_session_storage` |  |
| `disable_beforeunload` | implemented | `BaseCase::disable_beforeunload` |  |
| `dismiss_alert` | implemented | `BaseCase::dismiss_alert` |  |
| `display_chart` | implemented | `BaseCase::display_chart` |  |
| `double_click` | implemented | `BaseCase::double_click` |  |
| `double_click_with_offset` | implemented | `BaseCase::double_click_with_offset` | The offset is from the element's top-left corner, or from its centre when `center` is true, as in Python. Differs: Takes whole-pixel offsets (Python takes numbers), and no `mark`, `timeout` or `scroll` arguments; it waits for the element to be displayed for the default timeout. |
| `download_file` | implemented | `BaseCase::download_file` | Differs: Opens the URL in a browser tab and waits for the browser to save it, taking a file name and timeout; Python fetches it over HTTP into a folder. |
| `drag_and_drop` | implemented | `BaseCase::drag_and_drop` |  |
| `drag_and_drop_with_offset` | implemented | `BaseCase::drag_and_drop_with_offset` |  |
| `enter_mfa_code` | implemented | `BaseCase::enter_mfa_code` |  |
| `enter_totp_code` | implemented | `BaseCase::enter_totp_code` |  |
| `evaluate` | implemented | `BaseCase::evaluate` |  |
| `execute_async_script` | implemented | `BaseCase::execute_async_script` |  |
| `execute_cdp_cmd` | implemented | `BaseCase::execute_cdp_cmd` |  |
| `execute_script` | implemented | `BaseCase::execute_script` | Differs: Takes the script only; pass values by formatting them in, each one quoted with js_code::quote. |
| `export_tour` | implemented | `BaseCase::export_tour` |  |
| `extract_chart` | implemented | `BaseCase::extract_chart` |  |
| `fail` | implemented | `BaseCase::fail` |  |
| `fast_type` | implemented | `BaseCase::fast_type` |  |
| `fill` | implemented | `BaseCase::fill` |  |
| `find_element` | implemented | `BaseCase::find_element` | Differs: Returns a thirtyfour::WebElement; takes CSS or XPath only. |
| `find_elements` | implemented | `BaseCase::find_elements` | Differs: Returns thirtyfour::WebElements; takes CSS or XPath only. |
| `find_exact_text` | implemented | `BaseCase::find_exact_text` | Differs: Takes no timeout: it waits for the default timeout (set_timeout). Fails with a wait timeout. |
| `find_link_text` | implemented | `BaseCase::find_link_text` |  |
| `find_non_empty_text` | implemented | `BaseCase::find_non_empty_text` | Differs: Takes no timeout: it waits for the default timeout (set_timeout). Fails with a wait timeout. |
| `find_partial_link_text` | implemented | `BaseCase::find_partial_link_text` |  |
| `find_text` | implemented | `BaseCase::find_text` | Differs: Takes no timeout: it waits for the default timeout (set_timeout). Fails with a wait timeout. |
| `find_visible_elements` | implemented | `BaseCase::find_visible_elements` |  |
| `flash` | implemented | `BaseCase::flash` |  |
| `focus` | implemented | `BaseCase::focus` |  |
| `frame_switch` | implemented | `BaseCase::frame_switch` |  |
| `generate_referral` | implemented | `BaseCase::generate_referral` | A real click-through: it opens start_page (an empty string means the current page), builds a link to destination_page in it with a script and clicks it, so the destination receives a Referer header. With a selector, that element is clicked on the destination page too. Differs: Builds the link with DOM calls and quotes the URL, where Python pastes it into markup; waits for the destination's readyState after the click, where Python only pauses 0.15 s. An invalid page is SeleniumBaseError::Parse, checked before the browser is touched. |
| `generate_referral_chain` | implemented | `BaseCase::generate_referral_chain` | Takes a slice of pages. Builds and clicks a link to each page in turn, starting from the page the browser is on, so each page after the first sees the one before it as its Referer. Differs: Fewer than two pages is SeleniumBaseError::InvalidConfig and an invalid page is SeleniumBaseError::Parse, both before the first click (Python raises plain exceptions). |
| `generate_traffic` | implemented | `BaseCase::generate_traffic` | Runs generate_referral `loops` times (a u32), with a 0.05 s pause after each. |
| `generate_traffic_chain` | implemented | `BaseCase::generate_traffic_chain` | Runs generate_referral_chain `loops` times (a u32), with a 0.05 s pause after each. |
| `get` | implemented | `BaseCase::get` |  |
| `get_active_element_css` | implemented | `BaseCase::get_active_element_css` |  |
| `get_attribute` | implemented | `BaseCase::get_attribute` |  |
| `get_beautiful_soup` | implemented | `BaseCase::get_beautiful_soup` |  |
| `get_browser_downloads_folder` | implemented | `BaseCase::get_browser_downloads_folder` |  |
| `get_chrome_version` | implemented | `BaseCase::get_chrome_version` |  |
| `get_chromedriver_version` | implemented | `BaseCase::get_chromedriver_version` |  |
| `get_chromium_driver_version` | implemented | `BaseCase::get_chromium_driver_version` |  |
| `get_chromium_version` | implemented | `BaseCase::get_chromium_version` |  |
| `get_cookie` | implemented | `BaseCase::get_cookie` |  |
| `get_cookie_string` | implemented | `BaseCase::get_cookie_string` |  |
| `get_cookies` | implemented | `BaseCase::get_cookies` | Differs: Returns a serde_json::Value. |
| `get_current_url` | implemented | `BaseCase::get_current_url` |  |
| `get_data_from_downloaded_file` | implemented | `BaseCase::get_data_from_downloaded_file` |  |
| `get_domain_url` | implemented | `BaseCase::get_domain_url` |  |
| `get_downloaded_files` | implemented | `BaseCase::get_downloaded_files` |  |
| `get_downloads_folder` | implemented | `BaseCase::get_downloads_folder` |  |
| `get_element` | implemented | `BaseCase::get_element` |  |
| `get_element_at_x_y` | implemented | `BaseCase::get_element_at_x_y` |  |
| `get_file_data` | implemented | `BaseCase::get_file_data` |  |
| `get_google_auth_code` | implemented | `BaseCase::get_google_auth_code` |  |
| `get_google_auth_password` | composed | `BaseCase::get_mfa_code` | Same TOTP computation. |
| `get_gui_element_center` | implemented | `BaseCase::get_gui_element_center` |  |
| `get_gui_element_rect` | implemented | `BaseCase::get_gui_element_rect` |  |
| `get_html` | implemented | `BaseCase::get_html` |  |
| `get_image_url` | implemented | `BaseCase::get_image_url` |  |
| `get_jqc_button_input` | not-applicable |  | JQuery-Confirm dialogs are a page UI; Rust uses native dialogs (show_prompt, show_confirm). |
| `get_jqc_form_inputs` | not-applicable |  | JQuery-Confirm dialogs are a page UI; Rust uses native dialogs (show_prompt, show_confirm). |
| `get_jqc_text_input` | not-applicable |  | JQuery-Confirm dialogs are a page UI; Rust uses native dialogs (show_prompt, show_confirm). |
| `get_link_attribute` | implemented | `BaseCase::get_link_attribute` |  |
| `get_link_status_code` | implemented | `BaseCase::get_link_status_code` |  |
| `get_link_text_attribute` | implemented | `BaseCase::get_link_text_attribute` |  |
| `get_local_storage_item` | implemented | `BaseCase::get_local_storage_item` |  |
| `get_local_storage_items` | implemented | `BaseCase::get_local_storage_items` |  |
| `get_local_storage_keys` | implemented | `BaseCase::get_local_storage_keys` |  |
| `get_locale_code` | implemented | `BaseCase::get_locale_code` |  |
| `get_mfa_code` | implemented | `BaseCase::get_mfa_code` |  |
| `get_new_driver` | implemented | `BaseCase::get_new_driver` | Differs: Returns a DriverId, not the driver object. The browser options of Python's arguments go in a BrowserConfig: get_new_driver_with(config). |
| `get_origin` | implemented | `BaseCase::get_origin` |  |
| `get_page_source` | implemented | `BaseCase::get_page_source` |  |
| `get_page_title` | implemented | `BaseCase::get_page_title` |  |
| `get_parent` | implemented | `BaseCase::get_parent` |  |
| `get_partial_link_text_attribute` | implemented | `BaseCase::get_partial_link_text_attribute` |  |
| `get_path_of_downloaded_file` | implemented | `BaseCase::get_path_of_downloaded_file` |  |
| `get_pdf_text` | implemented | `BaseCase::get_pdf_text` |  |
| `get_property` | implemented | `BaseCase::get_property` |  |
| `get_property_value` | implemented | `BaseCase::get_property_value` |  |
| `get_recorded_console_logs` | implemented | `BaseCase::get_recorded_console_logs` |  |
| `get_saved_cookies` | implemented | `BaseCase::get_saved_cookies` |  |
| `get_screen_rect` | implemented | `BaseCase::get_screen_rect` |  |
| `get_select_options` | implemented | `BaseCase::get_select_options` |  |
| `get_session_storage_item` | implemented | `BaseCase::get_session_storage_item` |  |
| `get_session_storage_items` | implemented | `BaseCase::get_session_storage_items` |  |
| `get_session_storage_keys` | implemented | `BaseCase::get_session_storage_keys` |  |
| `get_text` | implemented | `BaseCase::get_text` |  |
| `get_text_content` | implemented | `BaseCase::get_text_content` |  |
| `get_title` | implemented | `BaseCase::get_title` |  |
| `get_totp_code` | implemented | `BaseCase::get_totp_code` |  |
| `get_unique_links` | implemented | `BaseCase::get_unique_links` |  |
| `get_user_agent` | implemented | `BaseCase::get_user_agent` |  |
| `get_value` | implemented | `BaseCase::get_value` |  |
| `get_window_position` | implemented | `BaseCase::get_window_position` |  |
| `get_window_rect` | implemented | `BaseCase::get_window_rect` | Differs: Returns an (x, y, width, height) tuple; Python returns a dict. |
| `get_window_size` | implemented | `BaseCase::get_window_size` |  |
| `go_back` | implemented | `BaseCase::go_back` |  |
| `go_forward` | implemented | `BaseCase::go_forward` |  |
| `go_to` | implemented | `BaseCase::go_to` |  |
| `goto` | implemented | `BaseCase::goto` |  |
| `goto_if_not_url` | implemented | `BaseCase::goto_if_not_url` |  |
| `goto_start_page` | implemented | `BaseCase::goto_start_page` |  |
| `has_exception` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `hide_element` | implemented | `BaseCase::hide_element` |  |
| `hide_elements` | implemented | `BaseCase::hide_elements` |  |
| `highlight` | implemented | `BaseCase::highlight` | Differs: Scrolls to the element and outlines it once for about a second, restored by a timer in the page, so the call does not block; Python animates the element for `loops` rounds and takes scroll and timeout arguments. |
| `highlight_click` | implemented | `BaseCase::highlight_click` |  |
| `highlight_elements` | implemented | `BaseCase::highlight_elements` |  |
| `highlight_if_visible` | implemented | `BaseCase::highlight_if_visible` |  |
| `highlight_type` | implemented | `BaseCase::highlight_type` |  |
| `highlight_update_text` | implemented | `BaseCase::highlight_update_text` |  |
| `hover` | implemented | `BaseCase::hover` |  |
| `hover_and_click` | implemented | `BaseCase::hover_and_click` |  |
| `hover_and_double_click` | implemented | `BaseCase::hover_and_double_click` |  |
| `hover_and_js_click` | implemented | `BaseCase::hover_and_js_click` |  |
| `hover_element` | implemented | `BaseCase::hover_element` |  |
| `hover_on_element` | implemented | `BaseCase::hover_on_element` |  |
| `hover_over_element` | implemented | `BaseCase::hover_over_element` |  |
| `input` | implemented | `BaseCase::input` |  |
| `inspect_html` | implemented | `BaseCase::inspect_html` |  |
| `install_addon` | implemented | `BaseCase::install_addon` | Installs a Firefox add-on, an .xpi file or an unpacked add-on directory, through geckodriver's moz/addon/install command and returns the add-on id; BaseCase::uninstall_addon removes it again. A session that is not Firefox gets an Unsupported error. Tested against a mock WebDriver for the exact endpoint and JSON body. Checked against a real geckodriver 0.37.1 and Firefox 153 ESR in Docker (docker/firefox-check): the same bodies sent with curl installed a directory and an .xpi, the add-on's content script ran, and the uninstall stopped it; tests/install_addon_firefox.rs (ignored) runs BaseCase against that geckodriver and installs and removes an add-on. Differs: Takes a temporary flag where Python's install_addon always installs a temporary add-on, and returns the id. Sends geckodriver the path, where Python's Selenium reads the file and sends it as base64, so the file has to be on the machine geckodriver runs on. A path with .. in it, one that does not exist, and one that is neither an .xpi file nor a directory are refused before anything is sent. |
| `internalize_links` | implemented | `BaseCase::internalize_links` |  |
| `is_alert_present` | implemented | `BaseCase::is_alert_present` |  |
| `is_attribute_present` | implemented | `BaseCase::is_attribute_present` |  |
| `is_checked` | implemented | `BaseCase::is_checked` |  |
| `is_chromium` | implemented | `BaseCase::is_chromium` |  |
| `is_connected` | implemented | `BaseCase::is_connected` |  |
| `is_downloaded_file_present` | implemented | `BaseCase::is_downloaded_file_present` |  |
| `is_downloaded_file_regex_present` | implemented | `BaseCase::is_downloaded_file_regex_present` |  |
| `is_element_clickable` | implemented | `BaseCase::is_element_clickable` |  |
| `is_element_enabled` | implemented | `BaseCase::is_element_enabled` |  |
| `is_element_in_an_iframe` | implemented | `BaseCase::is_element_in_an_iframe` |  |
| `is_element_present` | implemented | `BaseCase::is_element_present` |  |
| `is_element_visible` | implemented | `BaseCase::is_element_visible` |  |
| `is_exact_text_visible` | implemented | `BaseCase::is_exact_text_visible` |  |
| `is_link_text_present` | implemented | `BaseCase::is_link_text_present` |  |
| `is_link_text_visible` | implemented | `BaseCase::is_link_text_visible` |  |
| `is_non_empty_text_visible` | implemented | `BaseCase::is_non_empty_text_visible` |  |
| `is_online` | implemented | `BaseCase::is_online` |  |
| `is_partial_link_text_present` | implemented | `BaseCase::is_partial_link_text_present` |  |
| `is_partial_link_text_visible` | implemented | `BaseCase::is_partial_link_text_visible` |  |
| `is_selected` | implemented | `BaseCase::is_selected` |  |
| `is_text_visible` | implemented | `BaseCase::is_text_visible` |  |
| `is_valid_url` | implemented | `BaseCase::is_valid_url` |  |
| `jq_format` | implemented | `BaseCase::jq_format` |  |
| `jquery_click` | implemented | `BaseCase::jquery_click` |  |
| `jquery_click_all` | implemented | `BaseCase::jquery_click_all` |  |
| `jquery_type` | implemented | `BaseCase::jquery_type` |  |
| `jquery_update_text` | implemented | `BaseCase::jquery_update_text` |  |
| `js_click` | implemented | `BaseCase::js_click` |  |
| `js_click_all` | implemented | `BaseCase::js_click_all` |  |
| `js_click_if_present` | implemented | `BaseCase::js_click_if_present` |  |
| `js_click_if_visible` | implemented | `BaseCase::js_click_if_visible` |  |
| `js_type` | implemented | `BaseCase::js_type` |  |
| `js_update_text` | implemented | `BaseCase::js_update_text` |  |
| `load_cookies` | implemented | `BaseCase::load_cookies` | Differs: The expiry argument is a CookieExpiry (load_cookies_with); load_cookies_from_path reads a file at any path, for the MCP server and the CLI. |
| `load_html_file` | implemented | `BaseCase::load_html_file` |  |
| `load_html_string` | implemented | `BaseCase::load_html_string` |  |
| `locator` | implemented | `BaseCase::locator` |  |
| `main` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `maximize` | implemented | `BaseCase::maximize` |  |
| `maximize_window` | implemented | `BaseCase::maximize_window` |  |
| `minimize` | implemented | `BaseCase::minimize` |  |
| `minimize_window` | implemented | `BaseCase::minimize_window` |  |
| `open` | implemented | `BaseCase::open` |  |
| `open_html_file` | implemented | `BaseCase::open_html_file` |  |
| `open_if_not_url` | implemented | `BaseCase::open_if_not_url` |  |
| `open_new_tab` | implemented | `BaseCase::open_new_tab` | Differs: Always switches to the new tab; Python has a switch_to option. |
| `open_new_window` | implemented | `BaseCase::open_new_window` |  |
| `open_start_page` | implemented | `BaseCase::open_start_page` |  |
| `open_url` | implemented | `BaseCase::open_url` |  |
| `play_tour` | implemented | `BaseCase::play_tour` |  |
| `post_error_message` | implemented | `BaseCase::post_error_message` | Differs: Shows a plain error box in the corner for the run's message duration, replacing the one showing; it is not Python's Messenger widget, takes no duration or pause arguments, and waits for the box to go as Python's default pause=True does. |
| `post_message` | implemented | `BaseCase::post_message` | Differs: Shows a plain box, not Python's Messenger widget (activate_messenger and set_messenger_theme drive the widget), for the run's message duration, 0.75 s at most in a headless browser, and waits for it to go as the default pause=True does. It takes no duration, pause or style arguments: post_message_for takes the duration. |
| `post_message_and_highlight` | implemented | `BaseCase::post_message_and_highlight` | Differs: Shows a plain box (see post_success_message), then highlights the selector's element as Python does; it does not wait for the message to go first. |
| `post_success_message` | implemented | `BaseCase::post_success_message` | Differs: Shows a plain success box in the corner for the run's message duration, replacing the one showing; it is not Python's Messenger widget, takes no duration or pause arguments, and waits for the box to go as Python's default pause=True does. |
| `press_down_arrow` | implemented | `BaseCase::press_down_arrow` | Differs: Presses the Down arrow once on the element that has focus; Python's takes a selector (default body) and a repeat count. |
| `press_keys` | implemented | `BaseCase::press_keys` | Differs: Takes the CSS selector and the text, like Python, and types the text one key at a time with a trailing newline pressing Enter; it has no timeout argument (use set_timeout). BaseCase::press_key presses one named key on whatever has focus. |
| `press_left_arrow` | implemented | `BaseCase::press_left_arrow` | Differs: Presses the Left arrow once on the element that has focus; Python's takes a selector (default body) and a repeat count. |
| `press_right_arrow` | implemented | `BaseCase::press_right_arrow` | Differs: Presses the Right arrow once on the element that has focus; Python's takes a selector (default body) and a repeat count. |
| `press_up_arrow` | implemented | `BaseCase::press_up_arrow` | Differs: Presses the Up arrow once on the element that has focus; Python's takes a selector (default body) and a repeat count. |
| `print_to_pdf` | implemented | `BaseCase::print_to_pdf` |  |
| `print_unique_links_with_status_codes` | implemented | `BaseCase::print_unique_links_with_status_codes` |  |
| `process_deferred_asserts` | implemented | `BaseCase::process_deferred_asserts` |  |
| `process_delayed_asserts` | implemented | `BaseCase::process_delayed_asserts` |  |
| `quit_extra_driver` | implemented | `BaseCase::quit_extra_driver` | Differs: Takes the DriverId get_new_driver returned, where Python takes the driver (or None for the active one); the default browser is refused, and quitting the active extra browser falls back to the default one. |
| `refresh` | implemented | `BaseCase::refresh` |  |
| `refresh_page` | implemented | `BaseCase::refresh_page` |  |
| `reload` | implemented | `BaseCase::reload` |  |
| `reload_page` | implemented | `BaseCase::reload_page` |  |
| `remove_attribute` | implemented | `BaseCase::remove_attribute` |  |
| `remove_attributes` | implemented | `BaseCase::remove_attributes` |  |
| `remove_element` | implemented | `BaseCase::remove_element` |  |
| `remove_elements` | implemented | `BaseCase::remove_elements` |  |
| `remove_local_storage_item` | implemented | `BaseCase::remove_local_storage_item` |  |
| `remove_session_storage_item` | implemented | `BaseCase::remove_session_storage_item` |  |
| `reset_default_timeout` | implemented | `BaseCase::reset_default_timeout` | Puts back the default wait from before set_default_timeout. |
| `reset_jqc_theme` | implemented | `BaseCase::reset_jqc_theme` |  |
| `reset_window_size` | implemented | `BaseCase::reset_window_size` |  |
| `right_click` | implemented | `BaseCase::right_click` |  |
| `run` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `safe_execute_script` | implemented | `BaseCase::safe_execute_script` |  |
| `save_as_html` | implemented | `BaseCase::save_as_html` |  |
| `save_as_html_to_logs` | implemented | `BaseCase::save_as_html_to_logs` |  |
| `save_as_pdf` | implemented | `BaseCase::save_as_pdf` |  |
| `save_as_pdf_to_logs` | implemented | `BaseCase::save_as_pdf_to_logs` |  |
| `save_chart` | implemented | `BaseCase::save_chart` |  |
| `save_cookies` | implemented | `BaseCase::save_cookies` | Differs: Returns the path it wrote; save_cookies_to_path writes to any path, for the MCP server and the CLI. |
| `save_data_as` | implemented | `BaseCase::save_data_as` |  |
| `save_data_to_logs` | implemented | `BaseCase::save_data_to_logs` |  |
| `save_element_as_image_file` | implemented | `BaseCase::save_element_as_image_file` |  |
| `save_file_as` | implemented | `BaseCase::save_file_as` |  |
| `save_page_source` | implemented | `BaseCase::save_page_source` |  |
| `save_page_source_to_logs` | implemented | `BaseCase::save_page_source_to_logs` |  |
| `save_presentation` | implemented | `BaseCase::save_presentation` |  |
| `save_recorded_actions` | implemented | `BaseCase::save_recorded_actions` |  |
| `save_screenshot` | implemented | `BaseCase::save_screenshot` |  |
| `save_screenshot_to_logs` | implemented | `BaseCase::save_screenshot_to_logs` |  |
| `save_teardown_screenshot` | implemented | `BaseCase::save_teardown_screenshot` |  |
| `scroll_by_y` | implemented | `BaseCase::scroll_by_y` |  |
| `scroll_down` | implemented | `BaseCase::scroll_down` | Differs: Takes no amount; Python scrolls by a percentage of the window height. |
| `scroll_into_view` | implemented | `BaseCase::scroll_into_view` |  |
| `scroll_to` | implemented | `BaseCase::scroll_to` |  |
| `scroll_to_bottom` | implemented | `BaseCase::scroll_to_bottom` |  |
| `scroll_to_element` | implemented | `BaseCase::scroll_to_element` |  |
| `scroll_to_top` | implemented | `BaseCase::scroll_to_top` |  |
| `scroll_to_y` | implemented | `BaseCase::scroll_to_y` |  |
| `scroll_up` | implemented | `BaseCase::scroll_up` | Differs: Takes no amount; Python scrolls by a percentage of the window height. |
| `select` | implemented | `BaseCase::select` |  |
| `select_all` | implemented | `BaseCase::select_all` |  |
| `select_if_unselected` | implemented | `BaseCase::select_if_unselected` |  |
| `select_option_by_index` | implemented | `BaseCase::select_option_by_index` |  |
| `select_option_by_text` | implemented | `BaseCase::select_option_by_text` |  |
| `select_option_by_value` | implemented | `BaseCase::select_option_by_value` |  |
| `send_keys` | implemented | `BaseCase::send_keys` |  |
| `setUp` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `setUpClass` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `set_attribute` | implemented | `BaseCase::set_attribute` |  |
| `set_attribute_all` | implemented | `BaseCase::set_attribute_all` |  |
| `set_attributes` | implemented | `BaseCase::set_attributes` |  |
| `set_content` | implemented | `BaseCase::set_content` |  |
| `set_content_to_default` | implemented | `BaseCase::set_content_to_default` | Brings back the page that set_content_to_frame replaced (all swaps at once). Python's nested=True is the separate method set_content_to_parent. Differs: With no frame swapped in it only leaves the frame the driver is in (switch_to_default_content), where Python refreshes the page. A swap whose page counters were lost to a navigation is answered with a refresh, as in Python. |
| `set_content_to_default_content` | implemented | `BaseCase::set_content_to_default_content` | Same as set_content_to_default. |
| `set_content_to_frame` | implemented | `BaseCase::set_content_to_frame` | Replaces the page with the content of an iframe that is on it, selected or named; an iframe whose src is a web or file address opens in a new tab instead. set_content_to_default and set_content_to_parent bring the page back. Differs: Swaps the frame's head and body in with a parsed document instead of Python's set_content, and its scripts do not run. Counts nested swaps correctly: Python resets its page counter on every call, so there a second set_content_to_parent only refreshes. Nothing is added to the recording. |
| `set_content_to_parent` | implemented | `BaseCase::set_content_to_parent` | Undoes the last set_content_to_frame (Python's set_content_to_default(nested=True)). Differs: With no frame swapped in it only leaves the current frame (switch_to_parent_frame), where Python refreshes the page. |
| `set_content_to_parent_frame` | implemented | `BaseCase::set_content_to_parent_frame` | Same as set_content_to_parent. |
| `set_default_timeout` | implemented | `BaseCase::set_default_timeout` | Raises or lowers how long actions wait by default; whole seconds, 1 to 60 (Python allows 0.5 to 60). |
| `set_introjs_colors` | implemented | `BaseCase::set_introjs_colors` |  |
| `set_jqc_theme` | implemented | `BaseCase::set_jqc_theme` |  |
| `set_local_storage_item` | implemented | `BaseCase::set_local_storage_item` |  |
| `set_messenger_theme` | implemented | `BaseCase::set_messenger_theme` | Takes MessengerSettings (theme, location, max_messages; the defaults are Python's), or a MessengerTheme or MessengerLocation alone, and loads Messenger first. The pure-CDP engine has Page::set_messenger_theme with the same arguments. The old colour setter is BaseCase::set_messenger_color. Differs: BaseCase::post_message shows a plain box of its own, so the theme changes the Messenger widget (which the page or your script posts with) and not post_message's box. |
| `set_session_storage_item` | implemented | `BaseCase::set_session_storage_item` |  |
| `set_text` | implemented | `BaseCase::set_text` | Differs: Sets the value of an input or textarea (firing input and change) or the textContent of any other element, as Python does; it presses no Enter for a trailing newline, and the selector is CSS. |
| `set_text_content` | implemented | `BaseCase::set_text_content` | Differs: Same as set_text, as in Python; the selector is CSS and there is no scroll argument. |
| `set_time_limit` | implemented | `BaseCase::set_time_limit` | Once the test has run longer than the limit (counted from creating the BaseCase), its next open, readiness wait or element action fails with a time-limit error; waits are cut to the time left. It is kept apart from the default wait that set_default_timeout changes. |
| `set_value` | implemented | `BaseCase::set_value` |  |
| `set_window_position` | implemented | `BaseCase::set_window_position` |  |
| `set_window_rect` | implemented | `BaseCase::set_window_rect` | Differs: Takes (x, y, width, height) with unsigned sizes. |
| `set_window_size` | implemented | `BaseCase::set_window_size` |  |
| `show_element` | implemented | `BaseCase::show_element` |  |
| `show_elements` | implemented | `BaseCase::show_elements` |  |
| `show_file_choosers` | implemented | `BaseCase::show_file_choosers` |  |
| `skip` | composed | `BaseCase::skip_test` | `skip_test(message)` returns Err(SeleniumBaseError::Skipped) for the test to `?` out with. libtest has no runtime skip: `run_browser_test` (and `Plugins::run_browser_test`) log the reason and count the test as passed, and any other harness has to map `is_skipped()` to Ok itself. Python also records the reason for its dashboard and database reports, which is not done here. |
| `sleep` | implemented | `BaseCase::sleep` | Differs: Takes seconds as f64 and is async. |
| `slow_click` | implemented | `BaseCase::slow_click` |  |
| `slow_scroll_to` | implemented | `BaseCase::slow_scroll_to` |  |
| `slow_scroll_to_element` | implemented | `BaseCase::slow_scroll_to_element` |  |
| `start_recording_console_logs` | implemented | `BaseCase::start_recording_console_logs` |  |
| `start_tour` | implemented | `BaseCase::start_tour` |  |
| `submit` | implemented | `BaseCase::submit` |  |
| `switch_to_alert` | implemented | `BaseCase::switch_to_alert` |  |
| `switch_to_default_content` | implemented | `BaseCase::switch_to_default_content` |  |
| `switch_to_default_driver` | implemented | `BaseCase::switch_to_default_driver` |  |
| `switch_to_default_tab` | implemented | `BaseCase::switch_to_default_tab` |  |
| `switch_to_default_window` | implemented | `BaseCase::switch_to_default_window` |  |
| `switch_to_driver` | implemented | `BaseCase::switch_to_driver` | Differs: Takes a DriverId, where Python takes the driver object. |
| `switch_to_frame` | implemented | `BaseCase::switch_to_frame` |  |
| `switch_to_frame_of_element` | implemented | `BaseCase::switch_to_frame_of_element` | Differs: Returns the frame's name, else its id, else an empty string, or None when the element is in the current document. Looks one level down, as Python does. |
| `switch_to_newest_tab` | implemented | `BaseCase::switch_to_newest_tab` |  |
| `switch_to_newest_window` | implemented | `BaseCase::switch_to_newest_window` |  |
| `switch_to_parent_frame` | implemented | `BaseCase::switch_to_parent_frame` |  |
| `switch_to_tab` | implemented | `BaseCase::switch_to_tab` |  |
| `switch_to_window` | implemented | `BaseCase::switch_to_window` |  |
| `tearDown` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `tearDownClass` | not-applicable |  | unittest/pytest harness plumbing; the Rust runner (api::runner) owns the lifecycle. |
| `type` | composed | `BaseCase::type_text` | One canonical name: Rust has type_text only. |
| `uncheck_if_checked` | implemented | `BaseCase::uncheck_if_checked` |  |
| `unselect_if_selected` | implemented | `BaseCase::unselect_if_selected` |  |
| `update_text` | implemented | `BaseCase::update_text` |  |
| `visit` | implemented | `BaseCase::visit` |  |
| `visit_url` | implemented | `BaseCase::visit_url` |  |
| `wait` | implemented | `BaseCase::wait` |  |
| `wait_for_and_accept_alert` | implemented | `BaseCase::wait_for_and_accept_alert` |  |
| `wait_for_and_dismiss_alert` | implemented | `BaseCase::wait_for_and_dismiss_alert` |  |
| `wait_for_and_switch_to_alert` | implemented | `BaseCase::wait_for_and_switch_to_alert` |  |
| `wait_for_angularjs` | implemented | `BaseCase::wait_for_angularjs` |  |
| `wait_for_any_of_elements_present` | implemented | `BaseCase::wait_for_any_of_elements_present` |  |
| `wait_for_any_of_elements_visible` | implemented | `BaseCase::wait_for_any_of_elements_visible` |  |
| `wait_for_attribute` | implemented | `BaseCase::wait_for_attribute` |  |
| `wait_for_attribute_not_present` | implemented | `BaseCase::wait_for_attribute_not_present` |  |
| `wait_for_element` | implemented | `BaseCase::wait_for_element` |  |
| `wait_for_element_absent` | implemented | `BaseCase::wait_for_element_absent` |  |
| `wait_for_element_clickable` | implemented | `BaseCase::wait_for_element_clickable` |  |
| `wait_for_element_not_present` | implemented | `BaseCase::wait_for_element_not_present` |  |
| `wait_for_element_not_visible` | implemented | `BaseCase::wait_for_element_not_visible` |  |
| `wait_for_element_present` | implemented | `BaseCase::wait_for_element_present` |  |
| `wait_for_element_visible` | implemented | `BaseCase::wait_for_element_visible` |  |
| `wait_for_exact_text` | implemented | `BaseCase::wait_for_exact_text` |  |
| `wait_for_exact_text_not_visible` | implemented | `BaseCase::wait_for_exact_text_not_visible` |  |
| `wait_for_exact_text_visible` | implemented | `BaseCase::wait_for_exact_text_visible` |  |
| `wait_for_link_text` | implemented | `BaseCase::wait_for_link_text` |  |
| `wait_for_link_text_present` | implemented | `BaseCase::wait_for_link_text_present` |  |
| `wait_for_link_text_visible` | implemented | `BaseCase::wait_for_link_text_visible` |  |
| `wait_for_non_empty_text` | implemented | `BaseCase::wait_for_non_empty_text` |  |
| `wait_for_non_empty_text_visible` | implemented | `BaseCase::wait_for_non_empty_text_visible` |  |
| `wait_for_partial_link_text` | implemented | `BaseCase::wait_for_partial_link_text` |  |
| `wait_for_partial_link_text_present` | implemented | `BaseCase::wait_for_partial_link_text_present` |  |
| `wait_for_query_selector` | implemented | `BaseCase::wait_for_query_selector` |  |
| `wait_for_ready_state_complete` | implemented | `BaseCase::wait_for_ready_state_complete` |  |
| `wait_for_selector` | implemented | `BaseCase::wait_for_selector` |  |
| `wait_for_text` | implemented | `BaseCase::wait_for_text` |  |
| `wait_for_text_not_visible` | implemented | `BaseCase::wait_for_text_not_visible` |  |
| `wait_for_text_visible` | implemented | `BaseCase::wait_for_text_visible` |  |
| `write` | implemented | `BaseCase::write` |  |

## Driver methods

Methods of Python's `Driver()`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `add_cookie` | implemented | `BaseCase::add_cookie` |  |
| `assert_element_not_visible` | implemented | `BaseCase::assert_element_not_visible` |  |
| `assert_element_present` | implemented | `BaseCase::assert_element_present` |  |
| `assert_element_visible` | implemented | `BaseCase::assert_element_visible` |  |
| `assert_exact_text` | implemented | `BaseCase::assert_exact_text` |  |
| `assert_non_empty_text` | implemented | `BaseCase::assert_non_empty_text` |  |
| `assert_text` | implemented | `BaseCase::assert_text` |  |
| `assert_text_not_visible` | implemented | `BaseCase::assert_text_not_visible` |  |
| `back` | composed | `BaseCase::go_back` | Named go_back, like the BaseCase method. |
| `click` | implemented | `BaseCase::click` |  |
| `click_active_element` | implemented | `BaseCase::click_active_element` |  |
| `click_if_visible` | implemented | `BaseCase::click_if_visible` |  |
| `click_link` | implemented | `BaseCase::click_link` |  |
| `delete_cookie` | implemented | `BaseCase::delete_cookie` |  |
| `find_element` | implemented | `BaseCase::find_element` |  |
| `find_elements` | implemented | `BaseCase::find_elements` |  |
| `forward` | composed | `BaseCase::go_forward` | Named go_forward, like the BaseCase method. |
| `get_active_element_css` | implemented | `BaseCase::get_active_element_css` |  |
| `get_attribute` | implemented | `BaseCase::get_attribute` |  |
| `get_cookie` | implemented | `BaseCase::get_cookie` |  |
| `get_cookie_string` | implemented | `BaseCase::get_cookie_string` |  |
| `get_current_url` | implemented | `BaseCase::get_current_url` |  |
| `get_locale_code` | implemented | `BaseCase::get_locale_code` |  |
| `get_origin` | implemented | `BaseCase::get_origin` |  |
| `get_page_source` | implemented | `BaseCase::get_page_source` |  |
| `get_parent` | implemented | `BaseCase::get_parent` |  |
| `get_screen_rect` | implemented | `BaseCase::get_screen_rect` |  |
| `get_text` | implemented | `BaseCase::get_text` |  |
| `get_title` | implemented | `BaseCase::get_title` |  |
| `get_user_agent` | implemented | `BaseCase::get_user_agent` |  |
| `highlight` | implemented | `BaseCase::highlight` | Differs: Scrolls to the element and outlines it once for about a second, restored by a timer in the page, so the call does not block; Python animates the element for `loops` rounds and takes scroll and timeout arguments. |
| `highlight_click` | implemented | `BaseCase::highlight_click` |  |
| `highlight_if_visible` | implemented | `BaseCase::highlight_if_visible` |  |
| `is_alert_present` | implemented | `BaseCase::is_alert_present` |  |
| `is_attribute_present` | implemented | `BaseCase::is_attribute_present` |  |
| `is_cdp_mode_active` | implemented | `BaseCase::is_cdp_mode_active` | True for a session in DriverMode::Cdp or DriverMode::Uc, which are the two that have a CDP client. Differs: Python reports true only after activate_cdp_mode(); UC sessions here have a CDP client from the start. |
| `is_connected` | implemented | `BaseCase::is_connected` |  |
| `is_element_present` | implemented | `BaseCase::is_element_present` |  |
| `is_element_visible` | implemented | `BaseCase::is_element_visible` |  |
| `is_exact_text_visible` | implemented | `BaseCase::is_exact_text_visible` |  |
| `is_non_empty_text_visible` | implemented | `BaseCase::is_non_empty_text_visible` |  |
| `is_online` | implemented | `BaseCase::is_online` |  |
| `is_text_visible` | implemented | `BaseCase::is_text_visible` |  |
| `is_uc_mode_active` | implemented | `BaseCase::is_uc_mode_active` |  |
| `is_valid_url` | implemented | `BaseCase::is_valid_url` |  |
| `js_click` | implemented | `BaseCase::js_click` |  |
| `locator` | implemented | `BaseCase::locator` |  |
| `open_new_tab` | implemented | `BaseCase::open_new_tab` |  |
| `open_new_window` | implemented | `BaseCase::open_new_window` |  |
| `open_url` | implemented | `BaseCase::open_url` |  |
| `press_keys` | implemented | `BaseCase::press_keys` | Differs: Takes the CSS selector and the text, like Python, and types the text one key at a time with a trailing newline pressing Enter; it has no timeout argument (use set_timeout). BaseCase::press_key presses one named key on whatever has focus. |
| `refresh` | implemented | `BaseCase::refresh` |  |
| `reset_window_size` | implemented | `BaseCase::reset_window_size` |  |
| `select` | implemented | `BaseCase::select` |  |
| `select_all` | implemented | `BaseCase::select_all` |  |
| `select_option_by_index` | implemented | `BaseCase::select_option_by_index` |  |
| `select_option_by_text` | implemented | `BaseCase::select_option_by_text` |  |
| `select_option_by_value` | implemented | `BaseCase::select_option_by_value` |  |
| `send_keys` | implemented | `BaseCase::send_keys` |  |
| `submit` | implemented | `BaseCase::submit` |  |
| `switch_to_default_window` | implemented | `BaseCase::switch_to_default_window` |  |
| `switch_to_frame` | implemented | `BaseCase::switch_to_frame` |  |
| `switch_to_newest_tab` | implemented | `BaseCase::switch_to_newest_tab` |  |
| `switch_to_newest_window` | implemented | `BaseCase::switch_to_newest_window` |  |
| `switch_to_tab` | implemented | `BaseCase::switch_to_tab` |  |
| `switch_to_window` | implemented | `BaseCase::switch_to_window` |  |
| `update_text` | implemented | `BaseCase::update_text` |  |
| `wait_for_and_accept_alert` | implemented | `BaseCase::wait_for_and_accept_alert` |  |
| `wait_for_and_dismiss_alert` | implemented | `BaseCase::wait_for_and_dismiss_alert` |  |
| `wait_for_element` | implemented | `BaseCase::wait_for_element` |  |
| `wait_for_element_absent` | implemented | `BaseCase::wait_for_element_absent` |  |
| `wait_for_element_not_visible` | implemented | `BaseCase::wait_for_element_not_visible` |  |
| `wait_for_element_present` | implemented | `BaseCase::wait_for_element_present` |  |
| `wait_for_element_visible` | implemented | `BaseCase::wait_for_element_visible` |  |
| `wait_for_exact_text` | implemented | `BaseCase::wait_for_exact_text` |  |
| `wait_for_non_empty_text` | implemented | `BaseCase::wait_for_non_empty_text` |  |
| `wait_for_selector` | implemented | `BaseCase::wait_for_selector` |  |
| `wait_for_text` | implemented | `BaseCase::wait_for_text` |  |
| `wait_for_text_not_visible` | implemented | `BaseCase::wait_for_text_not_visible` |  |

## CDP Mode methods

Python `sb.cdp.*`; Rust holds the selector in a `Locator`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `activate_cdp_mode` | not-applicable |  | Already in CDP mode: sb_cdp is the CDP engine. |
| `activate_messenger` | implemented | `Page::activate_messenger` | Loads jQuery and the Messenger library from their CDNs into the page; a page with no network cannot. |
| `add_handler` | not-applicable |  | Subscribe to protocol events with Page::events / Browser::events. |
| `append_data_to_logs` | not-applicable |  | Write files with std::fs; artifacts::ensure_latest_logs_dir gives the logs folder. |
| `assert_any_of_elements_present` | composed | `Page::wait_for_any` | `page.wait_for_any(..)` waits until one of several locators is ready and says which; it returns a timeout error where Python raises. |
| `assert_any_of_elements_visible` | composed | `Page::wait_for_any` | `page.wait_for_any(..)` waits until one of several locators is ready and says which; it returns a timeout error where Python raises. |
| `assert_downloaded_file` | implemented | `Page::assert_downloaded_file` | `page.assert_downloaded_file(name, timeout)` waits for the file in Browser::download_dir (the folder last given to set_download_dir or to a Page download method) and returns its path. A download the browser has not finished does not count. Differs: Looks in the folder the browser was told to save in, where Python always looks in ./downloaded_files (that is the default until a folder is chosen). Fails with SeleniumBaseError::WaitTimeout, where Python raises NoSuchFileException, and takes a Duration. The name must be a plain file name. |
| `assert_element` | composed | `LocatorExpect::to_be_visible` | Assert with `page.locator(selector).expect().to_be_visible(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_element_absent` | composed | `LocatorExpect::to_exist` | `page.locator(selector).expect().not().to_exist()`; the wait is the expect timeout. |
| `assert_element_attribute` | composed | `LocatorExpect::to_have_attribute` | Assert with `page.locator(selector).expect().to_have_attribute(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_element_not_visible` | composed | `LocatorExpect::to_be_hidden` | `page.locator(selector).expect().to_be_hidden()`; the wait is the expect timeout. |
| `assert_element_present` | composed | `LocatorExpect::to_exist` | `page.locator(selector).expect().to_exist()`; the wait is the expect timeout. |
| `assert_element_visible` | composed | `LocatorExpect::to_be_visible` | Assert with `page.locator(selector).expect().to_be_visible(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_equal` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_exact_text` | composed | `LocatorExpect::to_have_text` | `page.locator(selector).expect().to_have_text(text)`, which compares the whole text. |
| `assert_false` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_in` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_not_equal` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_not_in` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_text` | composed | `LocatorExpect::to_contain_text` | Assert with `page.locator(selector).expect().to_contain_text(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_text_not_visible` | composed | `LocatorExpect::to_contain_text` | `page.locator(selector).expect().not().to_contain_text(text)`; the wait is the expect timeout. |
| `assert_title` | composed | `PageExpect::to_have_title` | Assert with `page.expect().to_have_title(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_title_contains` | composed | `PageExpect::to_contain_title` | Assert with `page.expect().to_contain_title(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_true` | not-applicable |  | Rust has assert!, assert_eq! and friends. |
| `assert_url` | composed | `PageExpect::to_have_url` | Assert with `page.expect().to_have_url(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `assert_url_contains` | composed | `PageExpect::to_contain_url` | Assert with `page.expect().to_contain_url(..)`; add `.not()` to negate and `.timeout(d)` to set the wait. A failed expectation returns an error where Python raises AssertionError. |
| `bring_active_window_to_front` | composed | `Page::bring_to_front` | A method of the Page that sb.cdp drives: `page.bring_to_front(..)`. |
| `check_if_unchecked` | composed | `Locator::check` | Call `page.locator(selector).check(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `clear` | composed | `Locator::clear` | Call `page.locator(selector).clear(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `clear_cookies` | composed | `Cookies::clear` | `page.cookies().clear(..)`. |
| `clear_input` | composed | `Locator::clear` | Call `page.locator(selector).clear(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `click` | composed | `Locator::click` | Call `page.locator(selector).click(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `click_active_element` | implemented | `Page::click_active_element` | `page.click_active_element()` calls `click()` on `document.activeElement`. Differs: Does not pause for 0.2 seconds afterwards; wait for what the click causes with a Locator wait. |
| `click_and_hold` | composed | `Locator::click_and_hold` | `page.locator(selector).click_and_hold(Duration::from_secs(2))` scrolls the element into view, presses at its centre, holds for the given time and releases there. Mouse::down and Mouse::up act at coordinates. |
| `click_captcha` | composed | `Page::solve_captcha` | A method of the Page that sb.cdp drives: `page.solve_captcha(..)`. |
| `click_if_visible` | implemented | `Locator::click_if_visible` | `page.locator(selector).click_if_visible()` clicks if the element is visible now (Python's default `timeout=0`: look once) and says whether it clicked; `click_if_visible_with_timeout(timeout)` waits up to `timeout` for it. The Locator holds the selector, so it is not an argument of the call. Differs: Gives Ok(false) when the element is not visible in time or vanishes before the click; an invalid selector or a lost connection is still an error, where Python suppresses every error. The click always scrolls the element into view (`scroll=True`). |
| `click_link` | composed | `Locator::click` | `page.locator(SelectorBuf::partial_link_text(link_text)).click()` clicks the first link whose text contains `link_text`. The argument is link text, not a selector, so build the selector with `SelectorBuf::partial_link_text` (or `link_text` for an exact match) rather than passing the bare text. |
| `click_nth_element` | composed | `Locator::nth` | `page.locator(selector).nth(i).click()`; `nth` is zero-based, Python's number starts at 1. |
| `click_nth_visible_element` | composed | `Locator::nth` | `page.locator(selector).visible().nth(i).click()`; `nth` is zero-based, Python's number starts at 1. |
| `click_visible_elements` | composed | `Locator::visible` | `page.locator(selector).visible()` narrows the Locator to the displayed matches; click each with `nth`. |
| `click_with_offset` | implemented | `Locator::click_with_offset` | `page.locator(selector).click_with_offset(x, y, center)`; the offset is from the element's top-left corner, or from its centre when `center` is true, as in Python. `click_at(Point)` is the same call with `center` false and is deprecated. Differs: Always scrolls the element into view (Python's `scroll=True`, its default). |
| `close_active_tab` | composed | `Page::close` | `page.close()` closes that Page's tab. |
| `download_file` | implemented | `Page::download_file` | `page.download_file(url, dir)` has the page fetch the address and save the response, as Python does, then waits for the browser to finish and returns the saved path. `page.download_by_click(selector, dir)` follows a download that a click starts. Differs: Takes the folder to save in (Python uses ./downloaded_files) and waits for the browser's own download events, bounded by the page timeout; a bad HTTP status, a fetch the page refuses (CORS) or a cancelled download is SeleniumBaseError::Download. The name comes from the Content-Disposition header when the server sends one, else from the address (Python: the address only). |
| `drag_and_drop` | composed | `Locator::drag_to` | Call `page.locator(selector).drag_to(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `enter_mfa_code` | composed | `BaseCase::enter_mfa_code` | BaseCase::enter_mfa_code is a WebDriver-engine method; on the CDP engine compute the code with BaseCase::get_mfa_code and type it with Locator::type_text. |
| `evaluate` | composed | `Page::evaluate` | `page.evaluate(script)`; values come back as serde_json::Value, so an element comes back as `{}`. As in Python, a `return ` that starts the last line is dropped; a `return` anywhere else is a syntax error, so wrap such a script in `(() => { ... })()`. |
| `execute_script` | composed | `Page::evaluate` | `page.evaluate(script)`, as for `evaluate`: a `return ` that starts the last line is dropped, so Selenium-style `return document.title` works; values come back as serde_json::Value. |
| `fast_keys` | composed | `Keyboard::insert_text` | Python types into the element the selector names. Focus it first: `page.locator(selector).focus().await?; page.keyboard().insert_text(text).await?` inserts the text in one step after what the field holds. fast_type's Locator::fill clears the field first. |
| `fast_type` | composed | `Locator::fill` | `page.locator(selector).fill(text)` replaces the content in one step, with input events but no per-key ones. |
| `find_all` | composed | `Locator::all_waiting` | `page.locator(selector).all_waiting()` waits up to the timeout for a first match, then gives one Locator per match; after the timeout it gives an empty list, as Python does. `all()` does not wait. |
| `find_element` | composed | `Page::locator` | `page.locator(selector)` returns a Locator, the handle every element action goes through; CSS, XPath and `tag:contains("text")` selectors work. Python also searches by text when the selector is plain text, which Rust does not guess: use `SelectorBuf::containing_text`. Python's `best_match` option is not offered. |
| `find_element_by_text` | composed | `SelectorBuf::containing_text` | `page.locator(SelectorBuf::containing_text(text, Some("button")))` finds a tag element whose text contains the text, as Python's `tag:contains("text")` does (that form also works as a selector string); with `None` for the tag it finds the innermost elements that hold the text. A `text=` prefix still means link text, as in SeleniumBase. |
| `find_elements` | composed | `Locator::all_waiting` | `page.locator(selector).all_waiting()` waits up to the timeout for a first match, then gives one Locator per match; after the timeout it gives an empty list, as Python does. `all()` does not wait. |
| `find_elements_by_text` | composed | `SelectorBuf::containing_text` | `page.locator(SelectorBuf::containing_text(text, tag)).all()` gives one Locator per element that contains the text: the innermost ones when `tag` is None, every `tag` element otherwise. |
| `find_visible_elements` | composed | `Locator::visible` | Call `page.locator(selector).visible(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `flash` | composed | `Locator::flash_with` | `page.locator(selector).flash_with(color, duration)` outlines the element for the duration in any CSS colour; `flash()` uses the defaults. Python's `pause` is a `tokio::time::sleep` afterwards. The outline is an outline, not Python's vanishing dot. |
| `focus` | composed | `Locator::focus` | Call `page.locator(selector).focus(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get` | composed | `Page::goto` | A method of the Page that sb.cdp drives: `page.goto(..)`. |
| `get_active_element` | composed | `Page::active_element` | `page.active_element()` returns a Locator for the element that has focus, found through its selector. Python returns a dump of the element; read what you need from the Locator (`info()`, `text()`, `attribute(..)`). `page.evaluate("document.activeElement")` does not work: an element comes back as `{}`. |
| `get_active_element_css` | composed | `Page::active_element_css` | `page.active_element_css()` returns the shortest selector that finds the focused element, such as `input#email`, or `body` when nothing has focus. |
| `get_active_tab` | composed | `Browser::default_page` | Python's active tab is the one the engine drives; in Rust that is the Page you hold. `browser.default_page()` is only the first tab listed, which may be another one. |
| `get_all_cookies` | composed | `Cookies::all` | `page.cookies().all(..)`. |
| `get_all_urls` | composed | `Locator::urls` | `page.locator(selector).urls()` lists the absolute URLs under the element. |
| `get_attribute` | composed | `Locator::attribute` | Call `page.locator(selector).attribute(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_beautiful_soup` | not-applicable |  | HTML parsing lives in api::html (the scraper crate). |
| `get_cookie_string` | composed | `Cookies::header` | `page.cookies().header(..)`. |
| `get_current_url` | composed | `Page::url` | A method of the Page that sb.cdp drives: `page.url(..)`. |
| `get_document` | composed | `Page::execute` | Raw protocol call: `page.execute(..)` with `DOM.getDocument`. |
| `get_element_attribute` | composed | `Locator::attribute` | Call `page.locator(selector).attribute(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_element_attributes` | composed | `Locator::info` | `page.locator(selector).info()` returns the element's details, attributes included. |
| `get_element_html` | composed | `Locator::html` | Call `page.locator(selector).html(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_element_position` | composed | `Locator::viewport_rect` | `page.locator(selector).viewport_rect()` is measured from the window's visible area, as in Python. `bounding_box()` is measured from the top of the document and differs by how far the page is scrolled. |
| `get_element_rect` | composed | `Locator::viewport_rect` | `page.locator(selector).viewport_rect()` is measured from the window's visible area, as Python's window-based rectangle is. `bounding_box()` is measured from the top of the document and differs by how far the page is scrolled. |
| `get_element_size` | composed | `Locator::bounding_box` | `page.locator(selector).bounding_box()`; position, size and rect all come from the one bounding box. |
| `get_endpoint_url` | composed | `Browser::http_url` | `browser.http_url()` is the DevTools HTTP endpoint, on the host the browser was launched on or attached to. |
| `get_event_loop` | not-applicable |  | The async runtime is the caller's; there is no event loop to expose. |
| `get_flattened_document` | composed | `Page::execute` | Raw protocol call: `page.execute(..)` with `DOM.getFlattenedDocument`. |
| `get_gui_element_center` | composed | `Locator::screen_rect` | `page.locator(selector).screen_rect()` gives the rectangle in screen coordinates; take its centre. |
| `get_gui_element_rect` | composed | `Locator::screen_rect` | Call `page.locator(selector).screen_rect(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_html` | composed | `Page::content` | `page.content()` returns the whole page's HTML, `document.documentElement.outerHTML`, which is what Python returns with `include_shadow_dom=False`. Python's default (True) reads the html element's outer HTML through DevTools; whether that adds shadow-root content was not compared. For one element use `page.locator(selector).html()`. |
| `get_local_storage_item` | composed | `Storage::get` | `page.local_storage().get(key)`. |
| `get_locale_code` | implemented | `Page::locale_code` | `page.locale_code()` is `navigator.language`, or the first of `navigator.languages` when that is empty. |
| `get_mfa_code` | composed | `BaseCase::get_mfa_code` | BaseCase::get_mfa_code computes the TOTP code and needs no browser; it is a method of the WebDriver-engine BaseCase. |
| `get_navigation_history` | composed | `Page::execute` | Raw protocol call: `page.execute(..)` with `Page.getNavigationHistory`. |
| `get_nested_element` | composed | `Locator::locator` | Call `page.locator(selector).locator(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_origin` | implemented | `Page::origin` | `page.origin()` is `window.location.origin`. |
| `get_page_source` | composed | `Page::content` | `page.content()` returns the page's HTML. |
| `get_page_title` | composed | `Page::title` | `page.title()`. |
| `get_parent` | composed | `Locator::parent` | Call `page.locator(selector).parent(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_path_of_downloaded_file` | composed | `Browser::set_download_dir` | Rust has no helper: join the folder given to Browser::set_download_dir with the file name. |
| `get_port` | composed | `Browser::debugging_port` | `browser.debugging_port()`. |
| `get_rd_host` | composed | `Browser::debugging_host` | `browser.debugging_host()` is `127.0.0.1` for a launched browser and the host given to `Browser::connect` for an attached one. |
| `get_rd_port` | composed | `Browser::debugging_port` | `browser.debugging_port()`. |
| `get_rd_url` | composed | `Browser::http_url` | `browser.http_url()` is the DevTools HTTP endpoint, on the host the browser was launched on or attached to. |
| `get_screen_rect` | implemented | `Page::screen_rect` | `page.screen_rect()` returns a `ScreenRect` of the display (`window.screen`): size, usable area and colour depth. `page.window().bounds()` is the browser window's rectangle, not the screen's, and `Locator::screen_rect` is an element's rectangle in screen coordinates. Differs: Python returns the `window.screen` object as it serialises, a dict; this is a typed struct of the numeric fields. |
| `get_session_storage_item` | composed | `Storage::get` | `page.session_storage().get(key)`. |
| `get_tabs` | composed | `Browser::pages` | `browser.pages()`. |
| `get_text` | composed | `Locator::text` | Call `page.locator(selector).text(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `get_title` | composed | `Page::title` | `page.title()`. |
| `get_user_agent` | composed | `Page::user_agent` | `page.user_agent()`. |
| `get_websocket_url` | composed | `Browser::websocket_url` | `browser.websocket_url()`. |
| `get_window` | composed | `Window::bounds` | `page.window().bounds(..)`; sizes and positions come as a WindowBounds struct instead of separate values. |
| `get_window_position` | composed | `Window::bounds` | `page.window().bounds(..)`; sizes and positions come as a WindowBounds struct instead of separate values. |
| `get_window_rect` | composed | `Window::bounds` | `page.window().bounds(..)`; sizes and positions come as a WindowBounds struct instead of separate values. |
| `get_window_size` | composed | `Window::bounds` | `page.window().bounds(..)`; sizes and positions come as a WindowBounds struct instead of separate values. |
| `go_back` | composed | `Page::back` | A method of the Page that sb.cdp drives: `page.back(..)`. |
| `go_forward` | composed | `Page::forward` | A method of the Page that sb.cdp drives: `page.forward(..)`. |
| `goto` | composed | `Page::goto` | A method of the Page that sb.cdp drives: `page.goto(..)`. |
| `goto_if_not_url` | composed | `Page::goto_if_not_url` | `page.goto_if_not_url(url)` navigates only when the tab is on another page. Like Python it ignores what a search engine adds after the query (`?q=term&source=hp`). |
| `grant_all_permissions` | composed | `Browser::grant_all_permissions` | A method of the Browser, not of one page: `browser.grant_all_permissions()` grants the 23 kinds in `Permission::ALL`, which are the ones Python grants. |
| `grant_permissions` | composed | `Browser::grant_permissions_for` | A method of the Browser, not of one page: `browser.grant_permissions(&[..])` for all origins, `browser.grant_permissions_for(origin, &[..])` for one. Permissions are the `Permission` enum, not free-form names. |
| `gui_click_and_hold` | composed | `Gui::mouse_down` | Feature `gui`. Gui::mouse_down presses at the pointer's current position without moving it, so move first: take `let r = page.locator(selector).screen_rect().await?`, `gui.move_mouse(x, y)?` to the centre `(r.x + r.width / 2.0, r.y + r.height / 2.0)`, then `gui.mouse_down()?`, sleep for the hold time and `gui.mouse_up()?`. |
| `gui_click_captcha` | implemented | `Page::gui_click_captcha` | Feature `gui`. Page::gui_click_captcha finds the widget as `Page::solve_captcha` does, works out the checkbox's screen point (the window from `Browser.getWindowForTarget`, where the page starts inside it, the widget's frame, the vendor's checkbox offset), moves the real pointer there along a human path and presses; the DataDome slider is dragged. `Page::gui_captcha_plan` gives the point without moving anything. It has unit and mock coverage only: the arithmetic, the vendor offsets, the CDP calls and the pointer steps are tested against a mocked browser and a recording pointer; it has never moved the real pointer or been tried on a live CAPTCHA. Differs: Python's DataDome flow opens the challenge frame in a new tab and drags between the page's own slider elements; here the handle is taken to be 30 pixels in from the frame's left edge and is dragged to 30 pixels from its right edge. A headless browser and a minimised window are refused, and a point outside the main display is refused as PyAutoGUI refuses it. |
| `gui_click_element` | composed | `Gui::click` | Feature `gui`. Gui::click clicks where the pointer already is, so move first: `let r = page.locator(selector).screen_rect().await?; gui.move_mouse((r.x + r.width / 2.0) as i32, (r.y + r.height / 2.0) as i32)?; gui.click()?`. Python also glides the pointer over `timeframe` seconds. |
| `gui_click_with_offset` | composed | `Gui::click` | Feature `gui`. Move to the offset from the element's top-left corner, then click: `let r = page.locator(selector).screen_rect().await?; gui.move_mouse(r.x as i32 + dx, r.y as i32 + dy)?; gui.click()?`. |
| `gui_click_x_y` | composed | `Gui::click` | Feature `gui`. Gui::click does not move the pointer: `gui.move_mouse(x, y)?; gui.click()?`. |
| `gui_drag_and_drop` | composed | `Gui::drag` | Feature `gui`. Take the centre of `page.locator(drag_selector).screen_rect().await?` and of the drop selector's, and pass both points to `gui.drag((x1, y1), (x2, y2))?`. |
| `gui_drag_drop_points` | composed | `Gui::drag` | `Gui::drag` from api::gui (feature `gui`): it moves the real pointer and keyboard in screen coordinates, outside the page. |
| `gui_hover_and_click` | composed | `Gui::click` | Feature `gui`. Move to the centre of the first element's `screen_rect()` and wait for the page to react, then move to the centre of the second's and `gui.click()?`. |
| `gui_hover_element` | composed | `Gui::move_mouse` | Feature `gui`. Take the centre of `page.locator(selector).screen_rect().await?` and pass it to `gui.move_mouse(x, y)?`; the pointer is the operating system's, outside the page. |
| `gui_hover_x_y` | composed | `Gui::move_mouse` | `Gui::move_mouse` from api::gui (feature `gui`): it moves the real pointer and keyboard in screen coordinates, outside the page. |
| `gui_move_to_element` | composed | `Gui::move_mouse` | Feature `gui`. Take the centre of `page.locator(selector).screen_rect().await?` and pass it to `gui.move_mouse(x, y)?`; the pointer is the operating system's, outside the page. |
| `gui_press_key` | composed | `Gui::press_key` | `Gui::press_key` from api::gui (feature `gui`): it moves the real pointer and keyboard in screen coordinates, outside the page. |
| `gui_press_keys` | composed | `Gui::press_keys` | `Gui::press_keys(&[..])` holds the modifier keys while it presses the others; it needs feature `gui`. |
| `gui_write` | composed | `Gui::write` | `Gui::write` from api::gui (feature `gui`): it moves the real pointer and keyboard in screen coordinates, outside the page. |
| `highlight` | composed | `Locator::flash` | `page.locator(selector).flash()` outlines the element briefly; it has no loops or colour options. |
| `highlight_overlay` | composed | `Locator::flash` | `page.locator(selector).flash()` outlines the element briefly; it draws no overlay. |
| `hover_and_click` | composed | `Locator::hover` | Hover with `page.locator(hover_selector).hover()`, then click the second Locator: two calls instead of one. |
| `hover_element` | composed | `Locator::hover` | `page.locator(selector).hover()`. |
| `internalize_links` | composed | `Locator::set_attribute` | Set `target` to `_self` on the link Locator with `set_attribute` so links open in the same tab. |
| `is_attribute_present` | composed | `Locator::attribute` | `page.locator(selector).attribute(name)` returns an Option; the attribute is present when it is Some. |
| `is_checked` | composed | `Locator::is_checked` | Call `page.locator(selector).is_checked(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `is_element_present` | composed | `Locator::exists` | Call `page.locator(selector).exists(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `is_element_visible` | composed | `Locator::is_visible` | Call `page.locator(selector).is_visible(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `is_exact_text_visible` | composed | `Locator::text` | Compare `page.locator(selector).text()` with the text; there is no single predicate. |
| `is_online` | composed | `Page::is_online` | A method of the Page that sb.cdp drives: `page.is_online(..)`. |
| `is_selected` | composed | `Locator::is_selected` | `page.locator(selector).is_selected()`. |
| `is_text_visible` | composed | `Locator::text` | Test `page.locator(selector).text()` for the text; there is no single predicate. |
| `js_dumps` | not-applicable |  | Values cross as serde_json::Value; there is nothing to serialise by hand. |
| `js_scroll_into_view` | composed | `Locator::scroll_into_view` | Call `page.locator(selector).scroll_into_view(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `load_cookies` | composed | `Cookies::load` | `page.cookies().load(..)`. |
| `maximize` | composed | `Window::maximize` | `page.window().maximize()`. |
| `medimize` | composed | `Window::restore` | `page.window().restore()` returns the window to its normal state. |
| `minimize` | composed | `Window::minimize` | `page.window().minimize()`. |
| `mouse_click` | composed | `Locator::click` | `page.locator(selector).click()` waits for the element, scrolls it into view and clicks its centre with real mouse events. `page.mouse().click(point)` clicks at coordinates instead. |
| `nested_click` | composed | `Locator::locator` | Call `page.locator(selector).locator(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `open` | composed | `Page::goto` | A method of the Page that sb.cdp drives: `page.goto(..)`. |
| `open_new_tab` | composed | `Browser::new_page` | A method of the Browser, not of one page: `browser.new_page()` opens a blank tab and `browser.new_page_at(url)` one on a URL. |
| `open_new_window` | composed | `Browser::new_window` | A method of the Browser, not of one page: `browser.new_window()` opens a blank window and `browser.new_window_at(url)` one on a URL. |
| `post_message` | implemented | `Page::post_message` | Messenger shows its message as HTML, so the text is escaped and appears as typed. It loads Messenger first when the page lacks it. Differs: Python lets markup in the message through; here it is shown as text. Duration, pause and style are fields of MessageOptions. |
| `press_keys` | composed | `Locator::send_keys` | `page.locator(selector).send_keys(text)` types the text one key at a time, after what the field holds, without Python's human-speed delays; `Locator::press(Key)` sends one named key. |
| `print_to_pdf` | composed | `Page::pdf` | `page.pdf(..)` returns the PDF; write it with std::fs. |
| `quit` | composed | `Browser::close` | `browser.close()` closes the whole browser. |
| `refresh` | composed | `Page::reload` | A method of the Page that sb.cdp drives: `page.reload(..)`. |
| `reload` | composed | `Page::reload` | A method of the Page that sb.cdp drives: `page.reload(..)`. |
| `remove_element` | composed | `Locator::remove` | `page.locator(selector).first().remove()`. Python's remove_element removes one element, the first match; `Locator::remove` on its own removes every match, which is remove_elements. |
| `remove_elements` | composed | `Locator::remove` | `page.locator(selector).remove()` removes every match, as Python's remove_elements does. |
| `remove_from_dom` | composed | `Locator::remove` | `page.locator(selector).first().remove()`. Python's remove_from_dom removes one element, the first match; `Locator::remove` on its own removes every match. |
| `reset_permissions` | composed | `Browser::reset_permissions` | A method of the Browser, not of one page: `browser.reset_permissions(..)`. |
| `reset_window_size` | composed | `Window::set_bounds` | Read page.window().bounds() when the page opens and pass those values back to set_bounds, as Python restores the start position and size. Window::restore only leaves the maximized or minimized state; it does not restore a size. |
| `save_as_html` | composed | `Page::content` | `page.content()` returns the HTML; write it with std::fs. |
| `save_as_html_to_logs` | composed | `Page::content` | `page.content()` returns the HTML; write it into artifacts::ensure_latest_logs_dir() with std::fs. |
| `save_as_pdf` | composed | `Page::pdf` | `page.pdf(..)` returns the PDF; write it with std::fs. |
| `save_as_pdf_to_logs` | composed | `Page::pdf` | `page.pdf(..)` returns the PDF; write it into artifacts::ensure_latest_logs_dir() with std::fs. |
| `save_cookies` | composed | `Cookies::save` | `page.cookies().save(..)`. |
| `save_data_to_logs` | not-applicable |  | Write files with std::fs; artifacts::ensure_latest_logs_dir gives the logs folder. |
| `save_file_as` | implemented | `Page::save_file_as` | `page.save_file_as(url, path)` downloads the address like download_file, saves it at exactly `path` (creating the folders, replacing a file there) and returns that path. Differs: Takes a whole path, where Python takes a new file name and saves in ./downloaded_files. |
| `save_page_source` | composed | `Page::content` | `page.content()` returns the HTML; write it with std::fs. |
| `save_page_source_to_logs` | composed | `Page::content` | `page.content()` returns the HTML; write it into artifacts::ensure_latest_logs_dir() with std::fs. |
| `save_screenshot` | composed | `Page::screenshot` | `page.screenshot(..)` returns the viewport as image bytes; write them with std::fs. For Python's `selector` argument use `page.locator(selector).screenshot()`. |
| `save_screenshot_to_logs` | composed | `Page::screenshot` | `page.screenshot(..)` returns the image; write it into artifacts::ensure_latest_logs_dir() with std::fs. |
| `scroll_by_y` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `scroll_down` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `scroll_into_view` | composed | `Locator::scroll_into_view` | Call `page.locator(selector).scroll_into_view(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `scroll_to_bottom` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `scroll_to_top` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `scroll_to_y` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `scroll_up` | composed | `Page::scroll` | A method of the Page that sb.cdp drives: `page.scroll(..)`. |
| `select` | composed | `Locator::select_option` | Call `page.locator(selector).select_option(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `select_all` | composed | `Locator::all_waiting` | Python's select_all returns the matching elements, like find_elements; `page.locator(selector).all_waiting()` waits up to the timeout for a first match, then gives one Locator per match (an empty list after the timeout, as Python does). `all()` does not wait. |
| `select_if_unselected` | composed | `Locator::set_checked` | `page.locator(selector).set_checked(true)`. |
| `select_option_by_index` | composed | `Locator::select_option` | Call `page.locator(selector).select_option(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `select_option_by_text` | composed | `Locator::select_option` | Call `page.locator(selector).select_option(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `select_option_by_value` | composed | `Locator::select_option` | Call `page.locator(selector).select_option(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `send_keys` | implemented | `Locator::send_keys` | `page.locator(selector).send_keys(text)` types one key at a time after what the field holds; `type_text` clears first. |
| `set_all_cookies` | composed | `Cookies::set` | `page.cookies().set(..)`. |
| `set_attributes` | composed | `Locator::set_attribute` | Call `page.locator(selector).set_attribute(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `set_download_path` | composed | `Browser::set_download_dir` | `browser.set_download_dir(dir)`. |
| `set_local_storage_item` | composed | `Storage::set` | `page.local_storage().set(key, value)`. |
| `set_locale` | composed | `Emulation::locale` | `page.emulation().locale(..)` sets the Intl locale and also the language the page reads from `navigator.language` and the browser sends in `Accept-Language`, keeping the user agent and client hints it had. As in Python the language takes effect from the next page load. |
| `set_messenger_theme` | implemented | `Page::set_messenger_theme` | Theme, location and the message limit are typed in MessengerSettings; the defaults are Python's (flat, bottom right, 8). A MessengerTheme or a MessengerLocation alone is accepted too and keeps the defaults for the rest. |
| `set_session_storage_item` | composed | `Storage::set` | `page.session_storage().set(key, value)`. |
| `set_value` | composed | `Locator::set_value` | Call `page.locator(selector).set_value(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `set_window_rect` | composed | `Window::set_bounds` | `page.window().set_bounds(x, y, width, height)`; it first restores a minimised or maximised window. |
| `sleep` | not-applicable |  | Use tokio::time::sleep. |
| `solve_captcha` | composed | `Page::solve_captcha` | A method of the Page that sb.cdp drives: `page.solve_captcha(..)`. |
| `stop` | composed | `Browser::close` | `browser.close()` closes the whole browser. |
| `submit` | composed | `Locator::submit` | Call `page.locator(selector).submit(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `switch_to_newest_tab` | composed | `Browser::newest_page` | `browser.newest_page()` returns the Page of the newest tab. |
| `switch_to_newest_window` | composed | `Browser::newest_page` | `browser.newest_page()` returns the Page of the newest window. |
| `switch_to_tab` | composed | `Browser::pages` | Pick a page from `browser.pages()`; Rust holds a Page per tab, so there is no current tab to switch. |
| `switch_to_window` | composed | `Browser::pages` | Pick a page from `browser.pages()`; Rust holds a Page per tab, so there is no current window to switch. |
| `tile_windows` | composed | `Window::set_bounds` | Python tiles the browser windows with the CDP driver. Compute each tile's x, y, width and height and call set_bounds on each window; there is no one-call tiler. |
| `type` | implemented | `Locator::type_text` | `page.locator(selector).type_text(text)` clears the field, then types the text one key at a time, as Python's `type` does. `fill(text)` inserts it in one step; `send_keys(text)` appends. |
| `uncheck_if_checked` | composed | `Locator::uncheck` | Call `page.locator(selector).uncheck(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `unselect_if_selected` | composed | `Locator::set_checked` | `page.locator(selector).set_checked(false)`. |
| `wait_for_any_of_elements_present` | composed | `Page::wait_for_any` | `page.wait_for_any(..)` waits until one of several locators is ready and says which one (an index), not its selector. |
| `wait_for_any_of_elements_visible` | composed | `Page::wait_for_any` | `page.wait_for_any(..)` waits until one of several locators is ready and says which one (an index), not its selector. |
| `wait_for_element` | composed | `Locator::wait_for` | Call `page.locator(selector).wait_for(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `wait_for_element_absent` | composed | `Locator::wait_for` | Call `page.locator(selector).wait_for(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `wait_for_element_not_visible` | composed | `Locator::wait_for` | Call `page.locator(selector).wait_for(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `wait_for_element_present` | composed | `Locator::wait_for` | Call `page.locator(selector).wait_for(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `wait_for_element_visible` | composed | `Locator::wait_for` | Call `page.locator(selector).wait_for(..)`; the Locator holds the selector, so it is not an argument of the call. |
| `wait_for_text` | composed | `LocatorExpect::to_contain_text` | `page.locator(selector).expect().to_contain_text(text)` waits for the text; it does not return the element. |
| `wait_for_text_not_visible` | composed | `LocatorExpect::to_contain_text` | `page.locator(selector).expect().not().to_contain_text(text)` waits for the text to go. |

## Command-line commands

Python `seleniumbase` / `sbase`; Rust `sbrs`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `behave-gui` | implemented | `sbrs behave-gui` | Terminal UI instead of Tkinter (feature `tui`): lists the .feature files with their scenarios, runs the ones you mark through the crate's behave runner and shows the results; without `tui` it prints a hint and exits with status 2, as `sbrs commander` does. `--new` keeps the earlier prompt that writes a new feature file. Differs: Python starts `python -m behave` with the browser, session, demo, dashboard, headless, screenshot and extra options. Here the only run option is a tag filter, and the steps are the built-in ones: steps written in Rust cannot be loaded, so a scenario that uses one is reported as undefined. |
| `behave-options` | not-applicable |  | Lists behave (Python BDD) options; this crate has its own Gherkin runner. |
| `case-plans` | implemented | `sbrs caseplans` | Alias of caseplans upstream; terminal UI instead of Tkinter, as for `sbrs caseplans`, and `sbrs case-plans` is an alias of it here too. |
| `caseplans` | implemented | `sbrs caseplans` | Terminal UI instead of Tkinter (feature `tui`): lists the Rust test functions under a folder, creates, edits and saves `case_plans/<test>.md` for each and writes `case_summary.md`; without `tui` it prints a hint and exits with status 2, as `sbrs commander` does. `--starter` keeps the earlier command that writes a fixed CASE_PLANS.md checklist. Differs: Python lists what pytest collects (`file.py::Class::method`); here the test functions are found by reading the files, so a `#[test]` inside a string looks like a test. Plans and the summary are written with LF line ends, not CRLF. |
| `codegen` | composed | `sbrs record` | `sbrs record URL -o FILE` writes the recorded actions as a JSON or YAML list that `sbrs replay` runs. It does not write a test file; ActionRecorder::to_rust_test does that, from code. |
| `commander` | implemented | `sbrs commander` |  |
| `convert` | implemented | `sbrs convert` |  |
| `decrypt` | implemented | `sbrs decrypt` | Differs: Reads tokens made by `sbrs encrypt` only; see `encrypt`. |
| `download` | not-applicable |  | Python's `download server` fetches the Selenium Standalone Server. `sbrs` never downloads it: `sbrs grid-hub` and `sbrs grid-node` run a jar you supply with --jar or SB_SELENIUM_SERVER_JAR. (`sbrs download-file` downloads a file from a URL, which is another command.) |
| `encrypt` | implemented | `sbrs encrypt` | Differs: AES-256-GCM under a PBKDF2 key from SB_ENCRYPTION_KEY, not Python's fixed-key obfuscation; tokens are not interchangeable. |
| `extract-objects` | not-applicable |  | Edits the structure of Python test files. |
| `get` | implemented | `sbrs get` | An alias of `sbrs install`, as in Python: `sbrs get chromedriver\|geckodriver\|edgedriver [VERSION]` (also `firefoxdriver` and `msedgedriver`). chromedriver and edgedriver default to the driver for the installed Chrome and Edge, geckodriver to the newest GitHub release; VERSION is `latest`, a major version or a full build (a geckodriver version such as 0.36.0). Each driver goes to downloaded_drivers/&lt;driver&gt;-&lt;version&gt;/. Differs: No `--path`: the driver stays in downloaded_drivers/ and is not copied to a folder on the PATH. Chrome for Testing and chrome-headless-shell are not fetched by name here; they are fetched when a session chooses one of them as the browser. |
| `grid-hub` | implemented | `sbrs grid-hub` | start, stop, restart and status; needs a Selenium Server jar you supply and Java, and downloads nothing. |
| `grid-node` | implemented | `sbrs grid-node` | start, stop, restart and status; registers with the hub named by --hub. |
| `gui` | composed | `sbrs commander` | Python's `gui` is the same test runner as `commander`. |
| `gui-behave` | implemented | `sbrs behave-gui` | Alias of behave-gui upstream; terminal UI instead of Tkinter, as for `sbrs behave-gui`, and `sbrs gui-behave` is an alias of it here too. |
| `help` | composed | `usage` | Provided by the argument parser. |
| `inject-objects` | not-applicable |  | Edits the structure of Python test files. |
| `install` | implemented | `sbrs install` | `sbrs install chromedriver\|geckodriver\|edgedriver [VERSION]`; with no argument it fetches the chromedriver that matches the installed Chrome (or the stable one). The same command as `sbrs get`. Differs: No `--path`: the driver stays in downloaded_drivers/ and is not copied to a folder on the PATH. |
| `methods` | not-applicable |  | Lists Python methods; use `cargo doc` or docs/parity.md for the Rust API. |
| `mkchart` | implemented | `sbrs mkchart` |  |
| `mkdir` | implemented | `sbrs mkdir` |  |
| `mkfile` | implemented | `sbrs mkfile` |  |
| `mkpres` | implemented | `sbrs mkpres` |  |
| `mkrec` | composed | `sbrs record` | Python's mkrec creates a new test file with the Recorder. `sbrs record URL -o FILE` records in a browser and writes a JSON or YAML action list that `sbrs replay` runs, not a test file; `sbrs mkrec` only writes a starter recording file and opens no browser. |
| `obfuscate` | composed | `sbrs encrypt` | Alias of encrypt upstream, as here: `sbrs obfuscate` is accepted. It encrypts a string, not a source file. Tokens are AES-256-GCM under SB_ENCRYPTION_KEY, read from the environment instead of a prompt, and do not interchange with Python's. |
| `objectify` | not-applicable |  | Python's objectify rewrites the selectors of a Python test file into page-object variables, like extract-objects and inject-objects, and there is no Python source to rewrite here. `sbrs objectify` only writes a starter page_object.rs. |
| `options` | not-applicable |  | Lists pytest options; Rust settings are fields of BrowserConfig and RuntimeConfig. |
| `print` | implemented | `sbrs print` |  |
| `proxy` | implemented | `sbrs proxy` |  |
| `record` | implemented | `sbrs record` |  |
| `recorder` | composed | `sbrs record` | Python's recorder is a desktop app that launches the Recorder. `sbrs record URL -o FILE` has no window of its own: it opens the page, records until it is stopped, and writes a JSON or YAML action list that `sbrs replay` runs. It does not write a test file. |
| `revert-objects` | not-applicable |  | Edits the structure of Python test files. |
| `translate` | implemented | `sbrs translate` | sbrs translate FILE LANGUAGE [--print\|--overwrite\|--copy] rewrites the action of every step of a JSON scenario with the translation dictionary; Scenario::from_json reads actions in any of the ten languages. Differs: Python translates the method calls of a Python test file. A Rust test is compiled code with English method names, so the file translated here is the JSON scenario. The language is a positional argument, not a --zh style flag. |
| `unobfuscate` | composed | `sbrs decrypt` | Alias of decrypt upstream, as here: `sbrs unobfuscate` is accepted. Tokens are AES-256-GCM under SB_ENCRYPTION_KEY, read from the environment instead of a prompt, and do not interchange with Python's. |
| `version` | implemented | `sbrs version` | Prints the same line as `sbrs --version`. |

## pytest options

Python `--option` flags.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `--account` | not-applicable |  | Hands a free-text account string to pytest tests as sb.account; a Rust test reads its own values from std::env or a fixture file. |
| `--ad-block` | composed | `BrowserConfig::ad_block` | `sbrs --ad-block` sets BrowserConfig::ad_block. Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `--ad_block` | composed | `BrowserConfig::ad_block` | A Python spelling of --ad-block; `sbrs` takes --ad-block, and BrowserConfig::ad_block is the same setting. Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `--adblock` | composed | `BrowserConfig::ad_block` | A Python spelling of --ad-block; `sbrs` takes --ad-block, and BrowserConfig::ad_block is the same setting. Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `--agent` | composed | `BrowserConfig::user_agent` |  |
| `--all-scripts` | not-applicable |  | Makes pytest collect SB(), DriverContext() and Driver() scripts as tests; cargo test runs only #[test] functions, so there is no collection phase to extend. |
| `--all_scripts` | not-applicable |  | Makes pytest collect SB(), DriverContext() and Driver() scripts as tests; cargo test runs only #[test] functions, so there is no collection phase to extend. |
| `--archive-downloads` | not-applicable |  | Downloads go to the OS Downloads folder (BaseCase::get_downloads_folder) and are never cleared, so there is no project downloaded_files folder to archive; moving the user's Downloads would be unsafe. |
| `--archive-logs` | not-applicable |  | This crate never deletes latest_logs/ (artifacts::ensure_latest_logs_dir only creates it), so there are no deleted old logs to archive instead. |
| `--archive_downloads` | not-applicable |  | Downloads go to the OS Downloads folder (BaseCase::get_downloads_folder) and are never cleared, so there is no project downloaded_files folder to archive; moving the user's Downloads would be unsafe. |
| `--archive_logs` | not-applicable |  | This crate never deletes latest_logs/ (artifacts::ensure_latest_logs_dir only creates it), so there are no deleted old logs to archive instead. |
| `--auto-ext` | implemented | `BrowserConfig::with_automation_extension` | Sets `useAutomationExtension` to true. Upstream marks the option deprecated. Chromium only. |
| `--binary-location` | composed | `BrowserConfig::browser_binary_path` |  |
| `--binary_location` | composed | `BrowserConfig::browser_binary_path` |  |
| `--bl` | composed | `BrowserConfig::browser_binary_path` |  |
| `--block-ads` | composed | `BrowserConfig::ad_block` | A Python spelling of --ad-block; `sbrs` takes --ad-block, and BrowserConfig::ad_block is the same setting. Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `--block-images` | implemented | `BrowserConfig::with_block_images` | Chrome's content-setting preference (`prefs` of `goog:chromeOptions`), or Firefox's `permissions.default.image`. |
| `--block_ads` | composed | `BrowserConfig::ad_block` | A Python spelling of --ad-block; `sbrs` takes --ad-block, and BrowserConfig::ad_block is the same setting. Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `--block_images` | implemented | `BrowserConfig::with_block_images` | Chrome's content-setting preference (`prefs` of `goog:chromeOptions`), or Firefox's `permissions.default.image`. |
| `--brave` | implemented | `BrowserConfig::browser` | Run with chromedriver; the program is found in Brave's install locations or on the PATH. |
| `--browser` | implemented | `BrowserConfig::browser` |  |
| `--cap-file` | implemented | `CapabilityOverrides::from_file` | Reads JSON or the Python dictionary of a capabilities file without running Python; merged over the session's capabilities with `BrowserConfig::with_capabilities`. Differs: Python's parser reads one key per line; this reads the whole dictionary. |
| `--cap-string` | implemented | `CapabilityOverrides::from_text` | JSON, or a Python dictionary; merged over the session's capabilities with `BrowserConfig::with_capabilities`. |
| `--cap_file` | implemented | `CapabilityOverrides::from_file` | Reads JSON or the Python dictionary of a capabilities file without running Python; merged over the session's capabilities with `BrowserConfig::with_capabilities`. Differs: Python's parser reads one key per line; this reads the whole dictionary. |
| `--cap_string` | implemented | `CapabilityOverrides::from_text` | JSON, or a Python dictionary; merged over the session's capabilities with `BrowserConfig::with_capabilities`. |
| `--cft` | implemented | `BrowserConfig::browser` | Chrome for Testing, downloaded into downloaded_drivers/cft/ when missing; the driver follows its version. |
| `--check-js` | composed | `BaseCase::assert_no_js_errors` | Call it after the page loads. |
| `--check_js` | composed | `BaseCase::assert_no_js_errors` | Call it after the page loads. |
| `--chrome` | composed | `BrowserConfig::browser` | Choose the Browser variant. |
| `--chromium` | composed | `BrowserConfig::browser` | Choose the Browser variant. |
| `--chromium-arg` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--chromium_arg` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--chs` | implemented | `BrowserConfig::browser` | chrome-headless-shell, downloaded into downloaded_drivers/chs/ when missing; it cannot run UC mode. |
| `--codegen` | composed | `RecorderSession::install` | `RecorderSession::install(&sb)` injects the page recorder, so clicks and typing done by hand in the browser are captured; `drain(&mut sb)` collects them, and `ActionRecorder::to_rust_test` or `save_recording_as_test` writes the test. Nothing is saved when the test ends. BaseCase::start_recording only marks where the log of the test's own BaseCase calls begins. |
| `--comet` | implemented | `BrowserConfig::browser` | Run with chromedriver; the program is found in Comet's install locations or on the PATH (the Linux location is a guess). |
| `--crumbs` | composed | `BaseCase::delete_all_cookies` | With --reuse-session or --rcs, a browser handed to the next test always has its cookies deleted (every cookie, through DevTools, on Chromium) and goes to about:blank, so --crumbs is in effect whenever a browser is reused. Without reuse every test has a new browser and no cookies; call delete_all_cookies to clear them within a test. |
| `--crx` | implemented | `BrowserConfig::with_extension_archive` | A .zip or .crx file, sent in the `extensions` option of `goog:chromeOptions`. Chromium only. |
| `--dark` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--dark-mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--dark_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--dash-title` | not-applicable |  | Sets the title of the pytest session dashboard page; write_dashboard_html takes its title from the scenario's name. |
| `--dash_title` | not-applicable |  | Sets the title of the pytest session dashboard page; write_dashboard_html takes its title from the scenario's name. |
| `--dashboard` | not-applicable |  | Turns on the live dashboard.html that the pytest session rewrites during a run; a scenario run writes a static report with write_dashboard_html instead. |
| `--data` | not-applicable |  | Passes one free-text string through the pytest command line as self.data; a Rust test reads its own values from std::env or a fixture file. |
| `--database-env` | not-applicable |  | Picks which MySQL reporting database --with-db-reporting writes to; ResultStore is a local database opened from a path the caller gives, so there are no named environments. |
| `--database_env` | not-applicable |  | Picks which MySQL reporting database --with-db-reporting writes to; ResultStore is a local database opened from a path the caller gives, so there are no named environments. |
| `--dcsp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `--demo` | implemented | `RunSettings::with_demo_mode` | Outlines the element and pauses after the actions Python's demo mode covers (open, the clicks, typing, the selects, submit, focus, drag and drop, the window size calls and more); a pause is full after an action that changed the URL and 1/3.4 of it after one that did not; hand the settings to BaseCase::set_run_settings. |
| `--demo-mode` | implemented | `RunSettings::with_demo_mode` | Outlines the element and pauses after the actions Python's demo mode covers (open, the clicks, typing, the selects, submit, focus, drag and drop, the window size calls and more); a pause is full after an action that changed the URL and 1/3.4 of it after one that did not; hand the settings to BaseCase::set_run_settings. |
| `--demo-sleep` | implemented | `RunSettings::with_demo_sleep` | The pause demo and slow mode make after an action. |
| `--demo_mode` | implemented | `RunSettings::with_demo_mode` | Outlines the element and pauses after the actions Python's demo mode covers (open, the clicks, typing, the selects, submit, focus, drag and drop, the window size calls and more); a pause is full after an action that changed the URL and 1/3.4 of it after one that did not; hand the settings to BaseCase::set_run_settings. |
| `--demo_sleep` | implemented | `RunSettings::with_demo_sleep` | The pause demo and slow mode make after an action. |
| `--device-metrics` | implemented | `BrowserConfig::with_device_metrics` | Chrome's `mobileEmulation` experimental option. Differs: Python applies the metrics only together with --mobile; here setting them turns mobile emulation on. |
| `--device_metrics` | implemented | `BrowserConfig::with_device_metrics` | Chrome's `mobileEmulation` experimental option. Differs: Python applies the metrics only together with --mobile; here setting them turns mobile emulation on. |
| `--devtools` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable-beforeunload` | composed | `BaseCase::disable_beforeunload` | Call it after each navigation. |
| `--disable-cookies` | implemented | `BrowserConfig::with_disable_cookies` | Chrome's cookie content-setting preference, or Firefox's `network.cookie.cookieBehavior`. |
| `--disable-csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `--disable-features` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable-gpu` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable-js` | implemented | `BrowserConfig::with_disable_js` | Chrome's JavaScript content-setting preference, or Firefox's `javascript.enabled`. |
| `--disable-web-security` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable-ws` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable_beforeunload` | composed | `BaseCase::disable_beforeunload` | Call it after each navigation. |
| `--disable_cookies` | implemented | `BrowserConfig::with_disable_cookies` | Chrome's cookie content-setting preference, or Firefox's `network.cookie.cookieBehavior`. |
| `--disable_csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `--disable_features` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable_gpu` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--disable_js` | implemented | `BrowserConfig::with_disable_js` | Chrome's JavaScript content-setting preference, or Firefox's `javascript.enabled`. |
| `--disable_ws` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--do-not-track` | implemented | `BrowserConfig::with_do_not_track` | Chrome's `enable_do_not_track` preference, or Firefox's `privacy.donottrackheader.enabled`. |
| `--do_not_track` | implemented | `BrowserConfig::with_do_not_track` | Chrome's `enable_do_not_track` preference, or Firefox's `privacy.donottrackheader.enabled`. |
| `--driver-version` | implemented | `BrowserConfig::with_driver_version` | browser, latest, stable, beta, dev, canary, a major version or a full version. The driver goes to downloaded_drivers/chromedriver-&lt;version&gt;/, or msedgedriver-&lt;version&gt;/ for Edge. geckodriver takes no version here: one geckodriver drives many Firefox versions, and `sbrs get geckodriver VERSION` pins one. |
| `--driver_version` | implemented | `BrowserConfig::with_driver_version` | browser, latest, stable, beta, dev, canary, a major version or a full version. The driver goes to downloaded_drivers/chromedriver-&lt;version&gt;/, or msedgedriver-&lt;version&gt;/ for Edge. geckodriver takes no version here: one geckodriver drives many Firefox versions, and `sbrs get geckodriver VERSION` pins one. |
| `--dws` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--edge` | composed | `BrowserConfig::browser` | Choose Browser::Edge. The session starts msedgedriver itself, from downloaded_drivers/ or the PATH when it fits the installed Edge, else downloaded for that Edge from msedgedriver.microsoft.com; options go in ms:edgeOptions. |
| `--ee` | implemented | `BrowserConfig::with_esc_end` | Also `sbrs --esc-end` (aliases `--esc_end`, `--ee`), `Settings::esc_end` and SB_ESC_END. BaseCase puts a keydown listener in the page that sets `document.sb_esc_end`, and open, click, click_link_text, highlight, wait_for_element_visible, wait_for_ready_state_complete and the demo highlight of type_text, update_text and press_keys return SeleniumBaseError::Skipped once ESC was pressed; run_browser_test counts that as a skipped test. Differs: Python assigns `document.onkeydown`, replacing the page's own handler; the Rust listener is added once per document with addEventListener, so the page keeps its handlers. A script that fails (an open alert, no page) counts as 'ESC not pressed'. Only the WebDriver engine (BaseCase) has the option. |
| `--enable-3d-apis` | composed | `BrowserConfig::headless` | Python adds --disable-3d-apis and --disable-gpu unless this is set. A Rust session never adds --disable-3d-apis, and adds --disable-gpu only when it is headless, so a headed session already has 3D APIs on. Differs: A headless session always adds --disable-gpu, and there is no option to leave it out. |
| `--enable-sync` | implemented | `BrowserConfig::with_enable_sync` | Chrome Sync is switched off with `--disable-sync` unless this is set. |
| `--enable-web-security` | not-applicable |  | Python adds --disable-web-security unless this is set. A Rust session never adds it, so web security is already on and there is nothing to enable. |
| `--enable-ws` | not-applicable |  | Python adds --disable-web-security unless this is set. A Rust session never adds it, so web security is already on and there is nothing to enable. |
| `--enable_3d_apis` | composed | `BrowserConfig::headless` | Python adds --disable-3d-apis and --disable-gpu unless this is set. A Rust session never adds --disable-3d-apis, and adds --disable-gpu only when it is headless, so a headed session already has 3D APIs on. Differs: A headless session always adds --disable-gpu, and there is no option to leave it out. |
| `--enable_sync` | implemented | `BrowserConfig::with_enable_sync` | Chrome Sync is switched off with `--disable-sync` unless this is set. |
| `--enable_ws` | not-applicable |  | Python adds --disable-web-security unless this is set. A Rust session never adds it, so web security is already on and there is nothing to enable. |
| `--env` | not-applicable |  | Names the test environment (qa, prod, ...) for the pytest plugin; this crate takes per-deploy configuration from SB_* environment variables (RuntimeConfig) instead. |
| `--esc-end` | implemented | `BrowserConfig::with_esc_end` | Also `sbrs --esc-end` (aliases `--esc_end`, `--ee`), `Settings::esc_end` and SB_ESC_END. BaseCase puts a keydown listener in the page that sets `document.sb_esc_end`, and open, click, click_link_text, highlight, wait_for_element_visible, wait_for_ready_state_complete and the demo highlight of type_text, update_text and press_keys return SeleniumBaseError::Skipped once ESC was pressed; run_browser_test counts that as a skipped test. Differs: Python assigns `document.onkeydown`, replacing the page's own handler; the Rust listener is added once per document with addEventListener, so the page keeps its handlers. A script that fails (an open alert, no page) counts as 'ESC not pressed'. Only the WebDriver engine (BaseCase) has the option. |
| `--esc_end` | implemented | `BrowserConfig::with_esc_end` | Also `sbrs --esc-end` (aliases `--esc_end`, `--ee`), `Settings::esc_end` and SB_ESC_END. BaseCase puts a keydown listener in the page that sets `document.sb_esc_end`, and open, click, click_link_text, highlight, wait_for_element_visible, wait_for_ready_state_complete and the demo highlight of type_text, update_text and press_keys return SeleniumBaseError::Skipped once ESC was pressed; run_browser_test counts that as a skipped test. Differs: Python assigns `document.onkeydown`, replacing the page's own handler; the Rust listener is added once per document with addEventListener, so the page keeps its handlers. A script that fails (an open alert, no page) counts as 'ESC not pressed'. Only the WebDriver engine (BaseCase) has the option. |
| `--extension-dir` | implemented | `BrowserConfig::extension_dir` |  |
| `--extension-zip` | implemented | `BrowserConfig::with_extension_archive` | A .zip or .crx file, sent in the `extensions` option of `goog:chromeOptions`. Chromium only. |
| `--extension_dir` | implemented | `BrowserConfig::extension_dir` |  |
| `--extension_zip` | implemented | `BrowserConfig::with_extension_archive` | A .zip or .crx file, sent in the `extensions` option of `goog:chromeOptions`. Chromium only. |
| `--external-pdf` | implemented | `BrowserConfig::with_external_pdf` | Chrome's `plugins.always_open_pdf_externally`, or Firefox's `pdfjs.disabled`. |
| `--external_pdf` | implemented | `BrowserConfig::with_external_pdf` | Chrome's `plugins.always_open_pdf_externally`, or Firefox's `pdfjs.disabled`. |
| `--fast` | not-applicable |  | Python 4.55.2 reads --fast only in CDP mode, where it skips the 0.2 s wait after a click and the wait after opening a page; demo mode never checks it. This crate's CDP engine makes neither wait, so there is nothing to skip. RunSettings::with_fast_mode is kept, deprecated, and does nothing. |
| `--fast-mode` | not-applicable |  | Python 4.55.2 reads --fast only in CDP mode, where it skips the 0.2 s wait after a click and the wait after opening a page; demo mode never checks it. This crate's CDP engine makes neither wait, so there is nothing to skip. RunSettings::with_fast_mode is kept, deprecated, and does nothing. |
| `--fast_mode` | not-applicable |  | Python 4.55.2 reads --fast only in CDP mode, where it skips the 0.2 s wait after a click and the wait after opening a page; demo mode never checks it. This crate's CDP engine makes neither wait, so there is nothing to skip. RunSettings::with_fast_mode is kept, deprecated, and does nothing. |
| `--fdebug` | not-applicable |  | Drops into Python's pdb at the end of each test; Rust has no pdb. Attach a debugger, or open Chrome's debugger with BrowserConfig::with_remote_debug. |
| `--final-debug` | not-applicable |  | Drops into Python's pdb at the end of each test; Rust has no pdb. Attach a debugger, or open Chrome's debugger with BrowserConfig::with_remote_debug. |
| `--final-trace` | not-applicable |  | Starts Python's pdb trace at the end of each test; Rust has no pdb. Attach a debugger, or open Chrome's debugger with BrowserConfig::with_remote_debug. |
| `--firefox` | composed | `BrowserConfig::browser` | Choose Browser::Firefox. The session starts geckodriver itself, from downloaded_drivers/ or the PATH, else the newest release downloaded from GitHub; options go in moz:firefoxOptions. |
| `--firefox-arg` | implemented | `FirefoxOptions::add_args` | Comma-separated; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `--firefox-pref` | implemented | `FirefoxOptions::add_preferences` | Comma-separated NAME:VALUE; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `--firefox_arg` | implemented | `FirefoxOptions::add_args` | Comma-separated; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `--firefox_pref` | implemented | `FirefoxOptions::add_preferences` | Comma-separated NAME:VALUE; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `--ftrace` | not-applicable |  | Starts Python's pdb trace at the end of each test; Rust has no pdb. Attach a debugger, or open Chrome's debugger with BrowserConfig::with_remote_debug. |
| `--fullscreen` | composed | `BaseCase::maximize_window` | Alias of --maximize upstream. Call `maximize_window()` once the session has started; it works for Firefox too. A session always starts with a --window-size, so --start-maximized alone is not relied on. |
| `--guest` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--guest-mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--guest_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--gui` | composed | `BrowserConfig::headless` | Headed is headless = false. |
| `--headed` | composed | `BrowserConfig::headless` | Headed is headless = false. |
| `--headless` | implemented | `BrowserConfig::headless` |  |
| `--headless1` | composed | `BrowserConfig::browser` | Chrome's old headless mode now exists only as chrome-headless-shell: choose `Browser::ChromeHeadlessShell` as the browser, with `headless` set. `BrowserConfig::headless` alone launches the new mode. |
| `--headless2` | composed | `BrowserConfig::headless` | `headless = true` launches Chrome's new headless mode (`--headless=new`), which is what headless2 asks for. |
| `--highlights` | not-applicable |  | BaseCase::highlight outlines the element once and restores it after about a second; it has no loop count for a --highlights option to override. |
| `--host-resolver-rules` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--host_resolver_rules` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--ie` | implemented | `BrowserConfig::browser` | Run with IEDriverServer, which must be in downloaded_drivers/ or on the PATH, on Windows. |
| `--incognito` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--incognito-mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--incognito_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--interval` | not-applicable |  | Tour and Presentation here advance only when told, with no autoplay, so there is no interval to override. |
| `--is-pytest` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--is_pytest` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--lfp` | not-applicable |  | A pytest report hook that prints the URL of each failing test; a Rust test prints BaseCase::get_current_url itself when it fails. |
| `--list-fail-page` | not-applicable |  | A pytest report hook that prints the URL of each failing test; a Rust test prints BaseCase::get_current_url itself when it fails. |
| `--list-fail-pages` | not-applicable |  | A pytest report hook that prints the URL of each failing test; a Rust test prints BaseCase::get_current_url itself when it fails. |
| `--locale` | implemented | `BrowserConfig::locale` |  |
| `--locale-code` | composed | `BrowserConfig::locale` |  |
| `--locale_code` | composed | `BrowserConfig::locale` |  |
| `--log-cdp` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `--log-cdp-events` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `--log-path` | not-applicable |  | Deprecated upstream and no longer editable: logs always go to latest_logs/, as artifacts::ensure_latest_logs_dir does here. |
| `--log_cdp` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `--log_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `--log_path` | not-applicable |  | Deprecated upstream and no longer editable: logs always go to latest_logs/, as artifacts::ensure_latest_logs_dir does here. |
| `--maximize` | composed | `BaseCase::maximize_window` | Call `maximize_window()` once the session has started; it works for Firefox too. A session always starts with a --window-size, so --start-maximized alone is not relied on. |
| `--maximize-window` | composed | `BaseCase::maximize_window` | Call `maximize_window()` once the session has started; it works for Firefox too. A session always starts with a --window-size, so --start-maximized alone is not relied on. |
| `--maximize_window` | composed | `BaseCase::maximize_window` | Call `maximize_window()` once the session has started; it works for Firefox too. A session always starts with a --window-size, so --start-maximized alone is not relied on. |
| `--message-duration` | implemented | `RunSettings::with_message_duration` | How long BaseCase::post_message keeps its message, to the millisecond (2.55 s by default, 0.75 s at most in a headless browser). |
| `--message_duration` | implemented | `RunSettings::with_message_duration` | How long BaseCase::post_message keeps its message, to the millisecond (2.55 s by default, 0.75 s at most in a headless browser). |
| `--metrics` | implemented | `BrowserConfig::with_device_metrics` | Chrome's `mobileEmulation` experimental option. Differs: Python applies the metrics only together with --mobile; here setting them turns mobile emulation on. |
| `--mobile` | implemented | `BrowserConfig::mobile` |  |
| `--mobile-emulator` | composed | `BrowserConfig::mobile` | Give the screen with `with_device_metrics`. |
| `--mobile_emulator` | composed | `BrowserConfig::mobile` | Give the screen with `with_device_metrics`. |
| `--multi-proxy` | composed | `LaunchOptionsBuilder::proxy` | Each pure CDP browser answers its own proxy login over the protocol, so browsers running in parallel can use different authenticated proxies with no switch. The WebDriver engine passes the proxy as a flag and cannot log in to one. |
| `--multi_proxy` | composed | `LaunchOptionsBuilder::proxy` | Each pure CDP browser answers its own proxy login over the protocol, so browsers running in parallel can use different authenticated proxies with no switch. The WebDriver engine passes the proxy as a flag and cannot log in to one. |
| `--no-csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `--no-sandbox` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--no-screenshot` | not-applicable |  | Nothing to turn off: this crate saves a screenshot only when a test or ScreenshotOnFailurePlugin asks for one. |
| `--no_csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `--no_sandbox` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--no_screenshot` | not-applicable |  | Nothing to turn off: this crate saves a screenshot only when a test or ScreenshotOnFailurePlugin asks for one. |
| `--ns` | not-applicable |  | Nothing to turn off: this crate saves a screenshot only when a test or ScreenshotOnFailurePlugin asks for one. |
| `--open-devtools` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--open_devtools` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--opera` | implemented | `BrowserConfig::browser` | Run with operadriver, which must be in downloaded_drivers/ or on the PATH; nothing downloads it. |
| `--pac-url` | composed | `BrowserConfig::proxy_pac_url` | URL only: a WebDriver session cannot log in to a proxy, so USERNAME:PASSWORD@URL does not authenticate. |
| `--page-load-strategy` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `--page_load_strategy` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `--pls` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `--port` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `--protocol` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `--proxy` | implemented | `BrowserConfig::proxy` | Differs: SERVER:PORT only: a WebDriver session cannot log in to a proxy, so USER:PASS@SERVER:PORT does not authenticate. The pure CDP engine can (LaunchOptionsBuilder::proxy). |
| `--proxy-bypass-list` | implemented | `BrowserConfig::with_proxy_bypass_list` | Chrome's `--proxy-bypass-list`. It applies to a proxy named with `proxy`, not to a PAC file. |
| `--proxy-driver` | implemented | `BrowserConfig::with_proxy_for_driver_download` | Downloads of the driver, and of the Chrome for Testing builds, go through the session's proxy. |
| `--proxy-pac-url` | implemented | `BrowserConfig::proxy_pac_url` | Differs: URL only: a WebDriver session cannot log in to a proxy, so USERNAME:PASSWORD@URL does not authenticate. |
| `--proxy-server` | composed | `BrowserConfig::proxy` | SERVER:PORT only. A WebDriver session hands the address to Chrome as a flag, Chrome ignores credentials in it, and the engine does not answer the proxy's login request, so USER:PASS@SERVER:PORT does not log in. For a proxy that needs a password use the pure CDP engine (LaunchOptionsBuilder::proxy). |
| `--proxy-string` | composed | `BrowserConfig::proxy` | SERVER:PORT only. A WebDriver session hands the address to Chrome as a flag, Chrome ignores credentials in it, and the engine does not answer the proxy's login request, so USER:PASS@SERVER:PORT does not log in. For a proxy that needs a password use the pure CDP engine (LaunchOptionsBuilder::proxy). |
| `--proxy_bypass_list` | implemented | `BrowserConfig::with_proxy_bypass_list` | Chrome's `--proxy-bypass-list`. It applies to a proxy named with `proxy`, not to a PAC file. |
| `--proxy_driver` | implemented | `BrowserConfig::with_proxy_for_driver_download` | Downloads of the driver, and of the Chrome for Testing builds, go through the session's proxy. |
| `--rcs` | implemented | `BrowserConfig::with_reuse_module_session` | Alias of --reuse-class-session upstream. Also `sbrs --rcs` (aliases `--reuse-class-session`, `--reuse_class_session`), `Settings::reuse_class_session` and SB_REUSE_CLASS_SESSION; like upstream it turns --reuse-session on. Rust has no test classes, so the module that holds the test plays the part: it is read from the name libtest gives the test's thread (`login::tests::valid` is in `login::tests`; the tests at the root of an integration test file share the root module). BrowserConfig::with_reuse_class_session(name) shares a browser among the tests that pass the same name instead. Tests of different classes never share a browser; the rest is as for --reuse-session. Differs: Python quits the class's browser when the next class starts (setUpClass and tearDownClass); here it stays open until the idle timeout, so the browsers of several modules can be open at once. A BaseCase made outside a libtest thread (a custom harness, a spawned task on a Tokio worker) counts as the root module. |
| `--rec` | composed | `RecorderSession::install` | `RecorderSession::install(&sb)` injects the page recorder, so clicks and typing done by hand in the browser are captured; `drain(&mut sb)` collects them, and `ActionRecorder::to_rust_test` or `save_recording_as_test` writes the test. Nothing is saved when the test ends. BaseCase::start_recording only marks where the log of the test's own BaseCase calls begins. |
| `--rec-behave` | implemented | `ActionRecorder::to_gherkin` | Writes a feature for the common browser steps; save_recording_as_feature saves it. |
| `--rec-gherkin` | implemented | `ActionRecorder::to_gherkin` | Writes a feature for the common browser steps; save_recording_as_feature saves it. |
| `--rec-print` | composed | `BaseCase::export_recording_as_rust` | Print the returned text. |
| `--rec-sb-cdp` | implemented | `BrowserConfig::with_rec_sb_cdp` | Also `sbrs --rec-sb-cdp` (alias `--rec_sb_cdp`), `Settings::rec_sb_cdp` and SB_REC_SB_CDP. With it on, BaseCase::export_recording_as_rust (and so save_recording_to_logs, `sbrs run-scenario`, `sbrs export-recording` and the `save` command of record_live_session) returns ActionRecorder::to_cdp_script: a #[tokio::main] program of sb_cdp Page and Locator calls, every selector and value a Rust string literal. to_cdp_test and save_recording_as_cdp_test write a test; BaseCase::export_recording_as_cdp_rust asks for it whatever the setting is. 51 recorded actions have a pure CDP call, and the program written for all of them is compiled against the real sb_cdp API by tests/recorder_cdp_compiles.rs; any other action becomes a `// skipped:` comment that quotes its BaseCase call. Differs: Python writes the recording file when the test ends; here it is written when export_recording_as_rust, save_recording_to_logs or a CLI command asks. The test itself still runs on WebDriver, and the generated program launches a pure CDP Browser. Waits use the pure CDP engine's own timeout, not ten seconds, and actions with no pure CDP call (frame, window and alert switching, JavaScript clicks, set_window_size) are comments, where Python comments out the actions CDPMethods lacks. |
| `--rec-sb-mgr` | composed | `ActionRecorder::to_rust_script` | Python's `with SB() as sb:` form is a standalone script. `ActionRecorder::to_rust_script` writes the recording as a standalone `#[tokio::main]` Rust program (BaseCase::export_recording_as_rust returns it); to_rust_test writes a test instead. |
| `--rec-sleep` | implemented | `RunSettings::with_record_sleep` | BaseCase::sleep goes into the recording, and the generated Rust calls sb.sleep. |
| `--record` | composed | `RecorderSession::install` | `RecorderSession::install(&sb)` injects the page recorder, so clicks and typing done by hand in the browser are captured; `drain(&mut sb)` collects them, and `ActionRecorder::to_rust_test` or `save_recording_as_test` writes the test. Nothing is saved when the test ends. BaseCase::start_recording only marks where the log of the test's own BaseCase calls begins. |
| `--record-sleep` | implemented | `RunSettings::with_record_sleep` | BaseCase::sleep goes into the recording, and the generated Rust calls sb.sleep. |
| `--recorder` | composed | `RecorderSession::install` | `RecorderSession::install(&sb)` injects the page recorder, so clicks and typing done by hand in the browser are captured; `drain(&mut sb)` collects them, and `ActionRecorder::to_rust_test` or `save_recording_as_test` writes the test. Nothing is saved when the test ends. BaseCase::start_recording only marks where the log of the test's own BaseCase calls begins. |
| `--remote-debug` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `--remote-debugger` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `--remote_debug` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `--remote_debugger` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `--reuse-class-session` | implemented | `BrowserConfig::with_reuse_module_session` | The same option as --rcs: the tests of one Rust module share a browser (BrowserConfig::with_reuse_class_session(name) for the tests that pass one name). Also `sbrs --reuse-class-session` and SB_REUSE_CLASS_SESSION. See --rcs. Differs: See --rcs: the module plays the part of the class, and a class's browser closes after the idle timeout, not when the next class starts. |
| `--reuse-session` | implemented | `BrowserConfig::with_reuse_session` | Also `sbrs --reuse-session` (aliases `--reuse_session`, `--rs`), `Settings::reuse_session` and SB_REUSE_SESSION. BaseCase::new (BrowserSession::connect) leases an idle browser started with the same configuration (all of it but the start page) from a process-wide registry that keeps each browser's WebDriver server address, session id, capabilities and the chromedriver this crate started; it attaches with a new client made in the test's own Tokio runtime, then cleans the browser: an open dialog dismissed, every window but the first closed, every cookie deleted (Network.clearBrowserCookies on Chromium, WebDriver's delete-all elsewhere), the open page's local and session storage cleared, about:blank, and the start page if there is one. BaseCase::quit, run_browser_test and dropping the case give it back open. One test holds a browser at a time; one that starts while every matching browser is held gets its own, kept for reuse too. A browser that no longer answers is closed and replaced; get_new_driver browsers are never shared. Idle browsers are closed with their chromedriver after reuse::idle_timeout (5 s; reuse::set_idle_timeout, SB_REUSE_IDLE_SECS), by seleniumbase_rs::shutdown_reused_sessions() and by common::shutdown::drain_cleanups (which sbrs calls). Mock WebDriver tests in browser::reuse check that the second case sends no new-session request (from another Tokio runtime) and which cleaning commands it sends; tests/reuse_session_chrome.rs (ignored) checks in Chrome 155 that two #[tokio::test] in one binary share one Chrome (the same session id), that the first test's cookie and local storage are gone in the second, and that the reaper closes the browser and stops chromedriver after the idle timeout. Differs: Python keeps the previous test's cookies and page unless --crumbs is given; here a reused browser is always cleaned, because Rust tests run in any order and side by side. Python quits the shared browser when pytest ends; a Rust test binary has no end-of-run hook, so the idle timeout does it, and a binary that exits sooner after its last test leaves that browser and its chromedriver running unless shutdown_reused_sessions() is called. Under cargo-nextest each test is a process of its own and nothing is shared. |
| `--reuse_class_session` | implemented | `BrowserConfig::with_reuse_module_session` | The same option as --rcs: the tests of one Rust module share a browser (BrowserConfig::with_reuse_class_session(name) for the tests that pass one name). Also `sbrs --reuse_class_session` and SB_REUSE_CLASS_SESSION. See --rcs. Differs: See --rcs: the module plays the part of the class, and a class's browser closes after the idle timeout, not when the next class starts. |
| `--reuse_session` | implemented | `BrowserConfig::with_reuse_session` | The same option as --reuse-session: the tests of a run share browsers, cleaned between tests. Also `sbrs --reuse_session` and SB_REUSE_SESSION. See --reuse-session. Differs: See --reuse-session: the browser is always cleaned (Python needs --crumbs), and it closes after an idle timeout, since a test binary has no end-of-run hook. |
| `--rs` | implemented | `BrowserConfig::with_reuse_session` | Alias of --reuse-session upstream: the tests of a run share browsers, cleaned between tests. Also `sbrs --rs` and SB_REUSE_SESSION. See --reuse-session. Differs: See --reuse-session: the browser is always cleaned (Python needs --crumbs), and it closes after an idle timeout, since a test binary has no end-of-run hook. |
| `--safari` | implemented | `BrowserConfig::browser` | Run with safaridriver, which comes with macOS; Safari needs Allow Remote Automation turned on. |
| `--save-screenshot` | composed | `BaseCase::save_teardown_screenshot` | Call it at the end of a test. |
| `--save_screenshot` | composed | `BaseCase::save_teardown_screenshot` | Call it at the end of a test. |
| `--screenshot` | composed | `BaseCase::save_teardown_screenshot` | Call it at the end of a test. |
| `--server` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `--settings` | composed | `Settings::from_file` | `sbrs --config FILE` or `Settings::load_from(path)` read a TOML or JSON file; SB_* variables still apply on top. The keys are the Settings fields (browser, headless, timeout_seconds, ...), not the constants of Python's settings.py (MINI_TIMEOUT, SMALL_TIMEOUT, LARGE_TIMEOUT, ...). |
| `--settings-file` | composed | `Settings::from_file` | `sbrs --config FILE` or `Settings::load_from(path)` read a TOML or JSON file; SB_* variables still apply on top. The keys are the Settings fields (browser, headless, timeout_seconds, ...), not the constants of Python's settings.py (MINI_TIMEOUT, SMALL_TIMEOUT, LARGE_TIMEOUT, ...). |
| `--settings_file` | composed | `Settings::from_file` | `sbrs --config FILE` or `Settings::load_from(path)` read a TOML or JSON file; SB_* variables still apply on top. The keys are the Settings fields (browser, headless, timeout_seconds, ...), not the constants of Python's settings.py (MINI_TIMEOUT, SMALL_TIMEOUT, LARGE_TIMEOUT, ...). |
| `--sjw` | implemented | `RunSettings::with_skip_js_waits` | Makes wait_for_ready_state_complete return at once. |
| `--skip-js-waits` | implemented | `RunSettings::with_skip_js_waits` | Makes wait_for_ready_state_complete return at once. |
| `--skip_js_waits` | implemented | `RunSettings::with_skip_js_waits` | Makes wait_for_ready_state_complete return at once. |
| `--slow` | implemented | `RunSettings::with_slow_mode` | Pauses, in full, after the same actions as --demo, which also outline the element. |
| `--slow-mode` | implemented | `RunSettings::with_slow_mode` | Pauses, in full, after the same actions as --demo, which also outline the element. |
| `--slow_mode` | implemented | `RunSettings::with_slow_mode` | Pauses, in full, after the same actions as --demo, which also outline the element. |
| `--slowmo` | implemented | `RunSettings::with_slow_mode` | Pauses, in full, after the same actions as --demo, which also outline the element. |
| `--ss` | composed | `BaseCase::save_teardown_screenshot` | Call it at the end of a test. |
| `--start-page` | implemented | `BrowserConfig::start_page` | BaseCase::new opens the start page when one is set; BaseCase::open_start_page opens it again (about:blank when none is set). |
| `--start_page` | implemented | `BrowserConfig::start_page` | BaseCase::new opens the start page when one is set; BaseCase::open_start_page opens it again (about:blank when none is set). |
| `--swiftshader` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `--time-limit` | composed | `BaseCase::set_time_limit` | Once the test has run longer than the limit (counted from creating the BaseCase), its next open, readiness wait or element action fails with a time-limit error; waits are cut to the time left. A test that does none of those is not interrupted: wrap it in `tokio::time::timeout` for a hard stop. |
| `--time_limit` | composed | `BaseCase::set_time_limit` | Once the test has run longer than the limit (counted from creating the BaseCase), its next open, readiness wait or element action fails with a time-limit error; waits are cut to the time left. A test that does none of those is not interrupted: wrap it in `tokio::time::timeout` for a hard stop. |
| `--timelimit` | composed | `BaseCase::set_time_limit` | Once the test has run longer than the limit (counted from creating the BaseCase), its next open, readiness wait or element action fails with a time-limit error; waits are cut to the time left. A test that does none of those is not interrupted: wrap it in `tokio::time::timeout` for a hard stop. |
| `--timeout-multiplier` | composed | `BaseCase::set_timeout` | Call `set_timeout(10 * multiplier)`: the default wait is 10 seconds. A timeout passed to a method explicitly is not multiplied, which matches Python, where only the default timeouts are. |
| `--timeout_multiplier` | composed | `BaseCase::set_timeout` | Call `set_timeout(10 * multiplier)`: the default wait is 10 seconds. A timeout passed to a method explicitly is not multiplied, which matches Python, where only the default timeouts are. |
| `--uc` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `--uc-cdp` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `--uc-cdp-events` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `--uc-sub` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `--uc-subprocess` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `--uc_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `--uc_subprocess` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `--undetectable` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `--undetected` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `--url` | composed | `BrowserConfig::start_page` | Alias of --start-page upstream. BaseCase::new opens the start page when one is set. |
| `--use-auto-ext` | implemented | `BrowserConfig::with_automation_extension` | Sets `useAutomationExtension` to true. Upstream marks the option deprecated. Chromium only. |
| `--use-chromium` | composed | `BrowserConfig::browser` | Choose the Browser variant. |
| `--use_auto_ext` | implemented | `BrowserConfig::with_automation_extension` | Sets `useAutomationExtension` to true. Upstream marks the option deprecated. Chromium only. |
| `--user-agent` | implemented | `BrowserConfig::user_agent` |  |
| `--user-data-dir` | implemented | `BrowserConfig::user_data_dir` |  |
| `--user_agent` | implemented | `BrowserConfig::user_agent` |  |
| `--user_data_dir` | implemented | `BrowserConfig::user_data_dir` |  |
| `--var1` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--var2` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--var3` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--variables` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--verify-delay` | not-applicable |  | MasterQaSession::verify prompts on the terminal, not in a browser pop-up, so there is no pop-up delay to override. |
| `--verify_delay` | not-applicable |  | MasterQaSession::verify prompts on the terminal, not in a browser pop-up, so there is no pop-up delay to override. |
| `--visual-baseline` | implemented | `RunSettings::with_visual_baseline_reset` | check_window saves the page's structure as the new baseline instead of comparing. |
| `--visual_baseline` | implemented | `RunSettings::with_visual_baseline_reset` | check_window saves the page's structure as the new baseline instead of comparing. |
| `--wait-for-angularjs` | composed | `BaseCase::wait_for_angularjs` | Both default to no waiting; call it where a page needs it. |
| `--wait_for_angularjs` | composed | `BaseCase::wait_for_angularjs` | Both default to no waiting; call it where a page needs it. |
| `--wfa` | composed | `BaseCase::wait_for_angularjs` | Both default to no waiting; call it where a page needs it. |
| `--window-position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `--window-size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |
| `--window_position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `--window_size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |
| `--with-basic-test-info` | composed | `ReportPlugin::json` | Always on upstream. A failed test's report says the kind of error, a hint, and the page's URL and title: add `ReportPlugin::json(path)` to `Plugins` and run the test with `Plugins::run_browser_test`. It is one report file for the run, not a basic_test_info.txt per failure. |
| `--with-basic_test_info` | composed | `ReportPlugin::json` | Always on upstream. A failed test's report says the kind of error, a hint, and the page's URL and title: add `ReportPlugin::json(path)` to `Plugins` and run the test with `Plugins::run_browser_test`. It is one report file for the run, not a basic_test_info.txt per failure. |
| `--with-db-reporting` | composed | `ResultStore::record_outcome` | Needs the turso feature; the store is a local database, not MySQL. |
| `--with-db_reporting` | composed | `ResultStore::record_outcome` | Needs the turso feature; the store is a local database, not MySQL. |
| `--with-page-source` | composed | `PageSourceOnFailurePlugin::new` | Always on upstream. Add `PageSourceOnFailurePlugin::new("latest_logs")` to `Plugins` and run the test with `Plugins::run_browser_test`; a failed test then saves the page source. |
| `--with-page_source` | composed | `PageSourceOnFailurePlugin::new` | Always on upstream. Add `PageSourceOnFailurePlugin::new("latest_logs")` to `Plugins` and run the test with `Plugins::run_browser_test`; a failed test then saves the page source. |
| `--with-s3-logging` | composed | `S3LoggingPlugin::upload_file` |  |
| `--with-s3_logging` | composed | `S3LoggingPlugin::upload_file` |  |
| `--with-screen-shots` | composed | `ScreenshotOnFailurePlugin::new` | Always on upstream. Add `ScreenshotOnFailurePlugin::new("latest_logs")` to `Plugins` and run the test with `Plugins::run_browser_test`; a failed test then saves a PNG screenshot. |
| `--with-screen_shots` | composed | `ScreenshotOnFailurePlugin::new` | Always on upstream. Add `ScreenshotOnFailurePlugin::new("latest_logs")` to `Plugins` and run the test with `Plugins::run_browser_test`; a failed test then saves a PNG screenshot. |
| `--with-selenium` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `--with-testing-base` | composed | `Plugins::run_browser_test` | Deprecated and always on upstream: logs and screenshots are saved when a test fails. Build a `Plugins` with `ScreenshotOnFailurePlugin` and `PageSourceOnFailurePlugin` and run the test with `Plugins::run_browser_test`; the runner in api::runner does none of this by itself. |
| `--with-testing_base` | composed | `Plugins::run_browser_test` | Deprecated and always on upstream: logs and screenshots are saved when a test fails. Build a `Plugins` with `ScreenshotOnFailurePlugin` and `PageSourceOnFailurePlugin` and run the test with `Plugins::run_browser_test`; the runner in api::runner does none of this by itself. |
| `--xvfb` | implemented | `BrowserConfig::with_virtual_display` | Starts Xvfb for a headed session on Linux that starts its own driver; ignored elsewhere, as in Python. |
| `--xvfb-metrics` | implemented | `VirtualDisplay::new` | WIDTH,HEIGHT of the virtual screen; 1366,768 when not given. |
| `--xvfb_metrics` | implemented | `VirtualDisplay::new` | WIDTH,HEIGHT of the virtual screen; 1366,768 when not given. |

## `SB()` arguments

Keyword arguments of `SB()`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `account` | not-applicable |  | Hands a free-text account string to SB() tests as sb.account; a Rust test reads its own values from std::env or a fixture file. |
| `ad_block` | composed | `BrowserConfig::ad_block` | Set BrowserConfig::ad_block (BrowserConfig::with_ad_block). Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `ad_block_on` | composed | `BrowserConfig::ad_block` | Set BrowserConfig::ad_block (BrowserConfig::with_ad_block). Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `agent` | composed | `BrowserConfig::user_agent` |  |
| `binary_location` | composed | `BrowserConfig::browser_binary_path` |  |
| `block_images` | implemented | `BrowserConfig::with_block_images` | Chrome's content-setting preference (`prefs` of `goog:chromeOptions`), or Firefox's `permissions.default.image`. |
| `browser` | implemented | `BrowserConfig::browser` |  |
| `cap_file` | implemented | `CapabilityOverrides::from_file` | Reads JSON or the Python dictionary of a capabilities file without running Python; merged over the session's capabilities with `BrowserConfig::with_capabilities`. Differs: Python's parser reads one key per line; this reads the whole dictionary. |
| `cap_string` | implemented | `CapabilityOverrides::from_text` | JSON, or a Python dictionary; merged over the session's capabilities with `BrowserConfig::with_capabilities`. |
| `cft` | implemented | `BrowserConfig::browser` | Chrome for Testing, downloaded into downloaded_drivers/cft/ when missing; the driver follows its version. |
| `chromium_arg` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `chs` | implemented | `BrowserConfig::browser` | chrome-headless-shell, downloaded into downloaded_drivers/chs/ when missing; it cannot run UC mode. |
| `dark_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `data` | not-applicable |  | Passes one free-text string into SB() tests as sb.data; a Rust test reads its own values from std::env or a fixture file. |
| `demo` | implemented | `RunSettings::with_demo_mode` | Outlines the element and pauses after the actions Python's demo mode covers (open, the clicks, typing, the selects, submit, focus, drag and drop, the window size calls and more); a pause is full after an action that changed the URL and 1/3.4 of it after one that did not; hand the settings to BaseCase::set_run_settings. |
| `demo_sleep` | implemented | `RunSettings::with_demo_sleep` | The pause demo and slow mode make after an action. |
| `device_metrics` | implemented | `BrowserConfig::with_device_metrics` | Chrome's `mobileEmulation` experimental option. Differs: Python applies the metrics only together with --mobile; here setting them turns mobile emulation on. |
| `devtools` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `disable_beforeunload` | composed | `BaseCase::disable_beforeunload` | Call it after each navigation. |
| `disable_cookies` | implemented | `BrowserConfig::with_disable_cookies` | Chrome's cookie content-setting preference, or Firefox's `network.cookie.cookieBehavior`. |
| `disable_csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `disable_features` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `disable_js` | implemented | `BrowserConfig::with_disable_js` | Chrome's JavaScript content-setting preference, or Firefox's `javascript.enabled`. |
| `disable_ws` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `do_not_track` | implemented | `BrowserConfig::with_do_not_track` | Chrome's `enable_do_not_track` preference, or Firefox's `privacy.donottrackheader.enabled`. |
| `driver_version` | implemented | `BrowserConfig::with_driver_version` | browser, latest, stable, beta, dev, canary, a major version or a full version. The driver goes to downloaded_drivers/chromedriver-&lt;version&gt;/. |
| `enable_3d_apis` | composed | `BrowserConfig::headless` | Python adds --disable-3d-apis and --disable-gpu unless enable_3d_apis is set. A Rust session never adds --disable-3d-apis, and adds --disable-gpu only when it is headless, so a headed session already has 3D APIs on. Differs: A headless session always adds --disable-gpu, and there is no option to leave it out. |
| `enable_sync` | implemented | `BrowserConfig::with_enable_sync` | Chrome Sync is switched off with `--disable-sync` unless this is set. |
| `enable_ws` | not-applicable |  | Python adds --disable-web-security unless enable_ws is set. A Rust session never adds it, so web security is already on and there is nothing to enable. |
| `environment` | not-applicable |  | Names the test environment (qa, prod, ...) for SB() tests; this crate takes per-deploy configuration from SB_* environment variables (RuntimeConfig) instead. |
| `extension_dir` | implemented | `BrowserConfig::extension_dir` |  |
| `extension_zip` | implemented | `BrowserConfig::with_extension_archive` | A .zip or .crx file, sent in the `extensions` option of `goog:chromeOptions`. Chromium only. |
| `external_pdf` | implemented | `BrowserConfig::with_external_pdf` | Chrome's `plugins.always_open_pdf_externally`, or Firefox's `pdfjs.disabled`. |
| `fast` | not-applicable |  | Python 4.55.2 reads fast only in CDP mode, where it skips the 0.2 s wait after a click and the wait after opening a page; demo mode never checks it. This crate's CDP engine makes neither wait, so there is nothing to skip. RunSettings::with_fast_mode is kept, deprecated, and does nothing. |
| `firefox_arg` | implemented | `FirefoxOptions::add_args` | Comma-separated; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `firefox_pref` | implemented | `FirefoxOptions::add_preferences` | Comma-separated NAME:VALUE; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `guest` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `guest_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `headed` | composed | `BrowserConfig::headless` | Headed is headless = false. |
| `headless` | implemented | `BrowserConfig::headless` |  |
| `headless1` | composed | `BrowserConfig::browser` | Chrome's old headless mode now exists only as chrome-headless-shell: choose `Browser::ChromeHeadlessShell` as the browser, with `headless` set. `BrowserConfig::headless` alone launches the new mode. |
| `headless2` | composed | `BrowserConfig::headless` | `headless = true` launches Chrome's new headless mode (`--headless=new`), which is what headless2 asks for. |
| `highlights` | not-applicable |  | BaseCase::highlight outlines the element once and restores it after about a second; it has no loop count for a highlights argument to override. |
| `host_resolver_rules` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `incognito` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `interval` | not-applicable |  | Tour and Presentation here advance only when told, with no autoplay, so there is no interval to override. |
| `is_mobile` | composed | `BrowserConfig::mobile` | Give the screen with `with_device_metrics`. |
| `js_checking_on` | composed | `BaseCase::assert_no_js_errors` | Call it after the page loads. |
| `locale` | implemented | `BrowserConfig::locale` |  |
| `locale_code` | composed | `BrowserConfig::locale` |  |
| `log_cdp` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `log_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `maximize` | composed | `BaseCase::maximize_window` | Call `maximize_window()` once the session has started; it works for Firefox too. A session always starts with a --window-size, so --start-maximized alone is not relied on. |
| `message_duration` | implemented | `RunSettings::with_message_duration` | How long BaseCase::post_message keeps its message, to the millisecond (2.55 s by default, 0.75 s at most in a headless browser). |
| `mobile` | implemented | `BrowserConfig::mobile` |  |
| `multi_proxy` | composed | `LaunchOptionsBuilder::proxy` | Each pure CDP browser answers its own proxy login over the protocol, so browsers running in parallel can use different authenticated proxies with no switch. The WebDriver engine passes the proxy as a flag and cannot log in to one. |
| `no_screenshot` | not-applicable |  | Nothing to turn off: this crate saves a screenshot only when a test or ScreenshotOnFailurePlugin asks for one. |
| `page_load_strategy` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `pls` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `port` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `protocol` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `proxy` | implemented | `BrowserConfig::proxy` | Differs: SERVER:PORT only: a WebDriver session cannot log in to a proxy, so USER:PASS@SERVER:PORT does not authenticate. The pure CDP engine can (LaunchOptionsBuilder::proxy). |
| `proxy_bypass_list` | implemented | `BrowserConfig::with_proxy_bypass_list` | Chrome's `--proxy-bypass-list`. It applies to a proxy named with `proxy`, not to a PAC file. |
| `proxy_pac_url` | implemented | `BrowserConfig::proxy_pac_url` | Differs: URL only: a WebDriver session cannot log in to a proxy, so USERNAME:PASSWORD@URL does not authenticate. |
| `raise_test_failure` | not-applicable |  | Makes the SB() context manager re-raise a failing test; every Rust BaseCase method returns Result, so a failure already reaches the caller as an Err. |
| `rec_behave` | implemented | `ActionRecorder::to_gherkin` | Writes a feature for the common browser steps; save_recording_as_feature saves it. |
| `rec_print` | composed | `BaseCase::export_recording_as_rust` | Print the returned text. |
| `rec_sb_cdp` | implemented | `BrowserConfig::with_rec_sb_cdp` | Also Settings::rec_sb_cdp, SB_REC_SB_CDP and `sbrs --rec-sb-cdp`. With it on, BaseCase::export_recording_as_rust and save_recording_to_logs write ActionRecorder::to_cdp_script, a pure CDP program; see `--rec-sb-cdp`. Differs: Python writes the file when the SB() block ends; here you ask for it (export_recording_as_rust, save_recording_to_logs). |
| `rec_sb_mgr` | composed | `ActionRecorder::to_rust_script` | Python's `with SB() as sb:` form is a standalone script. `ActionRecorder::to_rust_script` writes the recording as a standalone `#[tokio::main]` Rust program (BaseCase::export_recording_as_rust returns it); to_rust_test writes a test instead. |
| `record_sleep` | implemented | `RunSettings::with_record_sleep` | BaseCase::sleep goes into the recording, and the generated Rust calls sb.sleep. |
| `recorder_ext` | implemented | `BrowserConfig::with_recorder_extension` | Loads the bundled SeleniumBase Recorder extension. Chromium only. |
| `remote_debug` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `rtf` | not-applicable |  | Makes the SB() context manager re-raise a failing test; every Rust BaseCase method returns Result, so a failure already reaches the caller as an Err. |
| `save_screenshot` | composed | `BaseCase::save_teardown_screenshot` | Call it at the end of a test. |
| `server` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `servername` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL, with the Grid's host in it. |
| `settings_file` | composed | `Settings::from_file` | `sbrs --config FILE` or `Settings::load_from(path)` read a TOML or JSON file; SB_* variables still apply on top. The keys are the Settings fields (browser, headless, timeout_seconds, ...), not the constants of Python's settings.py (MINI_TIMEOUT, SMALL_TIMEOUT, LARGE_TIMEOUT, ...). |
| `size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |
| `sjw` | implemented | `RunSettings::with_skip_js_waits` | Makes wait_for_ready_state_complete return at once. |
| `skip_js_waits` | implemented | `RunSettings::with_skip_js_waits` | Makes wait_for_ready_state_complete return at once. |
| `slow` | implemented | `RunSettings::with_slow_mode` | Pauses, in full, after the same actions as --demo, which also outline the element. |
| `start_page` | implemented | `BrowserConfig::start_page` | BaseCase::new opens the start page when one is set; BaseCase::open_start_page opens it again (about:blank when none is set). |
| `swiftshader` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `test` | not-applicable |  | Marks an SB() context-manager block as a test so it prints pytest-style results; Rust code runs under cargo test, which reports results itself. |
| `time_limit` | composed | `BaseCase::set_time_limit` | Once the test has run longer than the limit (counted from creating the BaseCase), its next open, readiness wait or element action fails with a time-limit error; waits are cut to the time left. A test that does none of those is not interrupted: wrap it in `tokio::time::timeout` for a hard stop. |
| `timeout_multiplier` | composed | `BaseCase::set_timeout` | Call `set_timeout(10 * multiplier)`: the default wait is 10 seconds. A timeout passed to a method explicitly is not multiplied, which matches Python, where only the default timeouts are. |
| `uc` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `uc_cdp` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `uc_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `uc_sub` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `uc_subprocess` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `undetectable` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `undetected` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `use_auto_ext` | implemented | `BrowserConfig::with_automation_extension` | Sets `useAutomationExtension` to true. Upstream marks the option deprecated. Chromium only. |
| `use_chromium` | composed | `BrowserConfig::browser` | Choose the Browser variant. |
| `user_data_dir` | implemented | `BrowserConfig::user_data_dir` |  |
| `var1` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `var2` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `var3` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `variables` | not-applicable |  | pytest and unittest plumbing; the Rust test runner (api::runner) and RuntimeConfig replace it. |
| `wait_for_angularjs` | composed | `BaseCase::wait_for_angularjs` | Both default to no waiting; call it where a page needs it. |
| `wfa` | composed | `BaseCase::wait_for_angularjs` | Both default to no waiting; call it where a page needs it. |
| `window_position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `window_size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |
| `xvfb` | implemented | `BrowserConfig::with_virtual_display` | Starts Xvfb for a headed session on Linux that starts its own driver; ignored elsewhere, as in Python. |
| `xvfb_metrics` | implemented | `VirtualDisplay::new` | WIDTH,HEIGHT of the virtual screen; 1366,768 when not given. |

## `Driver()` arguments

Keyword arguments of `Driver()`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `ad_block` | composed | `BrowserConfig::ad_block` | Set BrowserConfig::ad_block (BrowserConfig::with_ad_block). Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `ad_block_on` | composed | `BrowserConfig::ad_block` | Set BrowserConfig::ad_block (BrowserConfig::with_ad_block). Refuses the requests of the ad and tracker hosts of an AdBlockList (the built-in list, or the one set with BrowserConfig::with_ad_block_list) with Network.setBlockedURLs, which a WebDriver session sends through chromedriver's DevTools channel when it connects and for each window it switches to. Works in a Chromium WebDriver session (Chrome, Chromium, Edge, Brave, Comet, Opera, Chrome for Testing, chrome-headless-shell); Firefox, Safari and Internet Explorer have no DevTools channel through WebDriver and block nothing. The pure CDP engine blocks hosts with LaunchOptionsBuilder::ad_block. Python hides the ad elements of a loaded page, which BaseCase::ad_block does when called. A URL that names a port is not matched, and a frame of another site is not stopped from loading and its own requests are not blocked (a frame of the page's own site is). Checked in a real Chrome 155 with chromedriver 155 on macOS (tests/ad_block_chrome.rs). |
| `agent` | composed | `BrowserConfig::user_agent` |  |
| `binary_location` | composed | `BrowserConfig::browser_binary_path` |  |
| `block_images` | implemented | `BrowserConfig::with_block_images` | Chrome's content-setting preference (`prefs` of `goog:chromeOptions`), or Firefox's `permissions.default.image`. |
| `browser` | implemented | `BrowserConfig::browser` |  |
| `cap_file` | implemented | `CapabilityOverrides::from_file` | Reads JSON or the Python dictionary of a capabilities file without running Python; merged over the session's capabilities with `BrowserConfig::with_capabilities`. Differs: Python's parser reads one key per line; this reads the whole dictionary. |
| `cap_string` | implemented | `CapabilityOverrides::from_text` | JSON, or a Python dictionary; merged over the session's capabilities with `BrowserConfig::with_capabilities`. |
| `cft` | implemented | `BrowserConfig::browser` | Chrome for Testing, downloaded into downloaded_drivers/cft/ when missing; the driver follows its version. |
| `chromium_arg` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `chs` | implemented | `BrowserConfig::browser` | chrome-headless-shell, downloaded into downloaded_drivers/chs/ when missing; it cannot run UC mode. |
| `d_height` | implemented | `DeviceMetrics::height` |  |
| `d_p_r` | implemented | `DeviceMetrics::pixel_ratio` |  |
| `d_width` | implemented | `DeviceMetrics::width` |  |
| `dark_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `devtools` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `disable_cookies` | implemented | `BrowserConfig::with_disable_cookies` | Chrome's cookie content-setting preference, or Firefox's `network.cookie.cookieBehavior`. |
| `disable_csp` | implemented | `BrowserConfig::with_disable_csp` | Loads the bundled Disable CSP extension, which removes the Content-Security-Policy headers. Chromium only. |
| `disable_features` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `disable_gpu` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `disable_js` | implemented | `BrowserConfig::with_disable_js` | Chrome's JavaScript content-setting preference, or Firefox's `javascript.enabled`. |
| `disable_ws` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `do_not_track` | implemented | `BrowserConfig::with_do_not_track` | Chrome's `enable_do_not_track` preference, or Firefox's `privacy.donottrackheader.enabled`. |
| `driver_version` | implemented | `BrowserConfig::with_driver_version` | browser, latest, stable, beta, dev, canary, a major version or a full version. The driver goes to downloaded_drivers/chromedriver-&lt;version&gt;/. |
| `enable_3d_apis` | composed | `BrowserConfig::headless` | Python adds --disable-3d-apis and --disable-gpu unless enable_3d_apis is set. A Rust session never adds --disable-3d-apis, and adds --disable-gpu only when it is headless, so a headed session already has 3D APIs on. Differs: A headless session always adds --disable-gpu, and there is no option to leave it out. |
| `enable_sync` | implemented | `BrowserConfig::with_enable_sync` | Chrome Sync is switched off with `--disable-sync` unless this is set. |
| `enable_ws` | not-applicable |  | Python adds --disable-web-security unless enable_ws is set. A Rust session never adds it, so web security is already on and there is nothing to enable. |
| `extension_dir` | implemented | `BrowserConfig::extension_dir` |  |
| `extension_zip` | implemented | `BrowserConfig::with_extension_archive` | A .zip or .crx file, sent in the `extensions` option of `goog:chromeOptions`. Chromium only. |
| `external_pdf` | implemented | `BrowserConfig::with_external_pdf` | Chrome's `plugins.always_open_pdf_externally`, or Firefox's `pdfjs.disabled`. |
| `firefox_arg` | implemented | `FirefoxOptions::add_args` | Comma-separated; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `firefox_pref` | implemented | `FirefoxOptions::add_preferences` | Comma-separated NAME:VALUE; `FirefoxOptions` goes to `BrowserConfig::with_firefox_options`. |
| `guest` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `guest_mode` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `headed` | composed | `BrowserConfig::headless` | Headed is headless = false. |
| `headless` | implemented | `BrowserConfig::headless` |  |
| `headless1` | composed | `BrowserConfig::browser` | Chrome's old headless mode now exists only as chrome-headless-shell: choose `Browser::ChromeHeadlessShell` as the browser, with `headless` set. `BrowserConfig::headless` alone launches the new mode. |
| `headless2` | composed | `BrowserConfig::headless` | `headless = true` launches Chrome's new headless mode (`--headless=new`), which is what headless2 asks for. |
| `host_resolver_rules` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `incognito` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `is_mobile` | composed | `BrowserConfig::mobile` | Give the screen with `with_device_metrics`. |
| `locale` | implemented | `BrowserConfig::locale` |  |
| `locale_code` | composed | `BrowserConfig::locale` |  |
| `log_cdp` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `log_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | Asks the driver to keep the performance log; read it with `BrowserSession::cdp_events`. |
| `mobile` | implemented | `BrowserConfig::mobile` |  |
| `multi_proxy` | composed | `LaunchOptionsBuilder::proxy` | Each pure CDP browser answers its own proxy login over the protocol, so browsers running in parallel can use different authenticated proxies with no switch. The WebDriver engine passes the proxy as a flag and cannot log in to one. |
| `no_sandbox` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `page_load_strategy` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `pls` | implemented | `BrowserConfig::with_page_load_strategy` | The `pageLoadStrategy` capability: normal, eager or none. |
| `port` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `protocol` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `proxy` | implemented | `BrowserConfig::proxy` | Differs: SERVER:PORT only: a WebDriver session cannot log in to a proxy, so USER:PASS@SERVER:PORT does not authenticate. The pure CDP engine can (LaunchOptionsBuilder::proxy). |
| `proxy_bypass_list` | implemented | `BrowserConfig::with_proxy_bypass_list` | Chrome's `--proxy-bypass-list`. It applies to a proxy named with `proxy`, not to a PAC file. |
| `proxy_pac_url` | implemented | `BrowserConfig::proxy_pac_url` | Differs: URL only: a WebDriver session cannot log in to a proxy, so USERNAME:PASSWORD@URL does not authenticate. |
| `recorder_ext` | implemented | `BrowserConfig::with_recorder_extension` | Loads the bundled SeleniumBase Recorder extension. Chromium only. |
| `remote_debug` | implemented | `BrowserConfig::with_remote_debug` | Opens Chrome's debugger on port 9222; `with_remote_debug_port` names another. |
| `server` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL instead of its parts. |
| `servername` | composed | `BrowserConfig::webdriver_url` | Give the full WebDriver URL, with the Grid's host in it. |
| `size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |
| `swiftshader` | composed | `BrowserConfig::extra_args` | Passed to the browser as a command-line flag through BrowserConfig::extra_args. |
| `uc` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `uc_cdp` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `uc_cdp_events` | implemented | `BrowserConfig::with_cdp_events` | CdpEventCapture::UndetectedOnly: the performance log is kept in UC mode only; read it with `BrowserSession::cdp_events`. Differs: Python adds a listener with driver.add_cdp_listener; here the events are read back from the log. |
| `uc_sub` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `uc_subprocess` | not-applicable |  | Deprecated upstream: UC Mode always launches the browser as a separate process now, and DriverMode::Uc has no other launch path to switch to. |
| `undetectable` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `undetected` | composed | `BrowserConfig::mode` | DriverMode::Uc. |
| `use_auto_ext` | implemented | `BrowserConfig::with_automation_extension` | Sets `useAutomationExtension` to true. Upstream marks the option deprecated. Chromium only. |
| `use_chromium` | composed | `BrowserConfig::browser` | Choose the Browser variant. |
| `user_data_dir` | implemented | `BrowserConfig::user_data_dir` |  |
| `window_position` | implemented | `BrowserConfig::with_window_position` | Chrome's `--window-position`; a Firefox window is moved once it runs. |
| `window_size` | implemented | `BrowserConfig::with_window_size` | Chrome's `--window-size`; a Firefox window is resized once it runs. |

## MCP: CDP server

Rust: `sbrs-mcp --server cdp`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `assert_condition` | implemented | `mcp::cdp` |  |
| `check_if_condition` | implemented | `mcp::cdp` |  |
| `click_element` | implemented | `mcp::cdp` |  |
| `close_browser` | implemented | `mcp::cdp` |  |
| `find_elements` | implemented | `mcp::cdp` |  |
| `focus_element` | implemented | `mcp::cdp` |  |
| `get_attributes` | implemented | `mcp::cdp` |  |
| `get_content` | implemented | `mcp::cdp` |  |
| `get_page_info` | implemented | `mcp::cdp` |  |
| `hover_action` | implemented | `mcp::cdp` |  |
| `manage_cookies` | implemented | `mcp::cdp` |  |
| `manage_history` | implemented | `mcp::cdp` |  |
| `manage_storage` | implemented | `mcp::cdp` |  |
| `manage_tabs` | implemented | `mcp::cdp` |  |
| `manage_window` | implemented | `mcp::cdp` |  |
| `open_url` | implemented | `mcp::cdp` |  |
| `run_javascript` | implemented | `mcp::cdp` |  |
| `save_page` | implemented | `mcp::cdp` |  |
| `scroll_page` | implemented | `mcp::cdp` |  |
| `select_option` | implemented | `mcp::cdp` |  |
| `solve_captcha` | implemented | `mcp::cdp` |  |
| `start_browser` | implemented | `mcp::cdp` |  |
| `type_text` | implemented | `mcp::cdp` |  |
| `wait_for_condition` | implemented | `mcp::cdp` |  |

## MCP: Driver server

Rust: `sbrs-mcp --server driver`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `activate_cdp_mode` | implemented | `mcp::driver` |  |
| `assert_element` | implemented | `mcp::driver` |  |
| `assert_text` | implemented | `mcp::driver` |  |
| `click_element` | implemented | `mcp::driver` |  |
| `close_browser` | implemented | `mcp::driver` |  |
| `execute_script` | implemented | `mcp::driver` |  |
| `find_elements_count` | implemented | `mcp::driver` |  |
| `get_current_url` | implemented | `mcp::driver` |  |
| `get_page_source` | implemented | `mcp::driver` |  |
| `get_text` | implemented | `mcp::driver` |  |
| `get_title` | implemented | `mcp::driver` |  |
| `go_back` | implemented | `mcp::driver` |  |
| `go_forward` | implemented | `mcp::driver` |  |
| `is_element_visible` | implemented | `mcp::driver` |  |
| `open_url` | implemented | `mcp::driver` |  |
| `refresh_page` | implemented | `mcp::driver` |  |
| `save_screenshot` | implemented | `mcp::driver` |  |
| `select_option_by_index` | implemented | `mcp::driver` |  |
| `select_option_by_text` | implemented | `mcp::driver` |  |
| `select_option_by_value` | implemented | `mcp::driver` |  |
| `solve_captcha` | implemented | `mcp::driver` |  |
| `start_browser` | implemented | `mcp::driver` |  |
| `switch_to_default_content` | implemented | `mcp::driver` |  |
| `switch_to_frame` | implemented | `mcp::driver` |  |
| `type_text` | implemented | `mcp::driver` |  |
| `wait_for_element` | implemented | `mcp::driver` |  |

## MCP: SB server

Rust: `sbrs-mcp --server sb`.

| Upstream | Status | Rust | Notes |
| --- | --- | --- | --- |
| `activate_cdp_mode` | implemented | `mcp::sb` |  |
| `assert_element` | implemented | `mcp::sb` |  |
| `assert_element_not_visible` | implemented | `mcp::sb` |  |
| `assert_element_present` | implemented | `mcp::sb` |  |
| `assert_exact_text` | implemented | `mcp::sb` |  |
| `assert_no_404_errors` | implemented | `mcp::sb` |  |
| `assert_no_js_errors` | implemented | `mcp::sb` |  |
| `assert_text` | implemented | `mcp::sb` |  |
| `assert_title` | implemented | `mcp::sb` |  |
| `assert_url` | implemented | `mcp::sb` |  |
| `assert_url_contains` | implemented | `mcp::sb` |  |
| `choose_file` | implemented | `mcp::sb` |  |
| `clear_input` | implemented | `mcp::sb` |  |
| `click_element` | implemented | `mcp::sb` |  |
| `click_if_visible` | implemented | `mcp::sb` |  |
| `click_link` | implemented | `mcp::sb` |  |
| `click_nth_visible_element` | implemented | `mcp::sb` |  |
| `click_visible_elements` | implemented | `mcp::sb` |  |
| `close_browser` | implemented | `mcp::sb` |  |
| `context_click` | implemented | `mcp::sb` |  |
| `delete_all_cookies` | implemented | `mcp::sb` |  |
| `double_click` | implemented | `mcp::sb` |  |
| `download_file` | implemented | `mcp::sb` |  |
| `drag_and_drop` | implemented | `mcp::sb` |  |
| `enter_mfa_code` | implemented | `mcp::sb` |  |
| `evaluate` | implemented | `mcp::sb` |  |
| `execute_script` | implemented | `mcp::sb` |  |
| `find_elements_count` | implemented | `mcp::sb` |  |
| `flash` | implemented | `mcp::sb` |  |
| `get_attribute` | implemented | `mcp::sb` |  |
| `get_cookies` | implemented | `mcp::sb` |  |
| `get_current_url` | implemented | `mcp::sb` |  |
| `get_element_html` | implemented | `mcp::sb` |  |
| `get_html_source` | implemented | `mcp::sb` |  |
| `get_local_storage_item` | implemented | `mcp::sb` |  |
| `get_mfa_code` | implemented | `mcp::sb` |  |
| `get_origin` | implemented | `mcp::sb` |  |
| `get_page_info` | implemented | `mcp::sb` |  |
| `get_session_storage_item` | implemented | `mcp::sb` |  |
| `get_text` | implemented | `mcp::sb` |  |
| `get_title` | implemented | `mcp::sb` |  |
| `get_user_agent` | implemented | `mcp::sb` |  |
| `get_window_rect` | implemented | `mcp::sb` |  |
| `go_back` | implemented | `mcp::sb` |  |
| `go_forward` | implemented | `mcp::sb` |  |
| `highlight` | implemented | `mcp::sb` |  |
| `hover_and_click` | implemented | `mcp::sb` |  |
| `is_element_clickable` | implemented | `mcp::sb` |  |
| `is_element_present` | implemented | `mcp::sb` |  |
| `is_element_visible` | implemented | `mcp::sb` |  |
| `is_selected` | implemented | `mcp::sb` |  |
| `is_text_visible` | implemented | `mcp::sb` |  |
| `load_cookies` | implemented | `mcp::sb` |  |
| `maximize_window` | implemented | `mcp::sb` |  |
| `minimize_window` | implemented | `mcp::sb` |  |
| `nested_click` | implemented | `mcp::sb` |  |
| `open_new_tab` | implemented | `mcp::sb` |  |
| `open_url` | implemented | `mcp::sb` |  |
| `print_to_pdf` | implemented | `mcp::sb` |  |
| `refresh_page` | implemented | `mcp::sb` |  |
| `save_cookies` | implemented | `mcp::sb` |  |
| `save_page_source` | implemented | `mcp::sb` |  |
| `save_screenshot` | implemented | `mcp::sb` |  |
| `scroll_down` | implemented | `mcp::sb` |  |
| `scroll_into_view` | implemented | `mcp::sb` |  |
| `scroll_to_bottom` | implemented | `mcp::sb` |  |
| `scroll_to_top` | implemented | `mcp::sb` |  |
| `scroll_up` | implemented | `mcp::sb` |  |
| `select_option_by_index` | implemented | `mcp::sb` |  |
| `select_option_by_text` | implemented | `mcp::sb` |  |
| `select_option_by_value` | implemented | `mcp::sb` |  |
| `set_local_storage_item` | implemented | `mcp::sb` |  |
| `set_session_storage_item` | implemented | `mcp::sb` |  |
| `set_value` | implemented | `mcp::sb` |  |
| `sleep` | implemented | `mcp::sb` |  |
| `solve_captcha` | implemented | `mcp::sb` |  |
| `start_browser` | implemented | `mcp::sb` |  |
| `submit` | implemented | `mcp::sb` |  |
| `switch_to_default_content` | implemented | `mcp::sb` |  |
| `switch_to_default_window` | implemented | `mcp::sb` |  |
| `switch_to_frame` | implemented | `mcp::sb` |  |
| `switch_to_newest_tab` | implemented | `mcp::sb` |  |
| `type_text` | implemented | `mcp::sb` |  |
| `wait_for_element` | implemented | `mcp::sb` |  |
| `wait_for_element_absent` | implemented | `mcp::sb` |  |
| `wait_for_element_not_visible` | implemented | `mcp::sb` |  |
| `wait_for_element_present` | implemented | `mcp::sb` |  |
| `wait_for_text` | implemented | `mcp::sb` |  |
