Advanced Selenium Synchronization with 'Latches'

Selenium testing Tip of the Week: Synchronization with Selenium is the number two problem I see with people's scripts (the first being broken locators). This is actually a pretty easy problem to solve in all but the most pathological situations. Web 1.0 Remember the good ol' days when clicking a link caused the browser to fetch a new page? Those were, and remain, super easy to synchronize with using waitForPageToLoad and its language specific variants. Here's an example of this in Ruby:
@selenium.click "link=click here", :wait_for => :page
Web 2.0 But along came Web 2.0 and all its AJAX-y 'goodness'. No longer could we be guaranteed that some action or event on the page would trigger a page load. For that, we needed to use a combination of isElementPresent or isVisible.
@selenium.click "link=click here", :wait_for => :element, :element => "my locator"
@selenium.click "link=click here", :wait_for => :visible, :element => "my locator"
While I haven't done it yet for Ruby, I often combine the two together to create an 'available' condition to make sure that the element I care about is both present and visible. Something like this.
@selenium.click "link=click here", :wait_for => :available, :element => "my locator"
Post Web 2.0 Some AJAX calls affect multiple elements and are both tricky and/or time consuming to figure out all the places to watch. New technologies like COMET also make element availability more fallible than it might originally be. For these situations you need to use a 'latch' for synchronization. A what? The term 'latch' in this case is a value that is set in the browser's DOM that your script monitors for synchronization rather than something in the actual page. And example is in order. Here is an AJAX call in Ruby on Rails.
<%= link_to_remote( "click here",
                   :update => "time_div",
                   :url => { :action => :say_when },
                   :before => "window.latch = 'started'",
                   :complete => "window.latch = 'done'") %>
What this will do is set window.latch to the string value 'started' in the DOM before it actually executes and will set it to 'done' after it is complete. No problem. People who work with AJAX are used to working with callbacks. The twist happened in our Selenium script.
@selenium.click "link=click here", :wait_for => :condition, :javascript => "window.latch == 'done'"
Now instead of checking for an element to be present or visible, we are waiting via waitForCondition for the latch conditions; in this case, 'window.latch is done'. I consider the latch technique as the synchronization method of last resort since it requires changing production code to support automation. But successful automation often calls for just that.

Written by

Adam Goucher

Topics

SeleniumAutomated testing