As we know, Selenium IDE is a good browser automation tool for performing basic automation purpose since it has many commands which can be used in our day-to-day automation works. However this tool doesn't have some features like a looping feature but the tool does allow users to create an extension which can be added to IDE called as Flow control to perform the looping operation while automating application functionalities. So this post may be helpful for you to see and learn on how we can implement Selenium IDE loop with a simple example.
Note: This are additional command that we added to IDE through the java-script extension file that Selenium IDE doesn't provide or simply we can say it is 'OUT-OF-THE-BOX'.
Example:
Let us consider a small example which would demonstrate using one or two commands say In my case i will use Label and gotoLabel command. Also I will use Bing search page as an example here. We will see how Flow Control extension can be used to navigate to Bing Explore page and then would redirect to MSN Homepage multiple times.
(Note: Likewise we can make use of other commands generated by the flow control logic wherever applicable.)
=========
IDE Script:
=========
================
HTML Code Format:
================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="https://87sixdevelop.seedconnect.org/" />
<title>New Test</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">New Test</td></tr>
</thead><tbody>
<tr>
<td>label</td>
<td>openBingSearch</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>https://www.bing.com/</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>link=Explore</td>
<td></td>
</tr>
<tr>
<td>storeText</td>
<td>css=div.TaskTitle > span</td>
<td>Actual_Title</td>
</tr>
<tr>
<td>echo</td>
<td>${Actual_Title}</td>
<td></td>
</tr>
<tr>
<td>store</td>
<td>Spotlight</td>
<td>Expected_Title</td>
</tr>
<tr>
<td>echo</td>
<td>${Expected_Title}</td>
<td></td>
</tr>
<tr>
<td>verifyEval</td>
<td>storedVars['Actual_Title']==storedVars['Expected_Title']</td>
<td>true</td>
</tr>
<tr>
<td>open</td>
<td>http://www.msn.com/en-in/</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>css=h2 > a</td>
<td></td>
</tr>
<tr>
<td>storeText</td>
<td>css=h2 > a</td>
<td>ActualLinktitleMSN</td>
</tr>
<tr>
<td>echo</td>
<td>${ActualLinktitleMSN}</td>
<td></td>
</tr>
<tr>
<td>store</td>
<td>Make MSN my homepage</td>
<td>ExpectedLinktitleMSN</td>
</tr>
<tr>
<td>echo</td>
<td>${ExpectedLinktitleMSN}</td>
<td></td>
</tr>
<tr>
<td>verifyEval</td>
<td>storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN']</td>
<td>true</td>
</tr>
<tr>
<td>gotoLabel</td>
<td>openBingSearch</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
================
Test Execution Log:
================
[info] Playing test case Demo_Loop_Control_Test
[info] Executing: |label | openBingSearch | |
[info] Executing: |open | https://www.bing.com/ | |
[info] Executing: |clickAndWait | link=Explore | |
[info] Executing: |storeText | css=div.TaskTitle > span | Actual_Title |
[info] Executing: |echo | ${Actual_Title} | |
[info] echo: Spotlight
[info] Executing: |store | Spotlight | Expected_Title |
[info] Executing: |echo | ${Expected_Title} | |
[info] echo: Spotlight
[info] Executing: |verifyEval | storedVars['Actual_Title']==storedVars['Expected_Title'] | true |
[info] script is: storedVars['Actual_Title']==storedVars['Expected_Title']
[info] Executing: |open | http://www.msn.com/en-in/ | |
[info] Executing: |waitForElementPresent | css=h2 > a | |
[info] Executing: |storeText | css=h2 > a | ActualLinktitleMSN |
[info] Executing: |echo | ${ActualLinktitleMSN} | |
[info] echo: Make MSN my homepage
[info] Executing: |store | Make MSN my homepage | ExpectedLinktitleMSN |
[info] Executing: |echo | ${ExpectedLinktitleMSN} | |
[info] echo: Make MSN my homepage
[info] Executing: |verifyEval | storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN'] | true |
[info] script is: storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN']
[info] Executing: |gotoLabel | openBingSearch | |
[info] Executing: |open | https://www.bing.com/ | |
[info] Executing: |clickAndWait | link=Explore | |
[info] Executing: |storeText | css=div.TaskTitle > span | Actual_Title
...
...
==================
Test Summary Report:
==================
========================
Loop Control Logic Flow Code:
========================
var gotoLabels= {};
var whileLabels = {};
// overload the original Selenium reset function
Selenium.prototype.reset = function() {
// reset the labels
this.initialiseLabels();
// proceed with original reset code
this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
this.browserbot.selectWindow("null");
this.browserbot.resetPopups();
}
/*
* --- Initialize Conditional Elements --- *
* Run through the script collecting line numbers of all conditional elements
* There are three a results arrays: goto labels, while pairs and forEach pairs
*
*/
Selenium.prototype.initialiseLabels = function()
{
gotoLabels = {};
whileLabels = { ends: {}, whiles: {} };
var command_rows = [];
var numCommands = testCase.commands.length;
for (var i = 0; i < numCommands; ++i) {
var x = testCase.commands[i];
command_rows.push(x);
}
var cycles = [];
var forEachCmds = [];
for( var i = 0; i < command_rows.length; i++ ) {
if (command_rows[i].type == 'command')
switch( command_rows[i].command.toLowerCase() ) {
case "label":
gotoLabels[ command_rows[i].target ] = i;
break;
case "while":
case "endwhile":
cycles.push( [command_rows[i].command.toLowerCase(), i] )
break;
case "foreach":
case "endforeach":
forEachCmds.push( [command_rows[i].command.toLowerCase(), i] )
break;
}
}
var i = 0;
while( cycles.length ) {
if( i >= cycles.length ) {
throw new Error( "non-matching while/endWhile found" );
}
switch( cycles[i][0] ) {
case "while":
if( ( i+1 < cycles.length ) && ( "endwhile" == cycles[i+1][0] ) ) {
// pair found
whileLabels.ends[ cycles[i+1][1] ] = cycles[i][1];
whileLabels.whiles[ cycles[i][1] ] = cycles[i+1][1];
cycles.splice( i, 2 );
i = 0;
} else ++i;
break;
case "endwhile":
++i;
break;
}
}
}
Selenium.prototype.continueFromRow = function( row_num )
{
if(row_num == undefined || row_num == null || row_num < 0) {
throw new Error( "Invalid row_num specified." );
}
testCase.debugContext.debugIndex = row_num;
}
// do nothing. simple label
Selenium.prototype.doLabel = function(){};
Selenium.prototype.doGotoLabel = function( label )
{
if( undefined == gotoLabels[label] ) {
throw new Error( "Specified label '" + label + "' is not found." );
}
this.continueFromRow( gotoLabels[ label ] );
};
Selenium.prototype.doGoto = Selenium.prototype.doGotoLabel;
Selenium.prototype.doGotoIf = function( condition, label )
{
if( eval(condition) ) this.doGotoLabel( label );
}
Selenium.prototype.doWhile = function( condition )
{
if( !eval(condition) ) {
var last_row = testCase.debugContext.debugIndex;
var end_while_row = whileLabels.whiles[ last_row ];
if( undefined == end_while_row ) throw new Error( "Corresponding 'endWhile' is not found." );
this.continueFromRow( end_while_row );
}
}
Selenium.prototype.doEndWhile = function()
{
var last_row = testCase.debugContext.debugIndex;
var while_row = whileLabels.ends[ last_row ] - 1;
if( undefined == while_row ) throw new Error( "Corresponding 'While' is not found." );
this.continueFromRow( while_row );
}
Selenium.prototype.doPush= function(value, varName)
{
if(!storedVars[varName]) {
storedVars[varName] = new Array();
}
if(typeof storedVars[varName] !== 'object') {
throw new Error("Cannot push value onto non-array " + varName);
} else {
storedVars[varName].push(value);
}
}
Thanks,
Pinaki Mohapatra
- The Loop control flow code is mentioned towards the end of this post.
- Copy and paste the code in an text editor and create a .js extension file.
- Open Selenium IDE and Navigate to Options > General tab.
- Browse and locate the new Loop control JavaScript file and attached it in the Selenium Core Extensions section. (Note: Make sure to restart Selenium IDE for the changes/effects to take place.)
- Once this extension is configured, you should be able to see the following commands in Selenium IDE command list i.e.
- label | mylabel - creates a label called "mylabel" (a goto target)
- goto | mylabel - goto "mylabel"
- gotoLabel | mylabel - synonym for goto
- gotoIf | expression - jump to specified label if expression is true
- while | expression - loop while expression is true
- endWhile - indicate the end of a while loop
- push | value | arrayName - push value onto an array, creating array if necessary
Note: This are additional command that we added to IDE through the java-script extension file that Selenium IDE doesn't provide or simply we can say it is 'OUT-OF-THE-BOX'.
Example:
Let us consider a small example which would demonstrate using one or two commands say In my case i will use Label and gotoLabel command. Also I will use Bing search page as an example here. We will see how Flow Control extension can be used to navigate to Bing Explore page and then would redirect to MSN Homepage multiple times.
(Note: Likewise we can make use of other commands generated by the flow control logic wherever applicable.)
=========
IDE Script:
=========
HTML Code Format:
================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="https://87sixdevelop.seedconnect.org/" />
<title>New Test</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">New Test</td></tr>
</thead><tbody>
<tr>
<td>label</td>
<td>openBingSearch</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>https://www.bing.com/</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>link=Explore</td>
<td></td>
</tr>
<tr>
<td>storeText</td>
<td>css=div.TaskTitle > span</td>
<td>Actual_Title</td>
</tr>
<tr>
<td>echo</td>
<td>${Actual_Title}</td>
<td></td>
</tr>
<tr>
<td>store</td>
<td>Spotlight</td>
<td>Expected_Title</td>
</tr>
<tr>
<td>echo</td>
<td>${Expected_Title}</td>
<td></td>
</tr>
<tr>
<td>verifyEval</td>
<td>storedVars['Actual_Title']==storedVars['Expected_Title']</td>
<td>true</td>
</tr>
<tr>
<td>open</td>
<td>http://www.msn.com/en-in/</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>css=h2 > a</td>
<td></td>
</tr>
<tr>
<td>storeText</td>
<td>css=h2 > a</td>
<td>ActualLinktitleMSN</td>
</tr>
<tr>
<td>echo</td>
<td>${ActualLinktitleMSN}</td>
<td></td>
</tr>
<tr>
<td>store</td>
<td>Make MSN my homepage</td>
<td>ExpectedLinktitleMSN</td>
</tr>
<tr>
<td>echo</td>
<td>${ExpectedLinktitleMSN}</td>
<td></td>
</tr>
<tr>
<td>verifyEval</td>
<td>storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN']</td>
<td>true</td>
</tr>
<tr>
<td>gotoLabel</td>
<td>openBingSearch</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
================
Test Execution Log:
================
[info] Playing test case Demo_Loop_Control_Test
[info] Executing: |label | openBingSearch | |
[info] Executing: |open | https://www.bing.com/ | |
[info] Executing: |clickAndWait | link=Explore | |
[info] Executing: |storeText | css=div.TaskTitle > span | Actual_Title |
[info] Executing: |echo | ${Actual_Title} | |
[info] echo: Spotlight
[info] Executing: |store | Spotlight | Expected_Title |
[info] Executing: |echo | ${Expected_Title} | |
[info] echo: Spotlight
[info] Executing: |verifyEval | storedVars['Actual_Title']==storedVars['Expected_Title'] | true |
[info] script is: storedVars['Actual_Title']==storedVars['Expected_Title']
[info] Executing: |open | http://www.msn.com/en-in/ | |
[info] Executing: |waitForElementPresent | css=h2 > a | |
[info] Executing: |storeText | css=h2 > a | ActualLinktitleMSN |
[info] Executing: |echo | ${ActualLinktitleMSN} | |
[info] echo: Make MSN my homepage
[info] Executing: |store | Make MSN my homepage | ExpectedLinktitleMSN |
[info] Executing: |echo | ${ExpectedLinktitleMSN} | |
[info] echo: Make MSN my homepage
[info] Executing: |verifyEval | storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN'] | true |
[info] script is: storedVars['ActualLinktitleMSN']==storedVars['ExpectedLinktitleMSN']
[info] Executing: |gotoLabel | openBingSearch | |
[info] Executing: |open | https://www.bing.com/ | |
[info] Executing: |clickAndWait | link=Explore | |
[info] Executing: |storeText | css=div.TaskTitle > span | Actual_Title
...
...
==================
Test Summary Report:
==================
========================
Loop Control Logic Flow Code:
========================
var gotoLabels= {};
var whileLabels = {};
// overload the original Selenium reset function
Selenium.prototype.reset = function() {
// reset the labels
this.initialiseLabels();
// proceed with original reset code
this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
this.browserbot.selectWindow("null");
this.browserbot.resetPopups();
}
/*
* --- Initialize Conditional Elements --- *
* Run through the script collecting line numbers of all conditional elements
* There are three a results arrays: goto labels, while pairs and forEach pairs
*
*/
Selenium.prototype.initialiseLabels = function()
{
gotoLabels = {};
whileLabels = { ends: {}, whiles: {} };
var command_rows = [];
var numCommands = testCase.commands.length;
for (var i = 0; i < numCommands; ++i) {
var x = testCase.commands[i];
command_rows.push(x);
}
var cycles = [];
var forEachCmds = [];
for( var i = 0; i < command_rows.length; i++ ) {
if (command_rows[i].type == 'command')
switch( command_rows[i].command.toLowerCase() ) {
case "label":
gotoLabels[ command_rows[i].target ] = i;
break;
case "while":
case "endwhile":
cycles.push( [command_rows[i].command.toLowerCase(), i] )
break;
case "foreach":
case "endforeach":
forEachCmds.push( [command_rows[i].command.toLowerCase(), i] )
break;
}
}
var i = 0;
while( cycles.length ) {
if( i >= cycles.length ) {
throw new Error( "non-matching while/endWhile found" );
}
switch( cycles[i][0] ) {
case "while":
if( ( i+1 < cycles.length ) && ( "endwhile" == cycles[i+1][0] ) ) {
// pair found
whileLabels.ends[ cycles[i+1][1] ] = cycles[i][1];
whileLabels.whiles[ cycles[i][1] ] = cycles[i+1][1];
cycles.splice( i, 2 );
i = 0;
} else ++i;
break;
case "endwhile":
++i;
break;
}
}
}
Selenium.prototype.continueFromRow = function( row_num )
{
if(row_num == undefined || row_num == null || row_num < 0) {
throw new Error( "Invalid row_num specified." );
}
testCase.debugContext.debugIndex = row_num;
}
// do nothing. simple label
Selenium.prototype.doLabel = function(){};
Selenium.prototype.doGotoLabel = function( label )
{
if( undefined == gotoLabels[label] ) {
throw new Error( "Specified label '" + label + "' is not found." );
}
this.continueFromRow( gotoLabels[ label ] );
};
Selenium.prototype.doGoto = Selenium.prototype.doGotoLabel;
Selenium.prototype.doGotoIf = function( condition, label )
{
if( eval(condition) ) this.doGotoLabel( label );
}
Selenium.prototype.doWhile = function( condition )
{
if( !eval(condition) ) {
var last_row = testCase.debugContext.debugIndex;
var end_while_row = whileLabels.whiles[ last_row ];
if( undefined == end_while_row ) throw new Error( "Corresponding 'endWhile' is not found." );
this.continueFromRow( end_while_row );
}
}
Selenium.prototype.doEndWhile = function()
{
var last_row = testCase.debugContext.debugIndex;
var while_row = whileLabels.ends[ last_row ] - 1;
if( undefined == while_row ) throw new Error( "Corresponding 'While' is not found." );
this.continueFromRow( while_row );
}
Selenium.prototype.doPush= function(value, varName)
{
if(!storedVars[varName]) {
storedVars[varName] = new Array();
}
if(typeof storedVars[varName] !== 'object') {
throw new Error("Cannot push value onto non-array " + varName);
} else {
storedVars[varName].push(value);
}
}
Thanks,
Pinaki Mohapatra
No comments:
Post a Comment