Telerik blogs

Although I ended my Selenium adventure a few months ago, there is a final topic I’d like to cover here. This one completes my set of posts concerning RadControls for ASP.NET AJAX test automation with Selenium. The tool, the Telerik ASP.NET QA team relied on during the past couple of years, helped us catch in time most of the bugs in RadControls that never came into production!

A curios fact here is that Selenium 1.0 official release is finally coming soon after many years of development! Check out the recent post on Selenium blog announcing the exciting news.

Finally, as promised, this post presents the idea of extensibility in test automation including several examples of Selenium extensions for RadControls (ASP.NET AJAX).

I personally consider the simplicity of Selenium Core tests as a plus in tests suite creation. Additionally, the Selenium Command Reference allows building of powerful tests even over complex Web applications based on RadControls. We expanded the ease of test creation and maintainability with the help of further commands.

The concept of extending the command reference in Selenium is explained here, so I will not cover the basics. However, it’s important to put the attention to an option: defining just a single command via Selenium.prototype.getFoo and isFoo definitions builds several other and useful command variations – store/assert/waitForFoo and their negative counterparts. That’s helpful especially in building composite tests and such dealing with AJAX applications.

The sample extensions described in this post has never been published anywhere despite my willingness to contribute more to the Selenium community. I have also changed the original code a bit for the sake of simplicity.

There are two groups of commands– some of them are general that can be used outside the RadControls applications and the others, the core of our extensions, are specific to each component. Let me start with the first group.

I can’t imagine dealing with complex HTML without table commands. Some of the first extensions I found myself in bad need were the next two samples. Those get the count of table rows and the row cells. When you look at their simple definitions, you can’t imagine how often one may need them!

  

Selenium.prototype.getTableRowCount = function(tableId)   
{   
    var table = this.browserbot.findElement(tableId);  
    // throw an error in case table.tBodies.length is greater than 1  
    return table.tBodies[0].rows.length;  
}   
 
Selenium.prototype.getTableRowCellCount = function(tableId_rowIndex)   
{   
    var args = tableId_rowIndex.split(',');  
    var table = this.browserbot.findElement(args[0]);  
    // throw an error in case table.tBodies.length is greater than 1  
    return table.tBodies[0].rows[args[1]].cells.length;  
}  

 

Note: as an alternative, the latest Selenium Core version 0.8.3 exposes a new build-in command – storeXpathCount. One needs to specify an exact XPath script as an argument to verify the count of the matching elements. The above commands however are much easier for use, examples follow:

<tr>   
    <td>assertTableRowCount</td> 
    <td>RadGrid1_ctl00</td> 
    <td>2</td> 
</tr>   
<tr>   
    <td>assertTableRowCellCount</td> 
    <td>RadGrid1_ctl00,1</td> 
    <td>5</td> 
</tr>  

  

