Skip to content

Commit

Permalink
[rb] add initial support for selenium manager
Browse files Browse the repository at this point in the history
  • Loading branch information
titusfortner committed Oct 28, 2022
1 parent c927d4b commit 08dcad6
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ jobs:
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: ${{ matrix.ruby }}
- name: Cache Bazel artifacts
uses: actions/cache@v2
with:
Expand Down
21 changes: 21 additions & 0 deletions rb/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ copy_file(
out = "lib/selenium/webdriver/atoms/findElements.js",
)

copy_file(
name = "manager-linux",
src = "//common/manager:linux/selenium-manager",
out = "bin/linux/selenium-manager",
)

copy_file(
name = "manager-windows",
src = "//common/manager:windows/selenium-manager.exe",
out = "bin/windows/selenium-manager.exe",
)

copy_file(
name = "manager-macos",
src = "//common/manager:macos/selenium-manager",
out = "bin/macos/selenium-manager",
)

copy_file(
name = "get-attribute",
src = "//javascript/webdriver/atoms:get-attribute.js",
Expand Down Expand Up @@ -118,6 +136,9 @@ ruby_library(
":find-elements",
":get-attribute",
":is-displayed",
":manager-linux",
":manager-macos",
":manager-windows",
":license",
],
deps = [
Expand Down
2 changes: 1 addition & 1 deletion rb/lib/selenium/webdriver/chrome/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Service < WebDriver::Service
MISSING_TEXT = <<~ERROR
Unable to find chromedriver. Please download the server from
https://chromedriver.storage.googleapis.com/index.html and place it somewhere on your PATH.
More info at https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver.
More info at https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/?language=ruby.
ERROR
SHUTDOWN_SUPPORTED = true

Expand Down
1 change: 1 addition & 0 deletions rb/lib/selenium/webdriver/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
require 'selenium/webdriver/common/proxy'
require 'selenium/webdriver/common/log_entry'
require 'selenium/webdriver/common/file_reaper'
require 'selenium/webdriver/common/selenium_manager'
require 'selenium/webdriver/common/service'
require 'selenium/webdriver/common/service_manager'
require 'selenium/webdriver/common/socket_lock'
Expand Down
85 changes: 85 additions & 0 deletions rb/lib/selenium/webdriver/common/selenium_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

module Selenium
module WebDriver
#
# Wrapper for getting information from the Selenium Manager binaries.
# @api private
#
class SeleniumManager
BIN_PATH = "../../../../../bin"

class << self
# @param [String] driver_name which driver to use.
# @return [String] the path to the correct driver.
def driver_path(driver_name)
@driver_path ||= begin
unless %w[chromedriver geckodriver].include?(driver_name)
msg = "Unable to locate driver with name: #{driver_name}"
raise Error::WebDriverError, msg
end

location = run("#{binary} --driver #{driver_name}").split("\t").last.strip
WebDriver.logger.debug("Driver found at #{location}")
Platform.assert_executable location

location
end
end

private

# @return [String] the path to the correct selenium manager
def binary
@binary ||= begin
path = File.expand_path(BIN_PATH, __FILE__)
path << if Platform.windows?
'/windows/selenium-manager.exe'
elsif Platform.mac?
'/macos/selenium-manager'
elsif Platform.linux?
'/linux/selenium-manager'
end
location = File.expand_path(path, __FILE__)
unless location.is_a?(String) && File.exist?(location) && File.executable?(location)
raise Error::WebDriverError, "Unable to obtain Selenium Manager"
end

WebDriver.logger.debug("Selenium Manager found at #{location}")
location
end
end

def run(command)
WebDriver.logger.debug("Executing Process #{command}")

begin
result = `#{command}`
return result if result.match?(/^INFO\t/)
rescue StandardError => e
raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
end

raise Error::WebDriverError, "Unsuccessful command executed: #{command}"
end
end
end # SeleniumManager
end # WebDriver
end # Selenium
10 changes: 7 additions & 3 deletions rb/lib/selenium/webdriver/common/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ def initialize(path: nil, port: nil, args: nil)
end

def launch
sm = ServiceManager.new(self)
sm.start
sm
ServiceManager.new(self).tap(&:start)
end

def shutdown_supported
Expand All @@ -101,6 +99,12 @@ def binary_path(path = nil)
path = path.call if path.is_a?(Proc)
path ||= Platform.find_binary(self.class::EXECUTABLE)

begin
path ||= SeleniumManager.driver_path(self.class::EXECUTABLE)
rescue Error::WebDriverError => e
WebDriver.logger.debug("Unable obtain driver using Selenium Manager; #{e.message}")
end

raise Error::WebDriverError, self.class::MISSING_TEXT unless path

Platform.assert_executable path
Expand Down
38 changes: 38 additions & 0 deletions rb/spec/integration/selenium/webdriver/chrome/service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require_relative '../spec_helper'

module Selenium
module WebDriver
module Chrome
describe Service, exclusive: {browser: :chrome} do
let(:service) { Service.new }
let(:service_manager) { service.launch }

after { service_manager.stop }

it 'auto uses chromedriver' do
allow(Platform).to receive(:find_binary)
expect(service_manager.uri).to be_a(URI)
end
end
end # Chrome
end # WebDriver
end # Selenium
39 changes: 39 additions & 0 deletions rb/spec/integration/selenium/webdriver/firefox/service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require_relative '../spec_helper'

module Selenium
module WebDriver
module Firefox
describe Service, exclusive: {browser: :firefox} do
let(:service) { Service.new }
let(:service_manager) { service.launch }

after { service_manager.stop }

it 'auto uses geckodriver' do
allow(Platform).to receive(:find_binary)
service_manager = service.launch
expect(service_manager.uri).to be_a(URI)
end
end
end # Chrome
end # WebDriver
end # Selenium
2 changes: 2 additions & 0 deletions rb/spec/unit/selenium/webdriver/chrome/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ module WebDriver
allow(Platform).to receive(:assert_executable).and_return(true)
end

after { Chrome::Service.driver_path = nil }

it 'uses default path and port' do
allow(Platform).to receive(:find_binary).and_return(service_path)

Expand Down
111 changes: 111 additions & 0 deletions rb/spec/unit/selenium/webdriver/common/manager_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require File.expand_path('../spec_helper', __dir__)

module Selenium
module WebDriver
describe SeleniumManager do
describe 'self.binary' do
before do
SeleniumManager.instance_variable_set(:@binary, nil)
end

it 'detects Windows' do
allow(File).to receive(:exist?).and_return(true)
allow(File).to receive(:executable?).and_return(true)
allow(Platform).to receive(:windows?).and_return(true)

expect(SeleniumManager.send(:binary)).to match(%r{/windows/selenium-manager\.exe$})
end

it 'detects Mac' do
allow(File).to receive(:exist?).and_return(true)
allow(File).to receive(:executable?).and_return(true)
allow(Platform).to receive(:windows?).and_return(false)
allow(Platform).to receive(:mac?).and_return(true)

expect(SeleniumManager.send(:binary)).to match(%r{/macos/selenium-manager$})
end

it 'detects Linux' do
allow(File).to receive(:exist?).and_return(true)
allow(File).to receive(:executable?).and_return(true)
allow(Platform).to receive(:windows?).and_return(false)
allow(Platform).to receive(:mac?).and_return(false)
allow(Platform).to receive(:linux?).and_return(true)

expect(SeleniumManager.send(:binary)).to match(%r{/linux/selenium-manager$})
end

it 'errors if cannot find' do
allow(File).to receive(:exist?).and_return(false)

expect {
SeleniumManager.send(:binary)
}.to raise_error(Error::WebDriverError, /Unable to obtain Selenium Manager/)
end
end

describe 'self.run' do
it 'errors if a problem with command' do
expect {
SeleniumManager.send(:run, "anything")
}.to raise_error(Error::WebDriverError, /Unsuccessful command executed: /)
end
end

describe 'self.driver_path' do
it 'errors if not one of 3 valid drivers' do
expect {
SeleniumManager.driver_path('something')
}.to raise_error(Error::WebDriverError, /Unable to locate driver with name/)
end

it 'does not use if driver_path provided' do
allow(SeleniumManager).to receive(:driver_path)
allow(Platform).to receive(:assert_executable).and_return(false)

WebDriver::Service.chrome(path: 'something')

expect(SeleniumManager).not_to have_received(:driver_path)
end

it 'not used if found on PATH' do
allow(SeleniumManager).to receive(:driver_path)
allow(Platform).to receive(:assert_executable).and_return(false)
allow(Platform).to receive(:find_binary).and_return("something")

WebDriver::Service.chrome

expect(SeleniumManager).not_to have_received(:driver_path)
end

it 'gives original error if not found' do
allow(Platform).to receive(:find_binary)
allow(SeleniumManager).to receive(:driver_path)

expect {
WebDriver::Service.chrome
}.to raise_error(WebDriver::Error::WebDriverError, /Unable to find chromedriver. Please download/)
end
end
end
end # WebDriver
end # Selenium

0 comments on commit 08dcad6

Please sign in to comment.