diff --git a/.github/workflows/ci-ruby.yml b/.github/workflows/ci-ruby.yml index 66e0364ce17ed..74b9df0c4989e 100644 --- a/.github/workflows/ci-ruby.yml +++ b/.github/workflows/ci-ruby.yml @@ -4,6 +4,9 @@ on: workflow_call: workflow_dispatch: +permissions: + contents: read + jobs: build: name: Build @@ -55,26 +58,23 @@ jobs: //rb/spec/... integration-tests-local: - name: Local Tests + name: Integration Tests needs: build uses: ./.github/workflows/bazel.yml strategy: fail-fast: false matrix: - browser: - - chrome - - edge - - firefox - os: - - windows - - macos - exclude: - - browser: edge + browser: ['chrome', 'edge', 'firefox'] + os: ['windows'] + include: + - browser: edge-remote os: macos + java-version: 17 with: - name: Local Tests (${{ matrix.browser }}, ${{ matrix.os }}) + name: Integration (${{ matrix.browser }}, ${{ matrix.os }}) browser: ${{ matrix.browser }} cache-key: rb-${{ matrix.browser }}-${{ matrix.os }}-test + java-version: ${{ matrix.java-version }} os: ${{ matrix.os }} run: > bazel test @@ -86,28 +86,30 @@ jobs: --test_tag_filters ${{ matrix.browser }} //rb/spec/... - integration-tests-remote: - name: Remote Tests + selenium-manager-tests: + name: Selenium Manager Tests needs: build uses: ./.github/workflows/bazel.yml strategy: fail-fast: false matrix: - include: - - browser: edge - os: macos + os: + - windows + - macos + - ubuntu with: - name: Remote Tests (${{ matrix.browser }}, ${{ matrix.os }}) - browser: ${{ matrix.browser }} - cache-key: rb-remote-${{ matrix.browser }}-${{ matrix.os }}-test + name: Manager Tests (${{ matrix.os }}) + cache-key: rb-manager-${{ matrix.os }}-test os: ${{ matrix.os }} - java-version: 17 run: > bazel test --keep_going --build_tests_only --flaky_test_attempts 3 --local_test_jobs 1 - --test_size_filters large - --test_tag_filters ${{ matrix.browser }}-remote + --test_size_filters medium + --pin_browsers=false + --test_tag_filters="manager,-safari,-ie" + --test_env=SE_FORCE_BROWSER_DOWNLOAD=true + --test_env=SE_SKIP_DRIVER_IN_PATH=true //rb/spec/... diff --git a/.skipped-tests b/.skipped-tests index 41f225a3d45c6..2ed66c298ce98 100644 --- a/.skipped-tests +++ b/.skipped-tests @@ -23,14 +23,6 @@ -//javascript/selenium-webdriver:test-builder-test.js-chrome -//javascript/selenium-webdriver:test-chrome-devtools-test.js-chrome -//javascript/selenium-webdriver:test-firefox-options-test.js-firefox --//rb/spec/integration/selenium/webdriver/chrome:service-chrome --//rb/spec/integration/selenium/webdriver/chrome:service-chrome-remote --//rb/spec/integration/selenium/webdriver/edge:service-edge --//rb/spec/integration/selenium/webdriver/edge:service-edge-remote --//rb/spec/integration/selenium/webdriver/firefox:service-firefox --//rb/spec/integration/selenium/webdriver/firefox:service-firefox-beta --//rb/spec/integration/selenium/webdriver/firefox:service-firefox-beta-remote --//rb/spec/integration/selenium/webdriver/firefox:service-firefox-remote -//rb/spec/integration/selenium/webdriver/remote:driver-chrome-remote -//rb/spec/integration/selenium/webdriver/remote:driver-edge-remote -//rb/spec/integration/selenium/webdriver/remote:driver-firefox-beta-remote diff --git a/rb/lib/selenium/webdriver/common/platform.rb b/rb/lib/selenium/webdriver/common/platform.rb index dae3fcd72cb03..e7e6308f458f6 100644 --- a/rb/lib/selenium/webdriver/common/platform.rb +++ b/rb/lib/selenium/webdriver/common/platform.rb @@ -17,6 +17,7 @@ # specific language governing permissions and limitations # under the License. +require 'pathname' require 'rbconfig' require 'socket' @@ -119,13 +120,20 @@ def cygwin_path(path, only_cygwin: false, **opts) end def unix_path(path) - path.tr(File::ALT_SEPARATOR, File::SEPARATOR) + File::ALT_SEPARATOR.nil? ? path : path.tr(File::ALT_SEPARATOR, File::SEPARATOR) end def windows_path(path) path.tr(File::SEPARATOR, File::ALT_SEPARATOR) end + def includes_path?(path, root) + path_name = unix_path(path) + root_name = unix_path(root) + WebDriver.logger.debug("Checking if #{path_name} includes #{root_name}", id: :platform) + unix_path(path).include?("/#{unix_path(root)}/") + end + def make_writable(file) File.chmod 0o766, file end diff --git a/rb/sig/lib/selenium/webdriver/common/options.rbs b/rb/sig/lib/selenium/webdriver/common/options.rbs index b49c13380b71a..a7f8b9ddd1b94 100644 --- a/rb/sig/lib/selenium/webdriver/common/options.rbs +++ b/rb/sig/lib/selenium/webdriver/common/options.rbs @@ -33,7 +33,7 @@ module Selenium attr_accessor options: Hash[String | Symbol, String | Numeric | bool?] - def initialize: (Hash[String | Symbol, String | Numeric | bool] opts) -> void + def initialize: ?(Hash[String | Symbol, String | Numeric | bool] opts) -> void def add_option: (String | Symbol name, String | Numeric | bool? value) -> (String | Numeric | bool)? diff --git a/rb/sig/lib/selenium/webdriver/support/guards.rbs b/rb/sig/lib/selenium/webdriver/support/guards.rbs index 2f7c90896426d..45ea06479fe97 100644 --- a/rb/sig/lib/selenium/webdriver/support/guards.rbs +++ b/rb/sig/lib/selenium/webdriver/support/guards.rbs @@ -20,7 +20,7 @@ module Selenium def initialize: (untyped example, ?bug_tracker: String, ?conditions: untyped?) -> void - def add_condition: (untyped name, ?untyped? condition) { () -> untyped } -> untyped + def add_condition: (untyped name, ?untyped? condition) ?{ () -> untyped } -> untyped def add_message: (untyped name, untyped message) -> untyped diff --git a/rb/spec/integration/selenium/webdriver/chrome/BUILD.bazel b/rb/spec/integration/selenium/webdriver/chrome/BUILD.bazel index a86ffd7d547ad..cd440f12d7aa0 100644 --- a/rb/spec/integration/selenium/webdriver/chrome/BUILD.bazel +++ b/rb/spec/integration/selenium/webdriver/chrome/BUILD.bazel @@ -11,5 +11,18 @@ load("//rb/spec:tests.bzl", "rb_integration_test") ], data = ["//common/extensions"], ) - for file in glob(["*_spec.rb"]) + for file in glob( + ["*_spec.rb"], + exclude = ["service_spec.rb"], + ) ] + +rb_integration_test( + name = "service", + srcs = ["service_spec.rb"], + browsers = [ + "chrome", + "chrome-beta", + ], + tags = ["manager"], +) diff --git a/rb/spec/integration/selenium/webdriver/chrome/service_spec.rb b/rb/spec/integration/selenium/webdriver/chrome/service_spec.rb index 39fe65f39c03d..f0e0ffe7d2ae7 100644 --- a/rb/spec/integration/selenium/webdriver/chrome/service_spec.rb +++ b/rb/spec/integration/selenium/webdriver/chrome/service_spec.rb @@ -27,16 +27,22 @@ module Chrome exclusive: [{bidi: false, reason: 'Not yet implemented with BiDi'}, {browser: :chrome}]} do let(:service) { described_class.new } let(:service_manager) { service.launch } + let(:cache_dir) { ENV['SE_CACHE'] || File.join('.cache', 'selenium') } after { service_manager.stop } - it 'auto uses chromedriver' do - service.executable_path = DriverFinder.new(Options.new, described_class.new).driver_path + it 'selenium manager gets browser and driver', exclusive: {manager: true} do + driver_finder = DriverFinder.new(Options.new, service) + driver_path = driver_finder.driver_path + browser_path = driver_finder.browser_path - expect(service_manager.uri).to be_a(URI) - end + expect { Platform.assert_executable(driver_path) }.not_to raise_error + expect { Platform.assert_executable(browser_path) }.not_to raise_error + expect(Platform.includes_path?(browser_path, cache_dir)).to be(true) + expect(Platform.includes_path?(driver_path, cache_dir)).to be(true) + + service.executable_path = driver_path - it 'can be started outside driver' do expect(service_manager.uri).to be_a(URI) end end diff --git a/rb/spec/integration/selenium/webdriver/edge/BUILD.bazel b/rb/spec/integration/selenium/webdriver/edge/BUILD.bazel index 73f983fef259a..d13df6362e63f 100644 --- a/rb/spec/integration/selenium/webdriver/edge/BUILD.bazel +++ b/rb/spec/integration/selenium/webdriver/edge/BUILD.bazel @@ -6,5 +6,15 @@ load("//rb/spec:tests.bzl", "rb_integration_test") srcs = [file], browsers = ["edge"], # No need to run in other browsers. ) - for file in glob(["*_spec.rb"]) + for file in glob( + ["*_spec.rb"], + exclude = ["service_spec.rb"], + ) ] + +rb_integration_test( + name = "service", + srcs = ["service_spec.rb"], + browsers = ["edge"], + tags = ["manager"], +) diff --git a/rb/spec/integration/selenium/webdriver/edge/service_spec.rb b/rb/spec/integration/selenium/webdriver/edge/service_spec.rb index ad68ce5b43a6f..6ef33e562d953 100644 --- a/rb/spec/integration/selenium/webdriver/edge/service_spec.rb +++ b/rb/spec/integration/selenium/webdriver/edge/service_spec.rb @@ -27,16 +27,22 @@ module Edge exclusive: [{bidi: false, reason: 'Not yet implemented with BiDi'}, {browser: :edge}]} do let(:service) { described_class.new } let(:service_manager) { service.launch } + let(:cache_dir) { ENV['SE_CACHE'] || File.join('.cache', 'selenium') } after { service_manager.stop } - it 'auto uses edgedriver' do - service.executable_path = DriverFinder.new(Options.new, described_class.new).driver_path + it 'selenium manager gets browser and driver', exclusive: {manager: true} do + driver_finder = DriverFinder.new(Options.new, service) + driver_path = driver_finder.driver_path + browser_path = driver_finder.browser_path - expect(service_manager.uri).to be_a(URI) - end + expect { Platform.assert_executable(driver_path) }.not_to raise_error + expect { Platform.assert_executable(browser_path) }.not_to raise_error + expect(Platform.includes_path?(driver_path, cache_dir)).to be(true) + expect(Platform.includes_path?(browser_path, cache_dir)).to be(true) + + service.executable_path = driver_path - it 'can be started outside driver' do expect(service_manager.uri).to be_a(URI) end end diff --git a/rb/spec/integration/selenium/webdriver/firefox/BUILD.bazel b/rb/spec/integration/selenium/webdriver/firefox/BUILD.bazel index 6cb37b594a5fb..d384004d490a7 100644 --- a/rb/spec/integration/selenium/webdriver/firefox/BUILD.bazel +++ b/rb/spec/integration/selenium/webdriver/firefox/BUILD.bazel @@ -11,5 +11,18 @@ load("//rb/spec:tests.bzl", "rb_integration_test") ], data = ["//common/extensions"], ) - for file in glob(["*_spec.rb"]) + for file in glob( + ["*_spec.rb"], + exclude = ["service_spec.rb"], + ) ] + +rb_integration_test( + name = "service", + srcs = ["service_spec.rb"], + browsers = [ + "firefox", + "firefox-beta", + ], + tags = ["manager"], +) diff --git a/rb/spec/integration/selenium/webdriver/firefox/service_spec.rb b/rb/spec/integration/selenium/webdriver/firefox/service_spec.rb index 7c14994c56ae3..4af285cc3abaa 100644 --- a/rb/spec/integration/selenium/webdriver/firefox/service_spec.rb +++ b/rb/spec/integration/selenium/webdriver/firefox/service_spec.rb @@ -27,16 +27,22 @@ module Firefox exclusive: [{bidi: false, reason: 'Not yet implemented with BiDi'}, {browser: :firefox}]} do let(:service) { described_class.new } let(:service_manager) { service.launch } + let(:cache_dir) { ENV['SE_CACHE'] || File.join('.cache', 'selenium') } after { service_manager.stop } - it 'auto uses geckodriver' do - service.executable_path = DriverFinder.new(Options.new, described_class.new).driver_path + it 'selenium manager gets browser and driver', exclusive: {manager: true} do + driver_finder = DriverFinder.new(Options.new, service) + driver_path = driver_finder.driver_path + browser_path = driver_finder.browser_path - expect(service_manager.uri).to be_a(URI) - end + expect { Platform.assert_executable(driver_path) }.not_to raise_error + expect { Platform.assert_executable(browser_path) }.not_to raise_error + expect(Platform.includes_path?(browser_path, cache_dir)).to be(true) + expect(Platform.includes_path?(driver_path, cache_dir)).to be(true) + + service.executable_path = driver_path - it 'can be started outside driver' do expect(service_manager.uri).to be_a(URI) end end diff --git a/rb/spec/integration/selenium/webdriver/ie/BUILD.bazel b/rb/spec/integration/selenium/webdriver/ie/BUILD.bazel new file mode 100644 index 0000000000000..a7aef34edc6d0 --- /dev/null +++ b/rb/spec/integration/selenium/webdriver/ie/BUILD.bazel @@ -0,0 +1,8 @@ +load("//rb/spec:tests.bzl", "rb_integration_test") + +rb_integration_test( + name = "service", + srcs = ["service_spec.rb"], + browsers = ["ie"], + tags = ["manager"], +) diff --git a/rb/spec/integration/selenium/webdriver/ie/service_spec.rb b/rb/spec/integration/selenium/webdriver/ie/service_spec.rb index 7c2cc765fb49d..a926dbeb88c28 100644 --- a/rb/spec/integration/selenium/webdriver/ie/service_spec.rb +++ b/rb/spec/integration/selenium/webdriver/ie/service_spec.rb @@ -27,16 +27,19 @@ module IE exclusive: [{bidi: false, reason: 'Not yet implemented with BiDi'}, {browser: :ie}]} do let(:service) { described_class.new } let(:service_manager) { service.launch } + let(:cache_dir) { ENV['SE_CACHE'] || File.join('.cache', 'selenium') } after { service_manager.stop } - it 'auto uses iedriver' do - service.executable_path = DriverFinder.new(Options.new, described_class.new).driver_path + it 'selenium manager gets browser and driver', exclusive: {manager: true} do + driver_finder = DriverFinder.new(Options.new, service) + driver_path = driver_finder.driver_path - expect(service_manager.uri).to be_a(URI) - end + expect { Platform.assert_executable(driver_path) }.not_to raise_error + expect(Platform.includes_path?(driver_path, cache_dir)).to be(true) + + service.executable_path = driver_path - it 'can be started outside driver' do expect(service_manager.uri).to be_a(URI) end end diff --git a/rb/spec/integration/selenium/webdriver/safari/BUILD.bazel b/rb/spec/integration/selenium/webdriver/safari/BUILD.bazel index 54d03e20334c8..d79423ae4e393 100644 --- a/rb/spec/integration/selenium/webdriver/safari/BUILD.bazel +++ b/rb/spec/integration/selenium/webdriver/safari/BUILD.bazel @@ -10,5 +10,15 @@ load("//rb/spec:tests.bzl", "rb_integration_test") "safari-preview", ], ) - for file in glob(["*_spec.rb"]) + for file in glob( + ["*_spec.rb"], + exclude = ["service_spec.rb"], + ) ] + +rb_integration_test( + name = "service", + srcs = ["service_spec.rb"], + browsers = ["safari"], + tags = ["manager"], +) diff --git a/rb/spec/integration/selenium/webdriver/safari/service_spec.rb b/rb/spec/integration/selenium/webdriver/safari/service_spec.rb index 7d6e983b6b283..d19ee0e0c3ca2 100644 --- a/rb/spec/integration/selenium/webdriver/safari/service_spec.rb +++ b/rb/spec/integration/selenium/webdriver/safari/service_spec.rb @@ -27,16 +27,20 @@ module Safari exclusive: [{bidi: false, reason: 'Not yet implemented with BiDi'}, {browser: :safari}]} do let(:service) { described_class.new } let(:service_manager) { service.launch } + let(:cache_dir) { ENV['SE_CACHE'] || File.join('.cache', 'selenium') } after { service_manager.stop } - it 'auto uses safaridriver' do - service.executable_path = DriverFinder.new(Options.new, described_class.new).driver_path + it 'selenium manager gets browser and driver' do + driver_finder = DriverFinder.new(Options.new, service) + driver_path = driver_finder.driver_path + browser_path = driver_finder.browser_path - expect(service_manager.uri).to be_a(URI) - end + expect { Platform.assert_executable(driver_path) }.not_to raise_error + expect { Platform.assert_executable(browser_path) }.not_to raise_error + + service.executable_path = driver_path - it 'can be started outside driver' do expect(service_manager.uri).to be_a(URI) end end diff --git a/rb/spec/integration/selenium/webdriver/spec_helper.rb b/rb/spec/integration/selenium/webdriver/spec_helper.rb index d63f749f5a959..b8b32fa9dff1d 100644 --- a/rb/spec/integration/selenium/webdriver/spec_helper.rb +++ b/rb/spec/integration/selenium/webdriver/spec_helper.rb @@ -73,6 +73,7 @@ def example_finished(notification) guards.add_condition(:bidi, !ENV['WEBDRIVER_BIDI'].nil?) guards.add_condition(:rbe, GlobalTestEnv.rbe?) guards.add_condition(:version, GlobalTestEnv.browser_version) + guards.add_condition(:manager, !ENV['SE_FORCE_BROWSER_DOWNLOAD'].nil?) results = guards.disposition send(*results) if results diff --git a/rb/spec/tests.bzl b/rb/spec/tests.bzl index 8b646ec7542a8..fb55e914523e7 100644 --- a/rb/spec/tests.bzl +++ b/rb/spec/tests.bzl @@ -175,11 +175,14 @@ def rb_integration_test(name, srcs, deps = [], data = [], browsers = BROWSERS.ke visibility = ["//rb:__subpackages__"], ) + # Selenium manager tests are lighter weight (no full browser session needed) + size = "medium" if "manager" in tags else "large" + for browser in browsers: # Generate a test target for local browser execution. rb_test( name = "{}-{}".format(name, browser), - size = "large", + size = size, srcs = srcs, args = ["rb/spec/"], data = BROWSERS[browser]["data"] + data + ["//common/src/web"], @@ -192,33 +195,35 @@ def rb_integration_test(name, srcs, deps = [], data = [], browsers = BROWSERS.ke ) # Generate a test target for remote browser execution (Grid). - rb_test( - name = "{}-{}-remote".format(name, browser), - size = "large", - srcs = srcs, - args = ["rb/spec/"], - data = BROWSERS[browser]["data"] + data + [ - "//common/src/web", - "//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar", - "//rb/spec:java-location", - "@bazel_tools//tools/jdk:current_java_runtime", - ], - env = BROWSERS[browser]["env"] | { - "WD_BAZEL_JAVA_LOCATION": "$(rootpath //rb/spec:java-location)", - "WD_SPEC_DRIVER": "remote", - }, - main = "@bundle//bin:rspec", - tags = COMMON_TAGS + BROWSERS[browser]["tags"] + tags + ["{}-remote".format(browser)], - deps = ["//rb/spec/integration/selenium/webdriver:spec_helper"] + BROWSERS[browser]["deps"] + deps, - visibility = ["//rb:__subpackages__"], - target_compatible_with = BROWSERS[browser]["target_compatible_with"], - ) + # Skip remote targets for manager tests (no Grid session needed). + if "manager" not in tags: + rb_test( + name = "{}-{}-remote".format(name, browser), + size = "large", + srcs = srcs, + args = ["rb/spec/"], + data = BROWSERS[browser]["data"] + data + [ + "//common/src/web", + "//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar", + "//rb/spec:java-location", + "@bazel_tools//tools/jdk:current_java_runtime", + ], + env = BROWSERS[browser]["env"] | { + "WD_BAZEL_JAVA_LOCATION": "$(rootpath //rb/spec:java-location)", + "WD_SPEC_DRIVER": "remote", + }, + main = "@bundle//bin:rspec", + tags = COMMON_TAGS + BROWSERS[browser]["tags"] + tags + ["{}-remote".format(browser)], + deps = ["//rb/spec/integration/selenium/webdriver:spec_helper"] + BROWSERS[browser]["deps"] + deps, + visibility = ["//rb:__subpackages__"], + target_compatible_with = BROWSERS[browser]["target_compatible_with"], + ) # Generate a test target for bidi browser execution if there is a matching tag if "bidi" in tags: rb_test( name = "{}-{}-bidi".format(name, browser), - size = "large", + size = size, srcs = srcs, args = ["rb/spec/"], data = BROWSERS[browser]["data"] + data + ["//common/src/web"],