1
0
Fork 0
mirror of https://github.com/teamcapybara/capybara.git synced 2022-11-09 12:08:07 -05:00

Workaround geckodriver/firefox deficient send_keys implementation as much as possible

This commit is contained in:
Thomas Walpole 2018-08-02 12:56:16 -07:00
parent 6711aed299
commit 3e5f82bb23
5 changed files with 47 additions and 14 deletions

View file

@ -47,7 +47,6 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
# Array => an array of keys to send before the value being set, e.g. [[:command, 'a'], :backspace] # Array => an array of keys to send before the value being set, e.g. [[:command, 'a'], :backspace]
def set(value, **options) def set(value, **options)
raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" if value.is_a?(Array) && !multiple? raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" if value.is_a?(Array) && !multiple?
case tag_name case tag_name
when 'input' when 'input'
case self[:type] case self[:type]
@ -212,17 +211,17 @@ private
elsif clear == :backspace elsif clear == :backspace
# Clear field by sending the correct number of backspace keys. # Clear field by sending the correct number of backspace keys.
backspaces = [:backspace] * self.value.to_s.length backspaces = [:backspace] * self.value.to_s.length
native.send_keys(*([:end] + backspaces + [value.to_s])) send_keys(*([:end] + backspaces + [value.to_s]))
elsif clear == :none elsif clear == :none
native.send_keys(value.to_s) send_keys(value.to_s)
elsif clear.is_a? Array elsif clear.is_a? Array
native.send_keys(*clear, value.to_s) send_keys(*clear, value.to_s)
else else
# Clear field by JavaScript assignment of the value property. # Clear field by JavaScript assignment of the value property.
# Script can change a readonly element which user input cannot, so # Script can change a readonly element which user input cannot, so
# don't execute if readonly. # don't execute if readonly.
driver.execute_script "arguments[0].value = ''", self driver.execute_script "arguments[0].value = ''", self
native.send_keys(value.to_s) send_keys(value.to_s)
end end
end end

View file

@ -42,8 +42,51 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
end end
end end
def send_keys(*args)
# https://github.com/mozilla/geckodriver/issues/846
return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |s| s.is_a? Array }
native.click
actions = driver.browser.action
args.each do |keys|
_send_keys(keys, actions)
end
actions.perform
end
private private
def _send_keys(keys, actions, down_keys = nil)
case keys
when String
keys = keys.upcase if down_keys&.include?(:shift) # https://bugzilla.mozilla.org/show_bug.cgi?id=1405370
actions.send_keys(keys)
when :space
actions.send_keys(' ') # https://github.com/mozilla/geckodriver/issues/846
when :control, :left_control, :right_control,
:alt, :left_alt, :right_alt,
:shift, :left_shift, :right_shift,
:meta, :left_meta, :right_meta,
:command
if down_keys.nil?
actions.send_keys(keys)
else
down_keys << keys
actions.key_down(keys)
end
when Symbol
actions.send_keys(keys)
when Array
local_down_keys = []
keys.each do |sub_keys|
_send_keys(sub_keys, actions, local_down_keys)
end
local_down_keys.each { |key| actions.key_up(key) }
else
raise ArgumentError, 'Unknown keys type'
end
end
def bridge def bridge
driver.browser.send(:bridge) driver.browser.send(:bridge)
end end

View file

@ -60,10 +60,6 @@ skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLE
Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example| Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
case example.metadata[:full_description] case example.metadata[:full_description]
when 'Capybara::Session selenium_firefox_remote node #send_keys should generate key events',
'Capybara::Session selenium_firefox_remote node #send_keys should allow for multiple simultaneous keys',
'Capybara::Session selenium_firefox_remote node #send_keys should send special characters'
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters"
when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers' when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers'
pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session) pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session)
when /^Capybara::Session selenium node #double_click/ when /^Capybara::Session selenium node #double_click/

View file

@ -50,10 +50,6 @@ $stdout.puts `#{Selenium::WebDriver::Firefox.driver_path} --version` if ENV['CI'
Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, 'selenium', capybara_skip: skipped_tests do |example| Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, 'selenium', capybara_skip: skipped_tests do |example|
case example.metadata[:full_description] case example.metadata[:full_description]
when 'Capybara::Session selenium node #send_keys should generate key events',
'Capybara::Session selenium node #send_keys should allow for multiple simultaneous keys',
'Capybara::Session selenium node #send_keys should send special characters'
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters"
when 'Capybara::Session selenium node #click should allow multiple modifiers' when 'Capybara::Session selenium node #click should allow multiple modifiers'
pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session) pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session)
when /^Capybara::Session selenium node #double_click/ when /^Capybara::Session selenium node #double_click/

View file

@ -185,7 +185,6 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
context '#fill_in with { clear: Array } fill_options' do context '#fill_in with { clear: Array } fill_options' do
it 'should pass the array through to the element' do it 'should pass the array through to the element' do
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(session)
# this is mainly for use with [[:control, 'a'], :backspace] - however since that is platform dependant I'm testing with something less useful # this is mainly for use with [[:control, 'a'], :backspace] - however since that is platform dependant I'm testing with something less useful
session.visit('/form') session.visit('/form')
session.fill_in('form_first_name', session.fill_in('form_first_name',