Extending Selenium Via Javascript
Looks like I’ve already accomplished one of my new year’s resolutions by doing some polygot programming at work today embedding javascript within java. And it happened completely by accident.
Lately we’ve had a handful of Selenium Remote Control based fitnesse fixtures crop up at work… there’s a nice generic one, and several custom ones designed to tackle specific front end domain problems. On our latest project we have your run of the mill tabbed layout, you know… click on tabs and and you see different content, nothing special. What made things interesting, however, is that marketing wanted to track some specific usage information when each tab is clicked. Fine enough, just whip up some ajax and register some event handlers for the click event, and we’re ready to go. Well, hold on… what about testing?
Everything on the server side was unit tested and functionally tested to a T… in fact I am rather proud of the partner I worked with and myself on how well the tests are written and how many scenarios are covered. However, I still wanted to test the front end… I want to be sure that each time someone promotes, they didn’t do something to, as our team’s QA member would say, “jack it up.”
So I quickly wrote some selenium tests in fitnesse (note: this violates everything I believe FIT should be for, but fitneese is a convenient poor man’s application server) to get to the vehicle history report and test it. Speed bump number one. The interface that lets users run reports uses a target attribute on the form to open the report in a new window, and apparently selenium can’t focus on a window unless you explicitly use window.open to open the window. Drats… foiled. Or was I?
After a bit of searching, I found out that selenium remote control has a method called getEval that will simply evaluate any javascript you pass into it, which is handy for checking variable values for example. From there, you can access the runner via this.browserbot, which provides a whole slew of awesome commands you can use for manipulating the runner, including accessing the current window. And that’s where it sinks in… I can do anything in the world (almost) with javascript, and if I can access the window, I can make things happen. Bypassing the earlier speed bump was a simple matter of opening a new window with the same name as the target, and then focusing on it once the form is submitted. Piece of cake.
Since we have a lot of forms like this, I wrote a simple script to open new windows for any forms with a target on it using the name of the target, and wrapped in a java method. So that was step one… I now had a java method in a fitnesse fixture with javascript code inside a string indented all nicely… and evaluated on demand.
Now. at the new tabbed page is where things got immensely interesting… I wanted to intercept xmlHttpRequest calls, capture them, and be able to access them later. Redefining jQuery’s XHR methods were a piece of cake, the code was something like this (and whipped up in about 5 seconds):
var _d = this.browserbot._caughtValues = []
this.browserbot.getCurrentWindow().jQuery.post = function(a,b,c){
_d[_d.length] = b;
}
the second parameter here was the data packet being passed in, which is what I was interested in the most. Different meta data is fired off on different tab clicks.
Then topping this off was a simple matter. I created a method that would return a ListFixture (because I wanted to loop over the meta-data packets in the order they were fired, and also because it is vastly supperior to RowFixture) and got to work scraping the values out, which became a mix of BOTH java and js, together.
Building a list of java objects from the captured values was a matter of:
- Getting the length of the _caughtValues array and converting it to a java int (getEval only returns strings)
- iterate a number of times equal to the length to visit each value on the array
- do an eval against _caughtValues with an index specified to get the json packet:
String packet = getSelenium().getEval("this.browserbot._caughtValues["+index+"]"); - parse it into a
java.util.Mapby making a call to a nice JSON parsing library - populate a java object representing the packet with the map, add it to a list, and return a new ListFixture containing that list.
I wrestled a little to get it work, but I’ll have to admit it felt oddly great when I saw the table of expected packets light up green… and then red for the last 4 rows (good to know it was able to catch the invalid packets). There’s also a sense of joy in seeing it run consistently… for a session it worked, but would randomly fail.
It’s pretty interesting, but I think my coworkers might hate me for the embedded javascript code inside of java. So far they either think it’s really cool, or really insane. ![]()
If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!





















