Better Key Events in Capybara-Webkit

Keyboard operatorAs 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.

Conversation
  • Martin Foot says:

    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!

    • Will Pleasant-Ryan Will Ryan says:

      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!

  • Geoff Massanek says:

    This looks like exactly what I’m looking for. What is the interface for using it in a Cucumber step?

  • Martin Foot says:

    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!

    • Will Pleasant-Ryan Will Ryan says:

      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,

      $(".some-elem").keyup(function (e) {
        if (e.which == ENTER_KEY) {
          doSomething();
        }
      });
      

      In your ruby test, you would use
      elem.set("value\n") (or something like fill_in which calls set)
      which should trigger the handler. It doesn’t submit the form or anything. Let me know if that isn’t working for you. Thanks.

  • Darrell says:

    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?

    • Darrell says:

      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 use set on.

      • Will Pleasant-Ryan Will Pleasant-Ryan says:

        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.

        • Darrell says:

          Real browser also. On the form, hitting enter submits the form.

  • Comments are closed.