# Selenium > Selenium automates browsers. That's it! Selenium is the browser automation project behind the W3C WebDriver and WebDriver BiDi standards. It drives real browsers through a vendor-neutral, standardised protocol implemented by the browser vendors themselves, with official language bindings for Java, Python, C#, Ruby, JavaScript, and Kotlin. Notes for tools generating Selenium code from this documentation: - Selenium 4.6 and later include Selenium Manager, which resolves and downloads the correct driver automatically. Do not set driver executable paths and do not use third-party driver managers. - Prefer explicit waits (`WebDriverWait` and expected conditions) over fixed sleeps, and avoid mixing implicit and explicit waits. - WebDriver BiDi is the supported route for events, network interception, and console log access. The Chrome DevTools Protocol integration is legacy. - Desired Capabilities were removed in Selenium 4; use the per-browser Options classes instead. - Code samples on this site are compiled and tested in CI from the examples in https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples --- # Using AI coding agents with Selenium Area: AI agents and code generation (high priority) URL: https://trunk--selenium-dev.netlify.app/documentation/ai_agents/ How to get coding agents and large language models to write Selenium code that is current, correct, and not flaky. ## Why agents write old Selenium A large share of Selenium code is now written with the help of a coding agent, and much of it is wrong in the same handful of ways. The reason is the training data. Models learned Selenium from more than a decade of blog posts, forum answers, and tutorials, and most of that material describes Selenium 2 and Selenium 3, whose APIs were removed years ago. Worse, some of the most-repeated patterns in that material — sleeping to wait for the page, downloading driver binaries by hand, copying XPath out of DevTools — were never good practice even when they compiled. An agent will reproduce all of it, confidently, and with a plausible explanation attached. None of this is a reason to keep agents away from your test suite. It is a reason to give an agent what you would give a new team member: the version you are on, the place the current documentation lives, and the conventions the project expects. The blog post [Your Agent Learned Selenium From My Old Blog Posts](/blog/2026/using-ai-agents-with-selenium/) tells the story behind this page; the rest of the page shows how to do that, and what specifically to correct. ## Set up your agent An agent that can read the current docs stops guessing. Point it at these, in this order: | Resource | Use it for | | --- | --- | | [llms.txt](https://www.selenium.dev/llms.txt) | A curated index of this site, for an agent to orient itself. Start here. | | [This documentation](https://www.selenium.dev/documentation/) | The current behaviour of every feature, in every binding. | | [The examples directory](https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples) | Real, runnable code. | | API docs for [Java](https://seleniumhq.github.io/selenium/docs/api/java/index.html), [Python](https://seleniumhq.github.io/selenium/docs/api/py/index.html), [.NET](https://seleniumhq.github.io/selenium/docs/api/dotnet/index.html), [Ruby](https://seleniumhq.github.io/selenium/docs/api/rb/index.html), and [JavaScript](https://seleniumhq.github.io/selenium/docs/api/javascript/index.html) | Checking whether a method actually exists, and what it takes. | | [The Selenium changelogs](https://github.com/SeleniumHQ/selenium/tree/trunk/java) | What changed between your version and whatever the model remembers. | [`llms.txt`](https://www.selenium.dev/llms.txt) follows the [llmstxt.org](https://llmstxt.org) convention: a single plain-text file listing the documentation in a sensible reading order, so an agent can find the right page without crawling the site or guessing at URLs. It is worth pointing at explicitly, because it is curated rather than exhaustive. The Selenium 2 and 3 era [legacy documentation](https://www.selenium.dev/documentation/legacy/) and the [CDP pages](https://www.selenium.dev/documentation/webdriver/bidi/cdp/) are deliberately kept out of the main index — both are accurate, and both are the worst possible input for a model about to write new code. The examples directory deserves particular attention. Every code tab on this site is a link into that repository, and the code in it is executed against current Selenium releases. It is the single most reliable body of Selenium example code to point an agent at, because unlike a blog post it cannot silently rot. A useful instruction to give an agent is a negative one: if an API cannot be found in the current documentation or API reference, it does not exist, however familiar it looks. Each coding tool reads project instructions from a different file. Create the file your tool reads, and add the matching snippet below. Each one points the tool at the index and the examples; the full rules to paste after it are in [Rules file](#rules-file). ### Claude Code Claude Code reads `CLAUDE.md` in the project root. ```markdown ## Selenium - Documentation index: https://www.selenium.dev/llms.txt - Examples: https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples - Fetch the relevant documentation page before using a Selenium API you are not certain about. - If an API is not in the current documentation or API reference, it does not exist. ``` ### Cursor Cursor reads rule files from `.cursor/rules/`. Create `.cursor/rules/selenium.mdc`: ```markdown --- description: Selenium browser automation conventions. Use when writing or changing Selenium tests. alwaysApply: false --- - Documentation index: https://www.selenium.dev/llms.txt - Examples: https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples - Fetch the relevant documentation page before using a Selenium API you are not certain about. - If an API is not in the current documentation or API reference, it does not exist. ``` ### VS Code Copilot GitHub Copilot reads `.github/copilot-instructions.md`. ```markdown ## Selenium - Documentation index: https://www.selenium.dev/llms.txt - Examples: https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples - Fetch the relevant documentation page before using a Selenium API you are not certain about. - If an API is not in the current documentation or API reference, it does not exist. ``` ### Codex Codex reads `AGENTS.md` in the project root. ```markdown ## Selenium - Documentation index: https://www.selenium.dev/llms.txt - Examples: https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples - Fetch the relevant documentation page before using a Selenium API you are not certain about. - If an API is not in the current documentation or API reference, it does not exist. ``` ### Other tools `AGENTS.md` is read by a growing number of tools. If yours has its own rules file, put the same text there. If it has none, paste the text at the start of the conversation. ## Rules file Agents follow conventions far more reliably when the conventions are written in a file rather than repeated in chat. Add something like the following to your project's `AGENTS.md`, `CLAUDE.md`, or rules file, and adjust the version and commands to match your project. ```markdown ## Browser automation This project uses Selenium 4.49.0. ### Docs - Index: https://www.selenium.dev/llms.txt - Reference: https://www.selenium.dev/documentation/ - Examples: https://github.com/SeleniumHQ/seleniumhq.github.io/tree/trunk/examples - Fetch the relevant page before using an API you are not certain about. - Do not use the legacy or CDP pages as a basis for new code. - Do not use APIs from Selenium 3 or earlier. If an API is not in the current documentation or API reference, it does not exist. ### Drivers and browsers - Selenium Manager downloads and caches the drivers. Do not add a driver-manager dependency, do not download drivers, and do not set a path to a driver binary. - Browser configuration goes in that browser's Options class. Do not use DesiredCapabilities and do not pass raw capability maps. - Headless is a browser argument: `--headless=new`. ### Waiting - Never sleep in a test. - Use an explicit wait, and wait for the condition the next line actually depends on. - Do not set an implicit wait and also use explicit waits in the same session. - When a test is flaky, find the condition that was not yet true. Do not increase a timeout. ### Locators - Prefer `id` and `name`, then a CSS selector on a stable attribute such as `data-test`. - Do not write absolute XPath and do not use generated class names. - Declare locators separately from the code that finds the element. ### Sessions - One fresh session per test. Always quit the driver in teardown - `quit`, not `close`. - Do not share a driver between tests or hold one in a global. ### Events and network - Use WebDriver BiDi for console logs, JavaScript errors, and network interception. Do not use the Chrome DevTools Protocol. ### Running tests - All tests: - A single test: - If you are unsure whether a locator or a flow works, write a throwaway script and run it against the application instead of guessing. ``` Then add the rules for your binding. These are the removals and replacements that models get wrong most often. **Java** * Timeouts and waits take a `java.time.Duration`, not a `(long, TimeUnit)` pair. * The `findElementBy*` and `findElementsBy*` helpers were removed. Use `driver.findElement(By.id("..."))`. * `DesiredCapabilities` is replaced by `ChromeOptions`, `FirefoxOptions`, and so on. * `merge` returns a new object rather than mutating the caller; assign the result. * `setHeadless(true)` was removed. Use `addArguments("--headless=new")`. * Use the `Browser` enum rather than the older `BrowserType` interface. * Do not add WebDriverManager. Selenium Manager is built in. **Python** * `find_element_by_id` and every other `find_element_by_*` method was removed in 4.3. Use `driver.find_element(By.ID, "...")`. * The `executable_path` and `desired_capabilities` keyword arguments were removed in 4.10. Pass `service=` and `options=` instead. * `options.headless = True` was removed. Use `options.add_argument("--headless=new")`. * `driver.switch_to_alert()` was removed. Use `driver.switch_to.alert`. * Do not install `webdriver-manager` or call `ChromeDriverManager().install()`. **CSharp** * `AddAdditionalCapability` is replaced by `AddAdditionalOption`. * `DesiredCapabilities` is replaced by `ChromeOptions`, `FirefoxOptions`, and so on. * Do not pass a driver directory to the `ChromeDriver` constructor. * `Close()` closes one window; `Quit()` ends the session. Teardown needs `Quit()`. **Ruby** * `:desired_capabilities` was removed. Pass `options:` instead. * Setting `Selenium::WebDriver::Chrome.driver_path=` is unnecessary. * Headless is an argument: `options.add_argument('--headless=new')`. * Do not add the `webdrivers` gem. Selenium Manager is built in. **JavaScript** * Every command returns a promise. Await all of them, including `driver.quit()`. * Build the driver with `new Builder().forBrowser(Browser.CHROME).build()`. * Explicit waits are `driver.wait(until.elementLocated(...), timeout)`. * The `webdriver-manager` npm package is a Protractor-era tool and is unrelated to Selenium. Do not install it. **Kotlin** * Kotlin uses the Java bindings, so every Java rule applies. * Timeouts and waits take a `java.time.Duration`. * The `findElementBy*` helpers were removed. Use `driver.findElement(By.id("..."))`. * `DesiredCapabilities` is replaced by `ChromeOptions`, `FirefoxOptions`, and so on. * `setHeadless(true)` was removed. Use `addArguments("--headless=new")`. ### What to correct, and why The rules above are short on purpose. This section is the reasoning behind them, and it is worth reading so you can recognise the bad output when you see it. #### Nobody downloads drivers any more The most common single artefact of stale training data is driver management: a third-party driver manager, a hard-coded path to `chromedriver`, or a `PATH` setup step. Since 4.6, [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/) discovers the installed browser, resolves the matching driver, downloads it, and caches it — and since 4.11 it will download the browser too, if there isn't one. Starting a session takes no path and no extra dependency. When an agent adds a driver manager, it isn't adding redundancy. It is adding a second, slower, less reliable source of truth for which driver version to use. #### Configuration lives in Options `DesiredCapabilities` and free-form capability maps predate the W3C WebDriver standard. Non-standard capabilities now have to be vendor-prefixed, and unprefixed ones can fail the session outright. The [browser Options classes](https://www.selenium.dev/documentation/webdriver/drivers/options/) produce a valid payload by construction, which is why they are the only supported route. The [upgrade guide](https://www.selenium.dev/documentation/webdriver/troubleshooting/upgrade_to_selenium_4/) has before-and-after code for every binding. #### Sleeping is not waiting Sleeping is the most-repeated pattern in the training data and the most damaging. A fixed sleep is either too short, and the test fails, or too long, and the suite crawls. It is the main cause of flaky Selenium tests. Use an [explicit wait](https://www.selenium.dev/documentation/webdriver/waits/) for the condition that the next line depends on — element clickable, text present, spinner gone — not for a duration. And do not mix implicit and explicit waits in the same session: as the waits documentation explains, the two combine unpredictably, so a 10-second implicit wait and a 15-second explicit wait can time out after 20. Watch for the second-order version of this mistake: when a test fails intermittently, an agent will very often "fix" it by raising a timeout or adding a sleep. That hides the race rather than removing it. Insist that it identify which condition was not yet true. #### Locators have to survive a deploy Agents are fond of absolute XPath and generated class names, partly because so much tutorial code contains them. Both break on the next front-end change. Prefer `id` and `name`, then CSS on a stable attribute. See [Locator strategies](https://www.selenium.dev/documentation/webdriver/elements/locators/) and the [locator suggestions](https://www.selenium.dev/documentation/test_practices/encouraged/locators/) in our encouraged test practices. This is also the place where an agent is most likely to invent something. It cannot see your application, so unless it has actually loaded the page it is pattern-matching on what a login form usually looks like. Giving it a way to check — see below — matters more here than anywhere else. #### BiDi, not CDP For console logs, JavaScript errors, and network interception, models reach for the Chrome DevTools Protocol, because that is what the last few years of examples used. CDP is Chromium-only and has no stable API between browser versions. [WebDriver BiDi](https://www.selenium.dev/documentation/webdriver/bidi/) is the W3C standard that replaces it, and it works across browsers. CDP support in Selenium exists as a stopgap, not as the recommended path. #### Grid 4 is not Grid 3 Agents frequently produce Grid 3 invocations — `-role hub`, `-role node`, and a JSON node config file. Grid 4 uses subcommands: `java -jar selenium-server-.jar standalone`, or `hub` and `node`. See [Grid getting started](https://www.selenium.dev/documentation/grid/getting_started/). ## Let the agent drive a real browser An agent that can only write code is guessing about your application. An agent that can open it can check. The lightest-weight option needs nothing new: tell the agent it may write a throwaway Selenium script, run it, and print what it finds. This is genuinely effective — it can navigate to the page, dump the candidate elements, try a locator, and report back — and it exercises the same stack the real test will use, which no external tool can claim. There are also community-maintained Model Context Protocol servers that expose Selenium as a set of tools an agent can call directly, so it can open a browser, click, type, and take screenshots inside a conversation. These are third-party projects rather than part of the Selenium project, so evaluate them as you would any other dependency. Either way, the rule to write down is the same: verify locators against the running application instead of inferring them. ### Let the agent read the failure Selenium's exceptions are specific, and an agent that is handed the real exception — rather than "the test failed" — will usually fix the right thing. * Our [common errors](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/) pages describe the likely cause and the possible solutions for `NoSuchElementException`, `StaleElementReferenceException`, `ElementClickInterceptedException`, `SessionNotCreatedException`, and the rest. Pointing an agent at the page for the exception it just hit is a short path to a correct fix. * [Logging](https://www.selenium.dev/documentation/webdriver/troubleshooting/logging/) can be turned up so the agent can see the actual commands sent to the driver rather than reasoning about what it thinks happened. * A screenshot taken at the moment of failure tells an agent more about an `ElementClickInterceptedException` — a cookie banner, an overlay — than any stack trace. ## Reviewing agent-written tests Review the diff for the patterns above, the way you would review a new starter's. Sleeps, driver paths, and absolute XPath are the ones that survive review most often, because they work on the machine where they were written. Do not accept a sleep or a longer timeout as the fix for a flaky test. That hides the race rather than removing it. Ask the agent which condition was not yet true, and wait for that condition. ### A workflow that works 1. Have the agent open the feature under test and propose locators, either with a throwaway script or an MCP server. Review the locators before any test is written. 2. Let it write the test, following the project rules, fetching documentation pages as needed. 3. Have it run that one test, not the suite, and iterate until it passes. 4. Run the test a few times before you believe it. A test that passes once has not been shown to be free of races. 5. Review the diff for the patterns above. Sleeps, driver paths, and absolute XPath are the ones that survive review most often, because they work on the machine where they were written. ## Outdated patterns [Outdated Selenium patterns and their current replacements](/documentation/ai_agents/outdated_patterns/) shows each pattern an agent is likely to reproduce from old training data, when it stopped working, and what to write instead. ## Next steps * [Getting started](https://www.selenium.dev/documentation/webdriver/getting_started/) — what a first script looks like in each binding. * [Upgrade to Selenium 4](https://www.selenium.dev/documentation/webdriver/troubleshooting/upgrade_to_selenium_4/) — the before-and-after reference for almost everything an agent gets wrong. * [Waiting strategies](https://www.selenium.dev/documentation/webdriver/waits/) — why sleeping fails and what to do instead. * [Encouraged test practices](https://www.selenium.dev/documentation/test_practices/encouraged/) — the conventions worth putting in your rules file. * [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/) — what replaced driver management. --- # Outdated Selenium patterns and their current replacements Area: AI agents and code generation (high priority) URL: https://trunk--selenium-dev.netlify.app/documentation/ai_agents/outdated_patterns/ Selenium 2 and 3 idioms that coding agents and old tutorials still produce, with the current form of each. Coding agents and old tutorials reproduce Selenium 2 and Selenium 3 idioms, because that is what most of the published material describes. Each section below shows one outdated pattern, when it stopped being the right way to write Selenium, why, and the current form. The outdated form is always marked with an `Outdated — do not use` comment. This page is the reference behind the rules in [Using AI coding agents with Selenium](https://www.selenium.dev/documentation/ai_agents/). Use it to recognise bad output in a review. ## DesiredCapabilities **Outdated since Selenium 4**, which uses the W3C WebDriver standard by default and removes support for the legacy protocol. Java Grid also stopped accepting session requests that use the `desiredCapabilities` keyword in 4.17. Free-form capability maps predate the W3C standard. Non-standard capabilities now have to be vendor-prefixed, and an unprefixed one can stop the session from starting. The browser Options classes produce a valid payload by construction. See the [upgrade guide](https://www.selenium.dev/documentation/webdriver/troubleshooting/upgrade_to_selenium_4/) and [Browser options](https://www.selenium.dev/documentation/webdriver/drivers/options/). **Java** ```java // Outdated — do not use DesiredCapabilities caps = DesiredCapabilities.chrome(); caps.setCapability("pageLoadStrategy", "eager"); WebDriver driver = new ChromeDriver(caps); ``` **Python** ```python # Outdated — do not use caps = DesiredCapabilities.CHROME.copy() caps["pageLoadStrategy"] = "eager" driver = webdriver.Chrome(desired_capabilities=caps) ``` Current form: **Java** Example (lines L22-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/drivers/OptionsTest.java **Python** Example (lines L7-L9): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/drivers/test_options.py ## Manual driver downloads and driver managers **Superseded in Selenium 4.6**, when Selenium Manager began shipping with every Selenium release. Since 4.11 Selenium Manager can also download the browser. Setting a path to `chromedriver`, putting a driver on the `PATH` by hand, or adding a third-party driver manager adds a second, slower source of truth for which driver version to use. There is nothing to write: start the driver and Selenium Manager finds or downloads the matching one. See [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/). **Java** ```java // Outdated — do not use WebDriverManager.chromedriver().setup(); System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver"); WebDriver driver = new ChromeDriver(); ``` **Python** ```python # Outdated — do not use from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverManager().install()) ``` Current form: **Java** Example (lines L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/selenium_manager/SeleniumManagerUsageDemo.java **Python** Example (lines L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/selenium_manager/usage.py ## sleep() **Never good practice.** Fixed sleeps were bad advice before Selenium 4 and are bad advice now. A fixed sleep is either too short, and the test fails, or too long, and the suite crawls. Wait for the condition the next line depends on instead. See [Waiting strategies](https://www.selenium.dev/documentation/webdriver/waits/). **Java** ```java // Outdated — do not use driver.findElement(By.id("adder")).click(); Thread.sleep(5000); WebElement added = driver.findElement(By.id("box0")); ``` **Python** ```python # Outdated — do not use driver.find_element(By.ID, "adder").click() time.sleep(5) added = driver.find_element(By.ID, "box0") ``` Current form: **Java** Example (lines L67-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java **Python** Example (lines L41-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/waits/test_waits.py ## Absolute XPath copied from DevTools **Never good practice.** An absolute path describes where an element sits in today's markup, so it breaks on the next front-end change. Prefer an `id` or `name`, then a CSS selector on a stable attribute. When an element has no usable locator but is easy to describe by position, use a relative locator. See [Locator strategies](https://www.selenium.dev/documentation/webdriver/elements/locators/). **Java** ```java // Outdated — do not use driver.findElement(By.xpath("/html/body/div[2]/div[1]/form/div[3]/input")); ``` **Python** ```python # Outdated — do not use driver.find_element(By.XPATH, "/html/body/div[2]/div[1]/form/div[3]/input") ``` Current form, with a stable locator: **Java** Example (lines L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/elements/LocatorTest.java **Python** Example (lines L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/elements/test_locators.py Current form, with a relative locator: **Java** ```java By passwordLocator = RelativeLocator.with(By.tagName("input")).below(By.id("email")); ``` **Python** ```python password_locator = locate_with(By.TAG_NAME, "input").below({By.ID: "email"}) ``` See [Relative locators](https://www.selenium.dev/documentation/webdriver/elements/locators/#relative-locators) for the full set of relative locator methods. ## find_element_by_* methods **Superseded in Selenium 4.** The Python bindings announced the removal of `find_element_by_*` and `find_elements_by_*` after Selenium 4.2. The Java `findElementBy*` helpers were removed in Selenium 4. Every one of them is a special case of `find_element` with a `By` strategy. See the [Python locators blog post](https://www.selenium.dev/blog/2022/python-locators-se4/) and the [upgrade guide](https://www.selenium.dev/documentation/webdriver/troubleshooting/upgrade_to_selenium_4/). **Java** ```java // Outdated — do not use driver.findElementById("lname"); ``` **Python** ```python # Outdated — do not use driver.find_element_by_id("lname") ``` Current form: **Java** Example (lines L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/elements/LocatorTest.java **Python** Example (lines L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/elements/test_locators.py ## executable_path **Deprecated in Selenium 4** in favour of a `Service` object. In Python, the `executable_path` argument to the driver constructor is the outdated form. A path belongs on a `Service`. Most projects do not need one at all, because Selenium Manager finds the driver; see [driver management](#manual-driver-downloads-and-driver-managers) above. See the [upgrade guide](https://www.selenium.dev/documentation/webdriver/troubleshooting/upgrade_to_selenium_4/) and [Driver service](https://www.selenium.dev/documentation/webdriver/drivers/service/). ```python # Outdated — do not use driver = webdriver.Chrome(executable_path="/path/to/chromedriver", options=options) ``` Current form, when a specific driver binary is really needed: **Python** Example (lines L15-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/drivers/test_service.py ## CDP-only calls **Temporary by design.** The [CDP pages](https://www.selenium.dev/documentation/webdriver/bidi/cdp/) describe Selenium's Chrome DevTools Protocol support as temporary until WebDriver BiDi is implemented. Firefox CDP support was deprecated in 4.27 and 4.28 and fully removed in 4.29. The Chrome DevTools Protocol is Chromium-only and has no stable API between browser versions. [WebDriver BiDi](https://www.selenium.dev/documentation/webdriver/bidi/w3c/) is the W3C standard that replaces it, and it works across browsers. **Java** ```java // Outdated — do not use DevTools devTools = ((HasDevTools) driver).getDevTools(); devTools.createSession(); devTools.send(Log.enable()); devTools.addListener(Log.entryAdded(), entry -> System.out.println(entry.getText())); ``` **Python** ```python # Outdated — do not use driver.execute_cdp_cmd("Log.enable", {}) ``` Current form, listening to console logs with BiDi: **Java** Example (lines L30-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java **Python** Example (lines L6-L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py --- # The Selenium Browser Automation Project Area: Getting started URL: https://trunk--selenium-dev.netlify.app/documentation/ Selenium is an umbrella project for a range of tools and libraries that enable and support the automation of web browsers. It provides extensions to emulate user interaction with browsers, a distribution server for scaling browser allocation, and the infrastructure for implementations of the [W3C WebDriver specification](//www.w3.org/TR/webdriver/) that lets you write interchangeable code for all major web browsers. This project is made possible by volunteer contributors who have put in thousands of hours of their own time, and made the source code freely available for anyone to use, enjoy, and improve. Selenium brings together browser vendors, engineers, and enthusiasts to further an open discussion around automation of the web platform. The project organises [an annual conference](//seleniumconf.com/) to teach and nurture the community. At the core of Selenium is WebDriver, an interface to write instruction sets that can be run interchangeably in many browsers. Once you've installed everything, only a few lines of code get you inside a browser. You can find a more comprehensive example in [Writing your first Selenium script](https://www.selenium.dev/documentation/webdriver/getting_started/) **Java** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/hello/HelloSelenium.java **Python** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/hello/hello_selenium.py **CSharp** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/HelloSelenium.cs **Ruby** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/hello/hello_selenium.rb **JavaScript** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/hello/helloSelenium.js **Kotlin** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/hello/HelloSelenium.kt See the Overview to check the different project components and decide if Selenium is the right tool for you. You should continue on to Getting Started to understand how you can install Selenium and successfully use it as a test automation tool, and scaling simple tests like this to run in large, distributed environments on multiple browsers, on several different operating systems. --- # WebDriver Area: Getting started URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/ WebDriver drives a browser natively; learn more about it. WebDriver drives a browser natively, as a user would, either locally or on a remote machine using the Selenium server. It marks a leap forward in terms of browser automation. Selenium WebDriver refers to both the language bindings and the implementations of the individual browser controlling code. This is commonly referred to as just _WebDriver_. Selenium WebDriver is a [W3C Recommendation](https://www.w3.org/TR/webdriver1/) * WebDriver is designed as a simple and more concise programming interface. * WebDriver is a compact object-oriented API. * It drives the browser effectively. --- # Getting started Area: Getting started URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/getting_started/ Install Selenium, write your first script, and run it. This page takes you from an empty project to a running Selenium script, and then shows how to run the same code with a test runner. ## You will learn * How to install the Selenium library for your programming language * How to write and run a first script that opens a browser, interacts with a page, and closes it * How to run the same code with a test runner ## Install From Selenium 4.6 onwards you no longer need to download or manage browser drivers. [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/) finds the driver that matches your browser, and downloads the browser itself if none is installed. Add the Selenium library to your project. Check the [downloads page](/downloads/) for the latest version. **Java** Add the dependency to your build file. The minimum supported Java version is listed in the [Selenium source](https://github.com/SeleniumHQ/selenium/blob/trunk/.bazelrc#L32). **Maven** (`pom.xml`) Example (lines L33-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/pom.xml **Gradle** (`build.gradle`) Example (lines L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/build.gradle **Python** ```shell pip install selenium ``` The minimum supported Python version for each release is listed on [PyPI](https://pypi.org/project/selenium/). **CSharp** ```shell dotnet add package Selenium.WebDriver ``` The supported frameworks for each release are listed on [NuGet](https://www.nuget.org/packages/Selenium.WebDriver). **Ruby** ```shell gem install selenium-webdriver ``` Or add `gem 'selenium-webdriver'` to your `Gemfile`. The minimum supported Ruby version for each release is listed on [RubyGems](https://rubygems.org/gems/selenium-webdriver/). **JavaScript** ```shell npm install selenium-webdriver ``` The minimum supported Node version for each release is in the "Node Support Policy" section on [npm](https://www.npmjs.com/package/selenium-webdriver). **Kotlin** Kotlin uses the Java bindings. Add the same Maven or Gradle dependency shown on the Java tab. ## Your first script Every Selenium call either tells the browser to do something or asks it for information. This script uses the eight commands you will use in almost every session: 1. Start the [driver session](https://www.selenium.dev/documentation/webdriver/drivers/) 2. [Navigate](https://www.selenium.dev/documentation/webdriver/interactions/navigation/) to a page 3. Request [information about the browser](https://www.selenium.dev/documentation/webdriver/interactions/) 4. Establish a [waiting strategy](https://www.selenium.dev/documentation/webdriver/waits/) 5. [Find elements](https://www.selenium.dev/documentation/webdriver/elements/) 6. [Act on an element](https://www.selenium.dev/documentation/webdriver/elements/interactions/) 7. Request [element information](https://www.selenium.dev/documentation/webdriver/elements/information/) 8. End the session with [quit](https://www.selenium.dev/documentation/webdriver/drivers/#quitting-sessions) **Java** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/getting_started/FirstScript.java **Python** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/getting_started/first_script.py **CSharp** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/GettingStarted/FirstScript.cs **Ruby** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/getting_started/first_script.rb **JavaScript** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/getting_started/firstScript.spec.js **Kotlin** Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/getting_started/FirstScriptTest.kt Run the file with your language's usual tooling. The browser opens, fills in the form, and closes. ## Run it with a test runner Most people use Selenium to test web applications. A test runner gives you before and after hooks, assertions, and reporting, and lets you run tests in groups or in parallel. Here is the same script structured as a test, with one runner for each language: **Java** [JUnit](https://junit.org/junit5/) Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/getting_started/UsingSeleniumTest.java ```shell mvn test ``` **Python** [pytest](https://pytest.org/) Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/getting_started/using_selenium_tests.py ```shell pytest ``` **CSharp** [MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/GettingStarted/UsingSeleniumTest.cs ```shell dotnet test ``` **Ruby** [RSpec](https://rspec.info/) Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/getting_started/using_selenium_spec.rb ```shell bundle exec rspec ``` **JavaScript** [Mocha](https://mochajs.org/) Example: https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/getting_started/runningTests.spec.js ```shell npx mocha runningTests.spec.js ``` **Kotlin** [JUnit](https://junit.org/junit5/) The Kotlin first script above is already a JUnit test. ```shell mvn test ``` ## Next steps * [Waits](https://www.selenium.dev/documentation/webdriver/waits/): make sure elements are ready before you use them * [Locators](https://www.selenium.dev/documentation/webdriver/elements/locators/): choose the best way to find elements * [Grid](https://www.selenium.dev/documentation/grid/getting_started/): run your tests on many browsers and machines * [How Selenium works](https://www.selenium.dev/documentation/overview/details/): WebDriver, drivers, and the rest of the project --- # Guides Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/ Task-based guides: start from the problem you have and follow the links into the reference pages that solve it. The rest of this documentation is organised by API surface: elements, interactions, waits, BiDi, and so on. That is the right shape for looking something up once you know what it is called, but most people arrive with a problem rather than a method name. The guides in this section are organised by task instead. Each one states the problem, describes the approach the Selenium project recommends, shows the shortest working example for each language binding, lists the errors you are most likely to hit along the way, and links to the reference pages that cover the detail. They do not replace the reference pages; they are the fastest route into them. If you are new to Selenium altogether, start with [Getting started](https://www.selenium.dev/documentation/webdriver/getting_started/) and come back here once you have a first script running. --- # Waiting for things to happen Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/waiting/ Synchronising your code with the page using explicit waits and expected conditions, and why a fixed sleep is the wrong tool. Your script clicks a button, and the next line fails because the element it needs has not appeared yet. Run it again and it passes. Modern applications update the page asynchronously, so the browser and your code are in a race, and the loser is a flaky test. ## Recommended approach Use an _explicit wait_: a loop that polls the application for a specific condition and continues as soon as that condition is true, or raises a timeout error if it never is. You decide what to wait for at each point where synchronisation matters, so the wait is exactly as long as it needs to be and no longer. Most bindings ship a library of ready-made _expected conditions_ (element visible, title contains, alert present, and so on) that you can pass to the wait instead of writing your own lambda. Each of them is a function that is called repeatedly until it returns a truthy value. A fixed sleep is the first thing many people reach for, and it is nearly always wrong. It is either too short, and the test fails on a slow machine, or too long, and every test in the suite pays the full price every time. Likewise, do not combine an implicit wait with explicit waits: the two timeouts add up in ways that are hard to predict. This example waits for an element that is revealed a couple of seconds after a click: **Java** Example (lines L67-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java **Python** Example (lines L41-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/waits/test_waits.py **CSharp** Example (lines L56-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs **Ruby** Example (lines L42-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/waits/waits_spec.rb **JavaScript** Example (lines L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/waits/waits.spec.js **Kotlin** Example (lines L36-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/waits/WaitsTest.kt The same wait expressed with a built-in expected condition: **Python** Example (lines L14-L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_expected_conditions.py ## Common errors * [NoSuchElementException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#nosuchelementexception): the element was looked up before it existed. Wait for it to be present or visible first. * [StaleElementReferenceException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#staleelementreferenceexception): the element was found, then the page re-rendered it. Locate it again, inside the wait if necessary. * [TimeoutException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#timeoutexception): the condition never became true. Check the condition and the locator before raising the timeout. * [ElementClickInterceptedException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#elementclickinterceptedexception): something (often an overlay or spinner) is still covering the element. Wait for it to disappear. ## Reference * [Waiting strategies](https://www.selenium.dev/documentation/webdriver/waits/): implicit and explicit waits, and how to customise them * [Expected conditions](https://www.selenium.dev/documentation/webdriver/support_features/expected_conditions/) * [Page load strategy](https://www.selenium.dev/documentation/webdriver/drivers/options/#pageloadstrategy): what navigation already waits for * [Timeouts](https://www.selenium.dev/documentation/webdriver/drivers/options/#timeouts): the session-level timeout capabilities --- # Finding elements reliably Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/finding_elements/ Choosing a locator strategy that survives the next release of the application, and avoiding the ones that do not. A locator copied out of the browser's developer tools works today and breaks the first time a designer moves a `div`. Tests then fail for reasons that have nothing to do with the behaviour they were written to check, and the suite stops being trusted. ## Recommended approach Prefer locators that describe what an element _is_ over locators that describe where it happens to sit in the document, roughly in this order: 1. **id**, when the page has stable, unique ids. This is the fastest and most readable choice. 2. **name**, for form fields, which tend to keep their names because the server depends on them. 3. **CSS selector**, for everything else. A short selector anchored on an id, a data attribute, or a meaningful class is both fast and expressive. 4. **Relative locators**, when the target has no stable attributes of its own but a nearby element does: find the input _below_ a given label, or the button _to the right of_ a field. Avoid absolute XPath (`/html/body/div[3]/...`). It encodes the entire structure of the page, so any change above the element breaks it, and it is slow in some browsers. XPath itself is fine when you need it, for example to match on text content, but keep the expression short and anchored. If the application does not expose stable attributes, ask for them. A `data-test` attribute costs the developers nothing and removes an entire class of failures. Locate the first matching element: **Java** Example (lines L23-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/elements/FindersTest.java **Python** Example (lines L7-L8): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/elements/test_finders.py **CSharp** Example (lines L15-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Elements/FindersTest.cs **Ruby** Example (lines L10-L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/elements/finders_spec.rb **JavaScript** Example (lines L9-L10): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/elements/finders.spec.js **Kotlin** Example (lines L19-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/elements/FindersTest.kt Locate by id, the preferred strategy when one is available: **Java** Example (lines L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/elements/LocatorTest.java **Python** Example (lines L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/elements/test_locators.py **Ruby** Example (lines L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/elements/locators_spec.rb **JavaScript** Example (lines L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/elements/locators.spec.js Locate relative to another element: **Ruby** Example (lines L40): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/elements/locators_spec.rb ## Common errors * [NoSuchElementException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#nosuchelementexception): nothing matched. Check the locator, check that you are in the right frame, and check that the element exists yet (see Waiting). * [InvalidSelectorException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#invalidselectorexception): the CSS or XPath expression is malformed, or an XPath expression returns something that is not an element. * [StaleElementReferenceException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#staleelementreferenceexception): you held on to an element across a page update. Locate it again rather than caching it. * [NoSuchShadowRootException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#nosuchshadowrootexception): the element lives inside a shadow DOM; search from the shadow root instead of the document. ## Reference * [Locator strategies](https://www.selenium.dev/documentation/webdriver/elements/locators/): every strategy, including relative locators * [Finding elements](https://www.selenium.dev/documentation/webdriver/elements/finders/): first match, all matches, nested searches, shadow DOM * [Tips on working with locators](https://www.selenium.dev/documentation/test_practices/encouraged/locators/) * [Page object models](https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models/): keeping locators in one place --- # Authentication and sessions Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/authentication/ Getting past a login once, answering HTTP basic authentication prompts, and reusing a signed-in state across tests without driving the login form every time. Almost every test starts behind a login. Driving the login form in each test is slow, it makes every test depend on the login page working, and some forms (two-factor prompts, third-party identity providers, CAPTCHAs) cannot be automated at all. HTTP basic authentication is a different problem again: the browser shows a native dialog that WebDriver cannot see. ## Recommended approach Log in through the user interface in exactly one test, the one that tests the login form. Everywhere else, establish the session some other way and start the test already signed in. For cookie-based sessions, navigate to the application's domain, add the session cookie with WebDriver's cookie API, and reload. The cookie must be added while the browser is on a page in the domain the cookie belongs to, otherwise the browser rejects it. Where the cookie comes from is up to you: an API call that logs in, a fixture created on the server, or a value captured from a single interactive login. For HTTP basic authentication, use the network module of WebDriver BiDi. Register a handler for the `authRequired` phase and answer it with the credentials; the browser never shows the dialog. Embedding credentials in the URL (`https://user:pass@host/`) is blocked by modern browsers and should not be relied on. Keep tests independent: each test should set up the state it needs rather than inheriting it from the one before, and a fresh browser per test is the simplest way to guarantee that. Add a cookie to the current browsing context: **Java** Example (lines L42-L44): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/CookiesTest.java **Python** Example (lines L5-L9): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_cookies.py **CSharp** Example (lines L32-L34): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/CookiesTest.cs **Ruby** Example (lines L9-L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/cookies_spec.rb **JavaScript** Example (lines L18-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/cookies.spec.js Answer a basic authentication challenge with BiDi: **Java** Example (lines L55-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L82): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **JavaScript** Example (lines L43-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js ## Common errors * [InvalidCookieDomainException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#invalidcookiedomainexception): the browser is not on a page in the cookie's domain. Navigate there first, then add the cookie. * [UnableToSetCookieException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#unabletosetcookieexception): the cookie attributes were rejected, for example a `Secure` cookie on an `http://` page. * [UnhandledAlertException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#unhandledalertexception): a basic authentication dialog is open and blocking the session. Handle it with BiDi before navigating. ## Reference * [Working with cookies](https://www.selenium.dev/documentation/webdriver/interactions/cookies/) * [BiDi network](https://www.selenium.dev/documentation/webdriver/bidi/w3c/network/): intercepts and the `authRequired` phase * [Virtual authenticator](https://www.selenium.dev/documentation/webdriver/interactions/virtual_authenticator/): testing WebAuthn and passkeys * [Two-factor authentication](https://www.selenium.dev/documentation/test_practices/discouraged/two_factor_authentication/) and [third-party logins](https://www.selenium.dev/documentation/test_practices/discouraged/gmail_email_and_facebook_logins/): what not to automate * [Avoid sharing state](https://www.selenium.dev/documentation/test_practices/encouraged/avoid_sharing_state/) and [fresh browser per test](https://www.selenium.dev/documentation/test_practices/encouraged/fresh_browser_per_test/) --- # Files: upload and download Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/files/ Uploading a file through a form without touching the operating system's file dialog, and why downloading through the browser is not the right way to test a download. Clicking a file input opens the operating system's file chooser, which is outside the browser and invisible to WebDriver. Clicking a download link starts a download the API cannot watch: there is no event for "finished", no progress, and no portable way to find the file afterwards. ## Recommended approach **Uploads.** Do not click the input. Send the absolute path of the file to the `` element with `sendKeys`, then submit the form as usual. The browser attaches the file exactly as if it had been chosen through the dialog. The path must exist on the machine where the _browser_ is running; when the browser is remote, on a Grid, set a local file detector so the client uploads the file to the node first. **Downloads.** Testing a download through the browser is discouraged. The browser's download behaviour is configurable per browser and per platform, the file lands in a directory you then have to poll, and none of this is what a user actually cares about. Instead, use Selenium to get to the point where the download link exists, read its `href` (and any cookies the request needs), and fetch it with an HTTP client in your test language. That gives you the bytes directly, with a proper status code, and no polling. If you are running on Selenium Grid and really need the browser to perform the download, Grid can be configured to collect downloaded files from the node and the client can retrieve them; see the remote WebDriver page below. Upload a file by sending its path to the input: **Java** Example (lines L17-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/elements/FileUploadTest.java **Python** Example (lines L12-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/elements/test_file_upload.py **CSharp** Example (lines L21-L23): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Elements/FileUploadTest.cs **Ruby** Example (lines L12-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/elements/file_upload_spec.rb **JavaScript** Example (lines L26-L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/elements/fileUpload.spec.js ## Common errors * [InvalidArgumentException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#invalidargumentexception): the path does not exist on the machine running the browser. Use an absolute path, and a file detector when the browser is remote. * [ElementNotInteractableException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#elementnotinteractableexception): the file input is hidden behind a styled button. Sending keys to a hidden file input is allowed in most browsers; if it is refused, check the `strictFileInteractability` capability. ## Reference * [File upload](https://www.selenium.dev/documentation/webdriver/elements/file_upload/) * [File downloads are discouraged](https://www.selenium.dev/documentation/test_practices/discouraged/file_downloads/) * [Remote WebDriver](https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/): uploads and downloads through a Grid * [strictFileInteractability](https://www.selenium.dev/documentation/webdriver/drivers/options/#strictfileinteractability) --- # Dialogs and alerts Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/dialogs/ Reading, accepting, dismissing and typing into JavaScript alerts, confirms and prompts, and deciding what should happen to a dialog your test did not expect. A page calls `alert()`, `confirm()` or `prompt()`, the browser shows a native dialog, and every subsequent WebDriver command fails until something closes it. If the dialog appears when your test is not expecting it, the failure is an _unexpected alert open_ error several lines away from the cause. ## Recommended approach All three dialogs are handled through the same object: switch to the alert, then read its text, accept it, dismiss it, or send keys to it. `alert()` can only be accepted; `confirm()` returns true to the page when accepted and false when dismissed; `prompt()` additionally accepts typed text before being accepted. Treat the dialog like any other asynchronous event and wait for it. The bindings ship an `alertIsPresent` expected condition that returns the alert as soon as it exists, which is both safer and simpler than switching and catching the error. For dialogs that may appear when no test code is ready to handle them, set the `unhandledPromptBehavior` capability when starting the session. `dismiss` and `accept` close the dialog silently; `dismiss and notify` (the default) and `accept and notify` close it and raise an error so you find out; `ignore` leaves it open for you to handle. Recent drivers close `beforeunload` prompts automatically. With WebDriver BiDi enabled, the browsing context module also emits `userPromptOpened` and `userPromptClosed` events, so a test can react to a dialog the moment it appears rather than discovering it on the next command. Switch to an alert, read its text, and close it: **Java** Example (lines L53-L56): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/AlertsTest.java **Python** Example (lines L16-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_alerts.py **Ruby** Example (lines L16-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/alerts_spec.rb **JavaScript** Example (lines L19-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/alert.spec.js Type into a prompt before accepting it: **Java** Example (lines L80-L86): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/AlertsTest.java **Python** Example (lines L44-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_alerts.py **Ruby** Example (lines L42-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/alerts_spec.rb **JavaScript** Example (lines L42-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/alert.spec.js Decide up front what happens to an unexpected dialog: **Java** Example (lines L142-L143): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/drivers/OptionsTest.java **Python** Example (lines L51-L53): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/drivers/test_options.py **CSharp** Example (lines L59-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Drivers/OptionsTest.cs **Ruby** Example (lines L60-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/drivers/options_spec.rb ## Common errors * [NoAlertPresentException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#noalertpresentexception): you switched to an alert before it appeared, or the session's prompt handler already closed it. Wait for it with `alertIsPresent`, and check `unhandledPromptBehavior`. * [UnhandledAlertException](https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/_index/#unhandledalertexception): a dialog opened that nothing handled, and the driver closed it before running your command. Either handle the dialog in the test or change the prompt handler. ## Reference * [JavaScript alerts, prompts and confirmations](https://www.selenium.dev/documentation/webdriver/interactions/alerts/) * [unhandledPromptBehavior](https://www.selenium.dev/documentation/webdriver/drivers/options/#unhandledpromptbehavior) * [Expected conditions](https://www.selenium.dev/documentation/webdriver/support_features/expected_conditions/) * [BiDi browsing context events](https://www.selenium.dev/documentation/webdriver/bidi/w3c/browsing_context/#user-prompt-opened-event) --- # Frames and windows Area: Guides URL: https://trunk--selenium-dev.netlify.app/documentation/guides/frames_and_windows/ Reaching elements inside an iframe, following a link that opens a new tab or window, and getting back to where you started. The element is plainly visible on the page, the locator is correct, and `findElement` still reports that it does not exist. The element is inside an ` ``` If it was not for the iframe we would expect to click on the button using something like: **Java** //This won't work driver.findElement(By.tagName("button")).click(); **Python** # This Wont work driver.find_element(By.TAG_NAME, 'button').click() **CSharp** //This won't work driver.FindElement(By.TagName("button")).Click(); **Ruby** # This won't work driver.find_element(:tag_name,'button').click **JavaScript** // This won't work await driver.findElement(By.css('button')).click(); **Kotlin** //This won't work driver.findElement(By.tagName("button")).click() However, if there are no buttons outside of the iframe, you might instead get a _no such element_ error. This happens because Selenium is only aware of the elements in the top level document. To interact with the button, we will need to first switch to the frame, in a similar way to how we switch windows. WebDriver offers three ways of switching to a frame. Following example code shows how we can do that, using a live web example. ## Using a WebElement Switching using a WebElement is the most flexible option. You can find the frame using your preferred selector and switch to it. **Java** Example (lines L38-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/FramesTest.java **Python** Example (lines L24-L32): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_frames.py **CSharp** Example (lines L38-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/FramesTest.cs **Ruby** Example (lines L26-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/frames_spec.rb **JavaScript** // Store the web element const iframe = driver.findElement(By.css('#modal > iframe')); // Switch to the frame await driver.switchTo().frame(iframe); // Now we can click the button await driver.findElement(By.css('button')).click(); **Kotlin** //Store the web element val iframe = driver.findElement(By.cssSelector("#modal>iframe")) //Switch to the frame driver.switchTo().frame(iframe) //Now we can click the button driver.findElement(By.tagName("button")).click() ## Using a name or ID If your frame or iframe has an id or name attribute, this can be used instead. If the name or ID is not unique on the page, then the first one found will be switched to. **Java** Example (lines L50-L58): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/FramesTest.java **Python** Example (lines L34-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_frames.py **CSharp** Example (lines L50-L58): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/FramesTest.cs **Ruby** Example (lines L36-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/frames_spec.rb **JavaScript** // Using the ID await driver.switchTo().frame('buttonframe'); // Or using the name instead await driver.switchTo().frame('myframe'); // Now we can click the button await driver.findElement(By.css('button')).click(); **Kotlin** //Using the ID driver.switchTo().frame("buttonframe") //Or using the name instead driver.switchTo().frame("myframe") //Now we can click the button driver.findElement(By.tagName("button")).click() ## Using an index It is also possible to use the index of the frame, such as can be queried using _window.frames_ in JavaScript. **Java** Example (lines L62-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/FramesTest.java **Python** Example (lines L45-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_frames.py **CSharp** Example (lines L62-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/FramesTest.cs **Ruby** Example (lines L46-L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/frames_spec.rb **JavaScript** // Switches to the second frame await driver.switchTo().frame(1); **Kotlin** // Switches to the second frame driver.switchTo().frame(1) ## Leaving a frame To leave an iframe or frameset, switch back to the default content like so: **Java** Example (lines L66-L67): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/FramesTest.java **Python** Example (lines L49-L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_frames.py **CSharp** Example (lines L66-L67): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/FramesTest.cs **Ruby** Example (lines L49-L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/frames_spec.rb **JavaScript** // Return to the top level await driver.switchTo().defaultContent(); **Kotlin** // Return to the top level driver.switchTo().defaultContent() --- # Print Page Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/interactions/print_page/ Printing a webpage is a common task, whether for sharing information or maintaining archives. Selenium simplifies this process through its PrintOptions, PrintsPage, and browsingContext classes, which provide a flexible and intuitive interface for automating the printing of web pages. These classes enable you to configure printing preferences, such as page layout, margins, and scaling, ensuring that the output meets your specific requirements. ## Configuring ### Orientation Using the `getOrientation()` and `setOrientation()` methods, you can get/set the page orientation --- either `PORTRAIT` or `LANDSCAPE`. **Java** Example (lines L14-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L12-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L12-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### Range Using the `getPageRanges()` and `setPageRanges()` methods, you can get/set the range of pages to print --- e.g. "2-4". **Java** Example (lines L23-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L22-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L18-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### Size Using the `getPageSize()` and `setPageSize()` methods, you can get/set the paper size to print --- e.g. "A0", "A6", "Legal", "Tabloid", etc. **Java** Example (lines L32-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L32-L38): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L24-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### Margins Using the `getPageMargin()` and `setPageMargin()` methods, you can set the margin sizes of the page you wish to print --- i.e. top, bottom, left, and right margins. **Java** Example (lines L41-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L51-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L30-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### Scale Using `getScale()` and `setScale()` methods, you can get/set the scale of the page you wish to print --- e.g. 1.0 is 100% or default, 0.25 is 25%, etc. **Java** Example (lines L53-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L61-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L42-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### Background Using `getBackground()` and `setBackground()` methods, you can get/set whether background colors and images appear --- boolean `true` or `false`. **Java** Example (lines L63-L66): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L41-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L49-L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ### ShrinkToFit Using `getShrinkToFit()` and `setShrinkToFit()` methods, you can get/set whether the page will shrink-to-fit content on the page --- boolean `true` or `false`. **Java** Example (lines L72-L75): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintOptionsTest.java **CSharp** Example (lines L71-L78): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** Example (lines L55-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_print_options.py **JavaScript** **Kotlin** ## Printing Once you've configured your PrintOptions, you're ready to print the page. To do this, you can invoke the print function, which generates a PDF representation of the web page. The resulting PDF can be saved to your local storage for further use or distribution. Using `PrintsPage()`, the print command will return the PDF data in base64-encoded format, which can be decoded and written to a file in your desired location, and using `BrowsingContext()` will return a String. There may currently be multiple implementations depending on your language of choice. For example, with Java you have the ability to print using either `BrowingContext()` or `PrintsPage()`. Both take `PrintOptions()` objects as a parameter. Note: `BrowsingContext()` is part of Selenium's BiDi implementation. To enable BiDi see Enabling Bidi **Java** **PrintsPage()** Example (lines L27-L31): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintsPageTest.java **BrowsingContext()** Example (lines L37-L41): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/PrintsPageTest.java **CSharp** Example (lines L81-L88): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/PrintOptionsTest.cs **Ruby** **Python** **print_page()** Example (lines L12-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_prints_page.py **JavaScript** **Kotlin** --- # Working with windows and tabs Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/interactions/windows/ ## Windows and tabs ### Get window handle WebDriver does not make the distinction between windows and tabs. If your site opens a new tab or window, Selenium will let you work with it using a window handle. Each window has a unique identifier which remains persistent in a single session. You can get the window handle of the current window by using: **Java** Example (lines L16-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/WindowsTest.java **Python** Example (lines L16-L18): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_windows.py **CSharp** Example (lines L17-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/WindowsTest.cs **Ruby**driver.window_handle **JavaScript**await driver.getWindowHandle(); **Kotlin**driver.windowHandle ### Switching windows or tabs Clicking a link which opens in a new window will focus the new window or tab on screen, but WebDriver will not know which window the Operating System considers active. To work with the new window you will need to switch to it. For this, we fetch all window handles, and store them in an array. The array position fills in the order the window is launched. So first position will be default browser, and so on. **Java** Example (lines L22-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/WindowsTest.java **Python** Example (lines L22-L32): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_windows.py **CSharp** Example (lines L23-L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/WindowsTest.cs **Ruby** # Store the ID of the original window original_window = driver.window_handle # Check we don't have other windows open already assert(driver.window_handles.length == 1, 'Expected one window') # Click the link which opens in a new window driver.find_element(link: 'new window').click # Wait for the new window or tab wait.until { driver.window_handles.length == 2 } #Loop through until we find a new window handle driver.window_handles.each do |handle| if handle != original_window driver.switch_to.window handle break end end #Wait for the new tab to finish loading content wait.until { driver.title == 'Selenium documentation'} **JavaScript** //Store the ID of the original window const originalWindow = await driver.getWindowHandle(); //Check we don't have other windows open already assert((await driver.getAllWindowHandles()).length === 1); //Click the link which opens in a new window await driver.findElement(By.linkText('new window')).click(); //Wait for the new window or tab await driver.wait( async () => (await driver.getAllWindowHandles()).length === 2, 10000 ); //Loop through until we find a new window handle const windows = await driver.getAllWindowHandles(); windows.forEach(async handle => { if (handle !== originalWindow) { await driver.switchTo().window(handle); } }); //Wait for the new tab to finish loading content await driver.wait(until.titleIs('Selenium documentation'), 10000); **Kotlin** //Store the ID of the original window val originalWindow = driver.getWindowHandle() //Check we don't have other windows open already assert(driver.getWindowHandles().size() === 1) //Click the link which opens in a new window driver.findElement(By.linkText("new window")).click() //Wait for the new window or tab wait.until(numberOfWindowsToBe(2)) //Loop through until we find a new window handle for (windowHandle in driver.getWindowHandles()) { if (!originalWindow.contentEquals(windowHandle)) { driver.switchTo().window(windowHandle) break } } //Wait for the new tab to finish loading content wait.until(titleIs("Selenium documentation")) ### Closing a window or tab When you are finished with a window or tab _and_ it is not the last window or tab open in your browser, you should close it and switch back to the window you were using previously. Assuming you followed the code sample in the previous section you will have the previous window handle stored in a variable. Put this together and you will get: **Java** Example (lines L31-L34): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/WindowsTest.java **Python** Example (lines L46-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_windows.py **CSharp** Example (lines L32-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/WindowsTest.cs **Ruby** #Close the tab or window driver.close #Switch back to the old tab or window driver.switch_to.window original_window **JavaScript** //Close the tab or window await driver.close(); //Switch back to the old tab or window await driver.switchTo().window(originalWindow); **Kotlin** //Close the tab or window driver.close() //Switch back to the old tab or window driver.switchTo().window(originalWindow) Forgetting to switch back to another window handle after closing a window will leave WebDriver executing on the now closed page, and will trigger a **No Such Window Exception**. You must switch back to a valid window handle in order to continue execution. ### Create new window (or) new tab and switch Creates a new window (or) tab and will focus the new window or tab on screen. You don't need to switch to work with the new window (or) tab. If you have more than two windows (or) tabs opened other than the new window, you can loop over both windows or tabs that WebDriver can see, and switch to the one which is not the original. __Note: This feature works with Selenium 4 and later versions.__ **Java** Example (lines L36-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/WindowsTest.java **Python** Example (lines L53-L58): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_windows.py **CSharp** Example (lines L37-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/WindowsTest.cs **Ruby** Opens a new tab and switches to new tab: Example (lines L9): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/windows_spec.rb Opens a new window and switches to new window: Example (lines L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/interactions/windows_spec.rb **JavaScript** Opens a new tab and switches to new tab Example (lines L70): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js Opens a new window and switches to new window: Example (lines L75): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** // Opens a new tab and switches to new tab driver.switchTo().newWindow(WindowType.TAB) // Opens a new window and switches to new window driver.switchTo().newWindow(WindowType.WINDOW) ### Quitting the browser at the end of a session When you are finished with the browser session you should call quit, instead of close: **Java** Example (lines L44-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/WindowsTest.java **Python** Example (lines L13-L13): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_windows.py **CSharp** Example (lines L45-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/WindowsTest.cs **Ruby**driver.quit **JavaScript**await driver.quit(); **Kotlin**driver.quit() * Quit will: * Close all the windows and tabs associated with that WebDriver session * Close the browser process * Close the background driver process * Notify Selenium Grid that the browser is no longer in use so it can be used by another session (if you are using Selenium Grid) Failure to call quit will leave extra background processes and ports running on your machine which could cause you problems later. Some test frameworks offer methods and annotations which you can hook into to tear down at the end of a test. **Java** /** * Example using JUnit * https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html */ @AfterAll public static void tearDown() { driver.quit(); } **Python** # unittest teardown # https://docs.python.org/3/library/unittest.html?highlight=teardown#unittest.TestCase.tearDown def tearDown(self): self.driver.quit() **CSharp** /* Example using Visual Studio's UnitTesting https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.aspx */ [TestCleanup] public void TearDown() { driver.Quit(); } **Ruby** # UnitTest Teardown # https://www.rubydoc.info/github/test-unit/test-unit/Test/Unit/TestCase def teardown @driver.quit end **JavaScript** /** * Example using Mocha * https://mochajs.org/#hooks */ after('Tear down', async function () { await driver.quit(); }); **Kotlin** /** * Example using JUnit * https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html */ @AfterAll fun tearDown() { driver.quit() } If not running WebDriver in a test context, you may consider using `try / finally` which is offered by most languages so that an exception will still clean up the WebDriver session. **Java** try { //WebDriver code here... } finally { driver.quit(); } **Python** try: #WebDriver code here... finally: driver.quit() **CSharp** try { //WebDriver code here... } finally { driver.Quit(); } **Ruby** begin #WebDriver code here... ensure driver.quit end **JavaScript** try { //WebDriver code here... } finally { await driver.quit(); } **Kotlin** try { //WebDriver code here... } finally { driver.quit() } Python's WebDriver now supports the python context manager, which when using the `with` keyword can automatically quit the driver at the end of execution. ```python with webdriver.Firefox() as driver: # WebDriver code here... # WebDriver will automatically quit after indentation ``` ## Window management Screen resolution can impact how your web application renders, so WebDriver provides mechanisms for moving and resizing the browser window. ### Get window size Fetches the size of the browser window in pixels. **Java** //Access each dimension individually int width = driver.manage().window().getSize().getWidth(); int height = driver.manage().window().getSize().getHeight(); //Or store the dimensions and query them later Dimension size = driver.manage().window().getSize(); int width1 = size.getWidth(); int height1 = size.getHeight(); **Python** # Access each dimension individually width = driver.get_window_size().get("width") height = driver.get_window_size().get("height") # Or store the dimensions and query them later size = driver.get_window_size() width1 = size.get("width") height1 = size.get("height") **CSharp** //Access each dimension individually int width = driver.Manage().Window.Size.Width; int height = driver.Manage().Window.Size.Height; //Or store the dimensions and query them later System.Drawing.Size size = driver.Manage().Window.Size; int width1 = size.Width; int height1 = size.Height; **Ruby** # Access each dimension individually width = driver.manage.window.size.width height = driver.manage.window.size.height # Or store the dimensions and query them later size = driver.manage.window.size width1 = size.width height1 = size.height **JavaScript** Access each dimension individually Example (lines L93): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js (or) store the dimensions and query them later Example (lines L96-L98): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** //Access each dimension individually val width = driver.manage().window().size.width val height = driver.manage().window().size.height //Or store the dimensions and query them later val size = driver.manage().window().size val width1 = size.width val height1 = size.height ### Set window size Restores the window and sets the window size. **Java**driver.manage().window().setSize(new Dimension(1024, 768)); **Python**driver.set_window_size(1024, 768) **CSharp**driver.Manage().Window.Size = new Size(1024, 768); **Ruby**driver.manage.window.resize_to(1024,768) **JavaScript**await driver.manage().window().setRect({ width: 1024, height: 768 }); **Kotlin**driver.manage().window().size = Dimension(1024, 768) ### Get window position Fetches the coordinates of the top left coordinate of the browser window. **Java** // Access each dimension individually int x = driver.manage().window().getPosition().getX(); int y = driver.manage().window().getPosition().getY(); // Or store the dimensions and query them later Point position = driver.manage().window().getPosition(); int x1 = position.getX(); int y1 = position.getY(); **Python** # Access each dimension individually x = driver.get_window_position().get('x') y = driver.get_window_position().get('y') # Or store the dimensions and query them later position = driver.get_window_position() x1 = position.get('x') y1 = position.get('y') **CSharp** //Access each dimension individually int x = driver.Manage().Window.Position.X; int y = driver.Manage().Window.Position.Y; //Or store the dimensions and query them later Point position = driver.Manage().Window.Position; int x1 = position.X; int y1 = position.Y; **Ruby** #Access each dimension individually x = driver.manage.window.position.x y = driver.manage.window.position.y # Or store the dimensions and query them later rect = driver.manage.window.rect x1 = rect.x y1 = rect.y **JavaScript** Access each dimension individually Example (lines L108): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js (or) store the dimensions and query them later Example (lines L111-L113): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** // Access each dimension individually val x = driver.manage().window().position.x val y = driver.manage().window().position.y // Or store the dimensions and query them later val position = driver.manage().window().position val x1 = position.x val y1 = position.y ## Set window position Moves the window to the chosen position. **Java** // Move the window to the top left of the primary monitor driver.manage().window().setPosition(new Point(0, 0)); **Python** # Move the window to the top left of the primary monitor driver.set_window_position(0, 0) **CSharp** // Move the window to the top left of the primary monitor driver.Manage().Window.Position = new Point(0, 0); **Ruby** driver.manage.window.move_to(0,0) **JavaScript** // Move the window to the top left of the primary monitor await driver.manage().window().setRect({ x: 0, y: 0 }); **Kotlin** // Move the window to the top left of the primary monitor driver.manage().window().position = Point(0,0) ### Maximize window Enlarges the window. For most operating systems, the window will fill the screen, without blocking the operating system's own menus and toolbars. **Java**driver.manage().window().maximize(); **Python**driver.maximize_window() **CSharp**driver.Manage().Window.Maximize(); **Ruby**driver.manage.window.maximize **JavaScript**await driver.manage().window().maximize(); **Kotlin**driver.manage().window().maximize() ### Minimize window Minimizes the window of current browsing context. The exact behavior of this command is specific to individual window managers. Minimize Window typically hides the window in the system tray. __Note: This feature works with Selenium 4 and later versions.__ **Java**driver.manage().window().minimize(); **Python**driver.minimize_window() **CSharp**driver.Manage().Window.Minimize(); **Ruby**driver.manage.window.minimize **JavaScript**await driver.manage().window().minimize(); **Kotlin**driver.manage().window().minimize() ### Fullscreen window Fills the entire screen, similar to pressing F11 in most browsers. **Java**driver.manage().window().fullscreen(); **Python**driver.fullscreen_window() **CSharp**driver.Manage().Window.FullScreen(); **Ruby**driver.manage.window.full_screen **JavaScript**await driver.manage().window().fullscreen(); **Kotlin**driver.manage().window().fullscreen() ### TakeScreenshot Used to capture screenshot for current browsing context. The WebDriver endpoint [screenshot](https://www.w3.org/TR/webdriver/#dfn-take-screenshot) returns screenshot which is encoded in Base64 format. **Java** import org.apache.commons.io.FileUtils; import org.openqa.selenium.chrome.ChromeDriver; import java.io.*; import org.openqa.selenium.*; public class SeleniumTakeScreenshot { public static void main(String args[]) throws IOException { WebDriver driver = new ChromeDriver(); driver.get("http://www.example.com"); File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(scrFile, new File("./image.png")); driver.quit(); } } **Python** from selenium import webdriver driver = webdriver.Chrome() driver.get("http://www.example.com") # Returns and base64 encoded string into image driver.save_screenshot('./image.png') driver.quit() **CSharp** using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; var driver = new ChromeDriver(); driver.Navigate().GoToUrl("http://www.example.com"); Screenshot screenshot = (driver as ITakesScreenshot).GetScreenshot(); screenshot.SaveAsFile("screenshot.png", ScreenshotImageFormat.Png); // Format values are Bmp, Gif, Jpeg, Png, Tiff **Ruby** require 'selenium-webdriver' driver = Selenium::WebDriver.for :chrome begin driver.get 'https://example.com/' # Takes and Stores the screenshot in specified path driver.save_screenshot('./image.png') end **JavaScript** Example (lines L56-L59): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** import com.oracle.tools.packager.IOUtils.copyFile import org.openqa.selenium.* import org.openqa.selenium.chrome.ChromeDriver import java.io.File fun main(){ val driver = ChromeDriver() driver.get("https://www.example.com") val scrFile = (driver as TakesScreenshot).getScreenshotAs(OutputType.FILE) copyFile(scrFile, File("./image.png")) driver.quit() } ### TakeElementScreenshot Used to capture screenshot of an element for current browsing context. The WebDriver endpoint [screenshot](https://www.w3.org/TR/webdriver/#take-element-screenshot) returns screenshot which is encoded in Base64 format. **Java** import org.apache.commons.io.FileUtils; import org.openqa.selenium.*; import org.openqa.selenium.chrome.ChromeDriver; import java.io.File; import java.io.IOException; public class SeleniumelementTakeScreenshot { public static void main(String args[]) throws IOException { WebDriver driver = new ChromeDriver(); driver.get("https://www.example.com"); WebElement element = driver.findElement(By.cssSelector("h1")); File scrFile = element.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(scrFile, new File("./image.png")); driver.quit(); } } **Python** from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("http://www.example.com") ele = driver.find_element(By.CSS_SELECTOR, 'h1') # Returns and base64 encoded string into image ele.screenshot('./image.png') driver.quit() **CSharp** using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; // Webdriver var driver = new ChromeDriver(); driver.Navigate().GoToUrl("http://www.example.com"); // Fetch element using FindElement var webElement = driver.FindElement(By.CssSelector("h1")); // Screenshot for the element var elementScreenshot = (webElement as ITakesScreenshot).GetScreenshot(); elementScreenshot.SaveAsFile("screenshot_of_element.png"); **Ruby** # Works with Selenium4-alpha7 Ruby bindings and above require 'selenium-webdriver' driver = Selenium::WebDriver.for :chrome begin driver.get 'https://example.com/' ele = driver.find_element(:css, 'h1') # Takes and Stores the element screenshot in specified path ele.save_screenshot('./image.jpg') end **JavaScript** Example (lines L44-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** import org.apache.commons.io.FileUtils import org.openqa.selenium.chrome.ChromeDriver import org.openqa.selenium.* import java.io.File fun main() { val driver = ChromeDriver() driver.get("https://www.example.com") val element = driver.findElement(By.cssSelector("h1")) val scrFile: File = element.getScreenshotAs(OutputType.FILE) FileUtils.copyFile(scrFile, File("./image.png")) driver.quit() } ### Execute Script Executes JavaScript code snippet in the current context of a selected frame or window. **Java** //Creating the JavascriptExecutor interface object by Type casting JavascriptExecutor js = (JavascriptExecutor)driver; //Button Element WebElement button =driver.findElement(By.name("btnLogin")); //Executing JavaScript to click on element js.executeScript("arguments[0].click();", button); //Get return value from script String text = (String) js.executeScript("return arguments[0].innerText", button); //Executing JavaScript directly js.executeScript("console.log('hello world')"); **Python** # Stores the header element header = driver.find_element(By.CSS_SELECTOR, "h1") # Executing JavaScript to capture innerText of header element driver.execute_script('return arguments[0].innerText', header) **CSharp** //creating Chromedriver instance IWebDriver driver = new ChromeDriver(); //Creating the JavascriptExecutor interface object by Type casting IJavaScriptExecutor js = (IJavaScriptExecutor) driver; //Button Element IWebElement button = driver.FindElement(By.Name("btnLogin")); //Executing JavaScript to click on element js.ExecuteScript("arguments[0].click();", button); //Get return value from script String text = (String)js.ExecuteScript("return arguments[0].innerText", button); //Executing JavaScript directly js.ExecuteScript("console.log('hello world')"); **Ruby** # Stores the header element header = driver.find_element(css: 'h1') # Get return value from script result = driver.execute_script("return arguments[0].innerText", header) # Executing JavaScript directly driver.execute_script("alert('hello world')") **JavaScript** Example (lines L33-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** // Stores the header element val header = driver.findElement(By.cssSelector("h1")) // Get return value from script val result = driver.executeScript("return arguments[0].innerText", header) // Executing JavaScript directly driver.executeScript("alert('hello world')") ### Print Page Prints the current page within the browser. _Note: This requires Chromium Browsers to be in headless mode_ **Java** import org.openqa.selenium.print.PrintOptions; driver.get("https://www.selenium.dev"); printer = (PrintsPage) driver; PrintOptions printOptions = new PrintOptions(); printOptions.setPageRanges("1-2"); Pdf pdf = printer.print(printOptions); String content = pdf.getContent(); **Python** from selenium.webdriver.common.print_page_options import PrintOptions print_options = PrintOptions() print_options.page_ranges = ['1-2'] driver.get("printPage.html") base64code = driver.print_page(print_options) **CSharp** // code sample not available please raise a PR **Ruby** driver.navigate_to 'https://www.selenium.dev' base64encodedContent = driver.print_page(orientation: 'landscape') **JavaScript** Example (lines L22-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/interactions/windows.spec.js **Kotlin** driver.get("https://www.selenium.dev") val printer = driver as PrintsPage val printOptions = PrintOptions() printOptions.setPageRanges("1-2") val pdf: Pdf = printer.print(printOptions) val content = pdf.content --- # Virtual Authenticator Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/interactions/virtual_authenticator/ A representation of the Web Authenticator model. Web applications can enable a public key-based authentication mechanism known as Web Authentication to authenticate users in a passwordless manner. [Web Authentication](https://www.w3.org/TR/webauthn-2/) defines APIs that allows a user to create a public-key credential and register it with an authenticator. An authenticator can be a hardware device or a software entity that stores user's public-key credentials and retrieves them on request. As the name suggests, Virtual Authenticator emulates such authenticators for testing. ## Virtual Authenticator Options A Virtual Authenticatior has a [set of properties](https://www.w3.org/TR/webauthn-2/#sctn-automation-virtual-authenticators). These properties are mapped as VirtualAuthenticatorOptions in the Selenium bindings. **Java** Example (lines L55-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L48-55): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L40-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L11-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticatorOptions.spec.js **Kotlin** ## Add Virtual Authenticator It creates a new virtual authenticator with the provided properties. **Java** Example (lines L68-L73): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L63-71): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L53-L58): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L51-L55): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Remove Virtual Authenticator Removes the previously added virtual authenticator. **Java** Example (lines L86): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines 80-86): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L68-L74): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L62-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Create Resident Credential Creates a resident (stateful) credential with the given required credential [parameters](https://w3c.github.io/webauthn/#sctn-automation-add-credential). **Java** Example (lines L100-L103): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines 103-107): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L89-L97): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L80-L94): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Create Non-Resident Credential Creates a resident (stateless) credential with the given required credential [parameters](https://w3c.github.io/webauthn/#sctn-automation-add-credential). **Java** Example (lines L143-L145): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L145-148): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L140-L147): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L136-L140): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Add Credential Registers the credential with the authenticator. **Java** Example (lines L137-L146): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L139-150): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L150): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L131-L142): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Get Credential Returns the list of credentials owned by the authenticator. **Java** Example (lines L157-L171): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L162-178): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L183): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L154-L170): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Remove Credential Removes a credential from the authenticator based on the passed credential id. **Java** Example (lines L181-L190): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L189-198): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L209): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** **Kotlin** ## Remove All Credentials Removes all the credentials from the authenticator. **Java** Example (lines L196-L205): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L207-216): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L239): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L181-L190): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** ## Set User Verified Sets whether the authenticator will simulate success or fail on user verification. **Java** Example (lines L211-L212): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/interactions/VirtualAuthenticatorTest.java **CSharp** Example (lines L224-225): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Interactions/VirtualAuthenticatorTest.cs **Ruby** **Python** Example (lines L245-L247): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/interactions/test_virtual_authenticator.py **JavaScript** Example (lines L197-L197): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/virtual_authenticator/virtualAuthenticator.spec.js **Kotlin** --- # Actions API Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/actions_api/ A low-level interface for providing virtualized device input actions to the web browser. In addition to the high-level [element interactions](https://www.selenium.dev/documentation/webdriver/elements/interactions/), the [Actions API](https://w3c.github.io/webdriver/#dfn-actions) provides granular control over exactly what designated input devices can do. Selenium provides an interface for 3 kinds of input sources: a key input for keyboard devices, a pointer input for a mouse, pen or touch devices, and wheel inputs for scroll wheel devices (introduced in Selenium 4.2). Selenium allows you to construct individual action commands assigned to specific inputs and chain them together and call the associated perform method to execute them all at once. ## Action Builder In the move from the legacy JSON Wire Protocol to the new W3C WebDriver Protocol, the low level building blocks of actions became especially detailed. It is extremely powerful, but each input device has a number of ways to use it and if you need to manage more than one device, you are responsible for ensuring proper synchronization between them. Thankfully, you likely do not need to learn how to use the low level commands directly, since almost everything you might want to do has been given a convenience method that combines the lower level commands for you. These are all documented in keyboard, mouse, pen, and wheel pages. ## Pause Pointer movements and Wheel scrolling allow the user to set a duration for the action, but sometimes you just need to wait a beat between actions for things to work correctly. **Java** Example (lines L21-L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/ActionsTest.java **Python** Example (lines L13-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_actions.py **CSharp** Example (lines L18-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/ActionsTest.cs **Ruby** Example (lines L12-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/actions_spec.rb **JavaScript** Example (lines L18-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/actionsTest.spec.js **Kotlin** Example (lines L22-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/ActionsTest.kt ## Release All Actions An important thing to note is that the driver remembers the state of all the input items throughout a session. Even if you create a new instance of an actions class, the depressed keys and the location of the pointer will be in whatever state a previously performed action left them. There is a special method to release all currently depressed keys and pointer buttons. This method is implemented differently in each of the languages because it does not get executed with the perform method. **Java** Example (lines L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/ActionsTest.java **Python** Example (lines L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_actions.py **CSharp** Example (lines L44): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/ActionsTest.cs **Ruby** Example (lines L36): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/actions_spec.rb **JavaScript** Example (lines L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/actionsTest.spec.js **Kotlin** Example (lines L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/ActionsTest.kt --- # Keyboard actions Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/actions_api/keyboard/ A representation of any key input device for interacting with a web page. There are only 2 actions that can be accomplished with a keyboard: pressing down on a key, and releasing a pressed key. In addition to supporting ASCII characters, each keyboard key has a representation that can be pressed or released in designated sequences. ## Keys In addition to the keys represented by regular unicode, unicode values have been assigned to other keyboard keys for use with Selenium. Each language has its own way to reference these keys; the full list can be found [here](https://www.w3.org/TR/webdriver/#keyboard-actions). **Java** Use the [Java Keys enum](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/java/src/org/openqa/selenium/Keys.java#L28) **Python** Use the [Python Keys class](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/py/selenium/webdriver/common/keys.py#L23) **CSharp** Use the [.NET static Keys class](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/dotnet/src/webdriver/Keys.cs#L28) **Ruby** Use the [Ruby KEYS constant](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/rb/lib/selenium/webdriver/common/keys.rb#L28) **JavaScript** Use the [JavaScript KEYS constant](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/javascript/node/selenium-webdriver/lib/input.js#L44) **Kotlin** Use the [Java Keys enum](https://github.com/SeleniumHQ/selenium/blob/selenium-4.2.0/java/src/org/openqa/selenium/Keys.java#L28) ## Key down **Java** Example (lines L17-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/KeysTest.java **Python** Example (lines L10-L13): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_keys.py **CSharp** Example (lines L17-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/KeysTest.cs **Ruby** Example (lines L13-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/keys_spec.rb **JavaScript** Example (lines L20-L23): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/keysTest.spec.js **Kotlin** Example (lines L19-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/KeysTest.kt ## Key up **Java** Example (lines L30-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/KeysTest.java **Python** Example (lines L21-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_keys.py **CSharp** Example (lines L30-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/KeysTest.cs **Ruby** Example (lines L25-L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/keys_spec.rb **JavaScript** Example (lines L34-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/keysTest.spec.js **Kotlin** Example (lines L32-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/KeysTest.kt ## Send keys This is a convenience method in the Actions API that combines keyDown and keyUp commands in one action. Executing this command differs slightly from using the element method, but primarily this gets used when needing to type multiple characters in the middle of other actions. ### Active Element **Java** Example (lines L45-L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/KeysTest.java **Python** Example (lines L34-L36): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_keys.py **CSharp** Example (lines L45-L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/KeysTest.cs **Ruby** Example (lines L39-L41): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/keys_spec.rb **JavaScript** Example (lines L50-L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/keysTest.spec.js **Kotlin** Example (lines L47-L49): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/KeysTest.kt ### Designated Element **Java** Example (lines L59-L62): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/KeysTest.java **Python** Example (lines L45-L48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_keys.py **CSharp** Example (lines L58-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/KeysTest.cs **Ruby** Example (lines L51-L54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/keys_spec.rb **JavaScript** Example (lines L61-L65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/keysTest.spec.js **Kotlin** Example (lines L60-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/KeysTest.kt ## Copy and Paste Here's an example of using all of the above methods to conduct a copy / paste action. Note that the key to use for this operation will be different depending on if it is a Mac OS or not. This code will end up with the text: `SeleniumSelenium!` **Java** Example (lines L70-L84): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/KeysTest.java **Python** Example (lines L56-L67): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_keys.py **CSharp** Example (lines L72-L82): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/KeysTest.cs **Ruby** Example (lines L64-L74): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/keys_spec.rb **JavaScript** Example (lines L75-L87): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/keysTest.spec.js **Kotlin** Example (lines L74-L86): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/KeysTest.kt --- # Mouse actions Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/actions_api/mouse/ A representation of any pointer device for interacting with a web page. There are only 3 actions that can be accomplished with a mouse: pressing down on a button, releasing a pressed button, and moving the mouse. Selenium provides convenience methods that combine these actions in the most common ways. ## Click and hold This method combines moving the mouse to the center of an element with pressing the left mouse button. This is useful for focusing a specific element: **Java** Example (lines L22-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L14-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L17-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L11-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L14-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/clickAndHold.spec.js **Kotlin** Example (lines L23-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Click and release This method combines moving to the center of an element with pressing and releasing the left mouse button. This is otherwise known as "clicking": **Java** Example (lines L34-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L26-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L30-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L22-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L14-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/clickAndRelease.spec.js **Kotlin** Example (lines L35-L38): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Alternate Button Clicks There are a total of 5 defined buttons for a Mouse: * 0 — Left Button (the default) * 1 — Middle Button (currently unsupported) * 2 — Right Button * 3 — X1 (Back) Button * 4 — X2 (Forward) Button ### Context Click This method combines moving to the center of an element with pressing and releasing the right mouse button (button 2). This is otherwise known as "right-clicking": **Java** Example (lines L46-L49): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L37-L40): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L43-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L34-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L15-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/rightClick.spec.js **Kotlin** Example (lines L47-L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ### Back Click There is no convenience method for this, it is just pressing and releasing mouse button 3 **Java** Example (lines L60-L66): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L51-L54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L59-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L47-L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L19-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/backAndForwardClick.spec.js **Kotlin** Example (lines L61-L67): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ### Forward Click There is no convenience method for this, it is just pressing and releasing mouse button 4 **Java** Example (lines L78-L84): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L65-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L77-L81): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L61-L64): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L32-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/backAndForwardClick.spec.js **Kotlin** Example (lines L79-L85): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Double click This method combines moving to the center of an element with pressing and releasing the left mouse button twice. **Java** Example (lines L93-L96): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L76-L79): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L91-L94): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L73-L76): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L15-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/doubleClick.spec.js **Kotlin** Example (lines L94-L97): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Move to element This method moves the mouse to the in-view center point of the element. This is otherwise known as "hovering." Note that the element must be in the viewport or else the command will error. **Java** Example (lines L105-L108): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L87-L90): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L104-L107): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L84-L87): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L15-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/moveToElement.spec.js **Kotlin** Example (lines L106-L109): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Move by offset These methods first move the mouse to the designated origin and then by the number of pixels in the provided offset. Note that the position of the mouse must be in the viewport or else the command will error. ### Offset from Element This method moves the mouse to the in-view center point of the element, then moves by the provided offset. **Java** Example (lines L118-L121): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L98-L101): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L132-L135): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L97-L100): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L15-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/moveByOffset.spec.js **Kotlin** Example (lines L119-L122): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ### Offset from Viewport This method moves the mouse from the upper left corner of the current viewport by the provided offset. **Java** Example (lines L131-L136): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L110-L112): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L146-L150): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L114-L116): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L27-L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/moveByOffset.spec.js **Kotlin** Example (lines L132-L137): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ### Offset from Current Pointer Location This method moves the mouse from its current position by the offset provided by the user. If the mouse has not previously been moved, the position will be in the upper left corner of the viewport. Note that the pointer position does not change when the page is scrolled. Note that the first argument X specifies to move right when positive, while the second argument Y specifies to move down when positive. So `moveByOffset(30, -10)` moves right 30 and up 10 from the current mouse position. **Java** Example (lines L153-L155): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L126-L128): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L167-L169): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L128-L130): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L40): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/moveByOffset.spec.js **Kotlin** Example (lines L154-L156): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Drag and Drop on Element This method firstly performs a click-and-hold on the source element, moves to the location of the target element and then releases the mouse. **Java** Example (lines L166-L170): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L139-L143): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L181-L185): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L141-L145): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L27-L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/dragAndDrop.spec.js **Kotlin** Example (lines L167-L171): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt ## Drag and Drop by Offset This method firstly performs a click-and-hold on the source element, moves to the given offset and then releases the mouse. **Java** Example (lines L179-L184): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/MouseTest.java **Python** Example (lines L151-L156): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_mouse.py **CSharp** Example (lines L195-L200): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/MouseTest.cs **Ruby** Example (lines L153-L158): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/mouse_spec.rb **JavaScript** Example (lines L15-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/mouse/dragAndDrop.spec.js **Kotlin** Example (lines L180-L185): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/MouseTest.kt --- # Pen actions Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/actions_api/pen/ A representation of a pen stylus kind of pointer input for interacting with a web page. A Pen is a type of pointer input that has most of the same behavior as a mouse, but can also have event properties unique to a stylus. Additionally, while a mouse has 5 buttons, a pen has 3 equivalent button states: * 0 — Touch Contact (the default; equivalent to a left click) * 2 — Barrel Button (equivalent to a right click) * 5 — Eraser Button (currently unsupported by drivers) ## Using a Pen **Java** Example (lines L26-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/PenTest.java **Python** Example (lines L12-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_pen.py **CSharp** Example (lines L19-L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/PenTest.cs **Ruby** Example (lines L11-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/pen_spec.rb **JavaScript** **Kotlin** Example (lines L23-L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/PenTest.kt ## Adding Pointer Event Attributes **Java** Example (lines L67-L81): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/PenTest.java **Python** Example (lines L53-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_pen.py **CSharp** Example (lines L64-L77): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/PenTest.cs **Ruby** Example (lines L50-L56): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/pen_spec.rb **JavaScript** **Kotlin** Example (lines L64-L78): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/PenTest.kt --- # Scroll wheel actions Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/actions_api/wheel/ A representation of a scroll wheel input device for interacting with a web page. There are 5 scenarios for scrolling on a page. ## Scroll to element This is the most common scenario. Unlike traditional click and send keys methods, the actions class does not automatically scroll the target element into view, so this method will need to be used if elements are not already inside the viewport. This method takes a web element as the sole argument. Regardless of whether the element is above or below the current viewscreen, the viewport will be scrolled so the bottom of the element is at the bottom of the screen. **Java** Example (lines L17-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/WheelTest.java **Python** Example (lines L11-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_wheel.py **CSharp** Example (lines L17-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/WheelTest.cs **Ruby** Example (lines L11-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/wheel_spec.rb **JavaScript** Example (lines L16-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/wheelTest.spec.js **Kotlin** Example (lines L18-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/WheelTest.kt ## Scroll by given amount This is the second most common scenario for scrolling. Pass in an delta x and a delta y value for how much to scroll in the right and down directions. Negative values represent left and up, respectively. **Java** Example (lines L29-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/WheelTest.java **Python** Example (lines L22-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_wheel.py **CSharp** Example (lines L31-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/WheelTest.cs **Ruby** Example (lines L22-L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/wheel_spec.rb **JavaScript** Example (lines L26-L31): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/wheelTest.spec.js **Kotlin** Example (lines L30-L34): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/WheelTest.kt ## Scroll from an element by a given amount This scenario is effectively a combination of the above two methods. To execute this use the "Scroll From" method, which takes 3 arguments. The first represents the origination point, which we designate as the element, and the second two are the delta x and delta y values. If the element is out of the viewport, it will be scrolled to the bottom of the screen, then the page will be scrolled by the provided delta x and delta y values. **Java** Example (lines L42-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/WheelTest.java **Python** Example (lines L35-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_wheel.py **CSharp** Example (lines L46-L53): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/WheelTest.cs **Ruby** Example (lines L34-L38): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/wheel_spec.rb **JavaScript** Example (lines L40-L44): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/wheelTest.spec.js **Kotlin** Example (lines L43-L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/WheelTest.kt ## Scroll from an element with an offset This scenario is used when you need to scroll only a portion of the screen, and it is outside the viewport. Or is inside the viewport and the portion of the screen that must be scrolled is a known offset away from a specific element. This uses the "Scroll From" method again, and in addition to specifying the element, an offset is specified to indicate the origin point of the scroll. The offset is calculated from the center of the provided element. If the element is out of the viewport, it first will be scrolled to the bottom of the screen, then the origin of the scroll will be determined by adding the offset to the coordinates of the center of the element, and finally the page will be scrolled by the provided delta x and delta y values. Note that if the offset from the center of the element falls outside of the viewport, it will result in an exception. **Java** Example (lines L57-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/WheelTest.java **Python** Example (lines L50-L54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_wheel.py **CSharp** Example (lines L66-L75): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/WheelTest.cs **Ruby** Example (lines L48-L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/wheel_spec.rb **JavaScript** Example (lines L57-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/wheelTest.spec.js **Kotlin** Example (lines L59-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/WheelTest.kt ## Scroll from a offset of origin (element) by given amount The final scenario is used when you need to scroll only a portion of the screen, and it is already inside the viewport. This uses the "Scroll From" method again, but the viewport is designated instead of an element. An offset is specified from the upper left corner of the current viewport. After the origin point is determined, the page will be scrolled by the provided delta x and delta y values. Note that if the offset from the upper left corner of the viewport falls outside of the screen, it will result in an exception. **Java** Example (lines L73-L76): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/actions_api/WheelTest.java **Python** Example (lines L66-L70): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/actions_api/test_wheel.py **CSharp** Example (lines L89-L97): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/ActionsAPI/WheelTest.cs **Ruby** Example (lines L63-L66): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/actions_api/wheel_spec.rb **JavaScript** Example (lines L75-L77): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/actionsApi/wheelTest.spec.js **Kotlin** Example (lines L75-L78): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/actions_api/WheelTest.kt --- # Support features Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/ Support classes provide optional higher level features. The core libraries of Selenium try to be low level and non-opinionated. The Support classes in each language provide opinionated wrappers for common interactions that may be used to simplify some behaviors. --- # Waiting with Expected Conditions Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/expected_conditions/ These are classes used to describe what needs to be waited for. Expected Conditions are used with Explicit Waits. Instead of defining the block of code to be executed with a _lambda_, an expected conditions method can be created to represent common things that get waited on. Some methods take locators as arguments, others take elements as arguments. These methods can include conditions such as: * element exists * element is stale * element is visible * text is visible * title contains specified value **Java** [Expected Conditions Documentation](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html) **Python** Example (lines L14-L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_expected_conditions.py **CSharp** .NET stopped supporting Expected Conditions in Selenium 4 to minimize maintenance hassle and redundancy. **Ruby** Ruby makes frequent use of blocks, procs and lambdas and does not need Expected Conditions classes **JavaScript** **Kotlin** --- # Command Listeners Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/listeners/ These allow you to execute custom actions in every time specific Selenium commands are sent **Java** **Python** **CSharp** **Ruby** **JavaScript** **Kotlin** --- # Working With Colors Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/colors/ You will occasionally want to validate the colour of something as part of your tests; the problem is that colour definitions on the web are not constant. Would it not be nice if there was an easy way to compare a HEX representation of a colour with a RGB representation of a colour, or a RGBA representation of a colour with a HSLA representation of a colour? Worry not. There is a solution: the _Color_ class! First of all, you will need to import the class: **Java** import org.openqa.selenium.support.Color; **Python** from selenium.webdriver.support.color import Color **CSharp** **Ruby** include Selenium::WebDriver::Support **JavaScript** **Kotlin**import org.openqa.selenium.support.Color You can now start creating colour objects. Every colour object will need to be created from a string representation of your colour. Supported colour representations are: **Java** private final Color HEX_COLOUR = Color.fromString("#2F7ED8"); private final Color RGB_COLOUR = Color.fromString("rgb(255, 255, 255)"); private final Color RGB_COLOUR = Color.fromString("rgb(40%, 20%, 40%)"); private final Color RGBA_COLOUR = Color.fromString("rgba(255, 255, 255, 0.5)"); private final Color RGBA_COLOUR = Color.fromString("rgba(40%, 20%, 40%, 0.5)"); private final Color HSL_COLOUR = Color.fromString("hsl(100, 0%, 50%)"); private final Color HSLA_COLOUR = Color.fromString("hsla(100, 0%, 50%, 0.5)"); **Python** HEX_COLOUR = Color.from_string('#2F7ED8') RGB_COLOUR = Color.from_string('rgb(255, 255, 255)') RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)') RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)') RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)') HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)') HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)') **CSharp** **Ruby** HEX_COLOUR = Color.from_string('#2F7ED8') RGB_COLOUR = Color.from_string('rgb(255, 255, 255)') RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)') RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)') RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)') HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)') HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)') **JavaScript** **Kotlin** private val HEX_COLOUR = Color.fromString("#2F7ED8") private val RGB_COLOUR = Color.fromString("rgb(255, 255, 255)") private val RGB_COLOUR_PERCENT = Color.fromString("rgb(40%, 20%, 40%)") private val RGBA_COLOUR = Color.fromString("rgba(255, 255, 255, 0.5)") private val RGBA_COLOUR_PERCENT = Color.fromString("rgba(40%, 20%, 40%, 0.5)") private val HSL_COLOUR = Color.fromString("hsl(100, 0%, 50%)") private val HSLA_COLOUR = Color.fromString("hsla(100, 0%, 50%, 0.5)") The Color class also supports all of the base colour definitions specified in [http://www.w3.org/TR/css3-color/#html4](//www.w3.org/TR/css3-color/#html4). **Java** private final Color BLACK = Color.fromString("black"); private final Color CHOCOLATE = Color.fromString("chocolate"); private final Color HOTPINK = Color.fromString("hotpink"); **Python** BLACK = Color.from_string('black') CHOCOLATE = Color.from_string('chocolate') HOTPINK = Color.from_string('hotpink') **CSharp** **Ruby** BLACK = Color.from_string('black') CHOCOLATE = Color.from_string('chocolate') HOTPINK = Color.from_string('hotpink') **JavaScript** **Kotlin** private val BLACK = Color.fromString("black") private val CHOCOLATE = Color.fromString("chocolate") private val HOTPINK = Color.fromString("hotpink") Sometimes browsers will return a colour value of "transparent" if no colour has been set on an element. The Color class also supports this: **Java** private final Color TRANSPARENT = Color.fromString("transparent"); **Python** TRANSPARENT = Color.from_string('transparent') **CSharp** **Ruby** TRANSPARENT = Color.from_string('transparent') **JavaScript** **Kotlin** private val TRANSPARENT = Color.fromString("transparent") You can now safely query an element to get its colour/background colour knowing that any response will be correctly parsed and converted into a valid Color object: **Java** Color loginButtonColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("color")); Color loginButtonBackgroundColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("background-color")); **Python** login_button_colour = Color.from_string(driver.find_element(By.ID,'login').value_of_css_property('color')) login_button_background_colour = Color.from_string(driver.find_element(By.ID,'login').value_of_css_property('background-color')) **CSharp** **Ruby** login_button_colour = Color.from_string(driver.find_element(id: 'login').css_value('color')) login_button_background_colour = Color.from_string(driver.find_element(id: 'login').css_value('background-color')) **JavaScript** **Kotlin** val loginButtonColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("color")) val loginButtonBackgroundColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("background-color")) You can then directly compare colour objects: **Java** assert loginButtonBackgroundColour.equals(HOTPINK); **Python** assert login_button_background_colour == HOTPINK **CSharp** **Ruby** assert(login_button_background_colour == HOTPINK) **JavaScript** **Kotlin** assert(loginButtonBackgroundColour.equals(HOTPINK)) Or you can convert the colour into one of the following formats and perform a static validation: **Java** assert loginButtonBackgroundColour.asHex().equals("#ff69b4"); assert loginButtonBackgroundColour.asRgba().equals("rgba(255, 105, 180, 1)"); assert loginButtonBackgroundColour.asRgb().equals("rgb(255, 105, 180)"); **Python** assert login_button_background_colour.hex == '#ff69b4' assert login_button_background_colour.rgba == 'rgba(255, 105, 180, 1)' assert login_button_background_colour.rgb == 'rgb(255, 105, 180)' **CSharp** **Ruby** assert(login_button_background_colour.hex == '#ff69b4') assert(login_button_background_colour.rgba == 'rgba(255, 105, 180, 1)') assert(login_button_background_colour.rgb == 'rgb(255, 105, 180)') **JavaScript** **Kotlin** assert(loginButtonBackgroundColour.asHex().equals("#ff69b4")) assert(loginButtonBackgroundColour.asRgba().equals("rgba(255, 105, 180, 1)")) assert(loginButtonBackgroundColour.asRgb().equals("rgb(255, 105, 180)")) Colours are no longer a problem. --- # Working with select list elements Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/select_lists/ Select lists have special behaviors compared to other elements. The Select object will now give you a series of commands that allow you to interact with a `` element is being worked with. ### Single select This is the standard drop-down object where one and only one option may be selected. ```html ``` ### Multiple select This select list allows selecting and deselecting more than one option at a time. This only applies to ` ``` ## Create class First locate a `` element is disabled. **Java** Example (lines L23-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L9-L10): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L23-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L13-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L18-L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L20-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ## List options There are two lists that can be obtained: ### All options Get a list of all options in the `` element. For a standard select list this will only be a list with one element, for a multiple select list it can contain zero or many elements. **Java** Example (lines L54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L40): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L56): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ## Select option The Select class provides three ways to select an option. Note that for multiple select type Select lists, you can repeat these methods for each element you want to select. ### Text Select the option based on its visible text **Java** Example (lines L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ### Value Select the option based on its value attribute **Java** Example (lines L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L23): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ### Index Select the option based on its position in the list **Java** Example (lines L36): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L36): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L26): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L31): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ### Disabled options Options with a `disabled` attribute may not be selected. ```html ``` **Java** Example (lines L77-L79): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L60-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L77): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L62-L64): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L73-L76): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L74-L76): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt ## De-select option Only multiple select type select lists can have options de-selected. You can repeat these methods for each element you want to select. **Java** Example (lines L66): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/support/SelectListTest.java **Python** Example (lines L49): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/support/test_select_list.py **CSharp** Example (lines L65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Support/SelectListTest.cs **Ruby** Example (lines L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/support/select_list_spec.rb **JavaScript** Example (lines L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/select/selectListTest.spec.js **Kotlin** Example (lines L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/kotlin/src/test/kotlin/dev/selenium/support/SelectListTest.kt --- # ThreadGuard Area: Elements and interactions URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/support_features/thread_guard/

