Archive

Archive for the ‘Robot Framework’ Category

Testing YUI Data Tables with Selenium

March 31st, 2010 1 comment

I’m automating tests of an application that displays data using YUI Data Tables. The data in those tables is refreshed when user sorts or paginates the table. The table object makes an AJAX request to the server and there is no way in Selenium to wait for that request to finish. So how do we know when the table is ready with new data?

We could sleep few seconds in the test script and then verify the data, but that is error prone. What if the request takes more time than our sleep? We can increase the sleep but we increase testing time as well. That is unacceptable.

The solution is to use YUI events. We can subscribe to an event that is fired when the table is rendered and set a flag. Then just loop and wait for that flag to change the state and flip the flag back. Sounds easy. How do we do that?

It’s only possible if the data table object (instance of DataTable) is accessible via variable. The event we have to subscribe to is “postRenderEvent“. Here is the code we have to inject into the site with getEval command.

// render flag
window.document.table_rendered_flag = false;
 
// function that will be called by the event to set the flag
window.document.table_rendered = function(o) {
    window.document.table_rendered_flag = true;
};
 
// function that we will call to check the status of the flag
// and reset the flag if the table has been rendered
window.document.check_table_rendered = function() {
    if (window.document.table_rendered_flag) {
        window.document.table_rendered_flag = false;
        return true;
    }
    return false;
};
 
// subscribe to the event
if (window.ourTableObject.dt) {
    window.ourTableObject.dt.subscribe("postRenderEvent", window.document.table_rendered);
};

After injecting that code we have to perform an action that will force the data change, wait for new data by calling window.document.check_table_rendered() in getEval until it returns True, and verify the data.

In Robot Framework, the code can be injected with “Execute Javascript” keyword and the check done with “Wait For Condition”:

Execute Javascript window.document.table_rendered_flag = false;
window.document.table_rendered = function(o) {
window.document.table_rendered_flag = true;
};
window.document.check_table_rendered = function() {
if (window.document.table_rendered_flag) {
window.document.table_rendered_flag = false;
return true;
}
return false;
};
if (window.ourTableObject.dt) {
window.ourTableObject.dt.subscribe(“postRenderEvent”, window.document.table_rendered);
};
 
Click Link sort  
Wait For Condition window.document.check_table_rendered(); 10s
Page Should Contain some text  
Categories: Robot Framework, Selenium, Testing Tags:

jQuery location strategy in Robot Framework Selenium Library revisited

March 30th, 2010 No comments

I wrote about jQuery location strategy in Selenium some time ago. I want to update on the topic a bit.

I proposed before to place jQuery and locator function inside selenium-server.jar. Later I found out that it is a waste of time. Selenium RC can be started with ‘-userExtensions’ option and passed a file with all extra Java Script code. Therefore, I placed downloaded jQuery code along with locator function inside users-extensions.js.

My locator function has changed a bit. I added some exception checks and it is now compatible single-window mode that selenium allows.

Selenium.prototype.locateElementByJQuerySelector = function(locator, inDocument, inWindow) {
    var loc = locator.replace(/>/g, '>');
    loc = loc.replace(/&lt;/g, '<');
    var element;
    try {
        element = $(inDocument).find(loc);
    } catch (e) {
        return null;
    }
    if (element.length == 1 ) {
        return element[0];
    } else if(element.length > 1) {
        return element.get();
    } else {
        return null;
    }
}

I was allowed to make changes to RF Selenium Library and the keyword Add Location Strategy is available in the newest version.

In order to use jQuery locator in RF, the Selenium Server must be started with user extensions. Then, after opening the browser window, location strategy must be registered.

| Start Selenium Server | -userExtensions | ${CURDIR}${/}user-extensions.js |
| Add Location Strategy | jquery | return Selenium.prototype.locateElementByJQuerySelector(locator, inDocument, inWindow); |

Use the new locator like this:

| Page Should Contain Element | jquery=div.#data-table > table |
Categories: Robot Framework, Selenium, Testing Tags:

