Instruction manual
SeleniumHQ/selenium instruction manual
Apache-2.0 browser-automation framework and ecosystem implementing W3C WebDriver infrastructure across major browsers, with language bindings, Selenium Grid, automated browser and driver management, and Chromium debugging-protocol support. It is not documented as a Claude Code extension, MCP server, hook, or skill; inference: Claude Code can use Selenium indirectly by creating or invoking project code and test infrastructure, so it belongs as an external automation library and infrastructure companion.
1. Purpose, scope, and relationship to Claude Code
SeleniumHQ/selenium is the public, Apache-2.0 repository for Selenium, described by its maintainers as an umbrella project of tools and libraries for browser automation. It supplies infrastructure for the W3C WebDriver specification: a browser- and language-neutral automation interface compatible with major browsers. The supplied files document user-facing Java and Ruby bindings, Selenium Manager, Selenium Grid links, and contributor workflows spanning Java, Python, Ruby, .NET, JavaScript, and Rust.
**Claude Code classification: unclassified.** Nothing supplied documents a Claude Code plugin, hook, MCP server, skill, slash command, or other reliable Claude-specific mechanism. `.local/README.md` merely reserves ignored workspace locations such as `.local/AGENTS.md` and `.local/agent/skills/<local-skill-name>/SKILL.md` for contributors’ private customizations and local agent instructions. That does not establish repository-provided integration. Do not classify Selenium itself as a Claude extension from this evidence.
This repository README is primarily a contributor manual. For broader end-user material, it points to the first-party Selenium User Manual at `https://selenium.dev/documentation/` and support at `https://www.selenium.dev/support/`. The supplied snapshot does not enumerate the complete WebDriver API, Python package usage, Grid operation, or every binding. Accordingly, this manual covers every function actually documented in the supplied files and does not infer missing APIs. Repository metadata identifies Java as the primary language, `trunk` as the default branch, and JavaScript, Python, Ruby, .NET, and Rust among its topics and files.
2. Use the documented Java and Ruby bindings
The Java binding requires Java 11 or newer. Add `org.seleniumhq.selenium:selenium-java`, replacing `4.x.y` with the current Maven Central version. Maven:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.x.y</version>
</dependency>Gradle:
implementation "org.seleniumhq.selenium:selenium-java:4.x.y"The documented Java example creates a Chrome driver, opens Selenium’s site, prints its title, and always closes the browser:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class Example {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://www.selenium.dev");
System.out.println(driver.getTitle());
} finally {
driver.quit();
}
}
}The Ruby binding supports MRI 3.3 or newer. Install and run it as documented:
gem install selenium-webdriverrequire "selenium-webdriver"
driver = Selenium::WebDriver.for :chrome
begin
driver.get "https://www.selenium.dev"
puts driver.title
ensure
driver.quit
endIn both examples, `for`/`ChromeDriver` starts Chrome, `get` navigates, `title`/`getTitle()` reads the page title, and `quit` ends the browser session. Both binding READMEs say Selenium Manager handles browser-driver installation automatically, so their quick starts require no manual driver setup. They link to first-party Getting Started, API, Selenium Manager, and Grid documentation. The supplied Python README only redirects to `docs/source/index.rst`; no source-supported Python end-user installation or script is present here.
3. Run Selenium Manager from source
Selenium Manager is a Rust command-line tool that automates browser and driver management for Selenium. The supplied Rust README documents two source execution paths: Cargo or Bazel. Cargo requires Rust and Cargo. On Linux or macOS, its documented Rust installation command is:
curl https://sh.rustup.rs -sSf | shFrom the repository’s top-level directory, build the manager with Bazel:
bazel build //rust:selenium-managerFrom the Rust source context, display Cargo-based help with:
cargo run -- --helpAsk it to manage Chrome’s driver with:
cargo run -- --browser chromeThe equivalent documented Bazel pattern places manager arguments after `--`; this example selects Chrome and enables debug output:
bazel run //rust:selenium-manager -- --browser chrome --debugHere, `cargo run` or `bazel run //rust:selenium-manager` builds and executes the CLI; `--browser chrome` selects Chrome, and `--debug` requests debugging output. The supplied file does not document the rest of the option set, so use `--help` rather than assuming flags.
Windows ARM64 has known build issues according to the README. Its stated workaround is to use Cargo with the `--config Cargo.aarch64-pc-windows-msvc.toml` flag. The exact complete Cargo invocation is not supplied, so this manual does not invent one. The Java and Ruby quick starts invoke Manager indirectly when driver provisioning is needed; direct CLI use is mainly documented for building or exercising Manager from this repository.
4. Prepare a contributor environment
All local contributor environments require Bazelisk and JDK 17 or newer. Point `JAVA_HOME` at the JDK—not a JRE—and run `javac`; seeing its command-line options confirms that the compiler is available. macOS additionally requires Xcode command-line tools:
xcode-select --installOn Apple Silicon, the README currently says to put `build --host_platform=//:rosetta` in `.bazelrc.local`. Windows offers either an administrator PowerShell setup script or manual setup. Before the automatic path, the documented process-scoped policy command is:
Set-ExecutionPolicy Bypass -Scope Process -ForceThe supplied text links `scripts/dev-environment-setup.ps1` but does not provide a complete download-and-execute command. Manual Windows setup calls for RemoteSigned script policy, Developer Mode, MSYS2 with `PATH` and `BAZEL_SH`, Visual Studio Community’s C++ workload with `BAZEL_VC` and `BAZEL_VC_FULL_VERSION`, long-path registry settings, 8.3 names, and `startup --output_user_root=C:/tmp` in `.bazelrc.windows.local`.
Alternatives are the linked Gitpod workspace, `.devcontainer/devcontainer.json` in a supporting IDE, or building from `scripts/dev-image/Dockerfile`; no shell commands for the latter two are supplied. For multiple worktrees, place shared caches in the user `.bazelrc`:
common --disk_cache=/path/to/your/home/.cache/bazel-disk
common --repository_cache=/path/to/your/home/.cache/bazel-repoThese caches grow without a bound and need periodic pruning if space matters. On macOS/Linux, make a worktree’s output base disposable by adding this to that worktree’s `.bazelrc.local`:
startup --output_base=.local/output-baseDo not use that nested output-base approach on Windows; retain the documented `C:/tmp` output root to limit path-length problems.
5. Build targets and develop each binding
Bazel drives dependency downloads, compilation, generated files, packages, and tests. `bazel build` creates artifacts, `bazel run` builds then executes, `bazel test` builds and tests, and `bazel query` finds targets. Targets use `//path:name` notation. Build Grid directly or through its alias:
bazel build //java/src/org/openqa/selenium/grid:executable-grid
bazel build gridBuild every target for a language, or use Selenium’s `./go` Rake wrapper:
bazel build //<language>/...
./go <language>:buildFor Java IDE work, import the repository as a Bazel project using `scripts/ij.bazelproject` on macOS/Linux or `scripts/ij-win.bazelproject` on Windows. Format Java or Python with `./scripts/format.sh`. Install Java artifacts into the local Maven repository with `./go java:install`. Dependency versions live in `MODULE.bazel`; after editing one, repin or automatically update:
RULES_JVM_EXTERNAL_REPIN=1 bazel run @maven//:pin
./go java:updateFor Python local source work:
pip install -r py/requirements_lock.txt
./go py:local_devThen import from `py`. Alternatively, `./go py:install` builds and installs a wheel; activate a virtual environment first if global `site-packages` is not writable.
For Ruby, `bazel run //rb:console` opens a loaded REPL; `./go rb:local_dev` prepares RubyMine artifacts. Debug by adding `binding.break`, running `bazel test --config ruby_debug <test>`, then connecting separately with `bazel-selenium/external/bundle/bin/rdbg -A`.
For .NET, build with `bazel build dotnet/...`. In `dotnet`, initialize Paket once with `dotnet new tool-manifest`, `dotnet tool install paket`, and `dotnet tool restore`; edit `//dotnet:paket.dependencies`, then run `./dotnet/update-deps.sh` from the root. Rust Bazel dependencies derive from `rust/Cargo.toml` and `rust/Cargo.lock`.
6. Run and filter repository tests
Use `bazel test` with a target and documented options. `--pin_browsers=false` lets Selenium Manager locate browsers and drivers. `--headless` runs Chrome, Edge, or Firefox without a visible window. `--flaky_test_attempts 3` retries failures up to three times; `--local_test_jobs 1` serializes local jobs. `--cache_test_results=no` or `-t-` forces reruns. `--test_output all` prints all test output, while `--test_output streamed` runs tests one by one and displays output immediately. `--test_env FOO=bar` adds an environment variable. `--run_under="xvfb-run -a"` prefixes test execution with a virtual X server.
Filter by test size—small usually means no browser, large usually drives a browser, and medium is in between:
bazel test //<language>/... --test_size_filters=smallFilter tags, including a negative tag, with:
bazel test //<language>/... --test_tag_filters=this,-not-thisOnly the final `--test_tag_filters` value takes effect, including when inherited configurations add one. Consult a language directory’s `TESTING.md` where available.
On Linux, tests normally use the current X server. The documented explicit virtual-display sequence is `Xvfb :99`, then `DISPLAY=:99 jwm`, followed by:
bazel test --test_env=DISPLAY=:99 //java/... --test_tag_filters=chromeThe simpler virtual-X form is:
bazel test --run_under="xvfb-run -a" //java/...For .NET integration tests, set `DriverServiceLocation` and `ActiveDriverConfig` in `common\appconfig.json`, then run in NUnit. For remote tests, start Selenium Server per the linked Grid quick start, update each remote driver URI, and run NUnit or `bazel test //dotnet/test/remote`. These edits and server steps are prerequisites, not performed by that Bazel command.
7. Work with JavaScript, local services, and documentation
The JavaScript contributor file documents dependency regeneration with:
./go calcdepsTo run JavaScript tests locally, first start Selenium’s test application server:
bazel run //java/test/org/openqa/selenium/environment:appserverOnce running, its documented browser address is `http://localhost:2310/javascript`. The supplied file does not give a JavaScript test command, so only the server startup and address are established here.
Generate API documentation for one binding or all bindings through the `./go` wrapper:
./go <language>:docs
./go all:docsThe root README links generated API references for C#, JavaScript, Java, Python, and Ruby. Python’s documentation source lives in `py/docs`, which also supplies the package’s main GitHub/PyPI README. Its specifically documented generation task is:
./go py:docs_generateAfterward, generated Python HTML is under `bazel-bin/py/docs/_build/html/`.
The `.local` directory is reserved for private contributor customizations, scratch work, generated artifacts, and local agent instructions. Git ignores its contents except its README. Documented optional locations include `.local/AGENTS.md`, `.local/agent/skills/<local-skill-name>/SKILL.md`, `.local/agent/scripts/`, `.local/output-base/`, `.local/plans/`, and `.local/scratch/`. These paths do not activate a documented Selenium feature by themselves; they are workspace conventions. In particular, the local skill path is not evidence that Selenium ships a Claude Code skill or that any host will discover it automatically.
8. Maintain protocol files and cross-binding design decisions
Selenium keeps multiple Chrome Debugging Protocol versions so it can generate bindings for particular Chromium releases. The documented maintenance sequence is manual: identify the current stable desktop Chrome version; create `common/devtools/chromium/vXX`; copy the preceding version’s `BUILD.bazel`; open the matching Chromium tag; download `third_party/blink/public/devtools_protocol/browser_protocol.pdl`; find `v8_revision` in Chromium’s `DEPS`; switch to that V8 revision; and download V8’s `include/js_protocol.pdl` into the same version directory. The README supplies URL patterns but no copy-paste download command, so none should be invented. Chrome and Edge can share this Chromium-derived protocol basis.
Cross-language, user-visible decisions belong in `docs/decisions`: API names and shapes, errors and messages, defaults, capability handling, WebDriver Classic/BiDi exposure, deprecations, compatibility promises, and resolved `A-needs-decision` matters. Single-binding internals, infrastructure choices, and cheaply reversible changes do not.
To propose a decision, copy `0000-template.md` to a short title, set `Status: Proposed`, and open a pull request. After GitHub assigns a number, rename it `NNNN-short-title.md`. Select the ADR PR template by appending `?expand=1&template=adr.md` to the compare URL. Discussion occurs in the PR and, when needed, a TLC meeting. Acceptance requires at least a week, a TLC agenda item, responses from a majority, and no unresolved objection; the Project Lead merges with `Status: Accepted`. Rejected proposals are merged as rejected; withdrawn pre-consideration proposals are closed.
After acceptance, open an ADR implementation-tracking issue with one checkbox per binding. Accepted records are immutable except status; changing one requires a new superseding record. Each record must stand alone, explain rationale and rejected alternatives, and specify behavior rather than binding-specific implementation.
9. Release boundaries, support, and evidence-based cautions
Release work combines building and publishing through stamped `./go` tasks and may require coordination and additional processing. The supplied repository commands are:
./go all:release
./go <language>:releaseMaintainers with access to the separate Selenium EngFlow repository may remotely build and download release assets with:
./go all:release['--config', 'release']These are publishing operations, not ordinary verification commands; use them only in the documented maintainer release process. The full process is linked from the Selenium wiki but was not supplied, so credentials, ordering, rollback, and publication details cannot be reconstructed here.
Before contributing, the root README says to read `CONTRIBUTING.md`; its contents were not supplied. Pull requests are welcomed, and the Java/Ruby files point to Selenium Chat and GitHub Issues for support. The repository metadata indicates public issue and pull-request support and an Apache-2.0 license.
Important scope limits follow directly from the evidence. This snapshot is contributor-heavy and repeatedly directs users to external first-party documentation for complete Selenium usage. It does not document every WebDriver operation, all language installation procedures, the full Grid setup, every Selenium Manager flag, or an end-to-end release procedure. It also gives no Claude Code integration path. Selenium can certainly be operated by commands or code in a development environment, but that generic possibility is not a reliable Claude mechanism. Treat any proposed Claude hook, MCP setup, plugin, skill installation, or agent automation as undocumented unless separate first-party evidence establishes it. Likewise, placeholders such as `<language>`, `<test>`, and `4.x.y` must be replaced with valid, context-specific values; the supplied files do not define an exhaustive list.