36

I need to send some key-presses to a web app in an integration test that uses Capybara and WebKit. Using Selenium (WebDriver and Firefox) I can achieve it like this:

find("#element_id").native.send_keys :tab

but WebKit's native element node doesn't have a send_keys method. Actually native in WebKit returned a string containing a number. Is there another way to send keystrokes to WebKit? Maybe even some workaround using JavaScript/jQuery?

Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • Did you ever have any luck with this Pablo? I still have the same issue you originally had with .native method. Just returns '4' for example. – kikuchiyo Oct 30 '12 at 21:22

8 Answers8

18

I've been trying to implement Marc's answer without any success, but I found some help from a similar question: capybara: fill in form field value with terminating enter key. And apparently there was a pull request from capybara that seems to address this issue.

What worked for me was:

before { fill_in "some_field_id", with: "\t" }

My example erases the text in the field and then presses Tab. To fill in a field with 'foobar', replace "\t" with "foobar\t". You can also use "\n" for the Enter key.

For your example, you could use:

find("#element_id").set("\t")
Community
  • 1
  • 1
d_rail
  • 4,109
  • 32
  • 37
15

This worked for me with Poltergeist, to trigger the asterisk key:

find("body").native.send_key("*")

I had no luck with the other solutions; not even Syn.

This was to trigger an angular-hotkeys event.

Henrik N
  • 15,786
  • 5
  • 82
  • 131
  • Yet another reason to use Poltergeist. It just makes life easier. This worked for me with zero friction. – DannyB Feb 11 '16 at 16:28
14

You can do it like that:

keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); $('body').trigger(e);"
page.driver.browser.execute_script(keypress_script)
Marc Lainez
  • 3,070
  • 11
  • 16
  • 1
    This worked for me. We're actually using the poltergeist driver (PhantomJS) instead of Capybara WebKit, so I had to make a minor change to the 2nd line of code there: page.driver.execute_script(keypress_script) – Liron Yahdav May 03 '12 at 03:30
  • 1
    This worked for me, but I should use page.execute_script(keypress_script). – rjurado01 Apr 04 '13 at 13:02
  • 1
    FYI - Poltergeist supports element.native.send_keys(*keys) – Rimian Mar 18 '14 at 00:49
6

Now since Capybara-webkit 1.9.0 you can send key presses like enter and others using send_keys:

find("textarea#comment").send_keys(:enter)

Source: https://github.com/thoughtbot/capybara-webkit/issues/191#issuecomment-228758761

Capybara API Docs: http://www.rubydoc.info/github/jnicklas/capybara/Capybara%2FNode%2FElement%3Asend_keys

Osmond
  • 345
  • 4
  • 9
3

I ended up doing the following:

Capybara.current_driver = Capybara.javascript_driver
keypress_script = "$('input#my_field').val('some string').keydown();"
page.driver.browser.execute_script(keypress_script)

I discovered in Chrome, testing my JavaScript, that actually creating an $.Event with keyCode or charCode and then triggering that on my input field didn't put the characters in the input. I was testing autocompletion which required a few characters be in the input field, and it would start the autocompletion on keydown. So I set the input value manually with val, then trigger keydown to cause the autocompletion script to start.

Sarah Vessels
  • 30,930
  • 33
  • 155
  • 222
1

For simple cases, triggering a keypress event in JS will work:

def press(code)
  page.execute_script("$('#my-input').trigger($.Event('keypress', {keyCode: #{code}}))")
end

For a more general and robust answer, use this great library that goes through the trouble of triggering the right events (i.e. keydown, then keypress and finally keyup).

def type(string)
  page.execute_script("Syn.click({}, 'my-input').wait().type(#{string.to_json})")
end

A more complex example can be found here

Community
  • 1
  • 1
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
0

Here is my solution, which works with capybara 2.1.0:

fill_in('token-input-machine_tag_list', :with => 'new tag name')
page.evaluate_script("var e = $.Event('keydown', { keyCode: 13 }); $('#token-input-machine_tag_list').trigger(e);") # Press enter

Please, note, that in new capybara you have to use page.evaluate_script.

ExiRe
  • 4,727
  • 7
  • 47
  • 92
0

For Capybara Webkit, this is the solution I used:

def press_enter(input)
  script = "var e = jQuery.Event('keypress');"
  script += "e.which = 13;"
  script += "$('#{input}').trigger(e);"
  page.execute_script(script);
end

Then I use it cleanly in my test like:

press_enter("textarea#comment")
Greg Blass
  • 3,523
  • 29
  • 42