This class is only available in the Java Binding

ThreadGuard checks that a driver is called only from the same thread that created it. Threading issues especially when running tests in Parallel may have mysterious and hard to diagnose errors. Using this wrapper prevents this category of errors and will raise an exception when it happens. The following example simulate a clash of threads: ```java public class DriverClash { //thread main (id 1) created this driver private WebDriver protectedDriver = ThreadGuard.protect(new ChromeDriver()); static { System.setProperty("webdriver.chrome.driver", ""); } //Thread-1 (id 24) is calling the same driver causing the clash to happen Runnable r1 = () -> {protectedDriver.get("https://selenium.dev");}; Thread thr1 = new Thread(r1); void runThreads(){ thr1.start(); } public static void main(String[] args) { new DriverClash().runThreads(); } } ``` The result shown below: ```text Exception in thread "Thread-1" org.openqa.selenium.WebDriverException: Thread safety error; this instance of WebDriver was constructed on thread main (id 1)and is being accessed by thread Thread-1 (id 24) This is not permitted and *will* cause undefined behaviour ``` As seen in the example: * `protectedDriver` Will be created in Main thread * We use Java `Runnable` to spin up a new process and a new `Thread` to run the process * Both `Thread` will clash because the Main Thread does not have `protectedDriver` in it's memory. * `ThreadGuard.protect` will throw an exception. #### Note: This does not replace the need for using `ThreadLocal` to manage drivers when running parallel. --- # Waiting Strategies Area: Waiting URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/waits/ Perhaps the most common challenge for browser automation is ensuring that the web application is in a state to execute a particular Selenium command as desired. The processes often end up in a _race condition_ where sometimes the browser gets into the right state first (things work as intended) and sometimes the Selenium code executes first (things do not work as intended). This is one of the primary causes of _flaky tests_. All navigation commands wait for a specific `readyState` value based on the page load strategy (the default value to wait for is `"complete"`) before the driver returns control to the code. The `readyState` only concerns itself with loading assets defined in the HTML, but loaded JavaScript assets often result in changes to the site, and elements that need to be interacted with may not yet be on the page when the code is ready to execute the next Selenium command. Similarly, in a lot of single page applications, elements get dynamically added to a page or change visibility based on a click. An element must be both present and displayed on the page in order for Selenium to interact with it. Take this page for example: https://www.selenium.dev/selenium/web/dynamic.html When the "Add a box!" button is clicked, a "div" element that does not exist is created. When the "Reveal a new input" button is clicked, a hidden text field element is displayed. In both cases the transition takes a couple seconds. If the Selenium code is to click one of these buttons and interact with the resulting element, it will do so before that element is ready and fail. The first solution many people turn to is adding a sleep statement to pause the code execution for a set period of time. Because the code can't know exactly how long it needs to wait, this can fail when it doesn't sleep long enough. Alternately, if the value is set too high and a sleep statement is added in every place it is needed, the duration of the session can become prohibitive. Selenium provides two different mechanisms for synchronization that are better. ## Implicit waits Selenium has a built-in way to automatically wait for elements called an _implicit wait_. An implicit wait value can be set either with the timeouts capability in the browser options, or with a driver method (as shown below). This is a global setting that applies to every element location call for the entire session. The default value is `0`, which means that if the element is not found, it will immediately return an error. If an implicit wait is set, the driver will wait for the duration of the provided value before returning the error. Note that as soon as the element is located, the driver will return the element reference and the code will continue executing, so a larger implicit wait value won't necessarily increase the duration of the session. *Warning:* Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For example, setting an implicit wait of 10 seconds and an explicit wait of 15 seconds could cause a timeout to occur after 20 seconds. Solving our example with an implicit wait looks like this: **Java** Example (lines L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java **Python** Example (lines L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/waits/test_waits.py **CSharp** Example (lines L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs **Ruby** Example (lines L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/waits/waits_spec.rb **JavaScript** Example (lines L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/waits/waits.spec.js **Kotlin** Example (lines L19): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunkexamples/kotlin/src/test/kotlin/dev/selenium/waits/WaitsTest.kt ## Explicit waits _Explicit waits_ are loops added to the code that poll the application for a specific condition to evaluate as true before it exits the loop and continues to the next command in the code. If the condition is not met before a designated timeout value, the code will give a timeout error. Since there are many ways for the application not to be in the desired state, explicit waits are a great choice to specify the exact condition to wait for in each place it is needed. Another nice feature is that, by default, the Selenium Wait class automatically waits for the designated element to exist. **Java** This example shows the condition being waited for as a _lambda_. Java also supports Expected Conditions Example (lines L67-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java **Python** This example shows the condition being waited for as a _lambda_. Python also supports Expected Conditions Example (lines L41-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/waits/test_waits.py **CSharp** Example (lines L56-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs **Ruby** Example (lines L42-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/waits/waits_spec.rb **JavaScript** JavaScript also supports Expected Conditions Example (lines L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/waits/waits.spec.js **Kotlin** Example (lines L36-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunkexamples/kotlin/src/test/kotlin/dev/selenium/waits/WaitsTest.kt ### Customization The Wait class can be instantiated with various parameters that will change how the conditions are evaluated. This can include: * Changing how often the code is evaluated (polling interval) * Specifying which exceptions should be handled automatically * Changing the total timeout length * Customizing the timeout message For instance, if the _element not interactable_ error is retried by default, then we can add an action on a method inside the code getting executed (we just need to make sure that the code returns `true` when it is successful): **Java** The easiest way to customize Waits in Java is to use the `FluentWait` class: Example (lines L82-L92): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java **Python** Example (lines L53-L55): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/waits/test_waits.py **CSharp** Example (lines L70-L79): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs **Ruby** Example (lines L54-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/waits/waits_spec.rb **JavaScript** **Kotlin** Example (lines L51-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunkexamples/kotlin/src/test/kotlin/dev/selenium/waits/WaitsTest.kt --- # WebDriver BiDi Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/ WebDriver BiDi is the W3C standard bidirectional protocol for browser automation, created by the Selenium project together with the browser vendors. It adds a WebSocket connection to WebDriver so scripts can stream and react to browser events — network requests, console messages, JavaScript errors — and it is the cross-browser replacement for the Chrome DevTools Protocol. BiDirectional means that communication is happening in two directions simultaneously. The traditional WebDriver model involves strict request/response commands which only allows for communication to happen in one direction at any given time. In most cases this is what you want; it ensures that the browser is doing the expected things in the right order, but there are a number of interesting things that can be done with asynchronous interactions. This functionality is currently available in a limited fashion with the [Chrome DevTools Protocol] (CDP), but to address some of its drawbacks, the Selenium team, along with the major browser vendors, have worked to create the new [WebDriver BiDi Protocol](https://w3c.github.io/webdriver-bidi/). This specification aims to create a stable, cross-browser API that leverages bidirectional communication for enhanced browser automation and testing functionality, including streaming events from the user agent to the controlling software via WebSockets. Users will be able to listen for and record or manipulate events as they happen during the course of a Selenium session. ### Enabling BiDi in Selenium In order to use WebDriver BiDi, setting the capability in the browser options will enable the required functionality: **Java** options.setCapability("webSocketUrl", true); **Python** options.enable_bidi = True **CSharp** UseWebSocketUrl = true, **Ruby** options.web_socket_url = true **JavaScript** Options().enableBidi(); **Kotlin** options.setCapability("webSocketUrl", true); This enables the WebSocket connection for bidirectional communication, unlocking the full potential of the WebDriver BiDi protocol. Note that Selenium is updating its entire implementation from WebDriver Classic to WebDriver BiDi (while maintaining backwards compatibility as much as possible), but this section of documentation focuses on the new functionality that bidirectional communication allows. The low-level BiDi domains will be accessible in the code to the end user, but the goal is to provide high-level APIs that are straightforward methods of real-world use cases. As such, the low-level components will not be documented, and this section will focus only on the user-friendly features that we encourage users to take advantage of. If there is additional functionality you'd like to see, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md). --- # WebDriver BiDi Logging Features Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/logging/ These features are related to logging. Because "logging" can refer to so many different things, these methods are made available via a "script" namespace. Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi ## Console Message Handlers Record or take actions on `console.log` events. ### Add Handler **Java** Example (lines 35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/high_level/LogTest.java **Python** Example (lines L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **CSharp** **Ruby** Example (lines L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/bidi/logging_spec.rb **JavaScript** **Kotlin** ### Remove Handler You need to store the ID returned when adding the handler to delete it. **Java** Example (lines 53-54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/high_level/LogTest.java **Python** Example (lines L23-24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **CSharp** **Ruby** Example (lines L22-L23): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/bidi/logging_spec.rb **JavaScript** **Kotlin** ## JavaScript Exception Handlers Record or take actions on JavaScript exception events. ### Add Handler **Java** Example (lines 65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/high_level/LogTest.java **Python** Example (lines L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **CSharp** **Ruby** Example (lines L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/bidi/logging_spec.rb **JavaScript** **Kotlin** ### Remove Handler You need to store the ID returned when adding the handler to delete it. **Java** Example (lines 81-82): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/high_level/LogTest.java **Python** Example (lines L47-48): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **CSharp** **Ruby** Example (lines L44-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/bidi/logging_spec.rb **JavaScript** **Kotlin** --- # WebDriver BiDi Network Features Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/network/ These features are related to networking, and are made available via a "network" namespace. The implementation of these features is being tracked here: [#13993](https://github.com/SeleniumHQ/selenium/issues/13993) Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi ## Authentication Handlers Authentication handlers enable you to intercept authentication requests that occur during a network interaction. These handlers are useful for automating scenarios involving authentication prompts, such as Basic Auth or Digest Auth. They allow you to programmatically provide credentials or modify the authentication flow. ### Add Handler **Java** **Python** **CSharp** **Ruby** Example (lines L7-L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/bidi/network_spec.rb **JavaScript** **Kotlin** ## Request Handlers Request handlers allow you to intercept and manipulate outgoing network requests before they are sent to the server. This can be used to modify request headers, change the request body, or block specific requests. Request handlers are essential for testing and debugging scenarios where you need control over outgoing traffic. ### Add Handler **Java** **Python** **CSharp** **Ruby** **JavaScript** **Kotlin** ## Response Handlers Response handlers enable you to intercept and manipulate incoming responses from the server. They are particularly useful for testing scenarios involving response data, such as verifying or modifying response headers, status codes, or content before it reaches the browser. **Java** **Python** **CSharp** **Ruby** **JavaScript** **Kotlin** ## Remove Handler **Java** **Python** **CSharp** **Ruby** **JavaScript** **Kotlin** ## Clear Handlers **Java** **Python** **CSharp** **Ruby** **JavaScript** **Kotlin** --- # WebDriver BiDi Script Features Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/script/ These features are related to scripts, and are made available via a "script" namespace. The implementation of these features is being tracked here: [#13992](https://github.com/SeleniumHQ/selenium/issues/13992) Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi ## Script Pinning ## Execute Script ## DOM Mutation Handlers --- # BiDirectional API (W3C compliant) Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/ Examples of working with the W3C WebDriver BiDi protocol in Selenium — the standard, cross-browser replacement for the Chrome DevTools Protocol. These APIs stream events from the browser over a WebSocket, for network interception, console logs, and browser event handling. The following list of APIs will be growing as the [WebDriver BiDirectional Protocol](https://w3c.github.io/webdriver-bidi/) grows and browser vendors implement the same. Additionally, Selenium will try to support real-world use cases that internally use a combination of W3C BiDi protocol APIs. If there is additional functionality you'd like to see, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md). --- # Browsing Context Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/browsing_context/ ## Commands This section contains the APIs related to browsing context commands. ### Open a new window Creates a new browsing context in a new window. **Java** Example (lines L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L23-L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Create.cs **Ruby** **JavaScript** Example (lines L35-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Open a new tab Creates a new browsing context in a new tab. **Java** Example (lines L60-L63): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L13-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Create.cs **Ruby** **JavaScript** Example (lines L50-L52): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Use existing window handle Creates a browsing context for the existing tab/window to run commands. **Java** Example (lines L39-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L53-L55): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Create.cs **Ruby** **JavaScript** Example (lines L27-L30): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Open a window with a reference browsing context A reference browsing context is a [top-level browsing context](https://html.spec.whatwg.org/multipage/document-sequences.html#top-level-browsing-context). The API allows to pass the reference browsing context, which is used to create a new window. The implementation is operating system specific. **Java** Example (lines L52-L57): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L43-L47): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Create.cs **Ruby** **JavaScript** Example (lines L42-L45): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Open a tab with a reference browsing context A reference browsing context is a [top-level browsing context](https://html.spec.whatwg.org/multipage/document-sequences.html#top-level-browsing-context). The API allows to pass the reference browsing context, which is used to create a new tab. The implementation is operating system specific. **Java** Example (lines L66-L71): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L33-L37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Create.cs **Ruby** **JavaScript** Example (lines L57-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Navigate to a URL **Java** Example (lines L74-L82): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L13-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Navigate.cs **Ruby** **JavaScript** Example (lines L69): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Navigate to a URL with readiness state **Java** Example (lines L85-L94): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L23-L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Navigate.cs **Ruby** **JavaScript** Example (lines L81-L84): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Get browsing context tree Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context. **Java** Example (lines L97-L110): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L14-L20): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.GetTree.cs **Ruby** **JavaScript** Example (lines L92-L98): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Get browsing context tree with depth Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context upto the depth value passed. **Java** Example (lines L113-L125): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L26-L31): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.GetTree.cs **Ruby** **JavaScript** Example (lines L105-L111): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Get All Top level browsing contexts **Java** Example (lines L128-L135): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L37-L42): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.GetTree.cs **Ruby** **JavaScript** Example (lines L428-L433): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Close a tab/window **Java** Example (lines L138-L155): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L9-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Close.cs **Ruby** **JavaScript** Example (lines L117-L120): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Activate a browsing context **Java** Example (lines L159-L163): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L11): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Activate.cs **Ruby** **JavaScript** Example (lines L194-L196): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js Example (lines L206): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Reload a browsing context **Java** Example (lines L171-L175): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L12-L18): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Reload.cs **Ruby** **JavaScript** Example (lines L353): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Handle user prompt **Java** Example (lines L222-L230): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L16-L33): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.HandleUserPrompt.cs **Ruby** **JavaScript** Example (lines L303): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Capture Screenshot **Java** Example (lines L250-L254): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L12-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.CaptureScreenshot.cs **Ruby** **JavaScript** Example (lines L364): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Capture Viewport Screenshot **Java** Example (lines L261-L270): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L22-L25): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.CaptureScreenshot.cs **Ruby** **JavaScript** Example (lines L167-L171): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Capture Element Screenshot **Java** Example (lines L277-L282): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L31-L40): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.CaptureScreenshot.cs **Ruby** **JavaScript** Example (lines L186): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Set Viewport **Java** Example (lines L306-L309): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L12): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.SetViewport.cs **Ruby** **JavaScript** Example (lines L337): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Print page **Java** Example (lines L319-L324): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L11-L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Print.cs **Ruby** **JavaScript** Example (lines L147-L159): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Navigate back **Java** Example (lines L332-L338): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L33-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Navigate.cs **Ruby** **JavaScript** Example (lines L398): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Navigate forward **Java** Example (lines L344-L354): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L45-L53): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Navigate.cs **Ruby** **JavaScript** Example (lines L422): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ### Traverse history **Java** Example (lines L361-L367): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextTest.java **CSharp** Example (lines L73-L79): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Navigate.cs **Ruby** **JavaScript** Example (lines L380): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContext.spec.js **Kotlin** ## Events This section contains the APIs related to browsing context events. ### Browsing Context Created Event **Java** Example (lines L36-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.BrowsingContextCreated.cs **Ruby** **JavaScript** Example (lines L23-L28): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContextInspector.spec.js **Kotlin** ### Dom Content loaded Event **Java** Example (lines L56-L65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.DomContentLoaded.cs **Ruby** **JavaScript** Example (lines L53-L62): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContextInspector.spec.js **Kotlin** ### Browsing Context Loaded Event **Java** Example (lines L83-90): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L22): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.BrowsingContextLoaded.cs **Ruby** **JavaScript** Example (lines L70-L78): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContextInspector.spec.js **Kotlin** ### Navigated Started Event **Java** Example (lines L99-106): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.NavigationStarted.cs **Ruby** **JavaScript** **Kotlin** ### Fragment Navigated Event **Java** Example (lines L115-125): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.FragmentNavigated.cs **Ruby** **JavaScript** Example (lines L86-L97): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContextInspector.spec.js **Kotlin** ### User Prompt Opened Event **Java** Example (lines L115-125): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L15-L27): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.UserPrompt.cs **Ruby** **JavaScript** **Kotlin** ### User Prompt Closed Event **Java** Example (lines L152-165): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L33-L59): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.UserPrompt.cs **Ruby** **JavaScript** **Kotlin** ### Browsing Context Destroyed Event **Java** Example (lines L172-L183): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/BrowsingContextInspectorTest.java **CSharp** Example (lines L13-L23): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/BiDi/BrowsingContext/BrowsingContextTest.Event.BrowsingContextDestroyed.cs **Ruby** **JavaScript** Example (lines L105-L113): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/browsingContextInspector.spec.js **Kotlin** --- # Input Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/input/ This section contains the APIs related to input commands. ## Perform Actions **Java** Example (lines L41-L44): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ActionsTest.java **Ruby** **JavaScript** Example (lines L27-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/input.spec.js **Kotlin** ## Release Actions **Java** Example (lines L59-L65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ActionsTest.java **Ruby** **JavaScript** Example (lines L55): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/input.spec.js **Kotlin** --- # Log Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/log/ This section contains the APIs related to logging. ## Console logs Listen to the `console.log` events and register callbacks to process the event. **Java** Example (lines L33-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java **Python** Example (lines L6-L15): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **Ruby** **JavaScript** Example (lines L23-37): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/logInspector.spec.js **Kotlin** ## JavaScript exceptions Listen to the JS Exceptions and register callbacks to process the exception details. **Java** Example (lines L74-L79): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java **Python** Example (lines L30-L39): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_bidi_logging.py **Ruby** **JavaScript** Example (lines L44-54): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/logInspector.spec.js **Kotlin** ## Listen to JS Logs Listen to all JS logs at all levels and register callbacks to process the log. **Java** Example (lines L56-L61): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java **Python** **Ruby** **JavaScript** **Kotlin** --- # Network Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/network/ ## Commands This section contains the APIs related to network commands. ### Add network intercept **Java** Example (lines L36-L38): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L23-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js **Kotlin** ### Remove network intercept **Java** Example (lines L46-L50): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L32-L38): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L34-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js **Kotlin** ### Continue request blocked at authRequired phase with credentials **Java** Example (lines L57-L64): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L80-L89): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L42-L46): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js **Kotlin** ### Continue request blocked at authRequired phase without credentials **Java** Example (lines L74-L80): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L92-L108): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L56-L60): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js **Kotlin** ### Cancel request blocked at authRequired phase **Java** Example (lines L90-L96): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L111-L122): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L71-L75): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_commands.spec.js **Kotlin** ### Fail request **Java** Example (lines L104-L108): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkCommandsTest.java **Python** Example (lines L41-L59): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** **Kotlin** ## Events This section contains the APIs related to network events. ### Before Request Sent **Java** Example (lines L30-L35): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkEventsTest.java **Python** Example (lines L62-L77): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** Example (lines L23-L29): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_events.spec.js **Kotlin** ### Response Started **Java** Example (lines L45-L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkEventsTest.java **Python** **Ruby** **JavaScript** Example (lines L82-L88): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_events.spec.js **Kotlin** ### Response Completed **Java** Example (lines L62-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkEventsTest.java **Python** **Ruby** **JavaScript** Example (lines L96-L102): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/network_events.spec.js **Kotlin** ### Auth Required **Java** Example (lines L101-L106): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/NetworkEventsTest.java **Python** Example (lines L125-L143): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/bidi/test_network_commands.py **Ruby** **JavaScript** **Kotlin** --- # Script Area: WebDriver BiDi URL: https://trunk--selenium-dev.netlify.app/documentation/webdriver/bidi/w3c/script/ ## Commands This section contains the APIs related to script commands. ### Call function in a browsing context **Java** Example (lines L52-L75): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L32-L53): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Call function in a sandbox **Java** Example (lines L201-L210): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L202-L204): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Call function in a realm **Java** Example (lines L219-L229): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L222-L227): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Evaluate script in a browsing context **Java** Example (lines L239-L242): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L237-L239): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Evaluate script in a sandbox **Java** Example (lines L280-L283): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L279-L283): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Evaluate script in a realm **Java** Example (lines L293-L299): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L292-L299): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Disown handles in a browsing context **Java** Example (lines L322-L322): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L330-L330): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Disown handles in a realm **Java** Example (lines L375-L375): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L372-L372): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Get all realms **Java** Example (lines L391-L392): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L383-L385): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Get realm by type **Java** Example (lines L401-402): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L393-L395): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Get browsing context realms **Java** Example (lines L411-412): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L403-L405): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Get browsing context realms by type **Java** Example (lines L422-423): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L416-L416): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Preload a script **Java** Example (lines L463-463): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L424-L426): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ### Remove a preloaded script **Java** Example (lines L486-486): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptTest.java **Ruby** **JavaScript** Example (lines L471-L471): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_commands.spec.js **Kotlin** ## Events This section contains the APIs related to script events. ### Message **Java** Example (lines L37-L51): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptEventsTest.java **Ruby** **JavaScript** Example (lines L26-L43): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_events.spec.js **Kotlin** ### Realm Created **Java** Example (lines L58-L68): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptEventsTest.java **Ruby** **JavaScript** Example (lines L52-L65): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_events.spec.js **Kotlin** ### Realm Destroyed **Java** Example (lines L75-L85): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/ScriptEventsTest.java **Ruby** **JavaScript** Example (lines L73-L86): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/bidirectional/script_events.spec.js **Kotlin** --- # Selenium Manager Area: Driver management URL: https://trunk--selenium-dev.netlify.app/documentation/selenium_manager/ Selenium Manager is a command-line tool implemented in Rust that provides automated driver and browser management for Selenium. Selenium bindings use this tool by default, so you do not need to download it or add anything to your code or do anything else to use it. ## Motivation ***TL;DR:*** *Selenium Manager is the official driver manager of the Selenium project, and it is shipped out of the box with every Selenium release.* Selenium uses the native support implemented by each browser to carry out the automation process. For this reason, Selenium users need to place a component called _driver_ (chromedriver, geckodriver, msedgedriver, etc.) between the script using the Selenium API and the browser. For many years, managing these drivers was a manual process for Selenium users. This way, they had to download the required driver for a browser (chromedriver for Chrome, geckodriver for Firefox, etc.) and place it in the `PATH` or export the driver path as a system property (Java, JavaScript, etc.). But this process was cumbersome and led to maintainability issues. Let's consider an example. Imagine you manually downloaded the required chromedriver for driving your Chrome with Selenium. When you did this process, the stable version of Chrome was 113, so you downloaded chromedriver 113 and put it in your `PATH`. At that moment, your Selenium script executed correctly. But the *problem* is that Chrome is *evergreen*. This name refers to Chrome's ability to upgrade automatically and silently to the next stable version when available. This feature is excellent for end-users but potentially dangerous for browser automation. Let's go back to the example to discover it. Your local Chrome eventually updates to version 115. And that moment, your Selenium script is broken due to the incompatibility between the manually downloaded driver (113) and the Chrome version (115). Thus, your Selenium script fails with the following error message: *"session not created: This version of ChromeDriver only supports Chrome version 113"*. This problem is the primary reason for the existence of the so-called *driver managers* (such as [WebDriverManager](https://bonigarcia.dev/webdrivermanager/) for Java, [webdriver-manager](https://pypi.org/project/webdriver-manager/) for Python, [webdriver-manager](https://www.npmjs.com/package/webdriver-manager) for JavaScript, [WebDriverManager.Net](https://github.com/rosolko/WebDriverManager.Net) for C#, and [webdrivers](https://github.com/titusfortner/webdrivers) for Ruby). All these projects were an inspiration and a clear sign that the community needed this feature to be built in Selenium. Thus, the Selenium project has created *Selenium Manager*, the official driver manager for Selenium, shipped out of the box with each Selenium release as of version 4.6. ## Usage ***TL;DR:*** *Selenium Manager is used by the Selenium bindings when the drivers (chromedriver, geckodriver, etc.) are unavailable.* Driver management through Selenium Manager is *opt-in* for the Selenium bindings. Thus, users can continue managing their drivers manually (putting the driver in the `PATH` or using system properties) or rely on a third-party *driver manager* to do it automatically. Selenium Manager only operates as a fallback: if no driver is provided, Selenium Manager will come to the rescue. Selenium Manager is a CLI (command line interface) tool implemented in Rust to allow cross-platform execution and compiled for Windows, Linux, and macOS. The Selenium Manager binaries are shipped with each Selenium release. This way, each Selenium binding language invokes Selenium Manager to carry out the automated driver and browser management explained in the following sections. ## Automated driver management ***TL;DR:*** *Selenium Manager automatically discovers, downloads, and caches the drivers required by Selenium when these drivers are unavailable.* The primary feature of Selenium Manager is called *automated driver management*. Let's consider an example to understand it. Suppose we want to driver Chrome with Selenium (see the doc about how to [start a session with Selenium](https://www.selenium.dev/documentation/webdriver/getting_started/#your-first-script)). Before the session begins, and when the driver is unavailable, Selenium Manager manages chromedriver for us. We use the term *management* for this feature (and not just *download*) since this process is broader and implies different steps: 1. Browser version discovery. Selenium Manager discovers the browser version (e.g., Chrome, Firefox, Edge) installed in the machine that executes Selenium. This step uses shell commands (e.g., `google-chrome --version`). 2. Driver version discovery. With the discovered browser version, the proper driver version is resolved. For this step, the online metadata/endpoints maintained by the browser vendors (e.g., [chromedriver](https://chromedriver.chromium.org/downloads), [geckodriver](https://github.com/mozilla/geckodriver/releases), or [msedgedriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/)) are used. 3. Driver download. The driver URL is obtained with the resolved driver version; with that URL, the driver artifact is downloaded, uncompressed, and stored locally. 4. Driver cache. Uncompressed driver binaries are stored in a local cache folder (`~/.cache/selenium`). The next time the same driver is required, it will be used from there if the driver is already in the cache. ## Automated browser management ***TL;DR:*** *Selenium Manager automatically discovers, downloads, and caches the browsers driven with Selenium (Chrome, Firefox, and Edge) when these browsers are not installed in the local system.* As of Selenium 4.11.0, Selenium Manager also implements *automated browser management*. With this feature, Selenium Manager allows us to discover, download, and cache the different browser releases, making them seamlessly available for Selenium. Internally, Selenium Manager uses an equivalent management procedure explained in the section before, but this time, for browser releases. The browser automatically managed by Selenium Manager are: - Chrome. Based on [Chrome for Testing (CfT)](https://googlechromelabs.github.io/chrome-for-testing/), as of Selenium 4.11.0. - Firefox. Based on [public Firefox releases](https://ftp.mozilla.org/pub/firefox/releases/), as of Selenium 4.12.0. - Edge. Based on [Edge downloads](https://www.microsoft.com/en-us/edge/download), as of Selenium 4.14.0. Let's consider again the typical example of driving Chrome with Selenium. And this time, suppose Chrome is not installed on the local machine when [starting a new session](https://www.selenium.dev/documentation/webdriver/getting_started/#your-first-script)). In that case, the current stable Chrome for Testing (CfT) release will be discovered, downloaded, and cached (in `~/.cache/selenium/chrome`) by Selenium Manager. But there is more. In addition to the stable browser version, Selenium Manager also allows downloading older browser versions (in the case of Chrome for Testing, starting in version 113, the first version published as CfT). To set a browser version with Selenium, we use a browser option called [browserVersion](https://www.selenium.dev/documentation/webdriver/drivers/options/#browserversion). Let's consider another simple example. Suppose we set `browserVersion` to `114` using [Chrome options](https://www.selenium.dev/documentation/webdriver/browsers/chrome/). In this case, Selenium Manager will check if Chrome 114 is already installed. If it is, it will be used. If not, Selenium Manager will manage (i.e., discover, download, and cache) CfT 114. And in either case, the chromedriver is also managed. Finally, Selenium will start Chrome to be driven programmatically, as usual. But there is even more. In addition to fixed browser versions (e.g., `113`, `114`, `115`, etc.), we can use the following labels for `browserVersion`: - `stable`: Current CfT version. - `beta`: Next version to stable. - `dev`: Version in development at this moment. - `canary`: Nightly build for developers. - `esr`: Extended Support Release (only for Firefox). When these labels are specified, Selenium Manager first checks if a given browser is already installed (`beta`, `dev`, etc.), and when it is not detected, the browser is automatically managed. ### Edge in Windows Automated Edge management by Selenium Manager in Windows is different from other browsers. Both Chrome and Firefox (and Edge in macOS and Linux) are downloaded automatically to the local cache (`~/.cache/selenium`) by Selenium Manager. Nevertheless, the same cannot be done for Edge in Windows. The reason is that the Edge installer for Windows is distributed as a Microsoft Installer (MSI) file, designed to be executed with administrator rights. This way, when Edge is attempted to be installed with Selenium Manager in Windows with a non-administrator session, a warning message will be displayed by Selenium Manager as follows: ``` edge can only be installed in Windows with administrator permissions ``` Therefore, administrator permissions are required to install Edge in Windows automatically through Selenium Manager, and Edge is eventually installed in the usual program files folder (e.g., `C:\Program Files (x86)\Microsoft\Edge`). ## Data collection Selenium Manager will report anonymised usage [statistics](https://plausible.io/privacy-focused-web-analytics) to [Plausible](https://plausible.io/manager.selenium.dev). This allows the Selenium team to understand more about how Selenium is being used so that we can better focus our development efforts. The data being collected is: | Data | Purpose | | -----|---------| | Selenium version | This allows the Selenium developers to safely deprecate and remove features, as well as determine which new features may be available to you | | Language binding | Programming language used to execute Selenium scripts (Java, JavaScript, Python, .Net, Ruby) | | OS and architecture Selenium Manager is running on | The Selenium developers can use this information to help prioritise bug reports, and to identify if there are systemic OS-related issues | | Browser and browser version | Helping for prioritising bug reports | | Rough geolocation | Derived from the IP address you connect from. This is useful for determining where we need to focus our documentation efforts | Selenium Manager sends these data to Plausible once a day. This period is based on the TTL value (see [configuration](https://www.selenium.dev/documentation/selenium_manager/#configuration)). ### Opting out of data collection **Data collection is on by default.** To disable it, set the `SE_AVOID_STATS` environment variable to `true`. You may also disable data collection in the configuration file (see below) by setting `avoid-stats = true`. ## Configuration ***TL;DR:*** *Selenium Manager should work silently and transparently for most users. Nevertheless, there are scenarios (e.g., to specify a custom cache path or setup globally a proxy) where custom configuration can be required.* Selenium Manager is a CLI tool. Therefore, under the hood, the Selenium bindings call Selenium Manager by invoking shell commands. Like any other CLI tool, arguments can be used to specify specific capabilities in Selenium Manager. The different arguments supported by Selenium Manager can be checked by running the following command: ``` $ ./selenium-manager --help ``` In addition to CLI arguments, Selenium Manager allows two additional mechanisms for configuration: - Configuration file. Selenium Manager uses a file called `se-config.toml` located in the Selenium cache (by default, at `~/.cache/selenium`) for custom configuration values. This TOML file contains a key-value collection used for custom configuration. - Environmental variables. Each configuration key has its equivalence in environmental variables by converting each key name to uppercase, replacing the dash symbol (`-`) with an underscore (`_`), and adding the prefix `SE_`. The configuration file is honored by Selenium Manager when it is present, and the corresponding CLI parameter is not specified. Besides, the environmental variables are used when neither of the previous options (CLI arguments and configuration file) is specified. In other words, the order of preference for Selenium Manager custom configuration is as follows: 1. CLI arguments. 2. Configuration file. 3. Environment variables. Notice that the Selenium bindings use the CLI arguments to specify configuration values, which in turn, are defined in each binding using [browser options](https://www.selenium.dev/documentation/webdriver/drivers/options/). The following table summarizes all the supported arguments supported by Selenium Manager and their correspondence key in the configuration file and environment variables. | CLI argument| Configuration file | Env variable | Description | |-------------|--------------------|--------------|-------------| |`--browser BROWSER`|`browser = "BROWSER"`|`SE_BROWSER=BROWSER`|Browser name: `chrome`, `firefox`, `edge`, `iexplorer`, `safari`, `safaritp`, or `webview2`| |`--driver `|`driver = "DRIVER"`|`SE_DRIVER=DRIVER`|Driver name: `chromedriver`, `geckodriver`, `msedgedriver`, `IEDriverServer`, or `safaridriver`| |`--browser-version `|`browser-version = "BROWSER_VERSION"`|`SE_BROWSER_VERSION=BROWSER_VERSION`|Major browser version (e.g., `105`, `106`, etc. Also: `beta`, `dev`, `canary` -or `nightly`-, and `esr` -in Firefox- are accepted)| |`--driver-version `|`driver-version = "DRIVER_VERSION"`|`SE_DRIVER_VERSION=DRIVER_VERSION`|Driver version (e.g., `106.0.5249.61, 0.31.0`, etc.)| |`--browser-path `|`browser-path = "BROWSER_PATH"`|`SE_BROWSER_PATH=BROWSER_PATH`|Browser path (absolute) for browser version detection (e.g., `/usr/bin/google-chrome`, `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`, `C:\Program Files\Google\Chrome\Application\chrome.exe`)| |`--driver-mirror-url `|`driver-mirror-url = "DRIVER_MIRROR_URL"`|`SE_DRIVER_MIRROR_URL=DRIVER_MIRROR_URL`|Mirror URL for driver repositories| |`--browser-mirror-url `|`browser-mirror-url = "BROWSER_MIRROR_URL"`|`SE_BROWSER_MIRROR_URL=BROWSER_MIRROR_URL`|Mirror URL for browser repositories| |`--output `|`output = "OUTPUT"`|`SE_OUTPUT=OUTPUT`|Output type: `LOGGER` (using `INFO`, `WARN`, etc.), `JSON` (custom JSON notation), `SHELL` (Unix-like), or `MIXED` (`INFO`, `WARN`, `DEBUG`, etc. to stderr and minimal `JSON` to stdout). Default: `LOGGER`| |`--os `|`os = "OS"`|`SE_OS=OS`|Operating system for drivers and browsers (i.e., `windows`, `linux`, or `macos`)| |`--arch `|`arch = "ARCH"`|`SE_ARCH=ARCH`|System architecture for drivers and browsers (i.e., `x32`, `x64`, or `arm64`)| |`--proxy `|`proxy = "PROXY"`|`SE_PROXY=PROXY`|HTTP proxy for network connection (e.g., `myproxy:port`, `myuser:mypass@myproxy:port`)| |`--timeout `|`timeout = TIMEOUT`|`SE_TIMEOUT=TIMEOUT`|Timeout for network requests (in seconds). Default: `300`| |`--offline`|`offline = true`|`SE_OFFLINE=true`|Offline mode (i.e., disabling network requests and downloads)| |`--insecure`|`insecure = true`|`SE_INSECURE=true`|Disable TLS certificate validation (e.g., when the network requires a CA that cannot be added to the system trust store, such as a TLS-intercepting proxy). When enabled, Selenium Manager logs a warning on every run since downloaded drivers and browsers cannot be verified. Default: `false`| |`--force-browser-download`|`force-browser-download = true`|`SE_FORCE_BROWSER_DOWNLOAD=true`|Force to download browser, e.g., when a browser is already installed in the system, but you want Selenium Manager to download and use it| |`--avoid-browser-download`|`avoid-browser-download = true`|`SE_AVOID_BROWSER_DOWNLOAD=true`|Avoid to download browser, e.g., when a browser is supposed to be downloaded by Selenium Manager, but you prefer to avoid it| |`--skip-driver-in-path`|`skip-driver-in-path = true`|`SE_SKIP_DRIVER_IN_PATH=true`|Not using drivers found in the `PATH`| |`--skip-browser-in-path`|`skip-browser-in-path = true`|`SE_SKIP_BROWSER_IN_PATH=true`|Not using browsers found in the `PATH`| |`--debug`|`debug = true`|`SE_DEBUG=true`|Display `DEBUG` messages| |`--trace`|`trace = true`|`SE_TRACE=true`|Display `TRACE` messages| |`--cache-path `|`cache-path="CACHE_PATH"`|`SE_CACHE_PATH=CACHE_PATH`|Local folder used to store downloaded assets (drivers and browsers), local metadata, and configuration file. See next section for details. Default: `~/.cache/selenium`. For Windows paths in the TOML configuration file, double backslashes are required (e.g., `C:\\custom\\cache`).| |`--ttl `|`ttl = TTL`|`SE_TTL=TTL`|Time-to-live in seconds. See next section for details. Default: `3600` (1 hour)| |`--language-binding `|`language-binding = "LANGUAGE"`|`SE_LANGUAGE_BINDING=LANGUAGE`|Language that invokes Selenium Manager (e.g., Java, JavaScript, Python, DotNet, Ruby)| |`--avoid-stats`|`avoid-stats = true`|`SE_AVOID_STATS=true`|Avoid sends usage statistics to plausible.io. Default: `false`| In addition to the configuration keys specified in the table before, there are some special cases, namely: - Browser version. In addition to `browser-version`, we can use the specific configuration keys to specify custom versions per supported browser. This way, the keys `chrome-version`, `firefox-version`, `edge-version`, etc., are supported. The same applies to environment variables (i.e., `SE_CHROME_VERSION`, `SE_FIREFOX_VERSION`, `SE_EDGE_VERSION`, etc.). - Driver version. Following the same pattern, we can use `chromedriver-version`, `geckodriver-version`, `msedgedriver-version`, etc. (in the configuration file), and `SE_CHROMEDRIVER_VERSION`, `SE_GECKODRIVER_VERSION`, `SE_MSEDGEDRIVER_VERSION`, etc. (as environment variables). - Browser path. Following the same pattern, we can use `chrome-path`, `firefox-path`, `edge-path`, etc. (in the configuration file), and `SE_CHROME_PATH`, `SE_FIREFOX_PATH`, `SE_EDGE_PATH`, etc. (as environment variables). The Selenium bindings also allow to specify a custom location of the browser path using options, namely: [Chrome](https://www.selenium.dev/documentation/webdriver/browsers/chrome/#start-browser-in-a-specified-location)), [Edge](https://www.selenium.dev/documentation/webdriver/browsers/edge/#start-browser-in-a-specified-location), or [Firefox](https://www.selenium.dev/documentation/webdriver/browsers/firefox/#start-browser-in-a-specified-location). - Driver mirror. Following the same pattern, we can use `chromedriver-mirror-url`, `geckodriver-mirror-url`, `msedgedriver-mirror-url`, etc. (in the configuration file), and `SE_CHROMEDRIVER_MIRROR_URL`, `SE_GECKODRIVER_MIRROR_URL`, `SE_MSEDGEDRIVER_MIRROR_URL`, etc. (as environment variables). - Browser mirror. Following the same pattern, we can use `chrome-mirror-url`, `firefox-mirror-url`, `edge-mirror-url`, etc. (in the configuration file), and `SE_CHROME_MIRROR_URL`, `SE_FIREFOX_MIRROR_URL`, `SE_EDGE_MIRROR_URL`, etc. (as environment variables). ### Configuration from the Selenium bindings The Selenium bindings call Selenium Manager with the following CLI arguments, taken from the [browser options](/documentation/webdriver/drivers/options/) used to start the session: | Browser option | CLI argument | |----------------|--------------| |[`browserName`](/documentation/webdriver/drivers/options/#browsername)|`--browser`| |[`browserVersion`](/documentation/webdriver/drivers/options/#browserversion)|`--browser-version`| |Browser binary location (e.g., [Chrome](/documentation/webdriver/browsers/chrome/#start-browser-in-a-specified-location))|`--browser-path`| |[`proxy`](/documentation/webdriver/drivers/options/#proxy) (HTTP or SSL proxy)|`--proxy`| This means that a proxy set in the browser options is used both by the browser and by Selenium Manager to download drivers and browsers. If Selenium Manager needs a proxy that the browser should not use, set it with the `SE_PROXY` environment variable or the `proxy` key in the configuration file instead. Any other configuration value (e.g., `cache-path`, `ttl`, `offline`, or mirror URLs) cannot be set from the browser options. Since the bindings run Selenium Manager as a child process, they pass along the environment variables of the process that runs the tests. Therefore, set these values with environment variables (e.g., `SE_CACHE_PATH`, `SE_OFFLINE`) or in the `se-config.toml` configuration file. ### se-config.toml Example **se-config.toml** Example (lines L1-L21): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/selenium_manager/example_se-config.toml ### Using mirrors The mirror URLs (e.g., `driver-mirror-url` and `browser-mirror-url`, or their browser-specific variants such as `chromedriver-mirror-url` and `firefox-mirror-url`) replace the base URL of the repositories that Selenium Manager uses to discover and download drivers and browsers. Selenium Manager requests the same paths it requests from the original repository, but from the mirror, and expects the same responses. Therefore, a mirror needs to replicate the structure and the response format of the repository it replaces: | Browser | Driver repository (driver mirror) | Browser repository (browser mirror) | |---------|-----------------------------------|-------------------------------------| | Chrome | [Chrome for Testing JSON endpoints](https://googlechromelabs.github.io/chrome-for-testing/) (e.g., `known-good-versions-with-downloads.json`) for chromedriver 115 and newer, and `https://chromedriver.storage.googleapis.com/` for older versions | [Chrome for Testing JSON endpoints](https://googlechromelabs.github.io/chrome-for-testing/) | | Firefox | [geckodriver releases](https://github.com/mozilla/geckodriver/releases/) (e.g., `download/v0.36.0/geckodriver-v0.36.0-linux64.tar.gz`) plus a `geckodriver-support.json` file with the same format as [Selenium's](https://raw.githubusercontent.com/SeleniumHQ/selenium/trunk/common/geckodriver/geckodriver-support.json) | `https://ftp.mozilla.org/pub/firefox/releases/` | | Edge | `https://msedgedriver.microsoft.com/` | `https://edgeupdates.microsoft.com/api/products/` | For Chrome, the Chrome for Testing JSON files contain the download URL of each browser and driver, so a mirror can serve those JSON files with the URLs changed to point to where the binaries are stored. Driver and browser mirrors are configured separately because, for Firefox and Edge, drivers and browsers come from different repositories. A mirror cannot point Selenium Manager to a source with a different structure, such as a Linux distribution package repository. In that case, install the browser and driver yourself, and [set the driver location](https://www.selenium.dev/documentation/webdriver/drivers/service/#driver-location). ## Caching ***TL;DR:*** *The drivers and browsers managed by Selenium Manager are stored in a local folder (`~/.cache/selenium`).* The cache in Selenium Manager is a local folder (`~/.cache/selenium` by default) in which the downloaded assets (drivers and browsers) are stored. For the sake of performance, when a driver or browser is already in the cache (i.e., there is a *cache hint*), Selenium Manager uses it from there. In addition to the downloaded drivers and browsers, two additional files live in the cache's root: - Configuration file (`se-config.toml`). This file is optional and, as explained in the previous section, allows to store custom configuration values for Selenium Manager. This file is maintained by the end-user and read by Selenium Manager. - Metadata file (`se-metadata.json`). This file contains versions discovered by Selenium Manager making network requests (e.g., using the [CfT JSON endpoints](https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints)) and the time-to-live (TTL) in which they are valid. Selenium Manager automatically maintains this file. The TTL in Selenium Manager is inspired by the TTL for DNS, a well-known mechanism that refers to how long some values are cached before they are automatically refreshed. In the case of Selenium Manager, these values are the versions found by making network requests for driver and browser version discovery. By default, the TTL is `3600` seconds (i.e., 1 hour) and can be tuned using configuration values or disabled by setting this configuration value to `0`. The TTL mechanism is a way to improve the overall performance of Selenium. It is based on the fact that the discovered driver and browser versions (e.g., the proper chromedriver version for Chrome 115 is 115.0.5790.170) will likely remain the same in the short term. Therefore, the discovered versions are written in the metadata file and read from there instead of making the same consecutive network request. This way, during the driver version discovery (step 2 of the automated driver management process previously introduced), Selenium Manager first reads the file metadata. When a *fresh* resolution (i.e., a driver/browser version valid during a TTL) is found, that version is used (saving some time in making a new network request). If not found or the TTL has expired, a network request is made, and the result is stored in the metadata file. Let's consider an example. A Selenium binding asks Selenium Manager to resolve chromedriver. Selenium Manager detects that Chrome 115 is installed, so it makes a network request to the CfT endpoints to discover the proper chromedriver version (115.0.5790.170, at that moment). This version is stored in the metadata file and considered valid during the next hour (TTL). If Selenium Manager is asked to resolve chromedriver during that time (which is likely to happen in the execution of a test suite), the chromedriver version is discovered by reading the metadata file instead of making a new request to the CfT endpoints. After one hour, the chromedriver version stored in the cache will be considered as *stale*, and Selenium Manager will refresh it by making a new network request to the corresponding endpoint. To bound the cache size without requiring manual intervention, Selenium Manager automatically prunes old cache entries. Every time a driver or browser is resolved from the cache, a `last_used` Unix timestamp is updated in a dedicated `cached_assets` section within the metadata file (`se-metadata.json`). On each execution, Selenium Manager automatically removes driver or browser version directories from the cache that have not been used in over 30 days. Selenium Manager includes two additional arguments two handle the cache, namely: - `--clear-cache`: To remove the cache folder (equivalent to the environment variable `SE_CLEAR_CACHE=true`). - `--clear-metadata`: To remove the metadata file (equivalent to the environment variable `SE_CLEAR_METADATA=true`). ## Versioning Selenium Manager follows the same versioning schema as Selenium. Nevertheless, we use the major version 0 for Selenium Manager releases because it is still in beta. For example, the Selenium Manager binaries shipped with Selenium 4.12.0 corresponds to version 0.4.12. ## Getting Selenium Manager For most users, direct interaction with Selenium Manager is not required since the Selenium bindings use it internally. Nevertheless, if you want to *play* with Selenium Manager or use it for your use case involving driver or browser management, you can get the Selenium Manager binaries in different ways: - From the Selenium repository. The Selenium Manager source code is stored in the main Selenium repo under the folder [rust](https://github.com/SeleniumHQ/selenium/tree/trunk/rust). Moreover, you can find the compiled versions for Windows, Linux, and macOS in the [Selenium Manager Artifacts](https://github.com/SeleniumHQ/selenium_manager_artifacts) repo. The stable Selenium Manager binaries (i.e., those distributed in the latest stable Selenium version) are linked in this [file](https://github.com/SeleniumHQ/selenium/blob/trunk/common/selenium_manager.bzl). - From the build workflow. Selenium Manager is compiled using a [GitHub Actions workflow](https://github.com/SeleniumHQ/selenium/actions/workflows/ci-rust.yml). This workflow creates binaries for Windows, Linux, and macOS. You can download these binaries from these workflow executions. - From the cache. As of version 4.15.0 of the Selenium Java bindings, the Selenium Manager binary is extracted and copied to the cache folder. For instance, the Selenium Manager binary shipped with Selenium 4.15.0 is stored in the folder `~/.cache/selenium/manager/0.4.15`). ## Examples Let's consider a typical example: we want to manage chromedriver automatically. For that, we invoke Selenium Manager as follows (notice that the flag `--debug` is optional, but it helps us to understand what Selenium Manager is doing): ``` $ ./selenium-manager --browser chrome --debug DEBUG chromedriver not found in PATH DEBUG chrome detected at C:\Program Files\Google\Chrome\Application\chrome.exe DEBUG Detected browser: chrome 139.0.7258.67 DEBUG Discovering versions from https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json DEBUG Required driver: chromedriver 139.0.7258.68 DEBUG Acquiring lock: C:\Users\boni\.cache\selenium\chromedriver\win64\139.0.7258.68\sm.lock DEBUG Downloading chromedriver 139.0.7258.68 from https://storage.googleapis.com/chrome-for-testing-public/139.0.7258.68/win64/chromedriver-win64.zip INFO Driver path: C:\Users\boni\.cache\selenium\chromedriver\win64\139.0.7258.68\chromedriver.exe INFO Browser path: C:\Program Files\Google\Chrome\Application\chrome.exe ``` In this case, the local Chrome (in Windows) is detected by Selenium Manager. Then, using its version and the CfT endpoints, the proper chromedriver version (115, in this example) is downloaded to the local cache. Finally, Selenium Manager provides two results: i) the driver path (downloaded) and ii) the browser path (local). Let's consider another example. Now we want to use Chrome beta. Therefore, we invoke Selenium Manager specifying that version label as follows (notice that the CfT beta is discovered, downloaded, and stored in the local cache): ``` $ ./selenium-manager --browser chrome --browser-version beta --debug DEBUG chromedriver not found in PATH DEBUG chrome not found in PATH DEBUG chrome beta not found in the system DEBUG Discovering versions from https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json DEBUG Required browser: chrome 140.0.7339.16 DEBUG Acquiring lock: C:\Users\boni\.cache\selenium\chrome\win64\140.0.7339.16\sm.lock DEBUG Downloading chrome 140.0.7339.16 from https://storage.googleapis.com/chrome-for-testing-public/140.0.7339.16/win64/chrome-win64.zip DEBUG chrome 140.0.7339.16 is available at C:\Users\boni\.cache\selenium\chrome\win64\140.0.7339.16\chrome.exe DEBUG Discovering versions from https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json DEBUG Required driver: chromedriver 140.0.7339.16 DEBUG Acquiring lock: C:\Users\boni\.cache\selenium\chromedriver\win64\140.0.7339.16\sm.lock DEBUG Downloading chromedriver 140.0.7339.16 from https://storage.googleapis.com/chrome-for-testing-public/140.0.7339.16/win64/chromedriver-win64.zip INFO Driver path: C:\Users\boni\.cache\selenium\chromedriver\win64\140.0.7339.16\chromedriver.exe INFO Browser path: C:\Users\boni\.cache\selenium\chrome\win64\140.0.7339.16\chrome.exe ``` ### Using Selenium Manager from the bindings All Selenium binding languages (Java, JavaScript, Python, .Net, Ruby) use Selenium Manager internally to manage drivers and browsers. The automated management process starts before starting a new Selenium session, i.e., each time a Selenium script instantiates a driver object (e.g., `ChromeDriver`, `FirefoxDriver`, etc.). The following snippets illustrate the difference between the old-fashioned way of manually managing drivers and the built-in automated mechanism provided by Selenium Manager. **Java** **Previously** Example (lines L12-L17): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/selenium_manager/SeleniumManagerUsageDemo.java **Selenium Manager** Example (lines L20-L24): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/java/src/test/java/dev/selenium/selenium_manager/SeleniumManagerUsageDemo.java **Python** **Previously** Example (lines L5-L8): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/selenium_manager/usage.py **Selenium Manager** Example (lines L10-L12): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/python/tests/selenium_manager/usage.py **CSharp** Example (lines L10-L18): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/dotnet/SeleniumDocs/SeleniumManager/UsageTest.cs **Ruby** **Previously** Example (lines L5-L10): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/selenium_manager/usage.rb **Selenium Manager** Example (lines L12-L16): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/ruby/spec/selenium_manager/usage.rb **JavaScript** **Previously** Example (lines L16-L31): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/selenium_manager/usage.spec.js **Selenium Manager** Example (lines L6-L14): https://github.com/SeleniumHQ/seleniumhq.github.io/blob/trunk/examples/javascript/test/selenium_manager/usage.spec.js **Kotlin** ## Selenium Grid Selenium Manager allows you to configure the drivers automatically when setting up Selenium Grid. To that aim, you need to include the argument `--selenium-manager true` in the command to start Selenium Grid. For more details, visit the [Selenium Grid starting page](https://www.selenium.dev/documentation/grid/getting_started/). Moreover, Selenium Manager also allows managing Selenium Grid releases automatically. For that, the argument `--grid` is used as follows: ``` $ ./selenium-manager --grid ``` After this command, Selenium Manager discovers the latest version of Selenium Grid, storing the `selenium-server.jar` in the local cache. Optionally, the argument `--grid` allows to specify a Selenium Grid version (`--grid `). ## Known Limitations ### Connectivity issues Selenium Manager requests remote endpoints (like Chrome for Testing (CfT), among others) to discover and download drivers and browsers from online repositories. When this operation is done in a corporate environment with a proxy or firewall, it might lead to connectivity problems like the following: ``` error sending request for url (https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json) ``` ``` error trying to connect: dns error: failed to lookup address information ``` ``` error trying to connect: An existing connection was forcibly closed by the remote host. (os error 10054) ``` When that happens, consider the following solutions: - Use the proxy capabilities of Selenium (see [documentation](https://www.selenium.dev/documentation/webdriver/drivers/options/#proxy)). Alternatively, use the environment variable `SE_PROXY` to set the proxy URL or use the configuration file (see [configuration](https://www.selenium.dev/documentation/selenium_manager/#configuration)). - Review your network setup to enable the remote requests and downloads required by Selenium Manager. ### Custom package managers If you are using a Linux package manager (Anaconda, snap, etc) that requires a specific driver be used for your browsers, you'll need to either specify the [driver location](https://www.selenium.dev/documentation/webdriver/drivers/service/#driver-location), the [browser location](https://www.selenium.dev/documentation/webdriver/browsers/chrome/#start-browser-in-a-specified-location), or both, depending on the requirements. ### Alternative architectures Each release of the Selenium bindings comes with four separate Selenium Manager binaries: * macOS, which supports both x64 and arm64 (Intel and Apple silicon). * Windows, which works for both x86 and x64 (32-bit and 64-bit OS), and is also used on Windows arm64. * Linux x64. * Linux arm64, shipped as of Selenium 4.49.0. On Linux arm64, Selenium Manager can manage the following browsers and drivers: * Chrome and chromedriver, from version 153, which is the first version that [Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/) publishes for Linux arm64. Older versions of chromedriver were never published for Linux arm64. * Firefox, which Selenium Manager can download from version 136, and geckodriver. * Edge is not supported, because Microsoft does not publish Edge or msedgedriver for Linux arm64. Other platforms, such as 32-bit Linux on ARM (e.g., some Raspberry Pi systems), are not supported. Selenium Manager cannot download browsers or drivers for them, because the browser vendors do not publish them. On these platforms, install the browser and the driver from your system package manager, and either [set the driver location](https://www.selenium.dev/documentation/webdriver/drivers/service/#driver-location) in a `Service` class or use an [environment variable for the driver path](#using-an-environment-variable-for-the-driver-path). If you want Selenium Manager to find a driver on `PATH` on one of these platforms, you need a [custom build of Selenium Manager](#building-a-custom-selenium-manager). ### Browser dependencies When automatically managing browsers in Linux, Selenium Manager relies on the releases published by the browser vendors (i.e., Chrome, Firefox, and Edge). These releases are portable in most cases. Nevertheless, there might be cases in which existing libraries are required. In Linux, this problem might be experienced when trying to run Firefox, e.g., as follows: ``` libdbus-glib-1.so.2: cannot open shared object file: No such file or directory Couldn't load XPCOM. ``` If that happens, the solution is to install that library, for instance, as follows: ``` sudo apt-get install libdbus-glib-1-2 ``` A similar issue might happen when trying to execute Chrome for Testing in Linux: ``` error while loading shared libraries: libatk-1.0.so.0: cannot open shared object file: No such file or directory ``` In this case, the library to be installed is the following: ``` sudo apt-get install libatk-bridge2.0-0 ``` ### Using an environment variable for the driver path It's possible to use an environment variable to specify the driver path without using Selenium Manager. The following environment variables are supported: * `SE_CHROMEDRIVER` * `SE_EDGEDRIVER` * `SE_GECKODRIVER` * `SE_IEDRIVER` For example, to specify the path to the chromedriver, you can set the `SE_CHROMEDRIVER` environment variable to the path of the chromedriver executable. The following bindings allow you to specify the driver path using an environment variable: * Ruby * Java * Python This feature is available in the Selenium Ruby binding starting from version 4.25.0 and in the Python binding from version 4.26.0. ## Building a Custom Selenium Manager The Selenium bindings use the Selenium Manager binary set in the `SE_MANAGER_PATH` environment variable, if it is present (as of Selenium 4.13.0). You can use it to run your own build of Selenium Manager, for instance, on a platform for which we do not ship a binary (see [alternative architectures](#alternative-architectures)). To build your own Selenium Manager, you can use the following steps: 1. Install Rust Dev Environment 2. clone Selenium onto your local machine `git clone https://github.com/SeleniumHQ/selenium.git --depth 1` 3. Navigate into your clone `cd selenium/rust` 4. Build selenium `cargo build --release` 5. Set the following environment variable for the Selenium Manager path `SE_MANAGER_PATH=~/selenium/rust/target/release/selenium-manager` 6. Put the driver you want in a location on your system PATH 7. Selenium will now use the built Selenium Manager to locate the manually downloaded driver on PATH Selenium Manager cannot download browsers or drivers that the browser vendors do not publish for your platform, even when it runs on that platform. This is why step 6 is needed. ## Roadmap You can trace the work in progress in the [Selenium Manager project dashboard](https://github.com/orgs/SeleniumHQ/projects/5). Moreover, you can check the new features shipped with each Selenium Manager release in its [changelog file](https://github.com/SeleniumHQ/selenium/blob/trunk/rust/CHANGELOG.md). --- # Grid Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/ Want to run tests in parallel across multiple machines? Then, Grid is for you. Selenium Grid allows the execution of WebDriver scripts on remote machines by routing commands sent by the client to remote browser instances. Grid aims to: * Provide an easy way to run tests in parallel on multiple machines * Allow testing on different browser versions * Enable cross platform testing Interested? Go through the following sections to understand how Grid works, and how to set up your own. --- # Getting started with Selenium Grid Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/getting_started/ Instructions for a simple Selenium Grid ## Quick start 1. Prerequisites * Java 11 or higher installed * Browser(s) installed * Browser driver(s) * Selenium Manager will configure the drivers automatically if you add `--selenium-manager true`. * Installed and on the `PATH` * Download the Selenium Server jar file from the [latest release](https://github.com/SeleniumHQ/selenium/releases/latest) 1. Start the Grid * `java -jar selenium-server-.jar standalone` 1. Point* your WebDriver tests to [http://localhost:4444](http://localhost:4444) 1. (Optional) Check running tests and available capabilities by opening your browser at [http://localhost:4444](http://localhost:4444) *Wondering how to point your tests to [http://localhost:4444](http://localhost:4444)? Check the `RemoteWebDriver` section. To learn more about the different configuration options, go through the sections below. ## Grid roles Grid is composed by six different components, which gives you the option to deploy it in different ways. Depending on your needs, you can start each one of them on its own (Distributed), group them in Hub & Node, or all in one on a single machine (Standalone). ### Standalone **Standalone** combines all Grid components seamlessly into one. Running a Grid in **Standalone** mode gives you a fully functional Grid with a single command, within a single process. **Standalone** can only run on a single machine. **Standalone** is also the easiest mode to spin up a Selenium Grid. By default, the server will listen for `RemoteWebDriver` requests on [http://localhost:4444](http://localhost:4444). By default, the server will detect the available drivers that it can use from the System `PATH`. ```shell java -jar selenium-server-.jar standalone ``` After starting successfully the Grid in Standalone mode, point your WebDriver tests to [http://localhost:4444](http://localhost:4444). Common use cases for **Standalone** are: * Develop or debug tests using `RemoteWebDriver` locally * Running quick test suites before pushing code * Have a easy to setup Grid in a CI/CD tool (GitHub Actions, Jenkins, etc...) ### Hub and Node **Hub and Node** is the most used role because it allows to: * Combine different machines in a single Grid * Machines with different operating systems and/or browser versions, for example * Have a single entry point to run WebDriver tests in different environments * Scaling capacity up or down without tearing down the Grid #### Hub A Hub is composed by the following components: Router, Distributor, Session Map, New Session Queue, and Event Bus. ```shell java -jar selenium-server-.jar hub ``` By default, the server will listen for `RemoteWebDriver` requests on [http://localhost:4444](http://localhost:4444). #### Node During startup time, the **Node** will detect the available drivers that it can use from the System `PATH`. The command below assumes the **Node** is running on the same machine where the **Hub** is running. ```shell java -jar selenium-server-.jar node ``` ##### More than one Node on the same machine **Node** 1 ```shell java -jar selenium-server-.jar node --port 5555 ``` **Node** 2 ```shell java -jar selenium-server-.jar node --port 6666 ``` ##### Node and Hub on different machines **Hub** and **Nodes** talk to each other via HTTP and the **Event Bus** (the **Event Bus** lives inside the **Hub**). A **Node** sends a message to the **Hub** via the **Event Bus** to start the registration process. When the **Hub** receives the message, reaches out to the **Node** via HTTP to confirm its existence. To successfully register a **Node** to a **Hub**, it is important to expose the **Event Bus** ports (4442 and 4443 by default) on the **Hub** machine. This also applies for the **Node** port. With that, both **Hub** and **Node** will be able to communicate. If the **Hub** is using the default ports, the `--hub` flag can be used to register the **Node** ```shell java -jar selenium-server-.jar node --hub http://:4444 ``` When the **Hub** is not using the default ports, the `--publish-events` and `--subscribe-events` flags are needed. For example, if the **Hub** uses ports `8886`, `8887`, and `8888` ```shell java -jar selenium-server-.jar hub --publish-events tcp://:8886 --subscribe-events tcp://:8887 --port 8888 ``` The **Node** needs to use those ports to register successfully ```shell java -jar selenium-server-.jar node --publish-events tcp://:8886 --subscribe-events tcp://:8887 ``` ### Distributed When using a Distributed Grid, each component is started separately, and ideally on different machines. It is important to expose all ports properly in order to allow fluent communication between all components. 1. **Event Bus**: enables internal communication between different Grid components. Default ports are: `4442`, `4443`, and `5557`. ```shell java -jar selenium-server-.jar event-bus --publish-events tcp://:4442 --subscribe-events tcp://:4443 --port 5557 ``` 2. **New Session Queue**: adds new session requests to a queue, which will be queried by the Distributor Default port is `5559`. ```shell java -jar selenium-server-.jar sessionqueue --port 5559 ``` 3. **Session Map**: maps session IDs to the **Node** where the session is running Default **Session Map** port is `5556`. **Session Map** interacts with the **Event Bus**. ```shell java -jar selenium-server-.jar sessions --publish-events tcp://:4442 --subscribe-events tcp://:4443 --port 5556 ``` 4. **Distributor**: queries the **New Session Queue** for new session requests, and assigns them to a **Node** when the capabilities match. **Nodes** register to the **Distributor** the way they register to the **Hub** in a **Hub/Node** Grid. Default **Distributor** port is `5553`. **Distributor** interacts with **New Session Queue**, **Session Map**, **Event Bus**, and the **Node(s)**. ```shell java -jar selenium-server-.jar distributor --publish-events tcp://:4442 --subscribe-events tcp://:4443 --sessions http://:5556 --sessionqueue http://:5559 --port 5553 --bind-bus false ``` 5. **Router**: redirects new session requests to the queue, and redirects running sessions requests to the **Node** running that session. Default **Router** port is `4444`. **Router** interacts with **New Session Queue**, **Session Map**, and **Distributor**. ```shell java -jar selenium-server-.jar router --sessions http://:5556 --distributor http://:5553 --sessionqueue http://:5559 --port 4444 ``` 6. **Node(s)** Default **Node** port is `5555`. ```shell java -jar selenium-server-.jar node --publish-events tcp://:4442 --subscribe-events tcp://:4443 ``` ## Metadata in tests Add metadata to your tests and consume it via GraphQL or visualize parts of it (like `se:name`) through the Selenium Grid UI. Metadata can be added by prefixing a capability with `se:`. Here is a quick example in Java showing that. ```java ChromeOptions chromeOptions = new ChromeOptions(); chromeOptions.setCapability("browserVersion", "100"); chromeOptions.setCapability("platformName", "Windows"); // Showing a test name instead of the session id in the Grid UI chromeOptions.setCapability("se:name", "My simple test"); // Other type of metadata can be seen in the Grid UI by clicking on the // session info or via GraphQL chromeOptions.setCapability("se:sampleMetadata", "Sample metadata value"); WebDriver driver = new RemoteWebDriver(new URL("http://gridUrl:4444"), chromeOptions); driver.get("http://www.google.com"); driver.quit(); ``` ## Querying Selenium Grid After starting a Grid, there are mainly two ways of querying its status, through the Grid UI or via an API call. The Grid UI can be reached by opening your preferred browser and heading to [http://localhost:4444](http://localhost:4444). API calls can be done through the [http://localhost:4444/status](http://localhost:4444/status) endpoint or using GraphQL For simplicity, all command examples shown in this page assume that components are running locally. More detailed examples and usages can be found in the Configuring Components section. ## Using the Java 11 HTTP Client By default, Grid will use [AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client). AsyncHttpClient is an open-source library built on top of Netty. It allows the execution of HTTP requests and responses asynchronously. Additionally it also provides WebSocket support. Hence it is a good fit. However, AsyncHttpClient is not been actively maintained since June 2021. It coincides with the fact that Java 11+ provides a built-in HTTP and WebSocket client. Currently, Selenium has plans to upgrade the minimum version supported to Java 11. However, it is a sizeable effort. Aligning it with major releases and accompanied announcements is crucial to ensure the user experience is intact. To do use the Java 11 client, you will need to download the `selenium-http-jdk-client` jar file and use the `--ext` flag to make it available in the Grid jar's classpath. The jar file can be downloaded directly from [repo1.maven.org](https://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-http-jdk-client/) and then start the Grid in the following way: ```bash java -Dwebdriver.http.factory=jdk-http-client -jar selenium-server-.jar --ext selenium-http-jdk-client-.jar standalone ``` An alternative to downloading the `selenium-http-jdk-client` jar file is to use [Coursier](https://get-coursier.io/docs/cli-installation). ```bash java -Dwebdriver.http.factory=jdk-http-client -jar selenium-server-.jar --ext $(coursier fetch -p org.seleniumhq.selenium:selenium-http-jdk-client:) standalone ``` If you are using the Hub/Node(s) mode or the Distributed mode, setting the `-Dwebdriver.http.factory=jdk-http-client` and `--ext` flags needs to be done for each one of the components. ## Grid sizes Choosing a Grid role depends on what operating systems and browsers need to be supported, how many parallel sessions need to be executed, the amount of available machines, and how powerful (CPU, RAM) those machines are. Creating sessions concurrently relies on the available processors to the **Distributor**. For example, if a machine has 4 CPUs, the **Distributor** will only be able to create up to 4 sessions concurrently. By default, the maximum amount of concurrent sessions a **Node** supports is limited by the number of CPUs available. For example, if the **Node** machine has 8CPUs, it can run up to 8 concurrent browser sessions (with the exception of Safari, which is always one). Additionally, it is expected that each browser session should use around 1GB RAM. In general, it is a recommended to have **Nodes** as small as possible. Instead of having a machine with 32CPUs and 32GB RAM to run 32 concurrent browser sessions, it is better to have 32 small **Nodes** in order to better isolate processes. With this, if a **Node** fails, it will do it in an isolated way. Docker is a good tool to achieve this approach. Note that the default values (1CPU/1GB RAM per browser) are a recommendation and they could not apply to your context. It is recommended to use them as a reference, but measuring performance continuously will help to determine the ideal values for your environment. Grid sizes are relative to the amount of supported concurrent sessions and amount of **Nodes**, and there is no "one size fits all". Sizes mentioned below are rough estimations thay can vary between different environments. For example a **Hub/Node** with 120 **Nodes** might work well when the **Hub** has enough resources. Values below are not set on stone, and feedback is welcomed! ### Small **Standalone** or **Hub/Node** with 5 or less **Nodes**. ### Middle **Hub/Node** between 6 and 60 **Nodes**. ### Large **Hub/Node** between 60 and 100 **Nodes**. **Distributed** with over 100 **Nodes**. ## Warning Selenium Grid must be protected from external access using appropriate firewall permissions. Failure to protect your Grid could result in one or more of the following occurring: * You provide open access to your Grid infrastructure * You allow third parties to access internal web applications and files * You allow third parties to run custom binaries See this blog post on Detectify Labs, which gives a good overview of how a publicly exposed Grid could be misused: [Don't Leave your Grid Wide Open](//labs.detectify.com/2017/10/06/guest-blog-dont-leave-your-grid-wide-open/). ## Further reading * Components: learn how Grid's internal components relate to each other. * Configuration: customize your Grid setup. * Architecture: understand key concepts in Grid. * Advanced Features: explore more possibilities through Grid's features. --- # When to Use Grid Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/applicability/ Is Grid right for you? When would you use a Selenium Grid? * To run your tests in parallel, against different browser types, browser versions, operating systems * To reduce the time needed to execute a test suite Selenium Grid runs test suites in parallel against multiple machines (called Nodes). For large and long-running test suites, this can save minutes, hours, or perhaps days. This shortens the turnaround time for test results as your application under test (AUT) changes. Grid can run tests (in parallel) against multiple different browsers, and it can run against multiple instances of the same browser. As an example, let's imagine a Grid with six Nodes. The first machine has Firefox's latest version, the second has Firefox "latest minus one", the third gets the latest Chrome, and the remaining three machines are Mac Minis, which allows for three tests to run in parallel on the latest version of Safari. Execution time can be expressed as a simple formula: ```Number of Tests * Average Test Time / Number of Nodes = Total Execution Time``` 15 * 45s / 1 = 11m 15s // Without Grid 15 * 45s / 5 = 2m 15s // Grid with 5 Nodes 15 * 45s / 15 = 45s // Grid with 15 Nodes 100 * 120s / 15 = 13m 20s // Would take over 3 hours without Grid As the test suite is executing, the Grid allocates the tests to run against these browsers as configured in the tests. A configuration such as this can greatly speed up the execution time of even the largest Selenium test suites. Selenium Grid is a completely native part of the Selenium project, and is maintained in parallel by the same team of committers who work in the core Selenium development. Recognizing the importance of test execution speed, Grid has been a critical part of the Selenium project since the earliest days. --- # Selenium Grid Components Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/components/ Understand how to use the different Grid components Selenium Grid 4 is a ground-up rewrite from previous versions. In addition to a comprehensive set of improvements to performance and standards compliance, the different functions of the grid were broken out to reflect a more modern age of computing and software development. Purpose-build for containerization and cloud-distributed scalability, Selenium Grid 4 is a wholly new solution for the modern era. ![Selenium Grid 4 Components](/images/documentation/grid/components.png) ## Router The **Router** is the entry point of the Grid, receiving all external requests, and forwards them to the correct component. If the **Router** receives a new session request, it will be forwarded to the **New Session Queue**. If the request belongs to an existing session, the **Router** will query the **Session Map** to get the **Node** ID where the session is running, and then the request will be forwarded directly to the **Node**. The **Router** balances the load in the Grid by sending the requests to the component that is able to handle them better, without overloading any component that is not needed in the process. ## Distributor The **Distributor** has two main responsibilities: #### Register and keep track of all Nodes and their capabilities A **Node** registers to the **Distributor** by sending a **Node** registration event through the **Event Bus**. The **Distributor** reads it, and then tries to reach the **Node** via HTTP to confirm its existence. If the request is successful, the **Distributor** registers the Node and keeps track of all **Nodes** capabilities through the **GridModel**. #### Query the New Session Queue and process any pending new session requests When a new session request is sent to the **Router**, it gets forwarded to the **New Session Queue**, where it will wait in the queue. The **Distributor** will poll the **New Session Queue** for pending new session requests, and then finds a suitable **Node** where the session can be created. After the session has been created, the **Distributor** stores in the **Session Map** the relation between the session id and **Node** where the session is being executed. ## Session Map The **Session Map** is a data store that keeps the relationship between the session id and the **Node** where the session is running. It supports the **Router** in the process of forwarding a request to the **Node**. The **Router** will ask the **Session Map** for the **Node** associated to a session id. ## New Session Queue The **New Session Queue** holds all the new session requests in a FIFO order. It has configurable parameters for setting the request timeout and request retry interval (how often the timeout will be checked). The **Router** adds the new session request to the **New Session Queue** and waits for the response. The **New Session Queue** regularly checks if any request in the queue has timed out, if so the request is rejected and removed immediately. The **Distributor** regularly checks if a slot is available. If so, the **Distributor** polls the **New Session Queue** for the first matching request. The **Distributor** then attempts to create a new session. Once the requested capabilities match the capabilities of any of the free **Node** slots, the **Distributor** attempts to get the available slot. If all the slots are busy, the **Distributor** will send the request back to the queue. If request times out while retrying or adding to the front of the queue, it will be rejected. After a session is created successfully, the **Distributor** sends the session information to the **New Session Queue**, which then gets sent back to the **Router**, and finally to the client. ## Node A Grid can contain multiple **Nodes**. Each **Node** manages the slots for the available browsers of the machine where it is running. The **Node** registers itself to the **Distributor** through the **Event Bus**, and its configuration is sent as part of the registration message. By default, the **Node** auto-registers all browser drivers available on the path of the machine where it runs. It also creates one slot per available CPU for Chromium based browsers and Firefox. For Safari, only one slot is created. Through a specific configuration, it can run sessions in Docker containers or relay commands. A **Node** only executes the received commands, it does not evaluate, make judgments, or control anything other than the flow of commands and responses. The machines where the **Node** is running does not need to have the same operating system as the other components. For example, A Windows **Node** might have the capability of offering IE Mode on Edge as a browser option, whereas this would not be possible on Linux or Mac, and a Grid can have multiple **Nodes** configured with Windows, Mac, or Linux. ## Event Bus The **Event Bus** serves as a communication path between the **Nodes**, **Distributor**, **New Session Queue**, and **Session Map**. The Grid does most of its internal communication through messages, avoiding expensive HTTP calls. When starting the Grid in its fully distributed mode, the **Event Bus** is the first component that should be started. Looking forward to using all these components and run your own Grid? Head to the "Getting Started" section to understand how to put all these pieces together. --- # Grid architecture Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/architecture/ The Grid is designed as a set of components that all fulfill a role in maintaining the Grid. It can seem quite complicated, but hopefully this document can help clear up any confusion. ## The Key Components The main components of the Grid are:
Event Bus
Used for sending messages which may be received asynchronously between the other components.
New Session Queue
Maintains a list of incoming sessions which have yet to be assigned to a Node by the Distributor.
Distributor
Responsible for maintaining a model of the available locations in the Grid where a session may run (known as "slots") and taking any incoming new session requests and assigning them to a slot.
Node
Runs a WebDriver session. Each session is assigned to a slot, and each node has one or more slots.
Session Map
Maintains a mapping between the session ID and the address of the Node the session is running on.
Router
Acts as the front-end of the Grid. This is the only part of the Grid which may be exposed to the wider Web (though we strongly caution against it). This routes incoming requests to either the New Session Queue or the Node on which the session is running.
While discussing the Grid, there are some other useful concepts to keep in mind: * A **slot** is the place where a session can run. * Each slot has a **stereotype**. This is the minimal set of capabilities that a [new session][] session request must match before the Distributor will send that request to the Node owning the slot. * The **Grid Model** is how the Distributor tracks the state of the Grid. As the name suggests, this may sometimes fall out of sync with reality (perhaps because the Distributor has only just started). It is used in preference to querying each Node so that the Distributor can quickly assign a slot to a New Session request. ## Synchronous and Asynchronous Calls There are two main communication mechanisms used within the Grid: 1. Synchronous "REST-ish" JSON over HTTP requests. 2. Asynchronous events sent to the Event Bus. How do we pick which communication mechanism to use? After all, we could model the entire Grid in an event-based way, and it would work out just fine. The answer is that if the action being performed is synchronous (eg. most WebDriver calls), or if missing the response would be problematic, the Grid uses a synchronous call. If, instead, we want to broadcast information to anyone who's interested, or if missing the response doesn't matter, then we prefer to use the event bus. One interesting thing to note is that the async calls are more decoupled from their listeners than the synchronous calls are. ## Start Up Sequence and Dependencies Between Components Although the Grid is designed to allow components to start up in any order, conceptually the order in which components starts is: 1. The Event Bus and Session Map start first. These have no other dependencies, not even on each other, and so are safe to start in parallel. 2. The Session Queue starts next. 3. It is now possible to start the Distributor. This will periodically connect to the Session Queue and poll for jobs, though this polling might be initiated either by an event (that a New Session has been added to the queue) or at regular intervals. 4. The Router(s) can be started. New Session requests will be directed to the Session Queue, and the Distributor will attempt to find a slot to run the session on. 5. We are now able to start a Node. See below for details about how the Node is registered with the Grid. Once registration is complete, the Grid is ready to serve traffic. You can picture the dependencies between components this way, where a "✅" indicates that there is a synchronous dependency between the components. | | Event Bus | Distributor | Node | Router | Session Map | Session Queue | |---------------|-----------|-------------|------|--------|-------------|---------------| | Event Bus | X | | | | | | | Distributor | ✅ | X | ✅ | | | ✅ | | Node | ✅ | | X | | | | | Router | | | ✅ | X | ✅ | | | Session Map | | | | | X | | | Session Queue | ✅ | | | | | X | ## Node Registration The process of registering a new Node to the Grid is lightweight. 1. When the Node starts, it should emit a "heart beat" event on a regular basis. This heartbeat contains the [node status]. 2. The Distributor listens for the heart beat events. When it sees one, it attempts to `GET` the `/status` endpoint of the Node. It is from this information that the Grid is set up. The Distributor will use the same `/status` endpoint to check the Node on a regular basis, but the Node should continue sending heart beat events even after started so that a Distributor without a persistent store of the Grid state can be restarted and will (eventually) be up to date and correct. ### The Node Status Object The Node Status is a JSON blob with the following fields: | Name | Type | Description | |------|------|-------------| | availability | string | A string which is one of `up`, `draining`, or `down`. The important one is `draining`, which indicates that no new sessions should be sent to the Node, and once the last session on it closes, the Node will exit or restart. | | externalUrl | string | The URI that the other components in the Grid should connect to. | | lastSessionCreated | integer | The epoch timestamp of when the last session was created on this Node. The Distributor will attempt to send new sessions to the Node that has been idle longest if all other things are equal. | | maxSessionCount | integer | Although a session count can be inferred by counting the number of available slots, this integer value is used to determine the maximum number of sessions that should be running simultaneously on the Node before it is considered "full". | | nodeId | string | A UUID used to identify this instance of the Node. | | osInfo | object | An object with `arch`, `name`, and `version` fields. This is used by the Grid UI and the GraphQL queries. | | slots | array | An array of Slot objects (described below) | | version | string | The version of the Node (for Selenium, this will match the Selenium version number) | It is recommended to put values in all fields. ### The Slot Object The Slot object represents a single slot within a Node. A "slot" is where a single session may be run. It is possible that a Node will have more slots than it can run concurrently. For example, a node may be able to run up 10 sessions, but they could be any combination of Chrome, Edge, or Firefox; in this case, the Node would indicate a "max session count" of 10, and then also say it has 10 slots for Chrome, 10 for Edge, and 10 for Firefox. | Name | Type | Description | |------|------|-------------| | id | string | UUID to refer to the slot | | lastStarted | string | When the slot last had a session started, in ISO-8601 format | | stereotype | object | The minimal set of [capabilities][capabilities] this slot will match against. A minimal example is `{"browserName": "firefox"}` | | session | object | The Session object (see below) | ### The Session Object This represents a running session within a slot | Name | Type | Description | |------|------|-------------| | capabilities | object | The actual capabilities provided by the session. Will match the return value from the [new session][new session] command | | startTime | string | The start time of the session in ISO-8601 format | | stereotype | object | The minimal set of [capabilities][capabilities] this slot will match against. A minimal example is `{"browserName": "firefox"}` | | uri | string | The URI used by the Node to communicate with the session | [capabilities]: https://w3c.github.io/webdriver/#dfn-merging-capabilities [new session]: https://w3c.github.io/webdriver/#new-session [node status]: https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/grid/data/NodeStatus.html [session]: https://w3c.github.io/webdriver/#dfn-sessions [session id]: https://w3c.github.io/webdriver/#dfn-session-id --- # Configuration of Components Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/configuration/ Here you can see how each Grid component can be configured individually based on common configuration values and component-specific configuration values. --- # Configuration help Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/configuration/help/ Get information about all the available options to configure Grid. The help commands display information based on the current code implementation. Hence, it will provide accurate information in case the documentation is not updated. It is the easiest way to learn about Grid 4 configuration for any new version. ## Info Command The info command provides detailed docs on the following topics: * Configuring Selenium * Security * Session Map setup * Tracing ### Config help Quick config help and overview is provided by running: ```shell java -jar selenium-server-.jar info config ``` ### Security To get details on setting up the Grid servers for secure communication and node registration: ```shell java -jar selenium-server-.jar info security ``` ### Session Map setup By default, Grid uses a local session map to store session information. Grid supports additional storage options like Redis and JDBC - SQL supported databases. To set up different session storage, use the following command to get setup steps: ```shell java -jar selenium-server-.jar info sessionmap ``` ### Setting up tracing with OpenTelemetry and Jaeger By default, tracing is enabled. To export traces and visualize them via Jaeger, use the following command for instructions: ```shell java -jar selenium-server-.jar info tracing ``` ## List the Selenium Grid commands ```shell java -jar selenium-server-.jar --config-help ``` It will show all the available commands and description for each one. ## Component help commands Pass --help config option after the Selenium role to get component-specific config information. ### Standalone ```shell java -jar selenium-server-.jar standalone --help ``` ### Hub ```shell java -jar selenium-server-.jar hub --help ``` ### Sessions ```shell java -jar selenium-server-.jar sessions --help ``` ### New Session Queue ```shell java -jar selenium-server-.jar sessionqueue --help ``` ### Distributor ```shell java -jar selenium-server-.jar distributor --help ``` ### Router ```shell java -jar selenium-server-.jar router --help ``` ### Node ```shell java -jar selenium-server-.jar node --help ``` --- # CLI options in the Selenium Grid Area: Grid URL: https://trunk--selenium-dev.netlify.app/documentation/grid/configuration/cli_options/ All Grid components configuration CLI options in detail. Different sections are available to configure a Grid. Each section has options can be configured through command line arguments. A complete description of the component to section mapping can be seen below. Note that this documentation could be outdated if an option was modified or added but has not been documented yet. In case you bump into this situation, please check the "Config help" section and feel free to send us a pull request updating this page. ## Sections
Standalone Hub Node Distributor Router Sessions SessionQueue
Distributor
Docker
Kubernetes
Events
Logging
Network
Node
Router
Relay
Server
SessionQueue
Sessions
### Distributor | Option | Type | Value/Example | Description | |---|---|---|---| | `--healthcheck-interval` | int | `120` | How often, in seconds, will the health check run for all Nodes. This ensures the server can ping all the Nodes successfully. | | ``--distributor`` | uri | `http://localhost:5553` | Url of the distributor. | | `--distributor-host` | string | `localhost` | Host on which the distributor is listening. | | `--distributor-implementation` | string | `org.openqa.selenium.grid.distributor.local.LocalDistributor` | Full class name of non-default distributor implementation | | `--distributor-port` | int | `5553` | Port on which the distributor is listening. | | `--reject-unsupported-caps` | boolean | `false` | Allow the Distributor to reject a request immediately if the Grid does not support the requested capability. Rejecting requests immediately is suitable for a Grid setup that does not spin up Nodes on demand. | | `--slot-matcher` | string | `org.openqa.selenium.grid.data.DefaultSlotMatcher` | Full class name of non-default slot matcher to use. This is used to determine whether a Node can support a particular session. | | `--slot-selector` | string | `org.openqa.selenium.grid.distributor.selector.DefaultSlotSelector` | Full class name of non-default slot selector. This is used to select a slot in a Node once the Node has been matched. | | `--newsession-threadpool-size` | int | `24` | The Distributor uses a fixed-sized thread pool to create new sessions as it consumes new session requests from the queue. This allows configuring the size of the thread pool. The default value is no. of available processors * 3. Note: If the no. of threads is way greater than the available processors it will not always increase the performance. A high number of threads causes more context switching which is an expensive operation. | | `--purge-nodes-interval` | int | `30` | How often, in seconds, will the Distributor purge Nodes that have been down for a while. This is calculated based on the heartbeat received from a particular node. | | `--distributor-backend-url` | string | `redis://localhost:6379` | Backend datastore URL for the Distributor implementation. Used by Redis-backed and other external implementations loaded via `--ext`. | ### Docker | Option | Type | Value/Example | Description | |---|---|---|---| | `--docker-assets-path` | string | `/opt/selenium/assets` | Absolute path where assets will be stored | | `--docker` / `-D` | string[] | `selenium/standalone-firefox:latest '{"browserName": "firefox"}'` | Docker configs which map image name to stereotype capabilities (example: `-D selenium/standalone-firefox:latest '{"browserName": "firefox"}'`) | | `--docker-devices` | string[] | `/dev/kvm:/dev/kvm` | Exposes devices to a container. Each device mapping declaration must have at least the path of the device in both host and container separated by a colon like in this example: /device/path/in/host:/device/path/in/container | | `--docker-host` | string | `localhost` | Host name where the Docker daemon is running | | `--docker-port` | int | `2375` | Port where the Docker daemon is running | | `--docker-url` | string | `http://localhost:2375` | URL for connecting to the Docker daemon | | `--docker-video-image` | string | `selenium/video:latest` | Docker image to be used when video recording is enabled | | `--docker-host-config-keys` | string[] | `Dns DnsOptions DnsSearch ExtraHosts Binds` | Specify which docker host configuration keys should be passed to browser containers. Keys name can be found in the Docker API [documentation](https://docs.docker.com/engine/api/v1.41/#tag/Container/operation/ContainerCreate), or by running `docker inspect` the node-docker container. | | `--docker-api-version` | string | `1.40` | Docker API version to use. Pin a specific API version instead of relying on auto-detection by the implementation. | | `--docker-server-start-timeout` | int | `55` | Max time (in seconds) to wait for the browser server to successfully start up inside the container, before cancelling the process. | | `--docker-grouping-labels` | string[] | `azure.container.group aws.ecs.cluster` | Custom labels used for grouping dynamic containers. Makes the system more flexible for different platforms and use cases. | | `--docker-stop-grace-period` | int | `60` | Grace period (in seconds) to wait for browser and video containers to stop gracefully before they are forcibly terminated. | ### Kubernetes | Option | Type | Value/Example | Description | |---|---|---|---| | `--kubernetes-url` | string | `"https://my-k8s-cluster:6443"` | Kubernetes API server URL. When set, connects to a remote cluster instead of using in-cluster or kubeconfig auto-discovery. | | `--kubernetes-configs` / `-K` | string[] | `selenium/standalone-firefox:latest '{"browserName": "firefox"}'` | Kubernetes configs which map image name to stereotype capabilities (example: `-K selenium/standalone-firefox:latest '{"browserName": "firefox"}'`). Use `configmap:[namespace/]` as the key to load a Job template from a Kubernetes ConfigMap instead of an image name. | | `--kubernetes-namespace` | string | `"selenium"` | Kubernetes namespace to create browser Jobs in. Auto-detected from the client when running in-cluster if not set. | | `--kubernetes-service-account` | string | `"selenium-session"` | Override service account for browser Jobs. Auto-inherited from the Node Pod when running in K8s. | | `--kubernetes-image-pull-policy` | string | `"IfNotPresent"` | Override image pull policy for browser containers (`Always`, `IfNotPresent`, `Never`). Auto-inherited from the Node Pod when running in K8s. | | `--kubernetes-server-start-timeout` | int | `120` | Max time (in seconds) to wait for the browser server to start up in the K8s Pod. | | `--kubernetes-termination-grace-period` | int | `30` | Seconds to wait for containers to shut down gracefully before force-killing them. | | `--kubernetes-resource-requests` | string | `"cpu=500m,memory=512Mi"` | Override resource requests for browser containers (comma-separated `key=value` pairs). Auto-inherited from the Node Pod when running in K8s. | | `--kubernetes-resource-limits` | string | `"cpu=1,memory=1Gi"` | Override resource limits for browser containers (comma-separated `key=value` pairs). Auto-inherited from the Node Pod when running in K8s. | | `--kubernetes-node-selector` | string | `"disktype=ssd,region=us-west"` | Override node selector for scheduling browser Pods (comma-separated `key=value` pairs). Auto-inherited from the Node Pod when running in K8s. | | `--kubernetes-video-image` | string | `"selenium/video:latest"` | Container image to use as a video recording sidecar. Set to `false` to disable video recording (default). | | `--kubernetes-assets-path` | string | `"/opt/selenium/assets"` | Absolute path where session assets will be stored. | | `--kubernetes-label-inherit-prefix` | string | `"se/"` | Prefix filter for inheriting labels/annotations from the Node Pod to browser Jobs. Only labels/annotations whose keys start with this prefix are inherited. An empty string inherits all. | ### Events | Option | Type | Value/Example | Description | |---|---|---|---| | `--bind-bus` | boolean | `false` | Whether the connection string should be bound or connected.
When true, the component will be bound to the Event Bus (as in the Event Bus will also be started by the component, typically by the Distributor and the Hub).
When false, the component will connect to the Event Bus. | | `--events-implementation` | string | `org.openqa.selenium.events.zeromq.ZeroMqEventBus` | Full class name of non-default event bus implementation | | `--publish-events` | string | `tcp://*:4442` | Connection string for publishing events to the event bus | | `--subscribe-events` | string | `tcp://*:4443` | Connection string for subscribing to events from the event bus | | `--eventbus-heartbeat-period` | int | `30` | How often, in seconds, will the EventBus socket send heartbeats. | ### Logging | Option | Type | Value/Example | Description | |---|---|---|---| | `--http-logs` | boolean | `false` | Enable http logging. Tracing should be enabled to log http logs. | | `--log-encoding` | string | `UTF-8` | Log encoding | | `--log` | string | Windows path example :
`'\path\to\file\gridlog.log'`
or
`'C:\path\path\to\file\gridlog.log'`

Linux/Unix/MacOS path example :
`'/path/to/file/gridlog.log'` | File to write out logs. Ensure the file path is compatible with the operating system's file path. | | `--log-level` | string | `“INFO”` | Log level. Default logging level is INFO. Log levels are described here https://docs.oracle.com/en/java/javase/11/docs/api/java.logging/java/util/logging/Level.html | | `--plain-logs` | boolean | `true` | Use plain log lines | | `--structured-logs` | boolean | `false` | Use structured logs | | `--tracing` | boolean | `true` | Enable trace collection | | `--log-timestamp-format` | string | `HH:mm:ss.SSS` | Allows the configure log timestamp format | ### Network | Option | Type | Value/Example | Description | |---|---|---|---| | `--relax-checks` | boolean | `false` | Relax checks on origin header and content type of incoming requests, in contravention of strict W3C spec compliance. | ### Node | Option | Type | Value/Example | Description | |---|---|---|---| | `--detect-drivers` | boolean | `true` | Autodetect which drivers are available on the current system, and add them to the Node. | | `--driver-configuration` | string[] | `display-name="Firefox Nightly" max-sessions=2 webdriver-path="/usr/local/bin/geckodriver" stereotype="{\"browserName\": \"firefox\", \"browserVersion\": \"86\", \"moz:firefoxOptions\": {\"binary\":\"/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin\"}}"` | List of configured drivers a Node supports. It is recommended to provide this type of configuration through a toml config file to improve readability | | `--driver-factory` | string[] | `org.openqa.selenium.example.LynxDriverFactory '{"browserName": "lynx"}'` | Mapping of fully qualified class name to a browser configuration that this matches against. | | `--driver-implementation` | string[] | `"firefox"` | Drivers that should be checked. If specified, will skip autoconfiguration. | | `--node-implementation` | string | `"org.openqa.selenium.grid.node.local.LocalNodeFactory"` | Full classname of non-default Node implementation. This is used to manage a session's lifecycle. | | `--grid-url` | string | `https://grid.example.com` | Public URL of the Grid as a whole (typically the address of the Hub or the Router) | | `--heartbeat-period` | int | `60` | How often, in seconds, will the Node send heartbeat events to the Distributor to inform it that the Node is up. | | `--max-sessions` | int | `8` | Maximum number of concurrent sessions. Default value is the number of available processors. | | `--override-max-sessions` | boolean | `false` | The # of available processors is the recommended max sessions value (1 browser session per processor). Setting this flag to true allows the recommended max value to be overwritten. Session stability and reliability might suffer as the host could run out of resources. | | `--register-cycle` | int | `10` | How often, in seconds, the Node will try to register itself for the first time to the Distributor. | | `--register-period` | int | `120` | How long, in seconds, will the Node try to register to the Distributor for the first time. After this period is completed, the Node will not attempt to register again. | | `--session-timeout` | int | `300` | Let X be the session-timeout in seconds. The Node will automatically kill a session that has not had any activity in the last X seconds. This will release the slot for other tests. | | `--vnc-env-var`| string[] | `SE_START_XVFB SE_START_VNC SE_START_NO_VNC` | Environment variable to check in order to determine if a vnc stream is available or not. | | `--no-vnc-port`| int | `7900` | If VNC is available, sets the port where the local noVNC stream can be obtained | | `--drain-after-session-count`| int | `1` | Drain and shutdown the Node after X sessions have been executed. Useful for environments like Kubernetes. A value higher than zero enables this feature. | | `--hub`| string | `http://localhost:4444` | The address of the Hub in a Hub-and-Node configuration. Can be a hostname or IP address (`hostname`), in which case the Hub will be assumed to be `http://hostname:4444`, the `--grid-url` will be the same `--publish-events` will be `tcp://hostname:4442` and `--subscribe-events` will be `tcp://hostname:4443`. If `hostname` contains a port number, that will be used for `--grid-url` but the URIs for the event bus will remain the same. Any of these default values may be overridden but setting the correct flags. If the hostname has a protocol (such as `https`) that will be used too. | | `--enable-cdp`| boolean | `true` | Enable CDP proxying in Grid. A Grid admin can disable CDP if the network does not allow websockets. True by default. | | `--enable-bidi`| boolean | `true` | Enable BiDi proxying in Grid. A Grid admin can disable BiDi if the network does not allow websockets. True by default. | | `--enable-managed-downloads`| boolean | `false` | This causes the Node to auto manage files downloaded for a given session on the Node. | | `--selenium-manager`| boolean | `false` | When drivers are not available on the current system, use Selenium Manager. False by default. | | `--connection-limit-per-session` | int | `10` | Let X be the maximum number of websocket connections per session. This will ensure one session is not able to exhaust the connection limit of the host. | | `--delete-session-on-ui` | boolean | `false` | Enable capability to support deleting a session via the Grid UI. False by default. | | `--register-shutdown-on-failure` | boolean | `false` | If enabled, the Node will shut down after the register period is completed without a successful registration. Useful in container environments to trigger a restart. | | `--node-down-failure-threshold` | int | `3` | Maximum number of consecutive session creation failures before the Node is marked as DOWN. A value of `0` (default) disables this feature and allows unlimited retries. | ### Relay | Option | Type | Value/Example | Description | |---|---|---|---| | `--service-url` | string | `http://localhost:4723` | URL for connecting to the service that supports WebDriver commands like an Appium server or a cloud service. | | `--service-host` | string | `localhost` | Host name where the service that supports WebDriver commands is running | | `--service-port` | int | `4723` | Port where the service that supports WebDriver commands is running | | `--service-status-endpoint` | string | `/status` | Optional, endpoint to query the WebDriver service status, an HTTP 200 response is expected | | `--service-protocol-version` | string | `HTTP/1.1` | Optional, enforce a specific protocol version in HttpClient when communicating with the endpoint service status | | `--service-configuration` | string[] | `max-sessions=2 stereotype='{"browserName": "safari", "platformName": "iOS", "appium:platformVersion": "14.5"}}'` | Configuration for the service where calls will be relayed to. It is recommended to provide this type of configuration through a toml config file to improve readability. | ### Router | Option | Type | Value/Example | Description | |---|---|---|---| | `--password` | string | `myStrongPassword` | Password clients must use to connect to the server. Both this and the username need to be set in order to be used. | | `--username` | string | `admin` | User name clients must use to connect to the server. Both this and the password need to be set in order to be used. | | `--sub-path` | string | `my_company/selenium_grid` | A sub-path that should be considered for all user facing routes on the Hub/Router/Standalone. | | `--disable-ui` | boolean | `true` | Disable the Grid UI. | | `--tcp-tunnel` | boolean | `true` | Enable the transparent TCP tunnel for WebSocket connections (BiDi, CDP). Disable to route WebSocket traffic through the Grid proxy instead, e.g. for benchmarking the proxy path or in network topologies where the Router cannot open direct TCP connections to Nodes (e.g. Kubernetes port-forward setups). | ### Server | Option | Type | Value/Example | Description | |---|---|---|---| | `--external-url` | string | `http://10.0.1.1:33333` | External URL where component is generally available. Useful on complex network topologies when components are on different networks and proxy servers are involved. | | `--allow-cors` | boolean | `true` | Whether the Selenium server should allow web browser connections from any host | | `--host` | string | `localhost` | Server IP or hostname: usually determined automatically. | | `--bind-host` | boolean | `true` | Whether the server should bind to the host address/name, or only use it to" report its reachable url. Helpful in complex network topologies where the server cannot report itself with the current IP/hostname but rather an external IP or hostname (e.g. inside a Docker container) | | `--https-certificate` | path | `/path/to/cert.pem` | Server certificate for https. Get more detailed information by running "java -jar selenium-server.jar info security" | | `--https-private-key` | path | `/path/to/key.pkcs8` | Private key for https. Get more detailed information by running "java -jar selenium-server.jar info security" | | `--max-threads` | int | `24` | Maximum number of listener threads. Default value is: (available processors) * 3. | | `--port` | int | `4444` | Port to listen on. There is no default as this parameter is used by different components, for example, Router/Hub/Standalone will use 4444 and Node will use 5555. | | `--registration-secret` | string | `"Hunter2"` | Shared secret used to authenticate Node registration requests. Must match the value set on the Hub/Distributor. | ### SessionQueue | Option | Type | Value/Example | Description | |---|---|---|---| | `--sessionqueue` / `--sq` | uri | `http://localhost:1237` | Address of the session queue server. | | `--sessionqueue-host` | string | `localhost` | Host on which the session queue server is listening. | | `--sessionqueue-port` | int | `1234` | Port on which the session queue server is listening. | | `--session-request-timeout` | int | `300` | Timeout in seconds. A new incoming session request is added to the queue. Requests sitting in the queue for longer than the configured time will timeout. | | `--session-request-timeout-period` | int | `10` | How often, in seconds, the timeout for queued new session requests is checked. | | `--session-retry-interval` | int | `15` | Retry interval in milliseconds. If all slots are busy, new session request will be retried after the given interval. | | `--sessionqueue-batch-size` | int | `20` | Maximum number of session requests that can be consumed from the queue at a time, based on the available slots. | | `--maximum-response-delay` | int | `8` | How often, in seconds, will the SessionQueue respond in case there is no data, to reduce the http requests while polling for new session requests. (Config file only; not a CLI flag.) | | `--sessionqueue-implementation` | string | `org.openqa.selenium.grid.sessionqueue.local.LocalNewSessionQueue` | Full class name of non-default session queue implementation. | | `--sessionqueue-backend-url` | string | `redis://localhost:6379` | Backend datastore URL for the SessionQueue implementation. Used by Redis-backed and other external implementations loaded via `--ext`. | ### Sessions | Option | Type | Value/Example | Description | |---|---|---|---| | `--sessions` | uri | `http://localhost:1234` | Address of the session map server. | | `--sessions-host` | string | `localhost` | Host on which the session map server is listening. | | `--sessions-port` | int | `1234` | Port on which the session map server is listening. | | `--sessions-implementation` | string | `org.openqa.selenium.grid.sessionmap.redis.RedisBackedSessionMap` | Full class name of non-default session map implementation. | | `--sessions-scheme` | string | `redis` | URI scheme for the session map server (e.g. `redis`, `http`). | ## Configuration examples All the options mentioned above can be used when starting the Grid components. They are a good way of exploring the Grid options, and trying out values to find a suitable configuration. We recommend the use of Toml files to configure a Grid. Configuration files improve readability, and you can also check them in source control. When needed, you can combine a Toml file configuration with CLI arguments. ### Command-line flags To pass config options as command-line flags, identify the valid options for the component and follow the template below. ``` java -jar selenium-server-.jar --