Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the script to use OOP via Selenium's API and port it over to support the selenese target of the Maven Selenium Plugin #11

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
sideflow - a flow control extension for Selenium IDE
===
Lets you do goto and while loops in the Selenium IDE Firefox add-on as well as via the _selenese_ goal in the
Maven Selenium Plugin. This is a Selenium IDE compatible port of the flow control extension from
[http://wiki.openqa.org/display/SEL/flowControl](http://wiki.openqa.org/display/SEL/flowControl) which is the older
outdated version of [https://addons.mozilla.org/en-us/firefox/addon/flow-control/](https://addons.mozilla.org/en-us/firefox/addon/flow-control/).

Lets you do goto and while loops in the Selenium IDE Firefox add-on. This is a Selenium
IDE compatible port of the flow control extension from http://wiki.openqa.org/display/SEL/flowControl.

<img src="http://4.bp.blogspot.com/_Vi1folaOZAs/R7N1_L5KjDI/AAAAAAAAAGQ/PyozuVCHBC4/s400/flow_control_ide.png"></img>
![picture](http://4.bp.blogspot.com/_Vi1folaOZAs/R7N1_L5KjDI/AAAAAAAAAGQ/PyozuVCHBC4/s400/flow_control_ide.png")

Requirements
---
Selenium IDE v1.0.5 +
Selenium Maven Plugin v2.3 +

Install
---
- Get Selenium IDE for Firefox from http://seleniumhq.org
- Launch Selenium IDE from Firefox and open the options menu
- Add the sideflow.js file to the "Selenium Core extensions (user-extensions.js)" field
__Firefox Selenium IDE__

* Get Selenium IDE for Firefox from [http://www.SeleniumHQ.org/projects/ide/](http://www.SeleniumHQ.org/projects/ide/)
* Launch Selenium IDE from Firefox and open the _Options_ menu
* Add the sideflow.js file to the "Selenium Core extensions (user-extensions.js)" field

__Selenium Maven Plugin ( _selenese_ )__

* Install and configure your Selenium Maven Plugin in your POM
* Configure the plugin _userExtensions_ property
* Configure your execution to use the _selenese_ goal

Commands
---
Expand All @@ -28,14 +38,14 @@ Commands

Resources
---

- [Full Documentation](http://51elliot.blogspot.com/2008/02/selenium-ide-goto.html)
- Selenium HQ [SeleniumHQ](http://seleniumhq.org/)

Authors
---
- Andrey Yegorov - original flow control extension
- Darren DeRidder - Selenium IDE port
- Paul Bors - Selenium Maven Plugin port

License
---
Expand Down
290 changes: 188 additions & 102 deletions sideflow.js
Original file line number Diff line number Diff line change
@@ -1,126 +1,212 @@
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 SideFlowUtils = classCreate();
objectExtend(SideFlowUtils.prototype, {
testCase: null,
banner: "SideFlow",
initialize: function() { },
setTestCase: function(testCase) {
this.testCase = testCase;
},
getTestCase: function() {
return this.testCase;
},
getCommands: function() {
var seleniumCommands;
if(this.isIDE()) {
seleniumCommands = this.getTestCase().commands;
} else {
seleniumCommands = this.getTestCase().commandRows;
}
return seleniumCommands;
},
isIDE: function() {
return (Application.prototype != undefined);
},
formatMessage: function(msg, error) {
return this.banner + ((error) ? "[" + error.lineNumber + "] " : " ") + msg;
},
debug: function(msg, error) {
LOG.debug(this.formatMessage(msg, error));
},
info: function(msg, error) {
LOG.info(this.formatMessage(msg, error));
},
warn: function(msg, error) {
LOG.warn(this.formatMessage(msg, error));
},
error: function(msg, error) {
LOG.error(this.formatMessage(msg, error));
},
throwError: function(err, error) {
throw new SeleniumError(this.formatMessage(err, error));
}
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 SideFlow = classCreate();
objectExtend(SideFlow.prototype, {
gotoLabels: {},
whileLabels: { ends: {}, whiles: {} },
utils: null,
/*
* --- 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
*/
initialize: function(sideFlowUtils) {
this.utils = sideFlowUtils;
this.utils.debug("detected runtime = Selenium " + (this.utils.isIDE() ? "IDE" : "RC"), new Error());
if(this.utils.isIDE()) {
this.utils.setTestCase(testCase);
} else {
this.utils.setTestCase(testFrame.getCurrentTestCase());
}
}
var i = 0;
while( cycles.length ) {
if( i >= cycles.length ) {
throw new Error( "non-matching while/endWhile found" );
try {
var commands = this.utils.getCommands(),
command_rows = [],
cycles = [],
forEachCmds = [];
for(var i = 0; i < commands.length; ++i) {
command_rows.push(commands[i]);
}
for(var i = 0; i < command_rows.length; i++) {
if (this.utils.isIDE()) {
if((command_rows[i].type == 'command')) {
switch (command_rows[i].command.toLowerCase()) {
case "label":
this.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;
}
}
} else {
var command = command_rows[i].trElement.cells[0].innerHTML;
var target = command_rows[i].trElement.cells[1].innerHTML;
var value = command_rows[i].trElement.cells[2].innerHTML;
switch (command.toLowerCase()) {
case "label":
this.gotoLabels[ target ] = i;
break;
case "while":
case "endwhile":
cycles.push([command.toLowerCase(), i]);
break;
case "foreach":
case "endforeach":
forEachCmds.push([command.toLowerCase(), i]);
break;
}
}
}
} catch (err) {
this.utils.error(err, new Error());
this.utils.throwError(err, new Error());
}
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;
var i = 0;
while (cycles.length) {
if(i >= cycles.length) {
this.utils.throwError("non-matching while/endWhile found", new Error());
}
switch(cycles[i][0]) {
case "while":
if(( i + 1 < cycles.length ) && ( "endwhile" == cycles[i + 1][0] )) {
// pair found
this.whileLabels.ends[ cycles[i + 1][1] ] = cycles[i][1];
this.whileLabels.whiles[ cycles[i][1] ] = cycles[i + 1][1];
cycles.splice(i, 2);
i = 0;
} else {
++i;
}
break;
case "endwhile":
++i;
break;
}
}
},
continueFromRow: function (row_num) {
if((row_num == undefined) || (row_num == null) || (row_num < 0) || isNaN(row_num)) {
this.utils.throwError("Invalid row_num specified.", new Error());
}
if(this.utils.isIDE()) {
this.utils.getTestCase().debugContext.debugIndex = row_num;
} else {
this.utils.getTestCase().nextCommandRowIndex = row_num + 1;
}
}
});

}

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;
}
var sideFlow = null;
(function() {
// Proxy design pattern - Overwrite Selenium's reset() function and then invoke the original impl
var proxied = Selenium.prototype.reset;
Selenium.prototype.reset = function() {
sideFlow = new SideFlow(new SideFlowUtils());
proxied.apply( this, arguments );
};
})();

// do nothing. simple label
Selenium.prototype.doLabel = function(){};
Selenium.prototype.doLabel = function() { };

Selenium.prototype.doGotoLabel = function( label )
{
if( undefined == gotoLabels[label] ) {
throw new Error( "Specified label '" + label + "' is not found." );
Selenium.prototype.doGotoLabel = function(label) {
if(undefined == sideFlow.gotoLabels[label]) {
sideFlow.utils.throwError( "Specified label '" + label + "' is not found.", new Error() );
}
this.continueFromRow( gotoLabels[ label ] );
sideFlow.continueFromRow( sideFlow.gotoLabels[label] );
};

Selenium.prototype.doGoto = Selenium.prototype.doGotoLabel;

Selenium.prototype.doGotoIf = function( condition, label )
{
if( eval(condition) ) this.doGotoLabel( label );
}
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.doWhile = function(condition) {
if(!eval(condition)) {
var last_row;
if(sideFlow.utils.isIDE()) {
last_row = sideFlow.utils.getTestCase().debugContext.debugIndex;
} else {
last_row = sideFlow.utils.getTestCase().nextCommandRowIndex - 1;
}
var end_while_row = sideFlow.whileLabels.whiles[ last_row ];
if((undefined == end_while_row) || isNaN(end_while_row)) {
sideFlow.utils.throwError( "Corresponding 'endWhile' is not found.", new Error() );
}
sideFlow.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.doEndWhile = function() {
var last_row;
if(sideFlow.utils.isIDE()) {
last_row = sideFlow.utils.getTestCase().debugContext.debugIndex;
} else {
last_row = sideFlow.utils.getTestCase().nextCommandRowIndex - 1;
}
var while_row = sideFlow.whileLabels.ends[ last_row ] - 1;
if((undefined == while_row) || isNaN(while_row)) {
sideFlow.utils.throwError( "Corresponding 'While' is not found.", new Error() );
}
sideFlow.continueFromRow( while_row );
};

Selenium.prototype.doPush= function(value, varName)
{
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);
sideFlow.utils.throwError("Cannot push value onto non-array " + varName, new Error());
} else {
storedVars[varName].push(value);
}
}
};