diff --git a/.travis.yml b/.travis.yml index b56b53f1..b87699f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,7 +59,7 @@ matrix: rvm: 2.7 env: HEADLESS=true - gemfile: gemfiles/Gemfile.beta-versions - rvm: 2.6 + rvm: 3.0 env: CAPYBARA_FF=true addons: firefox: latest-beta diff --git a/gemfiles/Gemfile.beta-versions b/gemfiles/Gemfile.beta-versions index 706ed0fa..7d474104 100644 --- a/gemfiles/Gemfile.beta-versions +++ b/gemfiles/Gemfile.beta-versions @@ -7,13 +7,14 @@ gem 'pkg-config' # needed by nokogiri gem 'xpath', github: 'teamcapybara/xpath' gem 'rack', github: 'rack/rack' gem 'sinatra', github: 'sinatra/sinatra', branch: 'master' -gem 'rspec', github: 'rspec/rspec' -gem 'rspec-core', github: 'rspec/rspec-core' -gem 'rspec-support', github: 'rspec/rspec-support' -gem 'rspec-mocks', github: 'rspec/rspec-mocks' -gem 'rspec-expectations', github: 'rspec/rspec-expectations' +gem 'rspec', github: 'rspec/rspec', branch: 'main' +gem 'rspec-core', github: 'rspec/rspec-core', branch: 'main' +gem 'rspec-support', github: 'rspec/rspec-support', branch: 'main' +gem 'rspec-mocks', github: 'rspec/rspec-mocks', branch: 'main' +gem 'rspec-expectations', github: 'rspec/rspec-expectations', branch: 'main' gem 'cucumber', github: 'cucumber/cucumber-ruby' gem 'cucumber-core', github: 'cucumber/cucumber-ruby-core' gem 'cucumber-wire', github: 'cucumber/cucumber-ruby-wire' gem 'puma', github: 'puma/puma' +gem 'selenium-webdriver', '>= 4.0.0.alpha7' diff --git a/lib/capybara/registrations/drivers.rb b/lib/capybara/registrations/drivers.rb index f80fa032..465ad5d4 100644 --- a/lib/capybara/registrations/drivers.rb +++ b/lib/capybara/registrations/drivers.rb @@ -9,32 +9,56 @@ Capybara.register_driver :selenium do |app| end Capybara.register_driver :selenium_headless do |app| - Capybara::Selenium::Driver.load_selenium + version = Capybara::Selenium::Driver.load_selenium browser_options = ::Selenium::WebDriver::Firefox::Options.new + if browser_options.respond_to?(:headless!) browser_options.headless! else browser_options.args << '-headless' end - Capybara::Selenium::Driver.new(app, browser: :firefox, options: browser_options) + + if version >= Gem::Version.new('4.0.0.alpha6') + Capybara::Selenium::Driver.new(app, browser: :firefox, capabilities: browser_options) + else + Capybara::Selenium::Driver.new(app, browser: :firefox, options: browser_options) + end end Capybara.register_driver :selenium_chrome do |app| - Capybara::Selenium::Driver.load_selenium + version = Capybara::Selenium::Driver.load_selenium browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts| # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary - opts.args << '--disable-site-isolation-trials' + if opts.respond_to?(:add_argument) + opts.add_argument('--disable-site-isolation-trials') + else + opts.args << '--disable-site-isolation-trials' + end + end + + if version >= Gem::Version.new('4.0.0.alpha6') + Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: browser_options) + else + Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) end - Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) end Capybara.register_driver :selenium_chrome_headless do |app| - Capybara::Selenium::Driver.load_selenium + version = Capybara::Selenium::Driver.load_selenium browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts| - opts.args << '--headless' + if opts.respond_to?(:headless!) + opts.headless! + else + opts.args << '--headless' + end opts.args << '--disable-gpu' if Gem.win_platform? # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary opts.args << '--disable-site-isolation-trials' end - Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) + + if version >= Gem::Version.new('4.0.0.alpha6') + Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: browser_options) + else + Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) + end end diff --git a/lib/capybara/selenium/driver.rb b/lib/capybara/selenium/driver.rb index b7452074..bb0e0d7e 100644 --- a/lib/capybara/selenium/driver.rb +++ b/lib/capybara/selenium/driver.rb @@ -15,6 +15,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base attr_reader :app, :options class << self + attr_reader :selenium_webdriver_version + def load_selenium require 'selenium-webdriver' require 'capybara/selenium/logger_suppressor' @@ -32,15 +34,18 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base # Selenium::WebDriver::VERSION. Ideally we'd # use the constant in all cases, but earlier versions # of `selenium-webdriver` didn't provide the constant. - selenium_webdriver_version = + @selenium_webdriver_version = if Gem.loaded_specs['selenium-webdriver'] Gem.loaded_specs['selenium-webdriver'].version else Gem::Version.new(Selenium::WebDriver::VERSION) end - if selenium_webdriver_version < Gem::Version.new('3.5.0') + + if @selenium_webdriver_version < Gem::Version.new('3.5.0') warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." end + + @selenium_webdriver_version rescue LoadError => e raise e unless e.message.include?('selenium-webdriver') @@ -66,7 +71,15 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base end end processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) } - @browser = Selenium::WebDriver.for(options[:browser], **processed_options) + + @browser = if options[:browser] == :firefox && + RUBY_VERSION >= '3.0' && + Capybara::Selenium::Driver.selenium_webdriver_version <= Gem::Version.new('4.0.0.alpha1') + # selenium-webdriver 3.x doesn't correctly pass options through for Firefox with Ruby 3 so workaround that + Selenium::WebDriver::Firefox::Driver.new(**processed_options) + else + Selenium::WebDriver.for(options[:browser], processed_options) + end specialize_driver setup_exit_handler diff --git a/lib/capybara/selenium/logger_suppressor.rb b/lib/capybara/selenium/logger_suppressor.rb index f9515636..69ec9ef5 100644 --- a/lib/capybara/selenium/logger_suppressor.rb +++ b/lib/capybara/selenium/logger_suppressor.rb @@ -8,7 +8,7 @@ module Capybara super end - def deprecate(*) + def deprecate(*, **, &block) super unless @suppress_for_capybara end diff --git a/spec/selenium_spec_chrome.rb b/spec/selenium_spec_chrome.rb index e7df53b1..4cde86ba 100644 --- a/spec/selenium_spec_chrome.rb +++ b/spec/selenium_spec_chrome.rb @@ -19,39 +19,71 @@ browser_options.add_preference('download.default_directory', Capybara.save_path) browser_options.add_preference(:download, default_directory: Capybara.save_path) Capybara.register_driver :selenium_chrome do |app| - Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options, timeout: 30).tap do |driver| + version = Capybara::Selenium::Driver.load_selenium + driver_options = { browser: :chrome, timeout: 30 }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + + Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver| # Set download dir for Chrome < 77 driver.browser.download_path = Capybara.save_path end end Capybara.register_driver :selenium_chrome_not_clear_storage do |app| - chrome_options = { - browser: :chrome, - options: browser_options - } - Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false, clear_session_storage: false)) + version = Capybara::Selenium::Driver.load_selenium + chrome_options = { browser: :chrome, clear_local_storage: false, clear_session_storage: false }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + + Capybara::Selenium::Driver.new(app, **chrome_options) end Capybara.register_driver :selenium_chrome_not_clear_session_storage do |app| - chrome_options = { - browser: :chrome, - options: browser_options - } - Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_session_storage: false)) + version = Capybara::Selenium::Driver.load_selenium + chrome_options = { browser: :chrome, clear_session_storage: false }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + + Capybara::Selenium::Driver.new(app, **chrome_options) end Capybara.register_driver :selenium_chrome_not_clear_local_storage do |app| - chrome_options = { - browser: :chrome, - options: browser_options - } - Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false)) + version = Capybara::Selenium::Driver.load_selenium + chrome_options = { browser: :chrome, clear_local_storage: false }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + Capybara::Selenium::Driver.new(app, **chrome_options) end Capybara.register_driver :selenium_driver_subclass_with_chrome do |app| + version = Capybara::Selenium::Driver.load_selenium subclass = Class.new(Capybara::Selenium::Driver) - subclass.new(app, browser: :chrome, options: browser_options, timeout: 30) + chrome_options = { browser: :chrome, timeout: 30 }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + + subclass.new(app, **chrome_options) end module TestSessions diff --git a/spec/selenium_spec_firefox.rb b/spec/selenium_spec_firefox.rb index fae7a531..87173c79 100644 --- a/spec/selenium_spec_firefox.rb +++ b/spec/selenium_spec_firefox.rb @@ -14,28 +14,36 @@ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |prof profile['browser.download.dir'] = Capybara.save_path profile['browser.download.folderList'] = 2 profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv' + profile['browser.startup.homepage'] = 'about:blank' # workaround bug in Selenium 4 alpha4-7 end Capybara.register_driver :selenium_firefox do |app| # ::Selenium::WebDriver.logger.level = "debug" - Capybara::Selenium::Driver.new( - app, - browser: :firefox, - options: browser_options, - timeout: 31 + version = Capybara::Selenium::Driver.load_selenium + driver_options = { browser: :firefox, timeout: 31 }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end # Get a trace level log from geckodriver # :driver_opts => { args: ['-vv'] } - ) + end + + Capybara::Selenium::Driver.new(app, **driver_options) end Capybara.register_driver :selenium_firefox_not_clear_storage do |app| - Capybara::Selenium::Driver.new( - app, - browser: :firefox, - clear_local_storage: false, - clear_session_storage: false, - options: browser_options - ) + version = Capybara::Selenium::Driver.load_selenium + driver_options = { browser: :firefox, clear_local_storage: false, clear_session_storage: false }.tap do |opts| + if version >= Gem::Version.new('4.0.0.alpha6') + opts[:capabilities] = browser_options + else + opts[:options] = browser_options + end + end + + Capybara::Selenium::Driver.new(app, **driver_options) end module TestSessions