Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .bazelrc.remote
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ test:rbe --test_env=HOME=/home/dev
# Make sure we sniff credentials properly
build:rbe --credential_helper=gypsum.cluster.engflow.com=%workspace%/scripts/credential-helper.sh

# Use pinned browsers when running remotely
build:rbe --//common:pin_browsers

# The remote build machines are pretty small, and 50 threads may leave them
# thrashing, but our dev machines are a lot larger. Scale the workload so we
# make reasonable usage of everything, everywhere, all at once.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jobs:
os: windows
run: |
fsutil 8dot3name set 0
bazel test //dotnet/test/common:ElementFindingTest-firefox //dotnet/test/common:ElementFindingTest-chrome --pin_browsers=true
bazel test //dotnet/test/common:ElementFindingTest-firefox //dotnet/test/common:ElementFindingTest-chrome
6 changes: 3 additions & 3 deletions .github/workflows/ci-java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
java-version: 17
run: |
fsutil 8dot3name set 0
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest `
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest `
//java/test/org/openqa/selenium/federatedcredentialmanagement:FederatedCredentialManagementTest `
//java/test/org/openqa/selenium/firefox:FirefoxDriverBuilderTest `
//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest `
Expand All @@ -48,7 +48,7 @@ jobs:
# https://github.com/bazelbuild/rules_jvm_external/issues/1046
java-version: 17
run: |
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote \
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote \
//java/test/org/openqa/selenium/federatedcredentialmanagement:FederatedCredentialManagementTest \
//java/test/org/openqa/selenium/firefox:FirefoxDriverBuilderTest \
//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest \
Expand All @@ -72,4 +72,4 @@ jobs:
# https://github.com/bazelbuild/rules_jvm_external/issues/1046
java-version: 17
run: |
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote
6 changes: 3 additions & 3 deletions .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
os: ${{ matrix.os }}
cache-key: py-browser-${{ matrix.browser }}
run: |
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:common-${{ matrix.browser }}-bidi //py:test-${{ matrix.browser }}
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:common-${{ matrix.browser }}-bidi //py:test-${{ matrix.browser }}

browser-tests-windows:
name: Browser Tests
Expand All @@ -135,7 +135,7 @@ jobs:
cache-key: py-browser-${{ matrix.browser }}
run: |
fsutil 8dot3name set 0
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:common-${{ matrix.browser }}-bidi //py:test-${{ matrix.browser }}
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:common-${{ matrix.browser }}-bidi //py:test-${{ matrix.browser }}

browser-tests-macos:
name: Browser Tests
Expand All @@ -153,4 +153,4 @@ jobs:
os: ${{ matrix.os }}
cache-key: py-browser-${{ matrix.browser }}
run: |
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:common-${{ matrix.browser }} //py:test-${{ matrix.browser }}
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:common-${{ matrix.browser }} //py:test-${{ matrix.browser }}
2 changes: 0 additions & 2 deletions .github/workflows/ci-ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ jobs:
--local_test_jobs 1
--test_size_filters large
--test_tag_filters ${{ matrix.browser }}
--pin_browsers
//rb/spec/...

integration-tests-remote:
Expand All @@ -111,5 +110,4 @@ jobs:
--local_test_jobs 1
--test_size_filters large
--test_tag_filters ${{ matrix.browser }}-remote
--pin_browsers
//rb/spec/...
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ There are a number of bazel configurations specific for testing.
### Common Options Examples

Here are examples of arguments we make use of in testing the Selenium code:
* `--pin_browsers` - run specific browser versions defined in the build (versions are updated regularly)
* `--pin_browsers=false` - use Selenium Manager to locate browsers/drivers
* `--headless` - run browsers in headless mode (supported be Chrome, Edge and Firefox)
* `--flaky_test_attempts 3` - re-run failed tests up to 3 times
* `--local_test_jobs 1` - control parallelism of tests
Expand Down Expand Up @@ -491,19 +491,19 @@ echo '<X.Y.Z>' > rb/.ruby-version
Run all tests with:

