From f5a9f9ea12d10d9aa0dce4f6dec77c50d5ee279c Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Sun, 23 Sep 2018 10:09:38 -0700 Subject: [PATCH] FF/geckodriver fixed issue with sending shifted keys --- .../selenium/nodes/marionette_node.rb | 55 ++++++++++++------- lib/capybara/spec/session/node_spec.rb | 6 ++ spec/selenium_spec_chrome.rb | 4 +- spec/selenium_spec_marionette.rb | 9 +++ 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/lib/capybara/selenium/nodes/marionette_node.rb b/lib/capybara/selenium/nodes/marionette_node.rb index 2096303b..cc818a9c 100644 --- a/lib/capybara/selenium/nodes/marionette_node.rb +++ b/lib/capybara/selenium/nodes/marionette_node.rb @@ -52,9 +52,7 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array } native.click - args.each_with_object(browser_action) do |keys, actions| - _send_keys(keys, actions) - end.perform + _send_keys(args).perform end def drag_to(element) @@ -71,35 +69,29 @@ private super end - def _send_keys(keys, actions, down_keys = nil) + def _send_keys(keys, actions = browser_action, down_keys = ModifierKeysStack.new) 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 + down_keys.press(keys) + actions.key_down(keys) + when String + # https://bugzilla.mozilla.org/show_bug.cgi?id=1405370 + keys = keys.upcase if (browser_version < 64.0) && down_keys&.include?(:shift) + actions.send_keys(keys) 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) } + down_keys.push + keys.each { |sub_keys| _send_keys(sub_keys, actions, down_keys) } + down_keys.pop.reverse_each { |key| actions.key_up(key) } else raise ArgumentError, 'Unknown keys type' end + actions end def bridge @@ -118,4 +110,27 @@ private def browser_version driver.browser.capabilities[:browser_version].to_f end + + class ModifierKeysStack + def initialize + @stack = [] + end + + def include?(key) + @stack.flatten.include?(key) + end + + def press(key) + @stack.last.push(key) + end + + def push + @stack.push [] + end + + def pop + @stack.pop + end + end + private_constant :ModifierKeysStack end diff --git a/lib/capybara/spec/session/node_spec.rb b/lib/capybara/spec/session/node_spec.rb index 9046b936..fd660cbc 100644 --- a/lib/capybara/spec/session/node_spec.rb +++ b/lib/capybara/spec/session/node_spec.rb @@ -478,6 +478,12 @@ Capybara::SpecHelper.spec 'node' do expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside' end + it 'should hold modifers at top level' do + @session.visit('/form') + @session.find(:css, '#address1_city').send_keys('ocean', :shift, 'side') + expect(@session.find(:css, '#address1_city').value).to eq 'oceanSIDE' + end + it 'should generate key events', requires: %i[send_keys js] do @session.visit('/with_js') @session.find(:css, '#with-key-events').send_keys([:shift, 't'], [:shift, 'w']) diff --git a/spec/selenium_spec_chrome.rb b/spec/selenium_spec_chrome.rb index 4f8eda47..d2a8ce4a 100644 --- a/spec/selenium_spec_chrome.rb +++ b/spec/selenium_spec_chrome.rb @@ -94,13 +94,13 @@ RSpec.describe 'Capybara::Session with chrome' do end it 'should fill in a date input with a String' do - @session.fill_in('form_date', with: "06/19/1983") + @session.fill_in('form_date', with: '06/19/1983') @session.click_button('awesome') expect(Date.parse(extract_results(@session)['date'])).to eq datetime.to_date end it 'should fill in a time input with a String' do - @session.fill_in('form_time', with: "06:30A") + @session.fill_in('form_time', with: '06:30A') @session.click_button('awesome') results = extract_results(@session)['time'] expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r') diff --git a/spec/selenium_spec_marionette.rb b/spec/selenium_spec_marionette.rb index d87878fd..a1ca11f9 100644 --- a/spec/selenium_spec_marionette.rb +++ b/spec/selenium_spec_marionette.rb @@ -169,4 +169,13 @@ RSpec.describe Capybara::Selenium::Node do expect(session).to have_link('Has been alt control meta') end end + + context '#send_keys' do + it 'should process space' do + session = TestSessions::SeleniumMarionette + session.visit('/form') + session.find(:css, '#address1_city').send_keys('ocean', [:shift, :space, 'side']) + expect(session.find(:css, '#address1_city').value).to eq 'ocean SIDE' + end + end end