views:

389

answers:

3

I have been running into intermittent errors with some java selenium-rc tests which I think are related to a page which has an ajax poll and automatically refreshes when some condition is reached on the server. In this scenario, I have no way of asking selenium to wait for the page to load, and so I run into a bunch of random "Couldn't access document.body" errors.

So, is there some way I can cause selenium to gracefully handle this situation? If not, is there some way I could detect whether the user is selenium from the page's javascript, and disable the automatic refresh?

If it helps at all, the javascript code in the page looks something like...

var ajax = new Ajax(url, { 
    update: state,
    method: 'get',
    onComplete: function(message) {
        if (some_condition) {
            window.location.replace(unescape(window.location));
        }
    }
});
A: 

I think that you can pause, or use a click and wait. There are a few good articles on the google. Good luck.

Edit for your comment:

How about the waitFor command?

UmYeah
Trouble is, the refresh is triggered by the underlying page, not selenium, so there's no point time at which selenium could know it needs to call pause or clickAndWait.
Matt Sheppard
+1  A: 

One solution might be to always use a waitForCondition using isElementPresent before attempting to interact with the application under test. You could put the following method in a superclass to keep your tests more readable. Alternatively you could create helper methods for common Selenium commands that perform this wait.

/** Waits for an element to be present */
public static void waitForElementToBePresent(String locator) {
    session().waitForCondition("var value = selenium.isElementPresent('" + locator.replace("'", "\\'") + "'); value == true", "60000");
}

You may also want to wait for the element to be visible, as waiting for it to just be present isn't always enough (imagine a textbox that is always present but hidden until a certain condition). You can combine this with the above method:

/** Waits for an element to be visible */
public static void waitForElementToBeVisible(String locator) {
    waitForElementToBePresent(locator);
    session().waitForCondition("var value = selenium.isVisible('" + locator.replace("'", "\\'") + "'); value == true", TIMEOUT);
}

Incidentally, the WebDriver (Selenium 2) team are working on having implicit waits, specifically to address AJAX issues where elements are not present immediately.

Dave Hunt
Couldn't the page refresh still occur after the waitForCondition completes (successfully) but before the next test step starts, causing the next step to fail?This solution might help if the page were in the middle of a refresh when the waitForCondition starts though - Thanks.
Matt Sheppard
Unfortunately it's still a possibility, yes. There also might be the chance that the page is in a state where the commands return failure as the page has not loaded anything yet. In this case I have had to wait for the window name to exist in a previous project.
Dave Hunt
Guess I'll have to look at trying to disable the refresh when running under Selenium somehow - Thanks.
Matt Sheppard
+1  A: 

My solution was to disable the refresh in javascript by wrapping it in something like the following...

var isSeleniumActive = parent.seleniumAlert;
if (isSeleniumActive) {
    alert("Selenium");
} else {
    alert("Not selenium");
}

I'm not sure if the seleniumAlert function here is likely to sick around forever, so be aware if you're taking this that you may be relying on internal selenium implementation details of selenium.

Matt Sheppard
Looks like a good workaround. I'd question having to change your app to suit your testing, but it sounds like you had little choice.
Dave Hunt