The test above asserts that RadGrid data table of the application under test consists of two rows, the second one (having index '1’) contains five cells.

Here is an interesting sample verifying the value is in the given range.

Selenium.prototype.isValueInRange = function(value, range)   
{   
    var rangeValues = eval(range);   
    //the range argument represents an array of min and max values  
    var min = rangeValues[0];  
    var max = rangeValues[1];  
    value = parseInt(this.getEval(value));  
    return value < max && value > min;  
}   
 

 

It can be used as follows:

<tr>   
    <td>assertValueInRange</td> 
    <td><your sctipt comes here></td>  
    <td>[min,max]</td> 
</tr>   
 

as ‘min’ and ‘max’ are exact numbers.

Let me pass to some examples for ASP.NET AJAX applications. The first one serves as a helper function to get a real client-side object from the AJAX page. We call the ‘$find’ function to get the AJAX object from the tested page:

function getAjaxControl(controlId)   
{   
    return this.page().getCurrentWindow().$find(controlId);  

 

Now we can go on and build a set of commands for each component in the RadControls suite. Both actions and verifications of the client-side tests use the components API due to the controls specific behavior. I discussed this in The Trickiest Tips in RadControls for ASP.NET (AJAX) Tests Automation post. So instead of evaluating complex single-line scripts, one can put that script in a separate helpful command:

Selenium.prototype.getGridRowUniqueName = function(gridId_rowIndex)   
{   
    var args = gridId_rowIndex.split(',');  
    var grid = this.getAjaxControl(args[0]);  
    var row = grid.get_masterTableView().get_dataItems()[args[1]];  
    return row.get_uniqueName();  
}   
 

and use it in the tests:

<tr>   
    <td>assertGridRowUniqueName</td> 
    <td>RadGrid1,0</td> 
    <td>FirstRow</td> 
</tr>   
 

Of course this also allows easy debugging of the script error.

More RadGrid Selenium extensions follow:

Selenium.prototype.isGridRowExpanded = function(gridId_rowIndex)   
{   
    var args = gridId_rowIndex.split(',');  
    var grid = this.getAjaxControl(args[0]);  
    var row = grid.get_masterTableView().get_dataItems()[args[1]];  
    return row.get_expanded();  
}   
 
Selenium.prototype.getGridHeaderCellText = function(gridId_columnIndex)   
{   
    var args = gridId_columnIndex.split(',');  
    var gridHeader = this.browserbot.findElement(args[0] + "_ctl00_Header");  
    var th = gridHeader.getElementsByTagName("th")[args[1]];  
    return th.innerHTML;  
}   
 
Selenium.prototype.getGridCellByColumnUniqueName = function(gridId_rowIndex_columnName)   
{   
    var args = gridId_rowIndex_columnName.split(',');  
    var grid = this.getAjaxControl(args[0]);  
    var row = grid.get_masterTableView().get_dataItems()[args[1]];  
    var cell = grid.get_masterTableView().getCellByColumnUniqueName(row, args[2]);  
    return cell.innerHTML;  
}   
 

The commands can also serve as actions executing client-side API methods. An excellent example is the use of the RadEditor object’s set_html() method:

Selenium.prototype.doSetEditorHtml = function(editorId_html)   
{   
    var args = editorId_html.split(',');  
    var editorControl = this.getAjaxControl(args[0]);  
    editorControl.set_html(args[1]);  
}   
 

and the respective verification comes here:

Selenium.prototype.getEditorHtml = function(editorControlId)   
{   
    var editorControl = this.getAjaxControl(editorControlId);  
    return editorControl.get_html()  
}  

Here is a sample Selenium Core test operating with the RadEditor client-side object:

<tr>   
    <td>setEditorHtml</td> 
    <td>NotesEditor,Just some text</td> 
    <td></td>  
</tr>   
<tr>   
    <td>assertEditorHtml</td> 
    <td>NotesEditor</td> 
    <td>Just some text</td> 
</tr>   
 

I cannot miss the last item from the “trickiest tips” post: an alternative to select and get the selected item text of RadComboBox:

Selenium.prototype.doSelectComboItem = function(comboId_itemText)   
{   
    var args = comboId_itemText.split(',');  
    var combo = this.getAjaxControl(args[0]);  
    var item = combo.findItemByText(args[1]);  
    item.select();   
}   
 
Selenium.prototype.getComboSelectedText = function(comboId)   
{   
    var combo = this.getAjaxControl(comboId);  
    return combo.get_selectedItem().get_text();  
}   
 

And a sample test case:

<tr>   
    <td>selectComboItem</td> 
    <td>RadComboBox1,FirstItemText</td> 
    <td></td>  
</tr>   
<tr>   
    <td>assertComboSelectedText</td> 
    <td>RadComboBox1</td> 
    <td>FirstItemText</td> 
</tr>   
 

 

I think this gives the basic idea behind the Selenium Extensions used in RadControls application tests. Should you need a particular command, do not hesitate to drop us a line and we will do our best to help.

 

Conclusion

This is a classic example of extensibility in Web-based test automation helping simple structured tests to cover complex applications and their components. I wouldn’t say you can get this as a perfect solution in test automation of RadControls applications but it is definitely a good base to compare with.

Once again, here is a quick reference of the set of post about RadControls application testing with Selenium:

RadControls test automation with Selenium

Happy testing!


Comments

Comments are disabled in preview mode.