blob: e27ca6bf74fdcd130bf3adfc1f1ca68c978bf80f [file] [edit]
load("@aspect_bazel_lib//lib:copy_directory.bzl", "copy_directory")
load("@bazel_skylib//rules:select_file.bzl", "select_file")
load("@py_dev_requirements//:requirements.bzl", "requirement")
load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
load("@rules_pkg//pkg:pkg.bzl", "pkg_tar")
load("@rules_python//python:defs.bzl", "py_binary", "py_library")
load("@rules_python//python:packaging.bzl", "py_package", "py_wheel")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
load("//common:defs.bzl", "copy_file")
load("//py:defs.bzl", "generate_devtools", "generate_devtools_latest", "py_test_suite")
load("//py/private:browsers.bzl", "BROWSERS")
load("//py/private:generate_bidi.bzl", "generate_bidi")
load("//py/private:generate_bidi_protocol.bzl", "generate_bidi_protocol")
load("//py/private:import.bzl", "py_import")
load("//py/private:sphinx_docs.bzl", "sphinx_docs")
exports_files(
["pyproject.toml"],
visibility = ["//py:__subpackages__"],
)
py_binary(
name = "selenium-release",
srcs = [
"release-selenium.py",
],
args = [
"upload",
"$(location :selenium-wheel)",
"$(location :selenium-sdist)",
],
data = [
":selenium-sdist",
":selenium-wheel",
],
main = "release-selenium.py",
deps = [
requirement("twine"),
],
)
py_binary(
name = "selenium-release-nightly",
srcs = [
"release-selenium.py",
],
args = [
"upload",
"--repository",
"testpypi",
"$(location :selenium-wheel)",
"$(location :selenium-sdist)",
],
data = [
":selenium-sdist",
":selenium-wheel",
],
main = "release-selenium.py",
deps = [
requirement("twine"),
],
)
compile_pip_requirements(
# base name for generated targets, typically "requirements"
name = "requirements",
srcs = [
"pyproject.toml",
"requirements.txt",
],
extra_args = [
"--no-annotate", # keep lock check platform agnostic
"--no-strip-extras",
],
requirements_txt = ":requirements_lock.txt",
)
SE_VERSION = "4.50.0.202609091537"
BROWSER_VERSIONS = [
"v152",
"v153",
"v151",
]
TEST_DEPS = [
requirement("filetype"),
requirement("pytest"),
requirement("pytest-instafail"),
requirement("pytest-trio"),
requirement("pytest-mock"),
requirement("rich"),
requirement("zipp"),
"@rules_python//python/runfiles",
]
genrule(
name = "java-location",
srcs = [],
outs = ["java-location.txt"],
cmd = "echo $(JAVA) > $@",
toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"],
)
copy_file(
name = "manager-linux-x86_64",
src = "//common/manager:selenium-manager-linux-x86_64",
out = "selenium/webdriver/common/linux-x86_64/selenium-manager",
)
copy_file(
name = "manager-linux-arm64",
src = "//common/manager:selenium-manager-linux-arm64",
out = "selenium/webdriver/common/linux-arm64/selenium-manager",
)
copy_file(
name = "manager-macos",
src = "//common/manager:selenium-manager-macos",
out = "selenium/webdriver/common/macos/selenium-manager",
)
copy_file(
name = "manager-windows",
src = "//common/manager:selenium-manager-windows",
out = "selenium/webdriver/common/windows/selenium-manager.exe",
)
copy_file(
name = "manager-sbom",
src = "//common/manager:selenium-manager-sbom",
out = "selenium/webdriver/common/selenium-manager.cdx.json",
)
copy_file(
name = "manager-notice",
src = "//common/manager:selenium-manager-notice",
out = "selenium/webdriver/common/selenium-manager-THIRD-PARTY-NOTICES.txt",
)
copy_file(
name = "get-attribute",
src = "//javascript/atoms/fragments:get-attribute-typescript.js",
out = "selenium/webdriver/remote/getAttribute.js",
)
copy_file(
name = "is-displayed",
src = "//javascript/atoms/fragments:is-displayed-typescript.js",
out = "selenium/webdriver/remote/isDisplayed.js",
)
copy_file(
name = "find-elements",
src = "//javascript/atoms/fragments:find-elements-typescript.js",
out = "selenium/webdriver/remote/findElements.js",
)
copy_file(
name = "mutation-listener",
src = "//javascript/cdp-support:mutation-listener.js",
out = "selenium/webdriver/common/mutation-listener.js",
)
copy_file(
name = "bidi-mutation-listener",
src = "//javascript/bidi-support:bidi-mutation-listener.js",
out = "selenium/webdriver/common/bidi-mutation-listener.js",
)
copy_file(
name = "firefox-driver-prefs",
src = "//third_party/js/selenium:webdriver_json",
out = "selenium/webdriver/firefox/webdriver_prefs.json",
)
copy_file(
name = "webextensions-selenium-example-xpi",
testonly = True,
src = "//common/extensions:webextensions-selenium-example.xpi",
out = "test/extensions/webextensions-selenium-example.xpi",
)
copy_file(
name = "webextensions-selenium-example-zip",
testonly = True,
src = "//common/extensions:webextensions-selenium-example.zip",
out = "test/extensions/webextensions-selenium-example.zip",
)
copy_file(
name = "webextensions-selenium-example-unsigned-zip",
testonly = True,
src = "//common/extensions:webextensions-selenium-example-unsigned.zip",
out = "test/extensions/webextensions-selenium-example-unsigned.zip",
)
copy_file(
name = "webextensions-selenium-example-crx",
testonly = True,
src = "//common/extensions:webextensions-selenium-example.crx",
out = "test/extensions/webextensions-selenium-example.crx",
)
copy_directory(
name = "webextensions-selenium-example-dir",
testonly = True,
src = "//common/extensions:webextensions-selenium-example",
out = "test/extensions/webextensions-selenium-example",
)
copy_directory(
name = "webextensions-selenium-example-signed-dir",
testonly = True,
src = "//common/extensions:webextensions-selenium-example-signed",
out = "test/extensions/webextensions-selenium-example-signed",
)
select_file(
name = "global-license",
srcs = "//:license",
subpath = "LICENSE",
)
copy_file(
name = "license",
src = ":global-license",
out = "LICENSE",
)
copy_file(
name = "license-wheel",
src = ":global-license",
out = "selenium-%s.dist-info/LICENSE" % SE_VERSION,
)
select_file(
name = "global-notice",
srcs = "//:license",
subpath = "NOTICE",
)
copy_file(
name = "notice",
src = ":global-notice",
out = "NOTICE",
)
copy_file(
name = "notice-wheel",
src = ":global-notice",
out = "selenium-%s.dist-info/NOTICE" % SE_VERSION,
)
# ==============================================================================
# Module Targets (following Ruby's modular pattern)
# ==============================================================================
# Exceptions and package init (no deps - foundational)
py_library(
name = "exceptions",
srcs = [
"selenium/__init__.py",
"selenium/webdriver/__init__.py",
] + glob(["selenium/common/**/*.py"]),
data = ["selenium/webdriver/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
)
# Remote/wire protocol (foundational)
py_library(
name = "remote",
srcs = glob(["selenium/webdriver/remote/**/*.py"]),
data = [
":find-elements",
":get-attribute",
":is-displayed",
],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":exceptions",
requirement("certifi"),
requirement("urllib3"),
requirement("websocket-client"),
],
)
# BiDi protocol support
py_library(
name = "bidi",
srcs = [":create-bidi-src"],
data = [
":bidi-mutation-listener",
":mutation-listener",
],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":exceptions",
":remote",
requirement("trio"),
requirement("trio-websocket"),
requirement("websocket-client"),
],
)
# Common utilities (shared by all browsers, includes devtools generated code)
py_library(
name = "common",
srcs = glob(
["selenium/webdriver/common/**/*.py"],
exclude = [
"selenium/webdriver/common/action_chains.py",
"selenium/webdriver/common/actions/**",
"selenium/webdriver/common/alert.py",
"selenium/webdriver/common/api_request_context.py",
"selenium/webdriver/common/_bidi/**",
"selenium/webdriver/common/bidi/**",
"selenium/webdriver/common/devtools/**",
"selenium/webdriver/common/fedcm/**",
"selenium/webdriver/common/print_page_options.py",
"selenium/webdriver/common/timeouts.py",
"selenium/webdriver/common/virtual_authenticator.py",
],
),
data = [
":manager-linux-arm64",
":manager-linux-x86_64",
":manager-macos",
":manager-notice",
":manager-sbom",
":manager-windows",
] + [":create-cdp-srcs-" + n for n in BROWSER_VERSIONS],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":bidi",
":exceptions",
":latest",
":remote",
requirement("typing_extensions"),
],
)
# Input actions API (action_chains + actions subpackage)
py_library(
name = "common_actions",
srcs = glob([
"selenium/webdriver/common/action_chains.py",
"selenium/webdriver/common/actions/**/*.py",
]),
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
py_library(
name = "common_alert",
srcs = ["selenium/webdriver/common/alert.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
py_library(
name = "common_api_request_context",
srcs = ["selenium/webdriver/common/api_request_context.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [":exceptions"],
)
py_library(
name = "common_fedcm",
srcs = glob(["selenium/webdriver/common/fedcm/**/*.py"]),
imports = ["."],
visibility = ["//visibility:public"],
deps = [":exceptions"],
)
py_library(
name = "common_print_page_options",
srcs = ["selenium/webdriver/common/print_page_options.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [],
)
py_library(
name = "common_timeouts",
srcs = ["selenium/webdriver/common/timeouts.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [],
)
py_library(
name = "common_virtual_authenticator",
srcs = ["selenium/webdriver/common/virtual_authenticator.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [":exceptions"],
)
# Module that points to the latest devtools module
py_library(
name = "latest",
srcs = [":create-latest-devtools"],
imports = ["selenium.webdriver.common.devtools"],
visibility = ["//visibility:public"],
)
# Support utilities (wait conditions, event listeners, etc.)
py_library(
name = "support",
srcs = glob(
["selenium/webdriver/support/**/*.py"],
exclude = ["selenium/webdriver/support/color.py"],
),
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":exceptions",
":remote",
],
)
py_library(
name = "support_color",
srcs = ["selenium/webdriver/support/color.py"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [],
)
# Chromium base (shared by Chrome and Edge)
py_library(
name = "chromium",
srcs = glob(["selenium/webdriver/chromium/**/*.py"]),
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# Chrome driver
py_library(
name = "chrome",
srcs = glob(["selenium/webdriver/chrome/**/*.py"]),
data = ["selenium/webdriver/chrome/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [":chromium"],
)
# Edge driver
py_library(
name = "edge",
srcs = glob(["selenium/webdriver/edge/**/*.py"]),
data = ["selenium/webdriver/edge/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [":chromium"],
)
# Firefox driver
py_library(
name = "firefox",
srcs = glob(["selenium/webdriver/firefox/**/*.py"]),
data = [
"selenium/webdriver/firefox/__init__.pyi",
":firefox-driver-prefs",
],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# Safari driver
py_library(
name = "safari",
srcs = glob(["selenium/webdriver/safari/**/*.py"]),
data = ["selenium/webdriver/safari/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# IE driver
py_library(
name = "ie",
srcs = glob(["selenium/webdriver/ie/**/*.py"]),
data = ["selenium/webdriver/ie/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# WebKitGTK driver
py_library(
name = "webkitgtk",
srcs = glob(["selenium/webdriver/webkitgtk/**/*.py"]),
data = ["selenium/webdriver/webkitgtk/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# WPEWebKit driver
py_library(
name = "wpewebkit",
srcs = glob(["selenium/webdriver/wpewebkit/**/*.py"]),
data = ["selenium/webdriver/wpewebkit/__init__.pyi"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":common",
":remote",
],
)
# ==============================================================================
# Aggregate Target (backwards compatible - includes all modules)
# ==============================================================================
py_library(
name = "selenium",
srcs = [],
data = ["selenium/py.typed"],
imports = ["."],
visibility = ["//visibility:public"],
deps = [
":bidi",
":bidi_protocol",
":chrome",
":chromium",
":common",
":common_actions",
":common_alert",
":common_api_request_context",
":common_fedcm",
":common_print_page_options",
":common_timeouts",
":common_virtual_authenticator",
":edge",
":exceptions",
":firefox",
":ie",
":remote",
":safari",
":support",
":support_color",
":webkitgtk",
":wpewebkit",
],
)
py_package(
name = "selenium-pkg",
packages = [
"py.selenium",
"py.selenium.common",
"py.selenium.webdriver",
"py.selenium.webdriver.chrome",
"py.selenium.webdriver.chromium",
"py.selenium.webdriver.common",
"py.selenium.webdriver.common._bidi",
"py.selenium.webdriver.common.bidi",
"py.selenium.webdriver.common.devtools",
"py.selenium.webdriver.common.devtools.latest",
"py.selenium.webdriver.edge",
"py.selenium.webdriver.firefox",
"py.selenium.webdriver.remote",
"py.selenium.webdriver.safari",
],
deps = [":selenium"],
)
pkg_files(
name = "selenium-sdist-pkg",
srcs = [
"CHANGES",
"README.rst",
"pyproject.toml",
":license",
":notice",
":selenium-pkg",
":selenium-pkginfo",
"//rust:selenium_manager_srcs",
],
excludes = [
":manager-linux-x86_64",
":manager-linux-arm64",
":manager-macos",
":manager-notice",
":manager-sbom",
":manager-windows",
],
strip_prefix = strip_prefix.from_pkg(),
)
pkg_tar(
name = "selenium-sdist",
srcs = [":selenium-sdist-pkg"],
extension = "tar.gz",
mode = "0644",
package_dir = "selenium-%s" % SE_VERSION,
package_file_name = "selenium-%s.tar.gz" % SE_VERSION,
)
genrule(
name = "selenium-pkginfo",
srcs = [":selenium-wheel-lib"],
outs = ["PKG-INFO"],
cmd = "cp $(location :selenium-wheel-lib)/selenium-%s.dist-info/METADATA $@" % SE_VERSION,
)
py_import(
name = "selenium-wheel-lib",
wheel = ":selenium-wheel",
)
py_wheel(
name = "selenium-wheel",
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS :: MacOS X",
"Topic :: Software Development :: Testing",
"Topic :: Software Development :: Libraries",
"Programming Language :: Python",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
],
description_file = "README.rst",
distribution = "selenium",
homepage = "https://www.selenium.dev",
license = "Apache-2.0",
python_requires = ">=3.10",
python_tag = "py3",
requires = [
"certifi>=2026.2.25",
"trio>=0.31.0,<1.0",
"trio-websocket>=0.12.2,<1.0",
"typing_extensions>=4.15.0,<5.0",
"urllib3[socks]>=2.6.3,<3.0",
"websocket-client>=1.8.0,<2.0",
],
strip_path_prefixes = [
"py/",
],
summary = "Official Python bindings for Selenium WebDriver",
tags = [
"release-artifact",
],
version = SE_VERSION,
visibility = ["//visibility:public"],
deps = [
":license-wheel",
":notice-wheel",
":selenium-pkg",
],
)
py_library(
name = "init-tree",
testonly = True,
srcs = [
"conftest.py",
"test/__init__.py",
"test/selenium/__init__.py",
"test/selenium/webdriver/__init__.py",
"test/selenium/webdriver/chrome/__init__.py",
"test/selenium/webdriver/common/__init__.py",
"test/selenium/webdriver/common/network.py",
"test/selenium/webdriver/common/webserver.py",
"test/selenium/webdriver/firefox/__init__.py",
"test/selenium/webdriver/safari/conftest.py",
"test/selenium/webdriver/support/__init__.py",
],
data = [
"pyproject.toml",
"test/selenium/webdriver/common/test_file.txt",
"test/selenium/webdriver/common/test_file2.txt",
":webextensions-selenium-example-crx",
":webextensions-selenium-example-dir",
":webextensions-selenium-example-signed-dir",
":webextensions-selenium-example-unsigned-zip",
":webextensions-selenium-example-xpi",
":webextensions-selenium-example-zip",
],
imports = ["."],
deps = [
":webserver",
],
)
py_binary(
name = "generate",
srcs = ["generate.py"],
srcs_version = "PY3",
deps = [requirement("inflection")],
)
copy_file(
name = "license_header_local",
src = "//scripts:license_header.txt",
out = "license_header.txt",
)
py_binary(
name = "generate_bidi",
srcs = ["generate_bidi.py"],
data = [":license_header_local"],
srcs_version = "PY3",
deps = ["//scripts:generated_note"],
)
[generate_devtools(
name = "create-cdp-srcs-{}".format(devtools_version),
browser_protocol = "//common/devtools/chromium/{}:browser_protocol".format(devtools_version),
generator = ":generate",
js_protocol = "//common/devtools/chromium/{}:js_protocol".format(devtools_version),
outdir = "selenium/webdriver/common/devtools/{}".format(devtools_version),
protocol_version = devtools_version,
) for devtools_version in BROWSER_VERSIONS]
generate_devtools_latest(
name = "create-latest-devtools",
browser_versions = BROWSER_VERSIONS,
)
# Generate BiDi source files from CDDL specification.
# extra_cddl_files are merged with the primary WebDriver BiDi spec before
# generation so that end users get the full set of BiDi-adjacent modules.
generate_bidi(
name = "create-bidi-src",
cddl_file = "@webdriver_bidi_all_cddl//file:spec.cddl",
enhancements_manifest = "//py/private:bidi_enhancements_manifest.py",
extra_cddl_files = [
"@permissions_all_cddl//file:spec.cddl",
"@prefetch_all_cddl//file:spec.cddl",
"@ua_client_hints_all_cddl//file:spec.cddl",
"@web_bluetooth_all_cddl//file:spec.cddl",
],
extra_srcs = [
"//py/private:_event_manager.py",
"//py/private:_network_handlers.py",
"//py/private:_script_handlers.py",
"//py/private:cdp.py",
],
generator = ":generate_bidi",
merge_tool = "//py/private:merge_cddl",
module_name = "selenium/webdriver/common/bidi",
spec_version = "1.0",
)
# Schema-driven internal BiDi protocol layer: generated at build time from the
# shared BiDi schema into `selenium/webdriver/common/_bidi/`. Only the hand-written
# runtime (serialization/transport/domain) is checked in; the domain modules are
# generated by the rule below and never committed.
generate_bidi_protocol(
name = "create-bidi-protocol-src",
generator = ":generate-bidi-protocol-tool",
package = "selenium/webdriver/common/_bidi",
schema = "//javascript/selenium-webdriver:create-bidi-src_schema",
)
# Build-graph tool: the generator invoked by the rule above (schema + output dir
# passed as arguments). No baked args, so it is reusable in the exec configuration.
# Depends on :remote because rendering reads errorhandler's error-code tables to decide
# which BiDi codes reuse a classic exception rather than declaring a new one.
py_binary(
name = "generate-bidi-protocol-tool",
srcs = ["generate_bidi_protocol.py"],
main = "generate_bidi_protocol.py",
visibility = ["//visibility:private"],
deps = [":remote"],
)
# `bazel run //py:generate-bidi-protocol` regenerates the checked-out tree for local
# development (writes under BUILD_WORKSPACE_DIRECTORY); the build itself uses the rule.
py_binary(
name = "generate-bidi-protocol",
srcs = ["generate_bidi_protocol.py"],
args = ["$(location //javascript/selenium-webdriver:create-bidi-src_schema)"],
data = ["//javascript/selenium-webdriver:create-bidi-src_schema"],
main = "generate_bidi_protocol.py",
visibility = ["//visibility:public"],
deps = [":remote"],
)
py_library(
name = "bidi_protocol",
# Listed explicitly, not globbed: a local generate run drops the generated modules here too, and a glob would double them against the rule's outputs.
srcs = [":create-bidi-protocol-src"] + [
"selenium/webdriver/common/_bidi/__init__.py",
"selenium/webdriver/common/_bidi/domain.py",
"selenium/webdriver/common/_bidi/serialization.py",
"selenium/webdriver/common/_bidi/transport.py",
],
imports = ["."],
visibility = ["//visibility:public"],
deps = [":exceptions"],
)
py_test_suite(
name = "unit",
size = "small",
srcs = glob([
"test/unit/**/*.py",
]),
args = [
"--instafail",
],
deps = [
":init-tree",
":selenium",
] + TEST_DEPS,
)
py_library(
name = "webserver",
testonly = True,
srcs = [
"test/selenium/webdriver/common/network.py",
"test/selenium/webdriver/common/webserver.py",
],
data = [
"//common/src/web",
],
deps = [],
)
BIDI_TESTS = glob([
"test/selenium/webdriver/common/bidi/**/*_tests.py",
"test/selenium/webdriver/common/_bidi/**/*_tests.py",
])
# Tests that have bidi and classic implementations.
BIDI_IMPLEMENTATIONS = []
# BiDi test files with Grid-specific behavior, run through Grid as well. Empty
# generates no targets: an empty test_suite would mean every test in the package.
REMOTE_BIDI_TESTS = []
# Test files that only run against browsers supporting the given feature.
# Each group is split into its own sub-suite so that changing the underlying
# library only triggers that group's targets, not the full ~700-target suite.
FEDCM_TESTS = ["test/selenium/webdriver/common/fedcm_tests.py"]
TIMEOUTS_TESTS = ["test/selenium/webdriver/common/timeout_tests.py"]
VIRTUAL_AUTH_TESTS = ["test/selenium/webdriver/common/virtual_authenticator_tests.py"]
API_REQUEST_TESTS = ["test/selenium/webdriver/common/api_request_context_tests.py"]
# alerts_tests.py and webdriverwait_tests.py both call driver.switch_to.alert,
# requiring :common_alert at runtime, so they share a sub-suite.
ALERT_TESTS = [
"test/selenium/webdriver/common/alerts_tests.py",
"test/selenium/webdriver/common/webdriverwait_tests.py",
]
# rendered_webelement_tests.py is the only browser test that imports Color.
RENDERED_WEBELEMENT_TESTS = ["test/selenium/webdriver/common/rendered_webelement_tests.py"]
# print_pdf_tests.py imports PrintOptions, which lives in its own library
# (:common_print_page_options) rather than :common.
PRINT_TESTS = ["test/selenium/webdriver/common/print_pdf_tests.py"]
FEATURE_TESTS = (
FEDCM_TESTS +
TIMEOUTS_TESTS +
VIRTUAL_AUTH_TESTS +
API_REQUEST_TESTS +
ALERT_TESTS +
RENDERED_WEBELEMENT_TESTS +
PRINT_TESTS
)
# Test files that import from selenium.webdriver.common.actions / action_chains.
# These are kept separate so they can depend on :common_actions without pulling
# that library into every other test suite.
ACTIONS_TESTS = [
"test/selenium/webdriver/common/interactions_tests.py",
"test/selenium/webdriver/common/interactions_with_device_tests.py",
"test/selenium/webdriver/common/w3c_interaction_tests.py",
"test/selenium/webdriver/support/event_firing_webdriver_tests.py",
]
DRIVER_FINDER_TESTS = ["test/selenium/webdriver/common/driver_finder_tests.py"]
# Behavior that differs by host OS (window geometry, screenshots); tagged so CI
# runs these on every OS rather than only on the Linux RBE pass.
OS_SENSITIVE_TESTS = [
"test/selenium/webdriver/common/takes_screenshots_tests.py",
"test/selenium/webdriver/common/window_tests.py",
]
# Browser-specific test configuration
BROWSER_TESTS = {
"chrome": {
"browser_srcs": ["test/selenium/webdriver/chrome/**/*.py"],
"deps": [
":chrome",
":common",
":support",
],
"actions_deps": [
":chrome",
":common_actions",
":support",
],
"bidi": True,
},
"edge": {
"browser_srcs": ["test/selenium/webdriver/edge/**/*.py"],
"deps": [
":edge",
":common",
":support",
],
"actions_deps": [
":edge",
":common_actions",
":support",
],
"bidi": True,
},
"firefox": {
"browser_srcs": [
"test/selenium/webdriver/firefox/**/*.py",
],
"deps": [
":firefox",
":common",
":support",
],
"actions_deps": [
":firefox",
":common_actions",
":support",
],
"extra_excludes": ["test/selenium/webdriver/common/devtools_tests.py"],
"bidi": True,
},
"ie": {
"browser_srcs": ["test/selenium/webdriver/ie/**/*.py"],
"deps": [
":ie",
":common",
":support",
],
"actions_deps": [
":ie",
":common_actions",
":support",
],
},
"safari": {
"browser_srcs": ["test/selenium/webdriver/safari/**/*.py"],
"deps": [
":safari",
":common",
":support",
],
"actions_deps": [
":safari",
":common_actions",
":support",
],
},
}
DEFAULT_BROWSER_TESTS = [b for b in BROWSER_TESTS if b != "ie"]
# Generate test-<browser>-common targets (non-bidi, non-actions)
[
py_test_suite(
name = "test-%s-common" % browser,
size = "large",
srcs = glob(
[
"test/selenium/webdriver/common/**/*.py",
"test/selenium/webdriver/support/**/*.py",
] + BROWSER_TESTS[browser]["browser_srcs"],
exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS +
BROWSER_TESTS[browser].get("extra_excludes", []),
),
args = [
"--instafail",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"],
env_inherit = ["DISPLAY"],
extra_tags = {src: ["os-sensitive"] for src in OS_SENSITIVE_TESTS},
tags = ["no-sandbox"] + BROWSERS[browser]["tags"],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = browser,
deps = [
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in DEFAULT_BROWSER_TESTS
]
# Generate test-<browser>-actions targets (non-bidi, actions tests only)
[
py_test_suite(
name = "test-%s-actions" % browser,
size = "large",
srcs = ACTIONS_TESTS,
args = [
"--instafail",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"],
env_inherit = ["DISPLAY"],
tags = [
"no-sandbox",
"os-sensitive",
] + BROWSERS[browser]["tags"],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-actions" % browser,
deps = [
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["actions_deps"] + TEST_DEPS,
)
for browser in DEFAULT_BROWSER_TESTS
]
# Feature test definitions: suffix -> (srcs, dep)
FEATURE_SUITE_DEFS = {
"fedcm": (FEDCM_TESTS, ":common_fedcm"),
"timeouts": (TIMEOUTS_TESTS, ":common_timeouts"),
"virtual-auth": (VIRTUAL_AUTH_TESTS, ":common_virtual_authenticator"),
"api-request": (API_REQUEST_TESTS, ":common_api_request_context"),
"alerts": (ALERT_TESTS, ":common_alert"),
"rendered": (RENDERED_WEBELEMENT_TESTS, ":support_color"),
"print": (PRINT_TESTS, ":common_print_page_options"),
}
# Generate test-<browser>-<feature> targets (non-bidi, one per feature library)
[
py_test_suite(
name = "test-%s-%s" % (browser, feature),
size = "large",
srcs = FEATURE_SUITE_DEFS[feature][0],
args = [
"--instafail",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"],
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-%s" % (browser, feature),
deps = [
":init-tree",
":webserver",
FEATURE_SUITE_DEFS[feature][1],
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in DEFAULT_BROWSER_TESTS
for feature in FEATURE_SUITE_DEFS
]
# Aggregate test-<browser> = common + actions + features (keeps CI targets unchanged)
[test_suite(
name = "test-%s" % browser,
tests = [
":test-%s-common" % browser,
":test-%s-actions" % browser,
] + [":test-%s-%s" % (browser, f) for f in FEATURE_SUITE_DEFS],
) for browser in DEFAULT_BROWSER_TESTS]
[
py_test_suite(
name = "test-%s-driver-finder" % browser,
size = "large",
srcs = DRIVER_FINDER_TESTS,
args = [
"--instafail",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"],
env_inherit = ["DISPLAY"],
flaky = True,
tags = BROWSERS[browser]["tags"] + ["se-manager"],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = browser,
deps = [
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in DEFAULT_BROWSER_TESTS
]
# Generate test-<browser>-bidi targets
[
py_test_suite(
name = "test-%s-bidi" % browser,
size = "large",
srcs = BIDI_TESTS + BIDI_IMPLEMENTATIONS,
args = [
"--instafail",
"--bidi",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"],
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-bidi" % browser,
deps = [
":bidi_protocol", # bidi/protocol_tests.py imports the generated _bidi layer directly
":common_alert", # bidi/browsing_context_tests.py calls EC.alert_is_present()
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in DEFAULT_BROWSER_TESTS
if BROWSER_TESTS[browser].get("bidi", False)
]
# Generate test-<browser>-remote-bidi targets (chrome and firefox only), folded
# into test-<browser>-remote below.
[
py_test_suite(
name = "test-%s-remote-bidi" % browser,
size = "large",
srcs = REMOTE_BIDI_TESTS,
args = [
"--instafail",
"--bidi",
"--remote",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"] + [
":java-location",
"//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar",
"@bazel_tools//tools/jdk:current_java_runtime",
],
env = {
"SE_BAZEL_JAVA_LOCATION": "$(rootpath :java-location)",
},
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"] + [
"remote",
"%s-remote" % browser,
],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-remote-bidi" % browser,
deps = [
":bidi_protocol",
":common_alert",
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in [
"chrome",
"firefox",
]
if REMOTE_BIDI_TESTS
]
# Generate test-<browser>-remote-common targets (chrome and firefox only)
[
py_test_suite(
name = "test-%s-remote-common" % browser,
size = "large",
srcs = glob(
[
"test/selenium/webdriver/common/**/*.py",
"test/selenium/webdriver/remote/**/*.py",
"test/selenium/webdriver/support/**/*.py",
] + BROWSER_TESTS[browser]["browser_srcs"],
exclude = BIDI_TESTS + ACTIONS_TESTS + FEATURE_TESTS + DRIVER_FINDER_TESTS +
BROWSER_TESTS[browser].get("extra_excludes", []),
),
args = [
"--instafail",
"--remote",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"] + [
":java-location",
"//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar",
"@bazel_tools//tools/jdk:current_java_runtime",
],
env = {
"SE_BAZEL_JAVA_LOCATION": "$(rootpath :java-location)",
},
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"] + [
"remote",
"%s-remote" % browser,
],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-remote" % browser,
deps = [
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in [
"chrome",
"firefox",
]
]
# Generate test-<browser>-remote-actions targets (chrome and firefox only)
[
py_test_suite(
name = "test-%s-remote-actions" % browser,
size = "large",
srcs = ACTIONS_TESTS,
args = [
"--instafail",
"--remote",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"] + [
":java-location",
"//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar",
"@bazel_tools//tools/jdk:current_java_runtime",
],
env = {
"SE_BAZEL_JAVA_LOCATION": "$(rootpath :java-location)",
},
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"] + [
"remote",
"%s-remote" % browser,
],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-remote-actions" % browser,
deps = [
":init-tree",
":webserver",
] + BROWSER_TESTS[browser]["actions_deps"] + TEST_DEPS,
)
for browser in [
"chrome",
"firefox",
]
]
# Generate test-<browser>-remote-<feature> targets (chrome and firefox only)
[
py_test_suite(
name = "test-%s-remote-%s" % (browser, feature),
size = "large",
srcs = FEATURE_SUITE_DEFS[feature][0],
args = [
"--instafail",
"--remote",
] + BROWSERS[browser]["args"],
data = BROWSERS[browser]["data"] + [
":java-location",
"//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar",
"@bazel_tools//tools/jdk:current_java_runtime",
],
env = {
"SE_BAZEL_JAVA_LOCATION": "$(rootpath :java-location)",
},
env_inherit = ["DISPLAY"],
tags = ["no-sandbox"] + BROWSERS[browser]["tags"] + [
"remote",
"%s-remote" % browser,
],
target_compatible_with = BROWSERS[browser]["target_compatible_with"],
test_suffix = "%s-remote-%s" % (browser, feature),
deps = [
":init-tree",
":webserver",
FEATURE_SUITE_DEFS[feature][1],
] + BROWSER_TESTS[browser]["deps"] + TEST_DEPS,
)
for browser in [
"chrome",
"firefox",
]
for feature in FEATURE_SUITE_DEFS
]
# Aggregate test-<browser>-remote = remote-common + remote-actions + remote-features
[test_suite(
name = "test-%s-remote" % browser,
tests = [
":test-%s-remote-common" % browser,
":test-%s-remote-actions" % browser,
] + [":test-%s-remote-%s" % (browser, f) for f in FEATURE_SUITE_DEFS] + ([":test-%s-remote-bidi" % browser] if REMOTE_BIDI_TESTS else []),
) for browser in [
"chrome",
"firefox",
]]
test_suite(
name = "test-remote",
tags = ["remote"],
tests = [
":test-chrome-remote",
":test-firefox-remote",
],
)
py_binary(
name = "generate-api-listing",
srcs = ["generate_api_module_listing.py"],
main = "generate_api_module_listing.py",
deps = [":selenium"],
)
py_binary(
name = "sphinx-autogen",
srcs = ["run_sphinx_autogen.py"],
main = "run_sphinx_autogen.py",
deps = [
":selenium",
requirement("sphinx"),
],
)
py_console_script_binary(
name = "sphinx-build",
pkg = "@py_dev_requirements//sphinx",
script = "sphinx-build",
deps = [
":selenium",
requirement("pydata_sphinx_theme"),
],
)
sphinx_docs(
name = "docs",
srcs = glob(["docs/source/**/*.rst"]),
config = "docs/source/conf.py",
sphinx = ":sphinx-build",
)
py_binary(
name = "mypy",
srcs = ["run_mypy.py"],
data = [
"pyproject.toml",
":selenium",
],
main = "run_mypy.py",
deps = [
":selenium",
requirement("mypy"),
],
)
alias(
name = "ruff",
actual = "//py/private:ruff",
)
alias(
name = "ruff-check",
actual = "//py/private:ruff_check",
)
alias(
name = "ruff-format",
actual = "//py/private:ruff_format",
)