Fix access to specializations when Selenium::Driver is subclassed

The specializations are stored in a class instance variable. However,
they are accessed from the specialize_driver method via `self.class`.

Previously if this method was called on an instance of a subclass of
Selenium::Driver, then it accessed the class instance variable
associated with the subclass (which is nil by default) and not the class
instance variable associated with the Selenium::Driver class as intended
resulting in an exception like this:

     NoMethodError:
       private method `select' called for nil:NilClass
       ./lib/capybara/selenium/driver.rb:417:in `specialize_driver'
       ./lib/capybara/selenium/driver.rb:49:in `browser'
       ./lib/capybara/selenium/driver.rb:66:in `visit'
       ./lib/capybara/session.rb:277:in `visit'
       ./spec/selenium_spec_chrome.rb:118:in `block (3 levels) in <top (required)>'

This commit adds a spec using a subclass of Selenium::Driver with Chrome
to demonstrate the problem and fixes it by changing the
specialize_driver method to access the specializations via the
explicitly specified class name.

An alternative fix would be to use a class variable for specializations
and do away with the class attribute reader altogether.
This commit is contained in:
James Mead 2019-05-11 12:07:16 +01:00
parent a62c7b32c5
commit e382792352
2 changed files with 14 additions and 1 deletions

View File

@ -414,7 +414,7 @@ private
def specialize_driver
browser_type = browser.browser
self.class.specializations.select { |k, _v| k === browser_type }.each_value do |specialization| # rubocop:disable Style/CaseEquality
Capybara::Selenium::Driver.specializations.select { |k, _v| k === browser_type }.each_value do |specialization| # rubocop:disable Style/CaseEquality
extend specialization
end
end

View File

@ -27,6 +27,11 @@ Capybara.register_driver :selenium_chrome_not_clear_storage do |app|
Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: false, clear_session_storage: false))
end
Capybara.register_driver :selenium_driver_subclass_with_chrome do |app|
subclass = Class.new(Capybara::Selenium::Driver)
subclass.new(app, browser: :chrome, options: browser_options, timeout: 30)
end
module TestSessions
Chrome = Capybara::Session.new(CHROME_DRIVER, TestApp)
end
@ -106,4 +111,12 @@ RSpec.describe 'Capybara::Session with chrome' do
expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
end
end
describe 'using subclass of selenium driver' do
it 'works' do
session = Capybara::Session.new(:selenium_driver_subclass_with_chrome, TestApp)
session.visit('/form')
expect(session).to have_current_path('/form')
end
end
end