follow me icons

Wednesday, November 3, 2010

How to send keystrokes to an element in the browser

From time to time you might need to test sending a keystroke to the browser. For example, for a map based application such as google map, you might want to test the arrow keys on the keyboard to test that pressing the arrow key will move the maps.

Fortunately, webdriver already implements the send-keys class and if you use capybara you can use this extensions by Mark Gandolfo. Please note that as of this writing, the current send-keys version in github does not support capybara 0.4.0 It only supports version < 0.4.0.

However, I have modified the code to work with capybara version 0.4.0 below:

Cucumber Scenario

And I send arrow_left to google map
And I send arrow_up to google map
And I send arrow_right to google map
And I send arrow_down to google map


Steps Definitions - send_keys_steps.rb
put this into your step_definitions directory

And /^I send (.*) to google map$/ do |key|
find(:css,"#page").send(key)
end


Class definition - send_keys.rb
put this into your support/patches/send_keys.rb. If you use capybara version < 0.4.0, then change the "Class Capybara::Element < Capybara::Node" into "Node < Capybara::Node" and change the "native.send_keys(send_key)" to "node.send_keys(send_key)".

If you don't, then you will get this error:
"superclass mismatch for class Node (TypeError)"


class Capybara::Driver::Selenium < Capybara::Driver::Base
class Capybara::Element < Capybara::Node
def allowed_keys
@allowed_keys ||= %q(option, null cancel help backspace
tab clear return enter shift left_shift control left_control
alt left_alt pause escape space page_up page_down end home
left arrow_left uparrow_up right arrow_rightdown arrow_down
insert delete semicolon equals numpad0 numpad1 numpad2 numpad3
numpad4 numpad5 numpad6 numpad7 numpad8 numpad9 multiplyadd
separator subtract decimal divide f1 f2 f3 f4 f5 f6 f7 f8
f9 f10 f11 f12)
end

def send(key)
send_key = []

if key.match(/\[.*\]/i)
key.gsub!(/[\[\]]/,'')
key = key.split(',')
else
key = [key]
end

key.each do |k|
if k.match(/(\'|\")/i)
send_key << k.gsub(/(\"|\')/, '')
elsif allowed_keys.include?(k)
send_key << k.to_sym
else
send_key << "#{k}"
end
end

native.send_keys(send_key)
end
end
end


Modify support/env.rb to include send_keys

require 'features/support/patches/send_keys'

3 comments:

  1. As of Capybara 0.4.1.2, you would have to change the following:

    Change "class Capybara::Element < Capybara::Node" to "class Capybara::Element"

    ReplyDelete
  2. actually I need to reopen "class Capybara::Node::Element" not "class Capybara::Element"

    ref: https://github.com/jnicklas/capybara/blob/master/lib/capybara/node/element.rb

    Thanks for all
    o/

    ReplyDelete
  3. Anyone got this working most recently? I'm still getting a superclass mismatch for class Selenium (TypeError)
    error.


    class Capybara::Driver::Selenium < Capybara::Driver::Base
    class Capybara::Node::Element
    def allowed_keys
    @allowed_keys ||= %q(option, null cancel help backspace
    tab clear return enter shift left_shift control left_control
    alt left_alt pause escape space page_up page_down end home
    left arrow_left uparrow_up right arrow_rightdown arrow_down
    insert delete semicolon equals numpad0 numpad1 numpad2 numpad3
    numpad4 numpad5 numpad6 numpad7 numpad8 numpad9 multiplyadd
    separator subtract decimal divide f1 f2 f3 f4 f5 f6 f7 f8
    f9 f10 f11 f12)
    end


    ..




    is correct .. right?

    ReplyDelete