jQuery selectors in Robot Framework Selenium Library

November 3rd, 2009 5 comments

Few months ago I selected a tool to test web interfaces: Robot Framework with Selenium Library. It allows the QA team to script test scenarios. Selenium provides a large set of keywords to drive a web-based user interface but more complicated interfaces developed using Java Script libraries like YUI and jQuery and AJAX can be harder to test. Recently I wrote a keyword to wait for YUI table to load using Java Script expression with jQuery selectors. I thought it would be great if I could use jQuery selectors to locate page elements, just like I use XPath at the moment. After doing some research I found it is possible and decided to give it a try.

I found Tellurium Automated Testing Framework that uses Selenium and jQuery selectors and a documentation page that describes how jQuery selector works.

The first thing to do is to make sure that Selenium loads jQuery. I checked out selenium library (download will also work) and unpacked the selenium-server.jar file.

cd src/SeleniumLibrary/lib
mkdir selenium-server
cd selenium-server
jar xvf ../selenium-server.jar

Then I downloaded jQuery and placed it in core/scripts directory – it’s a single Java Script file. I edited TestRunner.html andRemoteRunner.html and added a line to load jQuery just before user-extensions.js.

...
<script language="JavaScript" type="text/javascript" src="xpath/javascript-xpath-0.1.11.js"></script>
<script language="JavaScript" type="text/javascript" src="scripts/jquery-1.3.2.js"></script>
<script language="JavaScript" type="text/javascript" src="scripts/user-extensions.js"></script>
...

Then I added the following function definition to core/scripts/user-extensions.js file (RIDE replaces > and < with HTML encoded versions so those need to be converted again).

Selenium.prototype.locateElementByJQuerySelector = function(locator, inDocument, inWindow) {
    var loc = locator.replace(/&gt;/g, '>');
    loc = loc.replace(/&lt;/g, '<');
    var found = $(inDocument).find(loc);
    if (found.length == 1 ) {
        return found[0];
    } else if(found.length > 1) {
        return found.get();
    } else {
        return null;
    }
}

Next, I repackaged the jar file with ‘jar uf’ command only updating the files that I’ve changed.

jar uvf ../selenium-server.jar \
        core/TestRunner.html \
        core/RemoteRunner.html \
        core/scripts/jquery-1.3.2.js \
        core/scripts/user-extensions.js

At this point, the Selenium Library must be modified to expose “Add Location Strategy” keyword. It’s currently implemented but not visible to the user. I also added a possibility to start a different selenium-server.jar than the one distributed with the Library so I can keep my custom jar file with my test cases. I created an issue 59 and provided the patch. I hope those changes will get into the next release of the library. To simply enable the keyword, add the following method to SeleniumLibrary class in src/SeleniumLibrary/__init__.py

    def add_location_strategy(self, strategyName, functionDefinition):
        """Ads custom location strategy.
 
        'strategyName' is the name of the strategy; a prefix used when
        addressing an element.
 
        'functionDefinition' is the java script that will be called. It must
        return a DOM reference, an array with DOM references, or null.
 
        Together with the modified selenium-server.jar it can provide a new
        method of locating elements on the page. For example, a JQuery
        strategy can be added to locate elements given JQuery selector syntax.
 
        Examples:
        | Add Location Strategy | jquery | return Selenium.prototype.locateElementByJQuerySelector(locator, inDocument, inWindow); |
        | Page Should Contain Element | jquery=div.#data-table |  |
        """
        self._selenium.add_location_strategy(strategyName, functionDefinition)

Before using jQuery locators in test cases they have to be registered with Selenium. I do that in the suite setup after I open the browser window.

| Add Location Strategy | jquery | return Selenium.prototype.locateElementByJQuerySelector(locator, inDocument, inWindow); |

I can now check for existence of a table in a page (table in a div with id data-table).

| Page Should Contain Element | jquery=div.#data-table > table |
Categories: Robot Framework, Selenium, Testing Tags: