Tuesday, 25 August 2015

Selenium IDE: Flow Control Logic Extension for IDE

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.


  1. The Loop control flow code is mentioned towards the end of this post.
  2. Copy and paste the code in an text editor and create a .js extension file.
  3. Open Selenium IDE and Navigate to Options > General tab.
  4. 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.)
  5. 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 &gt; 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 &gt; a</td>
<td></td>
</tr>
<tr>
<td>storeText</td>
<td>css=h2 &gt; 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

Tuesday, 18 August 2015

Selenium IDE: Extracting a number or value/text from a string or URL and store it in a variable.

This post will basically explain about how we can extract a number say an Object ID or Object Name from a string or absolute URL.

1. Extract object ID from an URL.

Let say we have a URL - https://www.testfoo.org/folder1/folderA1/?objectID=1251

Now from the Url - How we can extract the object ID i.e. 1251 and store it in a variable which we can call or use the same variable (ID) wherever required in our IDE script.

1. store | https://www.testfoo.org/folder1/folderA1/?objectID=1251 | string 
2. store | 1 | delimiter 
3. store | javascript{storedVars['string'].split('?objectID=')[storedVars['delimiter']]} | result 
4. echo | ${result}

Step 1: Store the URL i.e. "https://www.testfoo.org/folder1/folderA1/?objectID=1251" in a variable - "string".
Step 3: Javascript will extract or split the stored variable (string) after "?objectID=" and store the value (ID) in a new variable i.e. result
Step 4: Print the result. The result will be - 1251

HTML Code format:

<tr>
<tr>
    <td>store</td>
    <td>https://www.testfoo.org/folder1/folderA1/?objectID=1251</td>
    <td>string</td>
</tr>
<tr>
    <td>store</td>
    <td>1</td>
    <td>delimiter</td>
</tr>
<tr>
    <td>store</td>
    <td>javascript{storedVars['string'].split('?objectID=')[storedVars['delimiter']]}</td>
    <td>result</td>
</tr>
<tr>
    <td>echo</td>
    <td>${result}</td>
</tr>

OR

1. storeLocation | string
2. store | 1 | delimiter
3. store | javascript{storedVars['string'].split('?objectID=')[storedVars['delimiter']]} | result
4. echo | ${result}

Step 1: Store the current URL location i.e. "https://www.testfoo.org/folder1/folderA1/?objectID=1251" in a variable - "string".
Step 3: Javascript will extract or split the stored variable (string) after "?objectID=" and store the value (ID) in a new variable i.e. result
Step 4: Print the result. The result will be - 1251

HTML Code format:

<tr>
<tr>
    <td>storeLocation</td>
    <td>string</td>
</tr>
<tr>
    <td>store</td>
    <td>1</td>
    <td>delimiter</td>
</tr>
<tr>
    <td>store</td>
    <td>javascript{storedVars['string'].split('?objectID=')[storedVars['delimiter']]}</td>
    <td>result</td>
</tr>
<tr>
    <td>echo</td>
    <td>${result}</td>
</tr>

2. Extract part of a text say Object name using selenium IDE and store it into a variable.

Let say we have a string inside a div (HTML content). For Example; 

<div class="Title">Edit XXX Centre 1-457898, India</div>

And here we want to extract amd store "XXX Centre" in a variable. How can we do this through IDE ?

1. store | Edit XXX Centre 1-457898, India | Text
2. store | 1   | delimiter1
3. store | javascript{storedVars['text'].split('Edit ')[storedVars['delimiter1']]}|string1
4. echo  | ${string1}
5. store | 0 |  delimiter2
6. store | javascript{storedVars['string1'].split(' 1-457898')[storedVars['delimiter2']]} | string2
7. echo  | ${string1}

Result will be: XXX Centre

Step 1: Store the entire string i.e. "Edit XXX Centre 1-457898, India" in a variable - "Text".
Step 3: Javascript will extract or split the stored variable (Text) after "Edit " and store the rest content/string in a new variable i.e. string1
Step 4: Print the result. The result will be - XXX Centre 1-457898, India
Step 6: Javascript will extract or split the stored variable [string1 i.e. XXX Centre 1-457898, India] before " 1-457898" and store the rest content/string in a new variable 
i.e. string2
Step 7: Print the result. The result will be - XXX Centre

HTML Code format:

<tr>
<tr>
    <td>store</td>
    <td>Edit XXX Centre 1-457898, India</td>
    <td>Text</td>
</tr>
<tr>
    <td>store</td>
    <td>1</td>
    <td>delimiter1</td>
</tr>
<tr>
    <td>store</td>
    <td>javascript{storedVars['text'].split('Edit ')[storedVars['delimiter1']]}</td>
    <td>string1</td>
</tr>
<tr>
    <td>echo</td>
    <td>${string1}</td>
</tr>
<tr>
    <td>store</td>
    <td>0</td>
    <td>delimiter2</td>
</tr>
<tr>
    <td>store</td>
    <td>javascript{storedVars['string1'].split(' 1-457898')[storedVars['delimiter2']]}</td>
    <td>string2</td>
</tr>
<tr>
    <td>echo</td>
    <td>${string2}</td>
</tr>
<tr>

Thanks,
Pinaki Mohapatra

Thursday, 13 August 2015

Selenium IDE - How to add random data into text, large/small text area fields.

For adding dynamic data we need to add a .js extension file in selenium IDE (Selenium IDE > Options > Options).

Copy paste the below code and save it as .js extension file (userextension.js).

===============

Selenium.prototype.doRandomString = function( options, varName ) {

    var length = 8;
    var type   = 'alphanumeric';
    var o = options.split( '|' );
    for ( var i = 0 ; i < 2 ; i ++ ) {
        if ( o[i] && o[i].match( /^\d+$/ ) )
            length = o[i];

        if ( o[i] && o[i].match( /^(?:alpha)?(?:numeric)?$/ ) )
            type = o[i];
    }

    switch( type ) {
        case 'alpha'        : storedVars[ varName ] = randomAlpha( length ); break;
        case 'numeric'      : storedVars[ varName ] = randomNumeric( length ); break;
        case 'alphanumeric' : storedVars[ varName ] = randomAlphaNumeric( length ); break;
        default             : storedVars[ varName ] = randomAlphaNumeric( length );
    };
};

function randomNumeric ( length ) {
    return generateRandomString( length, '0123456789'.split( '' ) );
}

function randomAlpha ( length ) {
    var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split( '' );
    return generateRandomString( length, alpha );
}

function randomAlphaNumeric ( length ) {
    var alphanumeric = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split( '' );
    return generateRandomString( length, alphanumeric );
}

function generateRandomString( length, chars ) {
    var string = '';
    for ( var i = 0 ; i < length ; i++ )
        string += chars[ Math.floor( Math.random() * chars.length ) ];
    return string;
}

==================

In Selenium IDE, enter

Command             Target             Value

randomString          6                Firstname
echo                ${Firstname}
type                   id=fname       ${Firstname}

==================

Scenario - Let say we want to create a new user profile and in firstname & lastname field we want to enter some random dynamic data.

Step 1: Copy paste the above code and save as .js extension file and add the javascript file to IDE (Selenium IDE > Options > Options > Selenium core extension). Restart your IDE.

Step 2: Add command

Command                  Target              Value
randomString                 6               Firstname
echo                       ${Firstname}
type                          id=fname        ${Fname}
randomString                 6                Lastname
echo                        ${Lastname}
type                           id=lname        ${Lname}
click                          id=submit

Once the user is added, for verification we can use;

Command                    Target                               Value

store                     ${Fname} ${Lname}             username
echo                          ${username}
verifyText           enter: id/css/xpath/dom      ${Fname} ${Lname}

OR    

verifyText           enter: id/css/xpath/dom            ${username}

=========
Incase of a drop down list,
=========
select                  enter: id/css/xpath/dom        ${Fname} ${Lname}
verifyselectedlabel    enter: id/css/xpath/dom        ${Fname} ${Lname}

OR    

select            enter: id/css/xpath/dom        ${username}
verifyselectedlabel    enter: id/css/xpath/dom        ${username}

===========

HTML Code Format

<tr>
    <td>randomString</td>
    <td>6</td>
    <td>Firstname</td>
</tr>
<tr>
    <td>echo</td>
    <td>${Firstname}</td>
</tr>
<tr>
    <td>randomString</td>
    <td>6</td>
    <td>Lastname</td>
</tr>
<tr>
    <td>echo</td>
    <td>${Lastname}</td>
</tr>
<tr>
    <td>Type</td>
    <td>id=fname</td>
    <td>${Fname}</td>
</tr>
<tr>
    <td>Type</td>
    <td>id=lname</td>
    <td>${Lname}</td>
</tr>
<tr>
    <td>click</td>
    <td>id=submit</td>
</tr>
<tr>
    <td>store</td>
    <td>${Fname} ${Lname}</td>
    <td>username</td>
</tr>
<tr>
    <td>echo</td>
    <td>${username}</td>
</tr>
<tr>
    <td>verifyText</td>
    <td>name=title</td>
    <td>${username}</td>
</tr>
<tr>
    <td>select</td>
    <td>id=username</td>
    <td>${username}</td>
</tr>
<tr>
    <td>verifyselectedlabel</td>
    <td>id=username</td>
    <td>${username}</td>
</tr>


Thanks,
Pinaki Mohapatra