```shell
bazel test //dotnet/test/common:AllTests --pin_browsers=true
bazel test //dotnet/test/common:AllTests
```

You can run specific tests by specifying the class name:

```shell
bazel test //dotnet/test/common:ElementFindingTest --pin_browsers=true
bazel test //dotnet/test/common:ElementFindingTest
```

If the module supports multiple browsers:

```shell
bazel test //dotnet/test/common:ElementFindingTest-edge --pin_browsers=true
bazel test //dotnet/test/common:ElementFindingTest-edge
```

</details>
Expand Down
16 changes: 8 additions & 8 deletions common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@ package(default_visibility = ["//visibility:public"])

bool_flag(
name = "pin_browsers",
build_setting_default = False,
)

config_setting(
name = "use_pinned_browser",
flag_values = {
":pin_browsers": "true",
},
build_setting_default = True,
)

bool_flag(
Expand Down Expand Up @@ -47,6 +40,13 @@ config_setting(
values = {"stamp": "true"},
)

config_setting(
name = "use_pinned_browser",
flag_values = {
":pin_browsers": "true",
},
)

alias(
name = "chromedriver",
actual = "@local_drivers//:chromedriver",
Expand Down
15 changes: 12 additions & 3 deletions common/manager/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,24 @@ package(

alias(
name = "selenium-manager-linux",
actual = "@download_sm_linux//file",
actual = select({
"//common:use_pinned_browser": "@download_sm_linux//file",
"//conditions:default": "//rust:selenium-manager-linux",
}),
)

alias(
name = "selenium-manager-macos",
actual = "@download_sm_macos//file",
actual = select({
"//common:use_pinned_browser": "@download_sm_macos//file",
"//conditions:default": "//rust:selenium-manager-macos",
}),
)

alias(
name = "selenium-manager-windows",
actual = "@download_sm_windows//file",
actual = select({
"//common:use_pinned_browser": "@download_sm_windows//file",
"//conditions:default": "//rust:selenium-manager-windows",
}),
)
9 changes: 9 additions & 0 deletions dotnet/src/webdriver/SeleniumManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ public static Dictionary<string, string> BinaryPaths(string arguments)
{
StringBuilder argsBuilder = new StringBuilder(arguments);
argsBuilder.Append(" --language-binding csharp");
#if NET8_0_OR_GREATER
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original motivation was:

how many people using the latest version of Selenium

This code doesn't include the version of Selenium binding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selenium Manager sets the Selenium version since the versions are in sync: https://github.com/SeleniumHQ/selenium/blob/selenium-4.39.0/rust/src/main.rs#L227

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plausible analytics are here: https://plausible.io/manager.selenium.dev
navigate to custom properties at the bottom to see specifics.
The reason for the PR is specifically Java, if 50% of our users are still on Java 11, then we aren't going to want to require a move to Java 17, etc
For .NET this means seeing how many people are still using .NET Framework vs NET 6/7 vs NET 8/9/10

Seems reasonable, let's think more about it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is your concern?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it is not about Selenium version, accepted. I propose to see the final output for all bindings and align the format, I mean python 3.14 or PyThoN_3_14. What is our preference?

Interesting, do we really want to see TFM (net8.0, netstandard2.0)? Or runtime version would be enough?..

PS: We can easily implement all variants.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as capturing TFM, I was thinking it would be useful to know if someone is targeting netstandard2, even if they are using Net 8 or something. Not essential, but the info was right there, so I figured we'd capture it and it only 3x the values at most.

Copy link
Member Author

@titusfortner titusfortner Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RenderMichael {Environment.Version.Major} seems sufficient to me (and limits the number of combinations with TFM). Is there something about the minor version that would give us extra insight?

The goal is to provide understanding about how we focus/update support. We changed targets a couple years ago pretty much blind, and if we had this info it would have made it more obvious what the tradeoffs were.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minor version is relevant for the .NET Standard 2.0 target. For example, there exists .NET Core 3.0 and .NET Core 3.1 (likewise 2.0 and 2.1, but adoption was so low and only from bleeding-edge folks back that it's completely irrelevant).

The much more relevant examples are on .NET Framework. .NET Standard 2.0 covers 4.7, 4.7.1, 4.7.2, 4.8, and 4.8.1 (as well 4.6.2 but Selenium targets that directly) source. Environment.Version.Major will not give us the information we need there. I don't think Version.Minor will either, actually, given what this outputs on 4.7.2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We changed targets a couple years ago pretty much blind

I disregards. I proposed to change it, still no issues.

Before:

image

After:

image

Anyway collecting usage stats will be helpful. Let's discuss it instantly in slack channel.

argsBuilder.Append($" --language-version net8.0/{Environment.Version.Major}");
#elif NETSTANDARD2_0
argsBuilder.Append($" --language-version netstandard2.0/{Environment.Version.Major}");
#elif NET462
argsBuilder.Append(" --language-version net462");
#else
#error Add support here
#endif
argsBuilder.Append(" --output json");
if (_logger.IsEnabled(LogEventLevel.Debug))
{
Expand Down
4 changes: 3 additions & 1 deletion java/src/org/openqa/selenium/manager/SeleniumManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,12 @@ private void saveToFileSafely(InputStream inputStream, Path target) throws IOExc
* @return the locations of the assets from Selenium Manager execution
*/
public Result getBinaryPaths(List<String> arguments) {
List<String> args = new ArrayList<>(arguments.size() + 5);
List<String> args = new ArrayList<>(arguments.size() + 7);
args.addAll(arguments);
args.add("--language-binding");
args.add("java");
args.add("--language-version");
args.add(Runtime.version().feature() + "");
args.add("--output");
args.add("json");

Expand Down
11 changes: 10 additions & 1 deletion javascript/selenium-webdriver/common/driverFinder.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,16 @@ function getBinaryPaths(capabilities) {
}

function getArgs(options) {
let args = ['--browser', options.getBrowserName(), '--language-binding', 'javascript', '--output', 'json']
let args = [
'--browser',
options.getBrowserName(),
'--language-binding',
'javascript',
'--language-version',
process.versions.node,
'--output',
'json',
]

if (options.getBrowserVersion() && options.getBrowserVersion() !== '') {
args.push('--browser-version', options.getBrowserVersion())
Expand Down
2 changes: 2 additions & 0 deletions py/selenium/webdriver/common/selenium_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def binary_paths(self, args: list) -> dict:
args.append("--debug")
args.append("--language-binding")
args.append("python")
args.append("--language-version")
args.append(f"{sys.version_info.major}.{sys.version_info.minor}")
args.append("--output")
args.append("json")

Expand Down
10 changes: 9 additions & 1 deletion py/test/selenium/webdriver/common/selenium_manager_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ def test_gets_results(monkeypatch):
SeleniumManager().binary_paths([])

mock_get_binary.assert_called_once()
expected_run_args = ["/path/to/sm", "--language-binding", "python", "--output", "json"]
expected_run_args = [
"/path/to/sm",
"--language-binding",
"python",
"--language-version",
f"{sys.version_info.major}.{sys.version_info.minor}",
"--output",
"json",
]
mock_run.assert_called_once_with(expected_run_args)


Expand Down
1 change: 1 addition & 0 deletions rb/lib/selenium/webdriver/common/selenium_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def bin_path
# @return [Hash] paths to the requested assets.
def binary_paths(*arguments)
arguments += %w[--language-binding ruby]
arguments += ['--language-version', RUBY_VERSION.split('.').first(2).join('.')]
arguments += %w[--output json]
arguments << '--debug' if WebDriver.logger.debug?

Expand Down
2 changes: 2 additions & 0 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub struct ManagerConfig {
pub force_browser_download: bool,
pub avoid_browser_download: bool,
pub language_binding: String,
pub language_binding_version: String,
pub selenium_version: String,
pub avoid_stats: bool,
pub skip_driver_in_path: bool,
Expand Down Expand Up @@ -131,6 +132,7 @@ impl ManagerConfig {
force_browser_download: BooleanKey("force-browser-download", false).get_value(),
avoid_browser_download: BooleanKey("avoid-browser-download", false).get_value(),
language_binding: StringKey(vec!["language-binding"], "").get_value(),
language_binding_version: StringKey(vec!["language-version"], "").get_value(),
selenium_version: StringKey(vec!["selenium-version"], "").get_value(),
avoid_stats: BooleanKey("avoid-stats", false).get_value(),
skip_driver_in_path: BooleanKey("skip-driver-in-path", false).get_value(),
Expand Down
11 changes: 11 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ pub trait SeleniumManager {
.unwrap_or(ARCH_OTHER)
.to_ascii_lowercase(),
lang: self.get_language_binding().to_ascii_lowercase(),
lang_version: self.get_language_binding_version().to_ascii_lowercase(),
selenium_version: self.get_selenium_version().to_ascii_lowercase(),
};
let http_client = self.get_http_client().to_owned();
Expand Down Expand Up @@ -1605,6 +1606,16 @@ pub trait SeleniumManager {
}
}

fn get_language_binding_version(&self) -> &str {
self.get_config().language_binding_version.as_str()
}

fn set_language_binding_version(&mut self, language_binding_version: String) {
if !language_binding_version.is_empty() {
self.get_config_mut().language_binding_version = language_binding_version;
}
}

fn get_selenium_version(&self) -> &str {
self.get_config().selenium_version.as_str()
}
Expand Down
5 changes: 5 additions & 0 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ struct Cli {
#[clap(long)]
language_binding: Option<String>,

/// Version of the language binding invoking Selenium Manager (e.g., 4.18.1, 3.12, net8.0/8)
#[clap(long)]
language_version: Option<String>,

/// Avoid sends usage statistics to plausible.io
#[clap(long)]
avoid_stats: bool,
Expand Down Expand Up @@ -223,6 +227,7 @@ fn main() {
selenium_manager.set_cache_path(cache_path.clone());
selenium_manager.set_offline(cli.offline);
selenium_manager.set_language_binding(cli.language_binding.unwrap_or_default());
selenium_manager.set_language_binding_version(cli.language_version.unwrap_or_default());
let sm_version = clap::crate_version!();
let selenium_version = sm_version.strip_prefix(SM_BETA_LABEL).unwrap_or(sm_version);
selenium_manager.set_selenium_version(selenium_version.to_string());
Expand Down
3 changes: 3 additions & 0 deletions rust/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct Stats {
pub os: String,
pub arch: String,
pub lang: String,
pub lang_version: String,
pub selenium_version: String,
pub stats_ttl: u64,
}
Expand Down Expand Up @@ -147,6 +148,7 @@ pub fn is_stats_in_metadata(stats_metadata: &[Stats], props: &Props) -> bool {
&& p.os.eq(&props.os)
&& p.arch.eq(&props.arch)
&& p.lang.eq(&props.lang)
&& p.lang_version.eq(&props.lang_version)
&& p.selenium_version.eq(&props.selenium_version)
})
.collect();
Expand Down Expand Up @@ -188,6 +190,7 @@ pub fn create_stats_metadata(props: &Props, stats_ttl: u64) -> Stats {
os: props.os.to_string(),
arch: props.arch.to_string(),
lang: props.lang.to_string(),
lang_version: props.lang_version.to_string(),
selenium_version: props.selenium_version.to_string(),
stats_ttl: now_unix_timestamp() + stats_ttl,
}
Expand Down
1 change: 1 addition & 0 deletions rust/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct Props {
pub os: String,
pub arch: String,
pub lang: String,
pub lang_version: String,
pub selenium_version: String,
}

Expand Down
Loading