diff --git a/lib/capybara/selenium/driver.rb b/lib/capybara/selenium/driver.rb index ae8d5c50..91fedbd0 100644 --- a/lib/capybara/selenium/driver.rb +++ b/lib/capybara/selenium/driver.rb @@ -14,17 +14,26 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage timeout].freeze attr_reader :app, :options - def self.load_selenium - require 'selenium-webdriver' - warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0') - rescue LoadError => e - raise e unless e.message.match?(/selenium-webdriver/) + class << self + def load_selenium + require 'selenium-webdriver' + warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0') + rescue LoadError => e + raise e unless e.message.match?(/selenium-webdriver/) - raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler." + raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler." + end + + attr_reader :specializations + + def register_specialization(browser_name, specialization) + @specializations ||= {} + @specializations[browser_name] = specialization + end end def browser - @browser ||= begin + unless @browser options[:http_client] ||= begin require 'capybara/selenium/patches/persistent_client' if options[:timeout] @@ -34,10 +43,10 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base end end processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) } - Selenium::WebDriver.for(options[:browser], processed_options).tap do |driver| - specialize_driver(driver) - setup_exit_handler - end + @browser = Selenium::WebDriver.for(options[:browser], processed_options) + + specialize_driver + setup_exit_handler end @browser end @@ -366,24 +375,13 @@ private ::Capybara::Selenium::Node.new(self, native_node, initial_cache) end - def specialize_driver(sel_driver) - case sel_driver.browser - when :chrome - extend ChromeDriver - when :firefox - require 'capybara/selenium/patches/pause_duration_fix' if pause_broken?(sel_driver) - extend FirefoxDriver if sel_driver.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities) - when :ie, :internet_explorer - extend InternetExplorerDriver - when :safari, :Safari_Technology_Preview - extend SafariDriver + def specialize_driver + browser_type = browser.browser + self.class.specializations.select { |k, _v| k === browser_type }.each_value do |specialization| # rubocop:disable Style/CaseEquality + extend specialization end end - def pause_broken?(driver) - driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.') - end - def setup_exit_handler main = Process.pid at_exit do diff --git a/lib/capybara/selenium/driver_specializations/chrome_driver.rb b/lib/capybara/selenium/driver_specializations/chrome_driver.rb index 61954bd6..3e518876 100644 --- a/lib/capybara/selenium/driver_specializations/chrome_driver.rb +++ b/lib/capybara/selenium/driver_specializations/chrome_driver.rb @@ -59,3 +59,5 @@ private browser.send(:bridge) end end + +Capybara::Selenium::Driver.register_specialization :chrome, Capybara::Selenium::Driver::ChromeDriver diff --git a/lib/capybara/selenium/driver_specializations/firefox_driver.rb b/lib/capybara/selenium/driver_specializations/firefox_driver.rb index 0df359e0..fc42c4c1 100644 --- a/lib/capybara/selenium/driver_specializations/firefox_driver.rb +++ b/lib/capybara/selenium/driver_specializations/firefox_driver.rb @@ -3,6 +3,26 @@ require 'capybara/selenium/nodes/firefox_node' module Capybara::Selenium::Driver::FirefoxDriver + def self.extended(driver) + driver.extend Capybara::Selenium::Driver::W3CFirefoxDriver if w3c?(driver) + end + + def self.w3c?(driver) + driver.browser.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities) + end +end + +module Capybara::Selenium::Driver::W3CFirefoxDriver + class << self + def extended(driver) + require 'capybara/selenium/patches/pause_duration_fix' if pause_broken?(driver.browser) + end + + def pause_broken?(sel_driver) + sel_driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.') + end + end + def resize_window_to(handle, width, height) within_given_window(handle) do # Don't set the size if already set - See https://github.com/mozilla/geckodriver/issues/643 @@ -48,3 +68,5 @@ private ::Capybara::Selenium::FirefoxNode.new(self, native_node, initial_cache) end end + +Capybara::Selenium::Driver.register_specialization :firefox, Capybara::Selenium::Driver::FirefoxDriver diff --git a/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb b/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb index 18351a33..808c976b 100644 --- a/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +++ b/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb @@ -11,3 +11,8 @@ module Capybara::Selenium::Driver::InternetExplorerDriver handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh) } end end + +module Capybara::Selenium + Driver.register_specialization :ie, Driver::InternetExplorerDriver + Driver.register_specialization :internet_explorer, Driver::InternetExplorerDriver +end diff --git a/lib/capybara/selenium/driver_specializations/safari_driver.rb b/lib/capybara/selenium/driver_specializations/safari_driver.rb index 82a5ee1b..8c944e93 100644 --- a/lib/capybara/selenium/driver_specializations/safari_driver.rb +++ b/lib/capybara/selenium/driver_specializations/safari_driver.rb @@ -23,3 +23,6 @@ private browser.send(:bridge) end end + +Capybara::Selenium::Driver.register_specialization(/^(safari|Safari_Technology_Preview)$/, + Capybara::Selenium::Driver::SafariDriver)