As anyone who’s worked on key events in Javascript can tell you, it’s a stunningly, needlessly complicated mess. Not only are there three variables to choose from – keyCode
, charCode
, and the enigmatically-named which
– but behavior differs from browser to browser, and between versions of the same browser. I found a pretty thorough summary of the situation here.
So perhaps it’s no surprise that capybara-webkit, a Ruby gem that lets you simulate a browser environment for your acceptance tests, doesn’t give you much in the way of mocking key events. The keypress
event gives you only the charCode
, without a keyCode
or which
. Even that is a recent improvement – it used to give you the actual single character as a string (which was completely non-standard). The keyup
and keydown
events lack any indicator whatsoever of the key involved.
Recently I wanted to use capybara’s fill_in
function to send an Enter character (“\r”) to a text field. Some of my Javascript code needed to listen for this event and respond accordingly. I really wanted to use the keyup
event, because it does not repeat when you hold down Enter. However, it simply was not possible given the code used by capybara-webkit, which we chose for the project instead of the default Selenium version. At the time, I solved the problem by manually executing some Javascript code via the execute_script
function in capybara. That said, it never sat well with me and I wanted to see if I could solve the problem by adding the standard key event functionality to capybara-webkit.
As I mentioned earlier, there are a wide variety of standards in play for the expected values of keyCode
, charCode
, and which
, so obviously I couldn’t meet them all. Instead, since this is capybara-webkit, I decided to just mimic what Chrome and Safari do. Specifically, keyCode
and which
are always equal, and always provided. charCode
is provided solely in keypress
, otherwise it is zero. Finally, in the keyup
and keydown
events, I had to do some translating to go from charCode
to keyCode
. For example, because the intent is to tell you which key was pressed, and not what character it became on screen, “a” and “A” give you the same keyCode
, as do “>” and “.”.
I forked capybara-webkit, set to work, and in a few hours it was done. In fact, what took the longest was getting the existing tests to run successfully. This required quite a bit of googling and tinkering with my environment. I had to downgrade my qt version from 4.8 to 4.7.4 (in order to downgrade QtWebKit from 2.2 to 2.0). I also had to set ulimit -n 1024
to get past some “too many open files” errors. Finally it appears you must be connected to the internet for some of the tests to pass. I submitted a pull request after I had all the tests passing including my changes; I’m hopeful the request makes it in soon.
As someone fairly new to the Ruby and Github communities (or open source in general), I feel compelled to comment on how great it is to be able to just go in and enhance or fix so many of the libraries we use. If you’re a programmer that has felt trapped by a piece of software you were forced to use but that didn’t meet your needs, I think you owe it to yourself to try out the collaborative development community.
Did this ever make it into master on capybara? I don’t see any pull requests (open or closed) on the capybara-webkit repo on GitHub. I don’t see your additions in your repository either, which branch are they on? :)
I’m trying to test whether hitting the enter button submits a form with the capybara-webkit driver, and this would be very useful!
Yes, it made it into master. The pull request (292) was merged into master on March 23rd. My additions are there in my main branch, though the log doesn’t show it very clearly. The changes are mainly in capybara.js and driver_spec.rb (the latter of which tests my changes). Hope the changes help!
This looks like exactly what I’m looking for. What is the interface for using it in a Cucumber step?
I’d also like to know what the API looks like. I see some JavaScript functions, and I can see the set method calling your function per character, but I don’t seem to be able to enter any special keys such as \n.
For instance, node.set(“hello\n”) just enters that exact text into the box (with the latest capybara-webkit gem, 0.12).
What am I missing?
Thanks!
I haven’t had a chance to revisit my original case, but the intent was to support javascript code that handles the enter key by means of event.which or event.keyCode. For example,
In your ruby test, you would use
elem.set("value\n")
(or something likefill_in
which callsset)
which should trigger the handler. It doesn’t submit the form or anything. Let me know if that isn’t working for you. Thanks.
Very useful, thanks. I was able to replicate a tab with “\t”. Out of curiousity, does this work on text fields only, or can you tab from a select tag?
Seems to be working for selects, too. Btw, “\n” was submitting the form for me when I used
set
on a text field. But, it may depend on the browser, form, and what kind of input you useset
on.Does it submit if you actually hit enter in the form in that field using a real browser? I would hope it is consistent between capybara-webkit and a real browser.
Real browser also. On the form, hitting enter submits the form.