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.