[Zope-CVS] CVS: Products/Zelenium/selenium - domviewer.html:1.1
selenium-domviewer.js:1.1 selenium-executioncontext.js:1.1
selenium-logging.js:1.1 selenium-tableparser.js:1.1
xmlextras.js:1.1 htmlutils.js:1.2 selenium-api.js:1.2
selenium-browserbot.js:1.2 selenium-commandhandlers.js:1.2
selenium-executionloop.js:1.2 selenium-fitrunner.js:1.2
selenium.css:1.2
Tres Seaver
tseaver at zope.com
Mon May 2 23:48:47 EDT 2005
Update of /cvs-repository/Products/Zelenium/selenium
In directory cvs.zope.org:/tmp/cvs-serv12572/selenium
Modified Files:
htmlutils.js selenium-api.js selenium-browserbot.js
selenium-commandhandlers.js selenium-executionloop.js
selenium-fitrunner.js selenium.css
Added Files:
domviewer.html selenium-domviewer.js
selenium-executioncontext.js selenium-logging.js
selenium-tableparser.js xmlextras.js
Log Message:
- Pick up support files from Selenium 0.3.
=== Added File Products/Zelenium/selenium/domviewer.html ===
<!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>
<title>DOM Viewer</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link href="/styles/default.css" rel="dom-styles/stylesheet"
type="text/css" />
<script type="text/javascript" src="selenium-domviewer.js" />
</head>
<body onload="loadDomViewer();">
<h3>DOM Viewer</h3>
<p> This page is generated using JavaScript. If you see this text, your
browser doesn't support JavaScript.</p>
</body>
</html>
=== Added File Products/Zelenium/selenium/selenium-domviewer.js ===
var HIDDEN="hidden";
var LEVEL = "level";
var PLUS_SRC="dom-images/butplus.gif"
var MIN_SRC="dom-images/butmin.gif"
var newRoot;
var maxColumns=1;
function loadDomViewer(){
if(window.opener != null){
//Open in a new window.
// Start with specified root object.
// It should be defined as a "newRoot" variable
// in the tested page. Could be any element in
// the DOM structure of the page that opened it.
// Default to document if no object is specified.
newRoot = window.opener.newRoot;
if (newRoot==null)
newRoot = window.opener.document;
document.writeln(displayDOM(newRoot));
document.close();
}else{
newRoot = parent.document.all['myiframe'].contentWindow.document;
newRoot.writeln(displayDOM(newRoot));
newRoot.close();
}
}
function displayDOM(root){
var str = "<html><head><title>DOM Viewerr</title><script type='text/javascript' src='domviewer.js'><!-- comments --> </script><link href='dom-styles/default.css' rel='stylesheet' type='text/css' /></head><body>";
str+="<table>";
str += treeTraversal(root,0);
// to make table columns work well.
str += "<tr>";
for (var i=0; i < maxColumns; i++) {
str+= "<td> </td>";
}
str += "</tr>";
str += "</table></body></html>";
return str;
}
function checkForChildren(element){
if(!element.hasChildNodes())
return false;
var nodes = element.childNodes;
var size = nodes.length;
var count=0;
for(var i=0; i< size; i++){
var node = nodes.item(i);
//if(node.toString()=="[object Text]"){
//this is equalent to the above
//but will work with more browsers
if(node.nodeType!=1){
count++;
}
}
if(count == size)
return false;
else
return true;
}
function treeTraversal(root, level){
var str = "";
var nodes= null;
var size = null;
//it is supposed to show the last node,
//but the last node is always nodeText type
//and we don't show it
if(!root.hasChildNodes())
return "";//displayNode(root,level,false);
nodes = root.childNodes;
size = nodes.length;
for(var i=0; i< size; i++){
var element = nodes.item(i);
//if the node is textNode, don't display
if(element.nodeType==1){
str+= displayNode(element,level,checkForChildren(element));
str+=treeTraversal(element, level+1);
}
}
return str;
}
function displayNode(element, level, isLink){
nodeContent = getNodeContent(element);
columns = Math.round((nodeContent.length / 12) + 0.5);
if (columns + level > maxColumns) {
maxColumns = columns + level;
}
var str ="<tr class='"+LEVEL+level+"'>";
for (var i=0; i < level; i++)
str+= "<td> </td>";
str+="<td colspan='"+ columns +"' class='box"+" boxlevel"+level+"' >";
if(isLink){
str+='<a onclick="hide(this);" href="javascript:void(this);">';
str+='<img src="'+MIN_SRC+'" />';
}
str += nodeContent;
if(isLink)
str+="</a></td></tr>";
return str;
}
function getNodeContent(element) {
str = "";
id ="";
if (element.id != null && element.id != "") {
id = " ID(" + element.id +")";
}
name ="";
if (element.name != null && element.name != "") {
name = " NAME(" + element.name + ")";
}
value ="";
if (element.value != null && element.value != "") {
value = " VALUE(" + element.value + ")";
}
href ="";
if (element.href != null && element.href != "") {
href = " HREF(" + element.href + ")";
}
text ="";
if (element.text != null && element.text != "" && element.text != "undefined") {
text = " #TEXT(" + trim(element.text) +")";
}
str+=" <b>"+ element.nodeName + id + name + value + href + text + "</b>";
return str;
}
function trim(val) {
val2 = val.substring(0,20) + " ";
var spaceChr = String.fromCharCode(32);
var length = val2.length;
var retVal = "";
var ix = length -1;
while(ix > -1){
if(val2.charAt(ix) == spaceChr) {
} else {
retVal = val2.substring(0, ix +1);
break;
}
ix = ix-1;
}
if (val.length > 20) {
retVal += "...";
}
return retVal;
}
function hide(hlink){
var isHidden = false;
var image = hlink.firstChild;
if(image.src.toString().indexOf(MIN_SRC)!=-1){
image.src=PLUS_SRC;
isHidden=true;
}else{
image.src=MIN_SRC;
}
var rowObj= hlink.parentNode.parentNode;
var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));
var sibling = rowObj.nextSibling;
var siblingLevel = sibling.className.substring(LEVEL.length);
if(siblingLevel.indexOf(HIDDEN)!=-1){
siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
}
siblingLevel=parseInt(siblingLevel);
while(sibling!=null && rowLevel<siblingLevel){
if(isHidden){
sibling.className += " "+ HIDDEN;
}else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
var str = sibling.className;
sibling.className=str.substring(0, str.length - HIDDEN.length-1);
}
sibling = sibling.nextSibling;
siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
}
}
=== Added File Products/Zelenium/selenium/selenium-executioncontext.js ===
/*
* Copyright 2004 ThoughtWorks, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
function IFrameExecutionContext() {
this.loadFrame = function() {
return document.getElementById('myiframe');
};
this.open = function(target,frame) {
frame.src = target;
};
this.getContentWindow = function(frame) {
return frame.contentWindow;
};
this.waitForPageLoad = function(testloop,selenium) {
// Since we're waiting for page to reload, we can't continue command execution
// directly, we need use a page load listener.
// TODO there is a potential race condition by attaching a load listener after
// the command has completed execution.
selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay()");});
};
}
function KonquerorIFrameExecutionContext() {
this.loadFrame = function() {
return document.getElementById('myiframe');
};
this.open = function(target, frame) {
// Window doesn't fire onload event when setting src to the current value,
// so we set it to blank first.
frame.src = "about:blank";
frame.src = target;
};
this.getContentWindow = function(frame) {
return frames['myiframe'];
};
this.waitForPageLoad = function(testloop,selenium) {
// Since we're waiting for page to reload, we can't continue command execution
// directly, we need use a page load listener.
// TODO there is a potential race condition by attaching a load listener after
// the command has completed execution.
selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay()");});
};
}
var windowExecutionContext;
function getWindowExecutionContext() {
if (windowExecutionContext == null) {
windowExecutionContext = new WindowExecutionContext();
}
return windowExecutionContext;
}
function WindowExecutionContext() {
this.externalWindow = null;
this.loadFrame = function() {
var newWindow = window.open("about:blank", "_blank", "toolbar=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=1024,height=740,left=250,top=250");
newWindow.opener = window.frame;
this.externalWindow = newWindow;
return this.externalWindow;
};
this.open = function(target,frame) {
frame.location = target;
};
this.getContentWindow = function(frame) {
return frame;
};
this.waitForPageLoad = function(testloop,selenium) {
if(window.addEventListener) {
selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay();");});
} else {
if(this.externalWindow != null) {
if(this.getValueWhenReady() != "complete" ) {
var localContext = this;
var localLoop = testloop;
var localSelenium = selenium;
window.setTimeout(function() {localContext.waitForPageLoad(localLoop, localSelenium); }, 100 );
} else {
testloop.continueCommandExecutionWithDelay();
}
}
}
};
// this function became necessary for IE in a NEW WINDOW. the document.readyState was not ready to be accessed.
this.getValueWhenReady = function() {
while (true) {
try {
return this.externalWindow.document.readyState;
} catch (x) {
}
}
};
}
=== Added File Products/Zelenium/selenium/selenium-logging.js ===
/*
* Copyright 2004 ThoughtWorks, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var LEVEL_DEBUG = 0;
var LEVEL_INFO = 1;
var LEVEL_WARN = 2;
var LEVEL_ERROR = 3;
function Logger(logLevel) {
this.level = logLevel;
this.logConsole = document.getElementById('logging-console');
this.logList = document.getElementById('log-list');
this.hide();
}
Logger.prototype.show = function() {
this.logConsole.style.display = "";
};
Logger.prototype.hide = function() {
this.logConsole.style.display = "none";
};
Logger.prototype.clear = function() {
while (this.logList.hasChildNodes()) {
this.logList.removeChild(this.logList.firstChild);
}
};
Logger.prototype.debug = function(message) {
if (this.level <= LEVEL_DEBUG) {
this.log(message, "debug");
}
};
Logger.prototype.info = function(message) {
if (this.level <= LEVEL_INFO) {
this.log(message, "info");
}
};
Logger.prototype.warn = function(message) {
if (this.level <= LEVEL_WARN) {
this.log(message, "warn");
}
};
Logger.prototype.error = function(message) {
if (this.level <= LEVEL_ERROR) {
this.log(message, "error");
}
};
Logger.prototype.log = function(message, className) {
var loggingNode = document.createElement('li');
loggingNode.className = className;
loggingNode.appendChild(document.createTextNode(message));
this.logList.appendChild(loggingNode);
this.show();
};
=== Added File Products/Zelenium/selenium/selenium-tableparser.js ===
/*
* Copyright 2004 ThoughtWorks, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
TableParser = function(wikiTableRows) {
this.wikiTableRows = wikiTableRows;
};
// Parses a Wiki table row into a SeleniumB Javascript expression
TableParser.prototype.createCommandFromWikiRow = function(wikiRow) {
var tokens;
if(tokens = wikiRow.trim().match(/^\|([^\|]*)\|([^\|]*)\|([^\|]*)\|$/m)) {
var functionName = tokens[1].trim();
var arg1 = tokens[2].trim();
var arg2 = tokens[3].trim();
return new SeleniumCommand(functionName, arg1, arg2);
} else {
throw new Error("Bad wiki row format:" + wikiRow);
}
};
// Parses a HTML table row into a SeleniumB Javascript expression
TableParser.prototype.createCommandFromHtmlRow = function(row) {
if(row.cells.length != 3) {
throw new Error("Bad HTML row format. Rows must have 3 coumns, but had " + row.cells.length);
}
var functionName = getText(row.cells[0]);
var arg1 = getText(row.cells[1]);
var arg2 = getText(row.cells[2]);
return new SeleniumCommand(functionName, arg1, arg2);
};
TableParser.prototype.loop = function() {
row = this.wikiTableRows.getRow();
if (row == null) return null;
return this.createCommandForRow(row);
};
=== Added File Products/Zelenium/selenium/xmlextras.js ===
// This is a third party JavaScript library from
// http://webfx.eae.net/dhtml/xmlextras/xmlextras.html
// i.e. This has not been written by ThoughtWorks.
//<script>
//////////////////
// Helper Stuff //
//////////////////
// used to find the Automation server name
function getDomDocumentPrefix() {
if (getDomDocumentPrefix.prefix)
return getDomDocumentPrefix.prefix;
var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
var o;
for (var i = 0; i < prefixes.length; i++) {
try {
// try to create the objects
o = new ActiveXObject(prefixes[i] + ".DomDocument");
return getDomDocumentPrefix.prefix = prefixes[i];
}
catch (ex) {};
}
throw new Error("Could not find an installed XML parser");
}
function getXmlHttpPrefix() {
if (getXmlHttpPrefix.prefix)
return getXmlHttpPrefix.prefix;
var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
var o;
for (var i = 0; i < prefixes.length; i++) {
try {
// try to create the objects
o = new ActiveXObject(prefixes[i] + ".XmlHttp");
return getXmlHttpPrefix.prefix = prefixes[i];
}
catch (ex) {};
}
throw new Error("Could not find an installed XML parser");
}
//////////////////////////
// Start the Real stuff //
//////////////////////////
// XmlHttp factory
function XmlHttp() {}
XmlHttp.create = function () {
try {
if (window.XMLHttpRequest) {
var req = new XMLHttpRequest();
// some versions of Moz do not support the readyState property
// and the onreadystate event so we patch it!
if (req.readyState == null) {
req.readyState = 1;
req.addEventListener("load", function () {
req.readyState = 4;
if (typeof req.onreadystatechange == "function")
req.onreadystatechange();
}, false);
}
return req;
}
if (window.ActiveXObject) {
return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
}
}
catch (ex) {}
// fell through
throw new Error("Your browser does not support XmlHttp objects");
};
// XmlDocument factory
function XmlDocument() {}
XmlDocument.create = function () {
try {
// DOM2
if (document.implementation && document.implementation.createDocument) {
var doc = document.implementation.createDocument("", "", null);
// some versions of Moz do not support the readyState property
// and the onreadystate event so we patch it!
if (doc.readyState == null) {
doc.readyState = 1;
doc.addEventListener("load", function () {
doc.readyState = 4;
if (typeof doc.onreadystatechange == "function")
doc.onreadystatechange();
}, false);
}
return doc;
}
if (window.ActiveXObject)
return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
}
catch (ex) {}
throw new Error("Your browser does not support XmlDocument objects");
};
// Create the loadXML method and xml getter for Mozilla
if (window.DOMParser &&
window.XMLSerializer &&
window.Node && Node.prototype && Node.prototype.__defineGetter__) {
// XMLDocument did not extend the Document interface in some versions
// of Mozilla. Extend both!
//XMLDocument.prototype.loadXML =
Document.prototype.loadXML = function (s) {
// parse the string to a new doc
var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
// remove all initial children
while (this.hasChildNodes())
this.removeChild(this.lastChild);
// insert and import nodes
for (var i = 0; i < doc2.childNodes.length; i++) {
this.appendChild(this.importNode(doc2.childNodes[i], true));
}
};
/*
* xml getter
*
* This serializes the DOM tree to an XML String
*
* Usage: var sXml = oNode.xml
*
*/
// XMLDocument did not extend the Document interface in some versions
// of Mozilla. Extend both!
/*
XMLDocument.prototype.__defineGetter__("xml", function () {
return (new XMLSerializer()).serializeToString(this);
});
*/
Document.prototype.__defineGetter__("xml", function () {
return (new XMLSerializer()).serializeToString(this);
});
}
=== Products/Zelenium/selenium/htmlutils.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/htmlutils.js:1.1.1.1 Fri Apr 15 14:48:44 2005
+++ Products/Zelenium/selenium/htmlutils.js Mon May 2 23:48:16 2005
@@ -1,122 +1,127 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// This script contains some HTML utility functions that
-// make it possible to handle elements in a way that is
-// compatible with both IE-like and Mozilla-like browsers
-
-function trim() {
- var result = this.replace( /^\s+/g, "" );// strip leading
- return result.replace( /\s+$/g, "" );// strip trailing
-}
-String.prototype.trim = trim;
-
-function toCamelCase() {
- return this.charAt(0).toLowerCase() + this.substr(1);
-}
-String.prototype.toCamelCase = toCamelCase;
-
-// Returns the text in this element
-function getText(element) {
- text = "";
-
- if(element.textContent) {
- text = element.textContent;
- } else if(element.innerText) {
- text = element.innerText;
- }
- return text.trim();
-}
-
-// Sets the text in this element
-function setText(element, text) {
- if(element.textContent) {
- element.textContent = text;
- } else if(element.innerText) {
- element.innerText = text;
- }
-}
-
-// Get the value of an <input> element
-function getInputValue(inputElement) {
- if (inputElement.type.toUpperCase() == 'CHECKBOX' ||
- inputElement.type.toUpperCase() == 'RADIO')
- {
- return (inputElement.checked ? 'on' : 'off');
- }
- return inputElement.value;
-}
-
-/* Fire an event in a browser-compatible manner */
-function triggerEvent(element, eventType, canBubble) {
- canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
- if (element.fireEvent) {
- element.fireEvent('on' + eventType);
- }
- else {
- var evt = document.createEvent('HTMLEvents');
- evt.initEvent(eventType, canBubble, true);
- element.dispatchEvent(evt);
- }
-}
-
-/* Fire a mouse event in a browser-compatible manner */
-function triggerMouseEvent(element, eventType, canBubble) {
- canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
- if (element.fireEvent) {
- element.fireEvent('on' + eventType);
- }
- else {
- var evt = document.createEvent('MouseEvents');
- evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
- element.dispatchEvent(evt);
- }
-}
-
-function removeLoadListener(element, command) {
- if (window.removeEventListener)
- element.removeEventListener("load", command, true);
- else if (window.detachEvent)
- element.detachEvent("onload", command);
-}
-
-function addLoadListener(element, command) {
- if (window.addEventListener)
- element.addEventListener("load",command, true);
- else if (window.attachEvent)
- element.attachEvent("onload",command);
-}
-
-/**
- * Override the broken getFunctionName() method from JsUnit
- * This file must be loaded _after_ the jsunitCore.js
- */
-function getFunctionName(aFunction) {
- var regexpResult = aFunction.toString().match(/function (\w*)/);
- if (regexpResult && regexpResult[1]) {
- return regexpResult[1];
- }
- return 'anonymous';
-}
-
-function describe(object) {
- var props = new Array();
- for (var prop in object) {
- props.push(prop);
- }
- return props.join('\n');
-}
+/*
+ * Copyright 2004 ThoughtWorks, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// This script contains some HTML utility functions that
+// make it possible to handle elements in a way that is
+// compatible with both IE-like and Mozilla-like browsers
+
+function trim() {
+ var result = this.replace( /^\s+/g, "" );// strip leading
+ return result.replace( /\s+$/g, "" );// strip trailing
+}
+String.prototype.trim = trim;
+
+function toCamelCase() {
+ return this.charAt(0).toLowerCase() + this.substr(1);
+}
+String.prototype.toCamelCase = toCamelCase;
+
+function startsWith(str) {
+ return this.indexOf(str) == 0;
+}
+String.prototype.startsWith = startsWith;
+
+// Returns the text in this element
+function getText(element) {
+ text = "";
+
+ if(element.textContent) {
+ text = element.textContent;
+ } else if(element.innerText) {
+ text = element.innerText;
+ }
+ return text.trim();
+}
+
+// Sets the text in this element
+function setText(element, text) {
+ if(element.textContent) {
+ element.textContent = text;
+ } else if(element.innerText) {
+ element.innerText = text;
+ }
+}
+
+// Get the value of an <input> element
+function getInputValue(inputElement) {
+ if (inputElement.type.toUpperCase() == 'CHECKBOX' ||
+ inputElement.type.toUpperCase() == 'RADIO')
+ {
+ return (inputElement.checked ? 'on' : 'off');
+ }
+ return inputElement.value;
+}
+
+/* Fire an event in a browser-compatible manner */
+function triggerEvent(element, eventType, canBubble) {
+ canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+ if (element.fireEvent) {
+ element.fireEvent('on' + eventType);
+ }
+ else {
+ var evt = document.createEvent('HTMLEvents');
+ evt.initEvent(eventType, canBubble, true);
+ element.dispatchEvent(evt);
+ }
+}
+
+/* Fire a mouse event in a browser-compatible manner */
+function triggerMouseEvent(element, eventType, canBubble) {
+ canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+ if (element.fireEvent) {
+ element.fireEvent('on' + eventType);
+ }
+ else {
+ var evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+ element.dispatchEvent(evt);
+ }
+}
+
+function removeLoadListener(element, command) {
+ if (window.removeEventListener)
+ element.removeEventListener("load", command, true);
+ else if (window.detachEvent)
+ element.detachEvent("onload", command);
+}
+
+function addLoadListener(element, command) {
+ if (window.addEventListener)
+ element.addEventListener("load",command, true);
+ else if (window.attachEvent)
+ element.attachEvent("onload",command);
+}
+
+/**
+ * Override the broken getFunctionName() method from JsUnit
+ * This file must be loaded _after_ the jsunitCore.js
+ */
+function getFunctionName(aFunction) {
+ var regexpResult = aFunction.toString().match(/function (\w*)/);
+ if (regexpResult && regexpResult[1]) {
+ return regexpResult[1];
+ }
+ return 'anonymous';
+}
+
+function describe(object) {
+ var props = new Array();
+ for (var prop in object) {
+ props.push(prop + " -> " + object[prop]);
+ }
+ return props.join('\n');
+}
=== Products/Zelenium/selenium/selenium-api.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-api.js:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-api.js Mon May 2 23:48:16 2005
@@ -1,265 +1,501 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-function Selenium(browserbot) {
- this.browserbot = browserbot;
- this.page = function() {return browserbot.getCurrentPage()};
-
- var self = this;
- this.callOnNextPageLoad = function(callback) {
- if (callback) {
- self.browserbot.callOnNextPageLoad(callback);
- }
- }
-}
-
-/*
- * Click on the located element, and attach a callback to notify
- * when the page is reloaded.
- */
-Selenium.prototype.doClick = function(locator) {
- var element = this.page().findElement(locator);
- this.page().clickElement(element);
-}
-
-/**
- * Overwrite the text in the located text element.
- * TODO fail if it can't be typed into.
- */
-Selenium.prototype.doType = function(locator, newText) {
- var element = this.page().findElement(locator);
- this.page().replaceText(element, newText);
-}
-
-/**
- * Select the option by label from the located select element.
- * TODO fail if it's not a select.
- */
-Selenium.prototype.doSelect = function(locator, optionText) {
- var element = this.page().findElement(locator);
- this.page().selectOptionWithLabel(element, optionText);
-}
-
-/*
- * Open the browser to a new location.
- */
-Selenium.prototype.doOpen = function(newLocation) {
- this.browserbot.openLocation(newLocation);
- return SELENIUM_PROCESS_WAIT;
-}
-
-/*
- * Select the named window to be the active window.
- */
-Selenium.prototype.doSelectWindow = function(windowName) {
- this.browserbot.selectWindow(windowName);
-}
-
-/*
- * Instruct Selenium to click Cancel on the next confirm dialog it encounters
- */
-Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
- this.browserbot.cancelNextConfirmation();
-}
-
-/*
- * Asserts that the supplied message was received as an alert
- */
- Selenium.prototype.assertAlert = function(expectedAlert) {
- if ( this.browserbot.hasAlerts()) {
-
- receivedAlert = this.browserbot.getNextAlert();
- if ( receivedAlert != expectedAlert ) {
- fail("The alert was [" + receivedAlert + "]");
- }
-
- } else {
- fail("There were no alerts");
- }
- }
-
- /*
- * Asserts that the supplied message was received as a confirmation
- */
- Selenium.prototype.assertConfirmation = function(expectedConfirmation) {
- if ( this.browserbot.hasConfirmations()) {
-
- receivedConfirmation = this.browserbot.getNextConfirmation();
- if ( receivedConfirmation != expectedConfirmation ) {
- fail("The confirmation message was [" + receivedConfirmation + "]");
- }
-
- } else {
- fail("There were no confirmations");
- }
- }
-
-/*
- * Verify the location of the current page.
- */
-Selenium.prototype.assertLocation = function(expectedLocation) {
- assertEquals(expectedLocation, this.page().location);
-}
-
-/*
- * Verify the title of the current page.
- */
-Selenium.prototype.assertTitle = function(expectedTitle) {
- assertEquals(expectedTitle, this.page().title());
-}
-
-/*
- * Verify the value of a form element.
- */
-Selenium.prototype.assertValue = function(locator, expectedValue) {
- var element = this.page().findElement(locator);
- var actualValue = getInputValue(element);
- assertEquals(expectedValue, actualValue.trim());
-}
-
-/*
- * Verifies that the entire text of the page matches the expected content.
- */
-Selenium.prototype.assertText = function(locator, expectedContent) {
- var element = this.page().findElement(locator);
- var actualText = getText(element);
- assertEquals(expectedContent, actualText.trim());
-}
-
-/*
- * Asserts that the text for a single cell within and HTML table matches the expected content.
- * The table locator syntax is table.row.column.
- */
-Selenium.prototype.assertTable = function(tableLocator, expectedContent) {
- // This regular expression matches "tableName.row.column"
- // For example, "mytable.3.4"
- pattern = /(.*)\.(\d)+\.(\d+)/
-
- if(!pattern.test(tableLocator)) {
- error("Invalid target format. Correct format is tableName.rowNum.columnNum");
- }
-
- pieces = tableLocator.match(pattern);
-
- tableName = pieces[1];
- row = pieces[2];
- col = pieces[3];
-
- var table = this.page().findElement(tableName);
- if (row > table.rows.length || col > table.rows[row].cells.length)
- fail("No such row or column in table");
- else {
- actualContent = getText(table.rows[row].cells[col]);
- assertEquals(expectedContent, actualContent.trim());
- }
-}
-
-/**
- * Verify the label of the option that is selected.
- */
-Selenium.prototype.assertSelected = function(target, expectedLabel) {
- var element = this.page().findElement(target);
- var selectedLabel = element.options[element.selectedIndex].text;
- assertEquals(expectedLabel, selectedLabel);
-}
-
-/**
- * Verify the label of all of the options in the drop=down.
- */
-Selenium.prototype.assertSelectOptions = function(target, options) {
- // Handle escpaced commas, by substitutine newlines.
- options = options.replace("\\,", "\n");
- var expectedOptions = options.split(",");
- var element = this.page().findElement(target);
-
- assertEquals("wrong number of options", expectedOptions.length, element.options.length);
-
- for (var i = 0; i < element.options.length; i++) {
- var option = element.options[i];
- // Put the escaped commas back in.
- var expectedOption = expectedOptions[i].replace("\n", ",");
- assertEquals(expectedOption, option.text);
- }
-}
-
-/**
- * Verify the value of an element attribute. The syntax for returning an element attribute
- * is <element-locator>@attribute-name
- */
-Selenium.prototype.assertAttribute = function(target, expected) {
- var attributeValue = this.page().findAttribute(target);
- assertEquals(expected, attributeValue);
-}
-
-/*
- * Asserts that the specified text is present in the page content.
- */
-Selenium.prototype.assertTextPresent = function(expectedText) {
- var allText = this.page().bodyText();
-
- if(allText == "") {
- error("Page text not found")
- } else if(allText.indexOf(expectedText) == -1) {
- fail("'" + expectedText + "' not found in page text.");
- }
-}
-
-/*
- * Asserts that the specified element can be found.
- */
-Selenium.prototype.assertElementPresent = function(locator) {
- try {
- this.page().findElement(locator);
- } catch (e) {
- fail("Element " + locator + " not found.");
- }
-}
-
-/*
- * Asserts that the specified element cannot be found.
- */
-Selenium.prototype.assertElementNotPresent = function(locator) {
- try {
- this.page().findElement(locator);
- }
- catch (e) {
- return;
- }
- fail("Element " + locator + " found.");
-}
-
-
- /*
- * Return all buttons on the screen.
- */
-Selenium.prototype.getAllButtons = function() {
- return this.page().getAllButtons();
-}
-
- /*
- * Return all links on the screen.
- */
-Selenium.prototype.getAllLinks = function() {
- return this.page().getAllLinks();
-}
-
- /*
- * Return all fields on the screen.
- */
-Selenium.prototype.getAllFields = function() {
- return this.page().getAllFields();
-}
\ No newline at end of file
+/*
+ * Copyright 2004 ThoughtWorks, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+var nextExecution;
+function executeNext() {
+ LOG.debug("CODED - LOAD");
+ if (nextExecution) {
+ nextExecution();
+ }
+ nextExecution = null;
+}
+
+var assert = new Assert();
+function Selenium(browserbot) {
+ this.browserbot = browserbot;
+ this.page = function() {
+ return browserbot.getCurrentPage();
+ };
+
+ var self = this;
+
+ this.callOnNextPageLoad = function(callback) {
+ nextExecution = callback;
+ self.browserbot.callOnNextPageLoad(executeNext);
+ };
+}
+
+/*
+ * Click on the located element, and attach a callback to notify
+ * when the page is reloaded.
+ */
+Selenium.prototype.doModalDialogTest = function(returnValue) {
+ this.browserbot.doModalDialogTest(returnValue);
+};
+
+/*
+ * Click on the located element, and attach a callback to notify
+ * when the page is reloaded.
+ */
+Selenium.prototype.doClick = function(locator) {
+ var element = this.page().findElement(locator);
+ this.page().clickElement(element);
+};
+
+/**
+ * Overwrite the text in the located text element.
+ * TODO fail if it can't be typed into.
+ */
+Selenium.prototype.doType = function(locator, newText) {
+ var element = this.page().findElement(locator);
+ this.page().replaceText(element, newText);
+};
+
+/**
+ * Select the option by label from the located select element.
+ * TODO fail if it's not a select.
+ */
+Selenium.prototype.doSelect = function(locator, optionText) {
+ var element = this.page().findElement(locator);
+ this.page().selectOptionWithLabel(element, optionText);
+};
+
+/*
+ * Open the browser to a new location.
+ */
+Selenium.prototype.doOpen = function(newLocation) {
+ this.browserbot.openLocation(newLocation);
+ return SELENIUM_PROCESS_WAIT;
+};
+
+/*
+ * Select the named window to be the active window.
+ */
+Selenium.prototype.doSelectWindow = function(windowName) {
+ this.browserbot.selectWindow(windowName);
+};
+
+/*
+ * Instruct Selenium to click Cancel on the next confirm dialog it encounters
+ */
+Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
+ this.browserbot.cancelNextConfirmation();
+};
+
+/*
+ * Simulate the browser back button
+ */
+Selenium.prototype.doGoBack = function() {
+ this.page().goBack();
+};
+
+/*
+ * Asserts that the supplied message was received as an alert
+ */
+ Selenium.prototype.assertAlert = function(expectedAlert) {
+ if ( this.browserbot.hasAlerts()) {
+
+ receivedAlert = this.browserbot.getNextAlert();
+ if ( receivedAlert != expectedAlert ) {
+ assert.fail("The alert was [" + receivedAlert + "]");
+ }
+
+ } else {
+ assert.fail("There were no alerts");
+ }
+ };
+
+ /*
+ * Asserts that the supplied message was received as a confirmation
+ */
+ Selenium.prototype.assertConfirmation = function(expectedConfirmation) {
+ if ( this.browserbot.hasConfirmations()) {
+
+ receivedConfirmation = this.browserbot.getNextConfirmation();
+ if ( receivedConfirmation != expectedConfirmation ) {
+ assert.fail("The confirmation message was [" + receivedConfirmation + "]");
+ }
+
+ } else {
+ assert.fail("There were no confirmations");
+ }
+ };
+
+/*
+ * Verify the location of the current page.
+ */
+Selenium.prototype.assertAbsoluteLocation = function(expectedLocation) {
+ this.assertMatches(expectedLocation, this.page().location);
+};
+
+
+/*
+ * Verify the location of the current page ends with the expected location
+ */
+Selenium.prototype.assertLocation = function(expectedLocation) {
+ var docLocation = this.page().location.toString();
+ if (docLocation.length != docLocation.indexOf(expectedLocation) + expectedLocation.length)
+ {
+ assert.fail("Expected location to end with '" + expectedLocation
+ + "' but was '" + docLocation + "'");
+ }
+};
+
+/*
+ * Verify the title of the current page.
+ */
+Selenium.prototype.assertTitle = function(expectedTitle) {
+ this.assertMatches(expectedTitle, this.page().title());
+};
+
+/*
+ * Verify the value of a form element.
+ */
+Selenium.prototype.assertValue = function(locator, expectedValue) {
+ var element = this.page().findElement(locator);
+ var actualValue = getInputValue(element);
+ this.assertMatches(expectedValue, actualValue.trim());
+};
+
+/*
+ * Verifies that the text of the located element matches the expected content.
+ */
+Selenium.prototype.assertText = function(locator, expectedContent) {
+ var element = this.page().findElement(locator);
+ var actualText = getText(element);
+ this.assertMatches(expectedContent, actualText.trim());
+};
+
+/*
+ * Asserts that the text for a single cell within and HTML table matches the expected content.
+ * The table locator syntax is table.row.column.
+ */
+Selenium.prototype.assertTable = function(tableLocator, expectedContent) {
+ // This regular expression matches "tableName.row.column"
+ // For example, "mytable.3.4"
+ pattern = /(.*)\.(\d+)\.(\d+)/;
+
+ if(!pattern.test(tableLocator)) {
+ assert.fail("Invalid target format. Correct format is tableName.rowNum.columnNum");
+ }
+
+ pieces = tableLocator.match(pattern);
+
+ tableName = pieces[1];
+ row = pieces[2];
+ col = pieces[3];
+
+ var table = this.page().findElement(tableName);
+ if (row > table.rows.length) {
+ assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
+ }
+ else if (col > table.rows[row].cells.length) {
+ assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
+ }
+ else {
+ actualContent = getText(table.rows[row].cells[col]);
+ this.assertMatches(expectedContent, actualContent.trim());
+ }
+};
+
+/**
+ * Verify the label of the option that is selected.
+ */
+Selenium.prototype.assertSelected = function(target, expectedLabel) {
+ var element = this.page().findElement(target);
+ var selectedLabel = element.options[element.selectedIndex].text;
+ this.assertMatches(expectedLabel, selectedLabel);
+};
+
+/**
+ * Verify the label of all of the options in the drop=down.
+ */
+Selenium.prototype.assertSelectOptions = function(target, options) {
+ // Handle escpaced commas, by substitutine newlines.
+ options = options.replace("\\,", "\n");
+ var expectedOptions = options.split(",");
+ var element = this.page().findElement(target);
+
+ assert.equals("Wrong number of options.", expectedOptions.length, element.options.length);
+
+ for (var i = 0; i < element.options.length; i++) {
+ var option = element.options[i];
+ // Put the escaped commas back in.
+ var expectedOption = expectedOptions[i].replace("\n", ",");
+ this.assertMatches(expectedOption, option.text);
+ }
+};
+
+/**
+ * Verify the value of an element attribute. The syntax for returning an element attribute
+ * is <element-locator>@attribute-name
+ */
+Selenium.prototype.assertAttribute = function(target, expected) {
+ var attributeValue = this.page().findAttribute(target);
+ this.assertMatches(expected, attributeValue);
+};
+
+/*
+ * Asserts that the specified text is present in the page content.
+ */
+Selenium.prototype.assertTextPresent = function(expectedText) {
+ var allText = this.page().bodyText();
+
+ if(allText == "") {
+ assert.fail("Page text not found");
+ } else if(allText.indexOf(expectedText) == -1) {
+ assert.fail("'" + expectedText + "' not found in page text.");
+ }
+};
+
+/*
+ * Asserts that the specified text is NOT present in the page content.
+ */
+Selenium.prototype.assertTextNotPresent = function(unexpectedText) {
+ var allText = this.page().bodyText();
+
+ if(allText == "") {
+ assert.fail("Page text not found");
+ } else if(allText.indexOf(unexpectedText) != -1) {
+ assert.fail("'" + unexpectedText + "' was found in page text.");
+ }
+};
+
+/*
+ * Asserts that the specified element can be found.
+ */
+Selenium.prototype.assertElementPresent = function(locator) {
+ try {
+ this.page().findElement(locator);
+ } catch (e) {
+ assert.fail("Element " + locator + " not found.");
+ }
+};
+
+/*
+ * Asserts that the specified element cannot be found.
+ */
+Selenium.prototype.assertElementNotPresent = function(locator) {
+ try {
+ this.page().findElement(locator);
+ }
+ catch (e) {
+ return;
+ }
+ assert.fail("Element " + locator + " found.");
+};
+
+/*
+ * Asserts that the specified element is visible
+ */
+Selenium.prototype.assertVisible = function(locator) {
+ var element;
+ try {
+ element = this.page().findElement(locator);
+ } catch (e) {
+ assert.fail("Element " + locator + " not present.");
+ }
+ if (! this.isVisible(element)) {
+ assert.fail("Element " + locator + " not visible.");
+ }
+};
+
+/*
+ * Asserts that the specified element is visible
+ */
+Selenium.prototype.assertNotVisible = function(locator) {
+ var element;
+ try {
+ element = this.page().findElement(locator);
+ } catch (e) {
+ return;
+ }
+ if (this.isVisible(element)) {
+ assert.fail("Element " + locator + " is visible.");
+ }
+};
+
+Selenium.prototype.isVisible = function(element) {
+ var visibility = this.getEffectiveStyleProperty(element, "visibility");
+ var isDisplayed = this.isDisplayed(element);
+ return (visibility != "hidden" && isDisplayed);
+};
+
+Selenium.prototype.getEffectiveStyleProperty = function(element, property) {
+ var effectiveStyle = this.getEffectiveStyle(element);
+ var propertyValue = effectiveStyle[property];
+ if (propertyValue == 'inherit' && element.parentNode.style) {
+ return this.getEffectiveStyleProperty(element.parentNode, property);
+ }
+ return propertyValue;
+};
+
+Selenium.prototype.isDisplayed = function(element) {
+ var display = this.getEffectiveStyleProperty(element, "display");
+ if (display == "none") return false;
+ if (element.parentNode.style) {
+ return this.isDisplayed(element.parentNode);
+ }
+ return true;
+};
+
+Selenium.prototype.getEffectiveStyle = function(element) {
+ if (element.style == undefined) {
+ return undefined; // not a styled element
+ }
+ var window = this.browserbot.getContentWindow();
+ if (window.getComputedStyle) {
+ // DOM-Level-2-CSS
+ return window.getComputedStyle(element, null);
+ }
+ if (element.currentStyle) {
+ // non-standard IE alternative
+ return element.currentStyle;
+ // TODO: this won't really work in a general sense, as
+ // currentStyle is not identical to getComputedStyle()
+ // ... but it's good enough for "visibility"
+ }
+ throw new Error("cannot determine effective stylesheet in this browser");
+};
+
+/**
+ * Asserts that the specified element accepts user input visible
+ */
+Selenium.prototype.assertEditable = function(locator) {
+ var element = this.page().findElement(locator);
+ if (element.value == undefined) {
+ assert.fail("Element " + locator + " is not an input.");
+ }
+ if (element.disabled) {
+ assert.fail("Element " + locator + " is disabled.");
+ }
+};
+
+/**
+ * Asserts that the specified element does not accept user input
+ */
+Selenium.prototype.assertNotEditable = function(locator) {
+ var element = this.page().findElement(locator);
+ if (element.value == undefined) {
+ return; // not an input
+ }
+ if (element.disabled == false) {
+ assert.fail("Element " + locator + " is editable.");
+ }
+};
+
+ /*
+ * Return all buttons on the screen.
+ */
+Selenium.prototype.getAllButtons = function() {
+ return this.page().getAllButtons();
+};
+
+ /*
+ * Return all links on the screen.
+ */
+Selenium.prototype.getAllLinks = function() {
+ return this.page().getAllLinks();
+};
+
+ /*
+ * Return all fields on the screen.
+ */
+Selenium.prototype.getAllFields = function() {
+ return this.page().getAllFields();
+};
+
+/*
+ * Set the context for the current Test
+ */
+Selenium.prototype.doContext = function(context) {
+ return this.page().setContext(context);
+};
+
+function Assert() {
+ this.equals = function()
+ {
+ if (arguments.length == 2)
+ {
+ var comment = "";
+ var expected = arguments[0];
+ var actual = arguments[1];
+ }
+ else {
+ var comment = arguments[0] + " ";
+ var expected = arguments[1];
+ var actual = arguments[2];
+ }
+
+ if (expected === actual) {
+ return;
+ }
+ var errorMessage = comment + "Expected '" + expected + "' but was '" + actual + "'";
+
+ throw new AssertionFailedError(errorMessage);
+ };
+
+ this.fail = function(message)
+ {
+ throw new AssertionFailedError(message);
+ };
+}
+
+function AssertionFailedError(message) {
+ this.isAssertionFailedError = true;
+ this.failureMessage = message;
+}
+
+/*
+ * assertMatches(comment?, pattern, actual)
+ */
+Selenium.prototype.assertMatches = function() {
+ if (arguments.length == 2)
+ {
+ var comment = "";
+ var pattern = arguments[0];
+ var actual = arguments[1];
+ }
+ else {
+ var comment = arguments[0] + "; ";
+ var pattern = arguments[1];
+ var actual = arguments[2];
+ }
+
+ if (this.matches(pattern, actual)) {
+ return;
+ }
+
+ var errorMessage = comment +
+ "Actual value '" + actual + "' did not match '" + pattern + "'";
+ assert.fail(errorMessage);
+};
+
+Selenium.prototype.globToRegexp = function(glob) {
+ var pattern = glob;
+ pattern = pattern.replace(/([.^$+(){}[\]\\|])/g, "\\$1");
+ pattern = pattern.replace(/\?/g, ".");
+ pattern = pattern.replace(/\*/g, ".*");
+ return "^" + pattern + "$";
+};
+
+Selenium.prototype.matches = function(pattern, actual) {
+ var regexp = new RegExp(this.globToRegexp(pattern));
+ // Work around Konqueror bug when matching empty strings.
+ var testString = '' + actual;
+ return regexp.test(testString);
+};
=== Products/Zelenium/selenium/selenium-browserbot.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-browserbot.js:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-browserbot.js Mon May 2 23:48:16 2005
@@ -1,429 +1,720 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/*
- * This script provides the Javascript API to drive the test application contained within
- * a Browser Window.
- * TODO:
- * Add support for more events (keyboard and mouse)
- * Allow to switch "user-entry" mode from mouse-based to keyboard-based, firing different
- * events in different modes.
- */
-
-// The window to which the commands will be sent. For example, to click on a
-// popup window, first select that window, and then do a normal click command.
-
-var browserName=navigator.appName;
-var isIE = (browserName =="Microsoft Internet Explorer");
-// Get the Gecko version as an 8 digit date.
-var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
-var geckoVersion = geckoResult == null ? null : geckoResult[1];
-
-
-
-/*
- * The 'invoke' method will call the required function, and then
- * remove itself from the window object. This allows a calling app
- * to provide a callback listener for the window load event, without the
- * calling app needing to worry about cleaning up afterward.
- * TODO: This could be more generic, but suffices for now.
- */
-function SelfRemovingLoadListener(fn, frame) {
- var self = this;
-
- this.invoke=function () {
- try {
- // we've moved to a new page - clear the current one
- browserbot.currentPage = null;
- fn();
- } finally {
- removeLoadListener(frame, self.invoke);
- }
- }
-}
-
-BrowserBot = function(frame) {
- this.frame = frame;
- this.currentPage = null;
- this.currentWindowName = null;
-
- this.recordedAlerts = new Array();
- this.recordedConfirmations = new Array();
- this.nextConfirmResult = true;
-
-}
-
-BrowserBot.prototype.cancelNextConfirmation = function() {
- this.nextConfirmResult = false;
-}
-
-BrowserBot.prototype.hasAlerts = function() {
- return (this.recordedAlerts.length > 0) ;
-}
-
-BrowserBot.prototype.getNextAlert = function() {
- return this.recordedAlerts.shift();
-}
-
-BrowserBot.prototype.hasConfirmations = function() {
- return (this.recordedConfirmations.length > 0) ;
-}
-
-BrowserBot.prototype.getNextConfirmation = function() {
- return this.recordedConfirmations.shift();
-}
-
-
-BrowserBot.prototype.getFrame = function() {
- return this.frame;
-}
-
-BrowserBot.prototype.getContentWindow = function() {
- return this.getFrame().contentWindow
-}
-
-BrowserBot.prototype.selectWindow = function(target) {
- // we've moved to a new page - clear the current one
- this.currentPage = null;
- this.currentWindowName = null;
- if (target != "null") {
- // If window exists
- if (this.getTargetWindow(target)) {
- this.currentWindowName = target;
- }
- }
-}
-
-BrowserBot.prototype.openLocation = function(target, onloadCallback) {
- // We're moving to a new page - clear the current one
- this.currentPage = null;
- this.callOnNextPageLoad(onloadCallback);
- this.getFrame().src = target;
-}
-
-BrowserBot.prototype.getCurrentPage = function() {
- if (this.currentPage == null) {
- var testWindow = this.getContentWindow().window;
- if (this.currentWindowName != null) {
- testWindow = this.getTargetWindow(this.currentWindowName);
- }
- modifyWindowToRecordPopUpDialogs(testWindow, this);
- modifyWindowToClearPageCache(testWindow, this);
- this.currentPage = new PageBot(testWindow);
- }
-
- return this.currentPage;
-
- // private functions below - is there a better way?
-
- function modifyWindowToRecordPopUpDialogs(window, browserBot) {
- window.alert = function(alert){browserBot.recordedAlerts.push(alert);};
- window.confirm = function(message){
- browserBot.recordedConfirmations.push(message);
- var result = browserBot.nextConfirmResult;
- browserBot.nextConfirmResult = true;
- return result
- };
- }
-
- function modifyWindowToClearPageCache(window, browserBot) {
- //SPIKE factor this better via TDD
- function clearPageCache() {
- browserbot.currentPage = null;
- }
-
- if (window.addEventListener) {
- testWindow.addEventListener("unload",clearPageCache, true);
- }
- else if (window.attachEvent) {
- testWindow.attachEvent("onunload",clearPageCache);
- }
- // End SPIKE
- }
-
-
-}
-
-BrowserBot.prototype.getTargetWindow = function(windowName) {
- var evalString = "this.getContentWindow().window." + windowName;
- var targetWindow = eval(evalString);
- if (!targetWindow) {
- throw new Error("Window does not exist");
- }
- return targetWindow;
-}
-
-BrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
- if (onloadCallback) {
- var el = new SelfRemovingLoadListener(onloadCallback, this.frame);
- addLoadListener(this.getFrame(), el.invoke);
- }
-}
-
-
-PageBot = function(pageWindow) {
- this.currentWindow = pageWindow;
- this.currentDocument = pageWindow.document;
- this.location = pageWindow.location.pathname;
- this.title = function() {return this.currentDocument.title};
-
- this.locators = new Array();
- this.locators.push(this.findIdentifiedElement);
- this.locators.push(this.findElementByDomTraversal);
- this.locators.push(this.findElementByXPath);
-
-}
-
-/*
- * Finds an element on the current page, using various lookup protocols
- */
-PageBot.prototype.findElement = function(locator) {
- // Try the locators one at a time.
- for (var i = 0; i < this.locators.length; i++) {
- var locatorFunction = this.locators[i];
- var element = locatorFunction.call(this, locator);
- if (element != null) {
- return element;
- }
- }
-
- // Element was not found by any locator function.
- throw new Error("Element " + locator + " not found");
-}
-
-/*
- * In IE, getElementById() also searches by name.
- * To provied consistent functionality with Firefox, we
- * search by name attribute if an element with the id isn't found.
- */
-PageBot.prototype.findIdentifiedElement = function(identifier) {
- // Since we try to get an id with _any_ string, we need to handle
- // cases where this causes an exception.
- try {
- var element = this.currentDocument.getElementById(identifier);
- if (element == null
- && !isIE // IE checks this without asking
- && document.evaluate )// DOM3 XPath
- {
- var xpath = "//*[@name='" + identifier + "']";
- element = document.evaluate(xpath, this.currentDocument, null, 0, null).iterateNext();
- }
- } catch (e) {
- return null;
- }
-
- return element;
-}
-
-/**
- * Finds an element using by evaluating the "document.*" string against the
- * current document object. Dom expressions must begin with "document."
- */
-PageBot.prototype.findElementByDomTraversal = function(domTraversal) {
- if (domTraversal.indexOf("document.") != 0) {
- return null;
- }
-
- // Trim the leading 'document'
- domTraversal = domTraversal.substr(9);
- var locatorScript = "this.currentDocument." + domTraversal;
- var element = eval(locatorScript);
-
- if (!element) {
- return null;
- }
-
- return element;
-}
-
-/**
- * Finds an element identified by the xpath expression. Expressions _must_
- * begin with "//".
- */
-PageBot.prototype.findElementByXPath = function(xpath) {
- if (xpath.indexOf("//") != 0) {
- return null;
- }
-
- // If the document doesn't support XPath, mod it with html-xpath.
- // This only works for IE.
- if (!this.currentDocument.evaluate) {
- addXPathSupport(this.currentDocument);
- }
-
- // If we still don't have XPath bail.
- // TODO implement subset of XPath for browsers without native support.
- if (!this.currentDocument.evaluate) {
- throw new Error("XPath not supported");
- }
-
- // Trim any trailing "/": not valid xpath, and remains from attribute locator.
- if (xpath.charAt(xpath.length - 1) == '/') {
- xpath = xpath.slice(0, xpath.length - 1);
- }
-
- return this.currentDocument.evaluate(xpath, this.currentDocument, null, 0, null).iterateNext();
-}
-
-/**
- * Returns an attribute based on an attribute locator. This is made up of an element locator
- * suffixed with @attribute-name.
- */
-PageBot.prototype.findAttribute = function(locator) {
- // Split into locator + attributeName
- var attributePos = locator.lastIndexOf("@");
- var elementLocator = locator.slice(0, attributePos);
- var attributeName = locator.slice(attributePos + 1);
-
- // Find the element.
- var element = this.findElement(elementLocator);
-
- // Handle missing "class" attribute in IE.
- if (isIE && attributeName == "class") {
- attributeName = "className";
- }
-
- // Get the attribute value.
- var attributeValue = element.getAttribute(attributeName);
-
- return attributeValue ? attributeValue.toString() : null;
-}
-
-/*
- * Selects the first option with a matching label from the select box element
- * provided. If no matching element is found, nothing happens.
- */
-PageBot.prototype.selectOptionWithLabel = function(element, stringValue) {
- triggerEvent(element, 'focus', false);
- for (var i = 0; i < element.options.length; i++) {
- var option = element.options[i];
- if (option.text == stringValue) {
- if (!option.selected) {
- option.selected = true;
- triggerEvent(element, 'change', true);
- }
- }
- }
- triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.replaceText = function(element, stringValue) {
- triggerEvent(element, 'focus', false);
- triggerEvent(element, 'select', true);
- element.value=stringValue;
- if (isIE) {
- triggerEvent(element, 'change', true);
- }
- triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.clickElement = function(element) {
-
- triggerEvent(element, 'focus', false);
-
- var wasChecked = element.checked;
- if (isIE) {
- element.click();
- }
- else {
- // Add an event listener that detects if the default action has been prevented.
- var preventDefault = false;
- element.addEventListener("click", function(evt) {preventDefault = evt.getPreventDefault()}, false);
-
- // Trigger the click event.
- triggerMouseEvent(element, 'click', true);
-
- // In FireFox < 1.0 Final, and Mozilla <= 1.7.3, just sending the click event is enough.
- // But in newer versions, we need to do it ourselves.
- var needsProgrammaticClick = (geckoVersion > '20041025');
- // Perform the link action if preventDefault was set.
- if (needsProgrammaticClick && element.href && !preventDefault) {
- this.currentWindow.location.href = element.href;
- }
- }
-
- if (this.windowClosed()) {
- return;
- }
- // Onchange event is not triggered automatically in IE.
- if (isIE && isDefined(element.checked) && wasChecked != element.checked) {
- triggerEvent(element, 'change', true);
- }
-
- triggerEvent(element, 'blur', false);
-}
-
-PageBot.prototype.windowClosed = function(element) {
- return this.currentWindow.closed;
-}
-
-PageBot.prototype.bodyText = function() {
- return getText(this.currentDocument.body)
-}
-
-PageBot.prototype.getAllButtons = function() {
- var elements = this.currentDocument.getElementsByTagName('input');
- var result = '';
-
- for (var i = 0; i < elements.length; i++) {
- if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {
- result += elements[i].id;
-
- result += ',';
- }
- }
-
- return result;
-}
-
-
-PageBot.prototype.getAllFields = function() {
- var elements = this.currentDocument.getElementsByTagName('input');
- var result = '';
-
- for (var i = 0; i < elements.length; i++) {
- if (elements[i].type == 'text') {
- result += elements[i].id;
-
- result += ',';
- }
- }
-
- return result;
-}
-
-PageBot.prototype.getAllLinks = function() {
- var elements = this.currentDocument.getElementsByTagName('a');
- var result = '';
-
- for (var i = 0; i < elements.length; i++) {
- result += elements[i].id;
-
- result += ',';
- }
-
- return result;
-}
-
-
-
-function isDefined(value) {
- return typeof(value) != undefined;
-}
-
-
-
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/*
+* This script provides the Javascript API to drive the test application contained within
+* a Browser Window.
+* TODO:
+* Add support for more events (keyboard and mouse)
+* Allow to switch "user-entry" mode from mouse-based to keyboard-based, firing different
+* events in different modes.
+*/
+
+// The window to which the commands will be sent. For example, to click on a
+// popup window, first select that window, and then do a normal click command.
+
+
+// Although it's generally better web development practice not to use browser-detection
+// (feature detection is better), the subtle browser differences that Selenium has to
+// work around seem to make it necessary. Maybe as we learn more about what we need,
+// we can do this in a more "feature-centric" rather than "browser-centric" way.
+// TODO we should probably reuse an available browser-detection library
+var browserName=navigator.appName;
+var isIE = (browserName =="Microsoft Internet Explorer");
+var isKonqueror = (browserName == "Konqueror");
+var isSafari = (navigator.userAgent.indexOf('Safari') != -1);
+
+// Get the Gecko version as an 8 digit date.
+var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
+var geckoVersion = geckoResult == null ? null : geckoResult[1];
+
+function createBrowserBot(frame, executionContext) {
+ if (isIE) {
+ return new IEBrowserBot(frame, executionContext);
+ }
+ else if (isKonqueror) {
+ return new KonquerorBrowserBot(frame, executionContext);
+ }
+ else if (isSafari) {
+ return new SafariBrowserBot(frame, executionContext);
+ }
+ else {
+ // Use mozilla by default
+ return new MozillaBrowserBot(frame, executionContext);
+ }
+}
+
+function createPageBot(windowObject) {
+ if (isIE) {
+ return new IEPageBot(windowObject);
+ }
+ else if (isKonqueror) {
+ return new KonquerorPageBot(windowObject);
+ }
+ else if (isSafari) {
+ return new SafariPageBot(windowObject);
+ }
+ else {
+ // Use mozilla by default
+ return new MozillaPageBot(windowObject);
+ }
+}
+
+BrowserBot = function(frame, executionContext) {
+ this.frame = frame;
+ this.executionContext = executionContext;
+ this.currentPage = null;
+ this.currentWindowName = null;
+
+ this.modalDialogTest = null;
+ this.recordedAlerts = new Array();
+ this.recordedConfirmations = new Array();
+ this.nextConfirmResult = true;
+};
+
+BrowserBot.prototype.doModalDialogTest = function(test) {
+ this.modalDialogTest = test;
+};
+
+BrowserBot.prototype.cancelNextConfirmation = function() {
+ this.nextConfirmResult = false;
+};
+
+BrowserBot.prototype.hasAlerts = function() {
+ return (this.recordedAlerts.length > 0) ;
+};
+
+BrowserBot.prototype.getNextAlert = function() {
+ return this.recordedAlerts.shift();
+};
+
+BrowserBot.prototype.hasConfirmations = function() {
+ return (this.recordedConfirmations.length > 0) ;
+};
+
+BrowserBot.prototype.getNextConfirmation = function() {
+ return this.recordedConfirmations.shift();
+};
+
+
+BrowserBot.prototype.getFrame = function() {
+ return this.frame;
+};
+
+BrowserBot.prototype.getContentWindow = function() {
+ return this.executionContext.getContentWindow(this.getFrame());
+
+};
+
+BrowserBot.prototype.selectWindow = function(target) {
+ // we've moved to a new page - clear the current one
+ this.currentPage = null;
+ this.currentWindowName = null;
+ if (target != "null") {
+ // If window exists
+ if (this.getTargetWindow(target)) {
+ this.currentWindowName = target;
+ }
+ }
+};
+
+BrowserBot.prototype.openLocation = function(target, onloadCallback) {
+ // We're moving to a new page - clear the current one
+ this.currentPage = null;
+ this.executionContext.open(target,this.getFrame());
+};
+
+BrowserBot.prototype.getCurrentPage = function() {
+ if (this.currentPage == null) {
+ var testWindow = this.getContentWindow().window;
+ if (this.currentWindowName != null) {
+ testWindow = this.getTargetWindow(this.currentWindowName);
+ }
+ this.modifyWindowToRecordPopUpDialogs(testWindow, this);
+ this.modifyWindowToClearPageCache(testWindow, this);
+ this.currentPage = createPageBot(testWindow);
+ }
+
+ return this.currentPage;
+};
+
+BrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+ windowToModify.alert = function(alert) {
+ browserBot.recordedAlerts.push(alert);
+ };
+
+ windowToModify.confirm = function(message) {
+ browserBot.recordedConfirmations.push(message);
+ var result = browserBot.nextConfirmResult;
+ browserBot.nextConfirmResult = true;
+ return result;
+ };
+};
+
+BrowserBot.prototype.modifyWindowToClearPageCache = function(windowToModify, browserBot) {
+ var clearCachedPage = function() {
+ LOG.debug("UNLOAD: clearCachedPage()");
+ browserbot.currentPage = null;
+ };
+
+ if (window.addEventListener) {
+ windowToModify.addEventListener("unload", clearCachedPage, true);
+ } else if (window.attachEvent) {
+ windowToModify.attachEvent("onunload", clearCachedPage);
+ }
+};
+
+BrowserBot.prototype.getTargetWindow = function(windowName) {
+ var evalString = "this.getContentWindow().window." + windowName;
+ var targetWindow = eval(evalString);
+ if (!targetWindow) {
+ throw new Error("Window does not exist");
+ }
+ return targetWindow;
+};
+
+BrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
+ addLoadListener(this.frame, onloadCallback);
+};
+
+function MozillaBrowserBot(frame, executionContext) {
+ BrowserBot.call(this, frame, executionContext);
+}
+MozillaBrowserBot.prototype = new BrowserBot;
+
+function KonquerorBrowserBot(frame, executionContext) {
+ BrowserBot.call(this, frame, executionContext);
+}
+KonquerorBrowserBot.prototype = new BrowserBot;
+
+function SafariBrowserBot(frame, executionContext) {
+ BrowserBot.call(this, frame, executionContext);
+}
+SafariBrowserBot.prototype = new BrowserBot;
+
+/**
+ * Since Safari 1.3 doesn't trigger unload, we clear cached page as soon as
+ * we know that we're expecting a new page.
+ */
+SafariBrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
+ this.currentPage = null;
+
+ try {
+ addLoadListener(this.frame, onloadCallback);
+ } catch (e) {
+ LOG.debug("Got on error adding LoadListener in BrowserBot.prototype.callOnNextPageLoad." +
+ "This occurs on the second and all subsequent calls in Safari");
+ }
+};
+
+function IEBrowserBot(frame, executionContext) {
+ BrowserBot.call(this, frame, executionContext);
+}
+IEBrowserBot.prototype = new BrowserBot;
+
+IEBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+ BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
+
+ // we will call the previous version of this method from within our own interception
+ oldShowModalDialog = windowToModify.showModalDialog;
+
+ windowToModify.showModalDialog = function(url, args, features) {
+ // Get relative directory to where TestRunner.html lives
+ // A risky assumption is that the user's TestRunner is named TestRunner.html
+ var doc_location = document.location.toString();
+ var end_of_base_ref = doc_location.indexOf('TestRunner.html');
+ var base_ref = doc_location.substring(0, end_of_base_ref);
+
+ var fullURL = base_ref + "TestRunner.html?singletest=" + escape(browserBot.modalDialogTest) + "&autoURL=" + escape(url) + "&runInterval=" + runInterval;
+ browserBot.modalDialogTest = null;
+
+ var returnValue = oldShowModalDialog(fullURL, args, features);
+ return returnValue;
+ };
+};
+
+SafariBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
+ BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
+
+ var originalOpen = windowToModify.open;
+ /*
+ * Safari seems to be broken, so that when we manually trigger the onclick method
+ * of a button/href, any window.open calls aren't resolved relative to the app location.
+ * So here we replace the open() method with one that does resolve the url correctly.
+ */
+ windowToModify.open = function(url, windowName, windowFeatures, replaceFlag) {
+
+ if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")) {
+ return originalOpen(url, windowName, windowFeatures, replaceFlag);
+ }
+
+ // Reduce the current path to the directory
+ var currentPath = windowToModify.location.pathname || "/";
+ currentPath = currentPath.replace(/\/[^\/]*$/, "/");
+
+ // Remove any leading "./" from the new url.
+ url = url.replace(/^\.\//, "");
+
+ newUrl = currentPath + url;
+
+ return originalOpen(newUrl, windowName, windowFeatures, replaceFlag);
+ };
+};
+
+PageBot = function(pageWindow) {
+ if (pageWindow) {
+ this.currentWindow = pageWindow;
+ this.currentDocument = pageWindow.document;
+ this.location = pageWindow.location.pathname;
+ this.title = function() {return this.currentDocument.title;};
+
+ // Register all locate* functions
+ this.locatorFunctions = new Array();
+ for (var f in this) {
+ if (typeof(this[f]) == 'function' && f.match(/^locate/)) {
+ this.locatorFunctions.push(this[f]);
+ }
+ }
+ }
+};
+
+MozillaPageBot = function(pageWindow) {
+ PageBot.call(this, pageWindow);
+};
+MozillaPageBot.prototype = new PageBot();
+
+KonquerorPageBot = function(pageWindow) {
+ PageBot.call(this, pageWindow);
+};
+KonquerorPageBot.prototype = new PageBot();
+
+SafariPageBot = function(pageWindow) {
+ PageBot.call(this, pageWindow);
+};
+SafariPageBot.prototype = new PageBot();
+
+IEPageBot = function(pageWindow) {
+ PageBot.call(this, pageWindow);
+};
+IEPageBot.prototype = new PageBot();
+
+/*
+* Finds an element on the current page, using various lookup protocols
+*/
+PageBot.prototype.findElement = function(locator) {
+ var element = this.findElementInDocument(locator, this.currentDocument);
+
+ if (element != null) {
+ return element;
+ } else {
+ for (var i = 0; i < this.currentWindow.frames.length; i++) {
+ element = this.findElementInDocument(locator, this.currentWindow.frames[i].document);
+ if (element != null) {
+ return element;
+ }
+ }
+ }
+
+ // Element was not found by any locator function.
+ throw new Error("Element " + locator + " not found");
+};
+
+PageBot.prototype.findElementInDocument = function(locator, inDocument) {
+ // Try the locatorFunctions one at a time.
+ for (var i = 0; i < this.locatorFunctions.length; i++) {
+ var locatorFunction = this.locatorFunctions[i];
+ var element = locatorFunction.call(this, locator, inDocument);
+ if (element != null) {
+ return element;
+ }
+ }
+};
+
+/**
+ * In IE, getElementById() also searches by name.
+ */
+IEPageBot.prototype.locateElementById = function(identifier, inDocument) {
+ try {
+ return inDocument.getElementById(identifier);
+ } catch (e) {
+ return null;
+ }
+};
+
+/**
+ * In other browsers, getElementById() does not search by name. To provide
+ * functionality consistent with IE, we search by @name if an element with
+ * the @id isn't found.
+ */
+PageBot.prototype.locateElementById = function(identifier, inDocument) {
+ try {
+ var element = inDocument.getElementById(identifier);
+ if (element == null)
+ {
+ if ( document.evaluate ) {// DOM3 XPath
+ var xpath = "//*[@name='" + identifier + "']";
+ element = document.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+ }
+ // Search through all elements for Konqueror/Safari
+ else {
+ var allElements = inDocument.getElementsByTagName("*");
+ for (var i = 0; i < allElements.length; i++) {
+ var testElement = allElements[i];
+ if (testElement.name && testElement.name === identifier) {
+ element = testElement;
+ break;
+ }
+ }
+ }
+ }
+ } catch (e) {
+ return null;
+ }
+
+ return element;
+};
+
+/**
+* Finds an element using by evaluating the "document.*" string against the
+* current document object. Dom expressions must begin with "document."
+*/
+PageBot.prototype.locateElementByDomTraversal = function(domTraversal, inDocument) {
+ if (domTraversal.indexOf("document.") != 0) {
+ return null;
+ }
+
+ // Trim the leading 'document'
+ domTraversal = domTraversal.substr(9);
+ var locatorScript = "inDocument." + domTraversal;
+ var element = eval(locatorScript);
+
+ if (!element) {
+ return null;
+ }
+
+ return element;
+};
+
+/**
+* Finds an element identified by the xpath expression. Expressions _must_
+* begin with "//".
+*/
+PageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
+ if (xpath.indexOf("//") != 0) {
+ return null;
+ }
+
+ // If don't have XPath bail.
+ // TODO implement subset of XPath for browsers without native support.
+ if (!inDocument.evaluate) {
+ throw new Error("XPath not supported");
+ }
+
+ // Trim any trailing "/": not valid xpath, and remains from attribute locator.
+ if (xpath.charAt(xpath.length - 1) == '/') {
+ xpath = xpath.slice(0, xpath.length - 1);
+ }
+
+ return inDocument.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+};
+
+/**
+ * For IE, we implement XPath support using the html-xpath library.
+ */
+IEPageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
+ if (xpath.indexOf("//") != 0) {
+ return null;
+ }
+
+ if (!inDocument.evaluate) {
+ addXPathSupport(inDocument);
+ }
+
+ return PageBot.prototype.locateElementByXPath(xpath, inDocument);
+};
+
+/**
+* Finds a link element with text matching the expression supplied. Expressions must
+* begin with "link:".
+*/
+PageBot.prototype.locateLinkByText = function(linkDescription, inDocument) {
+ var prefix = "link:";
+ if (linkDescription.indexOf(prefix) != 0) {
+ return null;
+ }
+
+ var linkText = linkDescription.substring(prefix.length);
+ var links = inDocument.getElementsByTagName('a');
+ for (var i = 0; i < links.length; i++) {
+ var element = links[i];
+ if (getText(element) == linkText) {
+ return element;
+ }
+ }
+ return null;
+};
+
+/**
+* Returns an attribute based on an attribute locator. This is made up of an element locator
+* suffixed with @attribute-name.
+*/
+PageBot.prototype.findAttribute = function(locator) {
+ // Split into locator + attributeName
+ var attributePos = locator.lastIndexOf("@");
+ var elementLocator = locator.slice(0, attributePos);
+ var attributeName = locator.slice(attributePos + 1);
+
+ // Find the element.
+ var element = this.findElement(elementLocator);
+
+ // Handle missing "class" attribute in IE.
+ if (isIE && attributeName == "class") {
+ attributeName = "className";
+ }
+
+ // Get the attribute value.
+ var attributeValue = element.getAttribute(attributeName);
+
+ return attributeValue ? attributeValue.toString() : null;
+};
+
+/*
+* Selects the first option with a matching label from the select box element
+* provided. If no matching element is found, nothing happens.
+*/
+PageBot.prototype.selectOptionWithLabel = function(element, stringValue) {
+ triggerEvent(element, 'focus', false);
+ for (var i = 0; i < element.options.length; i++) {
+ var option = element.options[i];
+ if (option.text == stringValue) {
+ if (!option.selected) {
+ option.selected = true;
+ triggerEvent(element, 'change', true);
+ }
+ triggerEvent(element, 'blur', false);
+ return;
+ }
+ }
+ throw new Error("Option with label '" + stringValue + "' not found");
+};
+
+PageBot.prototype.replaceText = function(element, stringValue) {
+ triggerEvent(element, 'focus', false);
+ triggerEvent(element, 'select', true);
+ element.value=stringValue;
+ if (isIE || isKonqueror || isSafari) {
+ triggerEvent(element, 'change', true);
+ }
+ triggerEvent(element, 'blur', false);
+};
+
+MozillaPageBot.prototype.clickElement = function(element) {
+
+ triggerEvent(element, 'focus', false);
+
+ // Add an event listener that detects if the default action has been prevented.
+ // (This is caused by a javascript onclick handler returning false)
+ var preventDefault = false;
+ if (geckoVersion) {
+ element.addEventListener("click", function(evt) {preventDefault = evt.getPreventDefault();}, false);
+ }
+
+ // Trigger the click event.
+ triggerMouseEvent(element, 'click', true);
+
+ // In FireFox < 1.0 Final, and Mozilla <= 1.7.3, just sending the click event is enough.
+ // But in newer versions, we need to do it ourselves.
+ var needsProgrammaticClick = (geckoVersion > '20041025');
+ // Perform the link action if preventDefault was set.
+ if (needsProgrammaticClick && !preventDefault) {
+ // Try the element itself, as well as it's parent - this handles clicking images inside links.
+ if (element.href) {
+ this.currentWindow.location.href = element.href;
+ }
+ else if (element.parentNode.href) {
+ this.currentWindow.location.href = element.parentNode.href;
+ }
+ }
+
+ if (this.windowClosed()) {
+ return;
+ }
+
+ triggerEvent(element, 'blur', false);
+};
+
+KonquerorPageBot.prototype.clickElement = function(element) {
+
+ triggerEvent(element, 'focus', false);
+
+ if (element.click) {
+ element.click();
+ }
+ else {
+ triggerMouseEvent(element, 'click', true);
+ }
+
+ if (this.windowClosed()) {
+ return;
+ }
+
+ triggerEvent(element, 'blur', false);
+};
+
+SafariPageBot.prototype.clickElement = function(element) {
+
+ triggerEvent(element, 'focus', false);
+
+ var wasChecked = element.checked;
+
+ // For form element it is simple.
+ if (element.click) {
+ element.click();
+ }
+ // For links and other elements, event emulation is required.
+ else {
+ triggerEvent(element, 'click', true);
+
+ // Unfortunately, triggering the event doesn't seem to activate onclick handlers.
+ // We currently call onclick for the link, but I'm guessing that the onclick for containing
+ // elements is not being called.
+ var success = true;
+ if (element.onclick) {
+ var evt = document.createEvent('HTMLEvents');
+ evt.initEvent('click', true, true);
+ var onclickResult = element.onclick(evt);
+ if (onclickResult === false) {
+ success = false;
+ }
+ }
+
+ if (success) {
+ // Try the element itself, as well as it's parent - this handles clicking images inside links.
+ if (element.href) {
+ this.currentWindow.location.href = element.href;
+ }
+ else if (element.parentNode.href) {
+ this.currentWindow.location.href = element.parentNode.href;
+ } else {
+ // This is true for buttons outside of forms, and maybe others.
+ LOG.warn("Ignoring 'click' call for button outside form, or link without href."
+ + "Using buttons without an enclosing form can cause wierd problems with URL resolution in Safari." );
+ // I implemented special handling for window.open, but unfortunately this behaviour is also displayed
+ // when we have a button without an enclosing form that sets document.location in the onclick handler.
+ // The solution is to always use an enclosing form for a button.
+ }
+ }
+ }
+
+ // Onchange event is not triggered automatically in Safari.
+ if (isDefined(element.checked) && wasChecked != element.checked) {
+ triggerEvent(element, 'change', true);
+ }
+
+ if (this.windowClosed()) {
+ return;
+ }
+
+ triggerEvent(element, 'blur', false);
+};
+
+IEPageBot.prototype.clickElement = function(element) {
+
+ triggerEvent(element, 'focus', false);
+
+ var wasChecked = element.checked;
+ element.click();
+
+ if (this.windowClosed()) {
+ return;
+ }
+ // Onchange event is not triggered automatically in IE.
+ if (isDefined(element.checked) && wasChecked != element.checked) {
+ triggerEvent(element, 'change', true);
+ }
+
+ triggerEvent(element, 'blur', false);
+};
+
+PageBot.prototype.windowClosed = function(element) {
+ return this.currentWindow.closed;
+};
+
+PageBot.prototype.bodyText = function() {
+ return getText(this.currentDocument.body);
+};
+
+PageBot.prototype.getAllButtons = function() {
+ var elements = this.currentDocument.getElementsByTagName('input');
+ var result = '';
+
+ for (var i = 0; i < elements.length; i++) {
+ if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {
+ result += elements[i].id;
+
+ result += ',';
+ }
+ }
+
+ return result;
+};
+
+
+PageBot.prototype.getAllFields = function() {
+ var elements = this.currentDocument.getElementsByTagName('input');
+ var result = '';
+
+ for (var i = 0; i < elements.length; i++) {
+ if (elements[i].type == 'text') {
+ result += elements[i].id;
+
+ result += ',';
+ }
+ }
+
+ return result;
+};
+
+PageBot.prototype.getAllLinks = function() {
+ var elements = this.currentDocument.getElementsByTagName('a');
+ var result = '';
+
+ for (var i = 0; i < elements.length; i++) {
+ result += elements[i].id;
+
+ result += ',';
+ }
+
+ return result;
+};
+
+PageBot.prototype.setContext = function(strContext) {
+ //set the current test title
+ context.innerHTML=strContext;
+};
+
+function isDefined(value) {
+ return typeof(value) != undefined;
+}
+
+PageBot.prototype.goBack = function() {
+ this.currentWindow.history.back();
+};
+
+PageBot.prototype.goForward = function() {
+ this.currentWindow.history.forward();
+};
=== Products/Zelenium/selenium/selenium-commandhandlers.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-commandhandlers.js:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-commandhandlers.js Mon May 2 23:48:16 2005
@@ -1,180 +1,177 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-function CommandHandlerFactory() {
- this.actions = {};
- this.asserts = {};
- this.accessors = {};
-
- var self = this;
-
- this.registerAction = function(name, action, wait) {
- var handler = new ActionHandler(action, wait);
- this.actions[name] = handler;
- }
-
- this.registerAccessor = function(name, accessor) {
- var handler = new AccessorHandler(accessor);
- this.accessors[name] = handler;
- }
-
- this.registerAssert = function(name, assertion, haltOnFailure) {
- var handler = new AssertHandler(assertion, haltOnFailure);
- this.asserts[name] = handler;
- }
-
- this.getCommandHandler = function(name) {
- return this.actions[name] || this.accessors[name] || this.asserts[name] || null;
- }
-
- this.registerAll = function(commandObject) {
- registerAllActions(commandObject);
- registerAllAsserts(commandObject);
- registerAllAccessors(commandObject);
- }
-
- var registerAllActions = function(commandObject) {
- for (var functionName in commandObject) {
- var result = /^do([A-Z].+)$/.exec(functionName);
- if (result != null) {
- var actionName = toCamelCase(result[1]);
-
- // Register the action without the wait flag.
- var action = commandObject[functionName];
- self.registerAction(actionName, action, false);
-
- // Register actionName + "AndWait" with the wait flag;
- var waitActionName = actionName + "AndWait";
- self.registerAction(waitActionName, action, true);
- }
- }
- }
-
- var registerAllAsserts = function(commandObject) {
- for (var functionName in commandObject) {
- var result = /^assert([A-Z].+)$/.exec(functionName);
- if (result != null) {
- var assert = commandObject[functionName];
-
- // Register the assert with the "assert" prefix, and halt on failure.
- var assertName = functionName;
- self.registerAssert(assertName, assert, true);
-
- // Register the assert with the "verify" prefix, and do not halt on failure.
- var verifyName = "verify" + result[1];
- self.registerAssert(verifyName, assert, false);
- }
- }
- }
-
- var registerAllAccessors = function(commandObject) {
- for (var functionName in commandObject) {
- if (/^get[A-Z].+$/.exec(functionName) != null) {
- var accessor = commandObject[functionName];
- self.registerAccessor(functionName, accessor);
- }
- }
- }
-
- function toCamelCase(aString) {
- return aString.charAt(0).toLowerCase() + aString.substr(1);
- }
-}
-
-
-// NOTE: The CommandHandler is effectively an abstract base for ActionHandler,
-// AccessorHandler and AssertHandler.
-function CommandHandler(type, haltOnFailure, executor) {
- this.type = type;
- this.haltOnFailure = haltOnFailure;
- this.executor = executor;
-}
-
-CommandHandler.prototype.execute = function(seleniumApi, command) {
- return new CommandResult(this.executor.call(seleniumApi, command.target, command.value));
-}
-
-function ActionHandler(action, wait) {
- this.base = CommandHandler;
- this.base("action", true, action);
- if (wait) {
- this.wait = true;
- }
-}
-ActionHandler.prototype = new CommandHandler;
-ActionHandler.prototype.execute = function(seleniumApi, command) {
- if ( seleniumApi.browserbot.hasAlerts() ) {
- throw new Error("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
- }
- if ( seleniumApi.browserbot.hasConfirmations() ) {
- throw new Error("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
- }
- var processState = this.executor.call(seleniumApi, command.target, command.value)
- // If the handler didn't return a wait flag, check to see if the
- // handler was registered with the wait flag.
- if (processState == undefined && this.wait) {
- processState = SELENIUM_PROCESS_WAIT;
- }
- return new CommandResult(processState);
-}
-
-function AccessorHandler(accessor) {
- this.base = CommandHandler;
- this.base("accessor", true, accessor);
-}
-AccessorHandler.prototype = new CommandHandler;
-
-AccessorHandler.prototype.execute = function(seleniumApi, command) {
- var returnValue = this.executor.call(seleniumApi, command.target, command.value);
- var result = new CommandResult();
- result.result = returnValue;
- return result;
-}
-
-function AssertHandler(assertion, haltOnFailure) {
- this.base = CommandHandler;
- this.base("assert", haltOnFailure || false, assertion);
-}
-AssertHandler.prototype = new CommandHandler;
-AssertHandler.prototype.execute = function(seleniumApi, command) {
- var result = new CommandResult();
- try {
- var processState = this.executor.call(seleniumApi, command.target, command.value);
- result.passed = true;
- } catch (e) {
- // If this is not a JsUnitException, or we should haltOnFailure, rethrow.
- if (!e.isJsUnitException) {
- throw e;
- }
- if (this.haltOnFailure) {
- throw new Error(e.jsUnitMessage);
- }
- result.failed = true;
- result.failureMessage = e.jsUnitMessage;
- }
- return result;
-}
-
-function CommandResult(processState) {
- this.processState = processState;
- this.result = "OK";
-}
-
-function SeleniumCommand(command, target, value) {
- this.command = command;
- this.target = target;
- this.value = value;
-}
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+function CommandHandlerFactory() {
+ this.actions = {};
+ this.asserts = {};
+ this.accessors = {};
+
+ var self = this;
+
+ this.registerAction = function(name, action, wait) {
+ var handler = new ActionHandler(action, wait);
+ this.actions[name] = handler;
+ };
+
+ this.registerAccessor = function(name, accessor) {
+ var handler = new AccessorHandler(accessor);
+ this.accessors[name] = handler;
+ };
+
+ this.registerAssert = function(name, assertion, haltOnFailure) {
+ var handler = new AssertHandler(assertion, haltOnFailure);
+ this.asserts[name] = handler;
+ };
+
+ this.getCommandHandler = function(name) {
+ return this.actions[name] || this.accessors[name] || this.asserts[name] || null;
+ };
+
+ this.registerAll = function(commandObject) {
+ registerAllActions(commandObject);
+ registerAllAsserts(commandObject);
+ registerAllAccessors(commandObject);
+ };
+
+ var registerAllActions = function(commandObject) {
+ for (var functionName in commandObject) {
+ var result = /^do([A-Z].+)$/.exec(functionName);
+ if (result != null) {
+ var actionName = toCamelCase(result[1]);
+
+ // Register the action without the wait flag.
+ var action = commandObject[functionName];
+ self.registerAction(actionName, action, false);
+
+ // Register actionName + "AndWait" with the wait flag;
+ var waitActionName = actionName + "AndWait";
+ self.registerAction(waitActionName, action, true);
+ }
+ }
+ };
+
+ var registerAllAsserts = function(commandObject) {
+ for (var functionName in commandObject) {
+ var result = /^assert([A-Z].+)$/.exec(functionName);
+ if (result != null) {
+ var assert = commandObject[functionName];
+
+ // Register the assert with the "assert" prefix, and halt on failure.
+ var assertName = functionName;
+ self.registerAssert(assertName, assert, true);
+
+ // Register the assert with the "verify" prefix, and do not halt on failure.
+ var verifyName = "verify" + result[1];
+ self.registerAssert(verifyName, assert, false);
+ }
+ }
+ };
+
+ var registerAllAccessors = function(commandObject) {
+ for (var functionName in commandObject) {
+ if (/^get[A-Z].+$/.exec(functionName) != null) {
+ var accessor = commandObject[functionName];
+ self.registerAccessor(functionName, accessor);
+ }
+ }
+ };
+
+ function toCamelCase(aString) {
+ return aString.charAt(0).toLowerCase() + aString.substr(1);
+ }
+}
+
+
+// NOTE: The CommandHandler is effectively an abstract base for ActionHandler,
+// AccessorHandler and AssertHandler.
+function CommandHandler(type, haltOnFailure, executor) {
+ this.type = type;
+ this.haltOnFailure = haltOnFailure;
+ this.executor = executor;
+}
+CommandHandler.prototype.execute = function(seleniumApi, command) {
+ return new CommandResult(this.executor.call(seleniumApi, command.target, command.value));
+};
+
+function ActionHandler(action, wait) {
+ CommandHandler.call(this, "action", true, action);
+ if (wait) {
+ this.wait = true;
+ }
+}
+ActionHandler.prototype = new CommandHandler;
+ActionHandler.prototype.execute = function(seleniumApi, command) {
+ if ( seleniumApi.browserbot.hasAlerts() ) {
+ throw new Error("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
+ }
+ if ( seleniumApi.browserbot.hasConfirmations() ) {
+ throw new Error("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
+ }
+ var processState = this.executor.call(seleniumApi, command.target, command.value);
+ // If the handler didn't return a wait flag, check to see if the
+ // handler was registered with the wait flag.
+ if (processState == undefined && this.wait) {
+ processState = SELENIUM_PROCESS_WAIT;
+ }
+ return new CommandResult(processState);
+};
+
+function AccessorHandler(accessor) {
+ CommandHandler.call(this, "accessor", true, accessor);
+}
+AccessorHandler.prototype = new CommandHandler;
+AccessorHandler.prototype.execute = function(seleniumApi, command) {
+ var returnValue = this.executor.call(seleniumApi, command.target, command.value);
+ var result = new CommandResult();
+ result.result = returnValue;
+ return result;
+};
+
+function AssertHandler(assertion, haltOnFailure) {
+ CommandHandler.call(this, "assert", haltOnFailure || false, assertion);
+}
+AssertHandler.prototype = new CommandHandler;
+AssertHandler.prototype.execute = function(seleniumApi, command) {
+ var result = new CommandResult();
+ try {
+ var processState = this.executor.call(seleniumApi, command.target, command.value);
+ result.passed = true;
+ } catch (e) {
+ // If this is not a AssertionFailedError, or we should haltOnFailure, rethrow.
+ if (!e.isAssertionFailedError) {
+ throw e;
+ }
+ if (this.haltOnFailure) {
+ var error = new Error(e.failureMessage);
+ error.message = e.failureMessage;
+ throw error;
+ }
+ result.failed = true;
+ result.failureMessage = e.failureMessage;
+ }
+ return result;
+};
+
+function CommandResult(processState) {
+ this.processState = processState;
+ this.result = "OK";
+}
+
+function SeleniumCommand(command, target, value) {
+ this.command = command;
+ this.target = target;
+ this.value = value;
+}
\ No newline at end of file
=== Products/Zelenium/selenium/selenium-executionloop.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-executionloop.js:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-executionloop.js Mon May 2 23:48:16 2005
@@ -1,129 +1,216 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-SELENIUM_PROCESS_WAIT = "wait";
-
-starting_up = true;
-TEST_FINISHED = true;
-TEST_CONTINUE = false;
-
-function TestLoop(commandFactory) {
- this.commandFactory = commandFactory;
-
- var self = this;
-
- this.start = function() {
- this.continueCurrentTest();
- }
-
- this.continueCurrentTest = function() {
- var testStatus = this.kickoffNextCommandExecution();
-
- if (testStatus == TEST_FINISHED) {
- this.testComplete();
- }
- }
-
- this.kickoffNextCommandExecution = function() {
-
- var command;
- if (starting_up == true) {
- command = this.firstCommand();
- starting_up = false;
- } else {
- command = this.nextCommand();
- }
-
- if (!command) return TEST_FINISHED;
-
- // Make the current row blue
- this.commandStarted(command);
-
- var result;
- try {
- var handler = this.commandFactory.getCommandHandler(command.command);
- if(handler == null) {
- throw new Error("Unknown command");
- }
-
- result = handler.execute(selenium, command);
- } catch (e) {
- this.commandError(e.message);
- return TEST_FINISHED;
- }
-
- // Record the result so that we can continue the execution using window.setTimeout()
- this.lastCommandResult = result;
- if (result.processState == SELENIUM_PROCESS_WAIT) {
- // Since we're waiting for page to reload, we can't continue command execution
- // directly, we need use a page load listener.
-
- // TODO there is a potential race condition by attaching a load listener after
- // the command has completed execution.
- selenium.callOnNextPageLoad(
- function() {eval("testLoop.continueCommandExecutionWithDelay()")}
- );
- } else {
- // Continue processing
- this.continueCommandExecutionWithDelay();
- }
-
- // Test is not finished.
- return TEST_CONTINUE;
- }
-
- /**
- * Continues the command execution, after waiting for the specified delay.
- */
- this.continueCommandExecutionWithDelay = function() {
- // Get the interval to use for this command execution, using the pauseInterval is
- // specified. Reset the pause interval, since it's a one-off thing.
- var interval = this.pauseInterval || this.getCommandInterval();
- this.pauseInterval = undefined;
-
- // Continue processing
- if (interval >= 0) {
- window.setTimeout("testLoop.finishCommandExecution()", interval);
- }
- }
-
- /**
- * Finishes the execution of the previous command, and continues the test
- */
- this.finishCommandExecution = function() {
- this.commandComplete(this.lastCommandResult);
- this.continueCurrentTest();
- }
-}
-
-/** The default is not to have any interval between commands. */
-TestLoop.prototype.getCommandInterval = function() {
- return 0;
-}
-
-TestLoop.prototype.firstCommand = noop;
-
-TestLoop.prototype.nextCommand = noop;
-
-TestLoop.prototype.commandStarted = noop;
-
-TestLoop.prototype.commandError = noop;
-
-TestLoop.prototype.commandComplete = noop;
-
-TestLoop.prototype.testComplete = noop;
-
-function noop() {};
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+SELENIUM_PROCESS_WAIT = "wait";
+
+starting_up = true;
+TEST_FINISHED = true;
+TEST_CONTINUE = false;
+
+function TestLoop(commandFactory, executionContext) {
+ this.commandFactory = commandFactory;
+
+ var self = this;
+
+ this.start = function() {
+ this.continueCurrentTest();
+ };
+
+ this.continueCurrentTest = function() {
+ var testStatus = this.kickoffNextCommandExecution();
+
+ if (testStatus == TEST_FINISHED) {
+ this.testComplete();
+ }
+ };
+
+ this.kickoffNextCommandExecution = function() {
+
+ var command;
+ if (starting_up == true) {
+ command = this.firstCommand();
+ starting_up = false;
+ } else {
+ command = this.nextCommand();
+ }
+
+ if (!command) return TEST_FINISHED;
+
+ // Make the current row blue
+ this.commandStarted(command);
+
+ LOG.debug("Executing: |" + command.command + " | " + command.target + " | " + command.value + " |");
+
+ var result;
+ try {
+ var handler = this.commandFactory.getCommandHandler(command.command);
+ if(handler == null) {
+ throw new Error("Unknown command");
+ }
+
+ result = handler.execute(selenium, command);
+ } catch (e) {
+ LOG.error(e);
+ // TODO: only throw typed errors from commands so that we can perform better error handling
+ // to differentiate between expected command errors and unexpected javascript errors.
+ if (e instanceof TypeError) {
+ // Not a command error.
+ throw e;
+ }
+ this.commandError(e.message);
+ return TEST_FINISHED;
+ }
+
+ // Record the result so that we can continue the execution using window.setTimeout()
+ this.lastCommandResult = result;
+ if (result.processState == SELENIUM_PROCESS_WAIT) {
+
+ executionContext.waitForPageLoad(this,selenium);
+
+ } else {
+ // Continue processing
+ this.continueCommandExecutionWithDelay();
+ }
+
+ // Test is not finished.
+ return TEST_CONTINUE;
+ };
+
+ /**
+ * Continues the command execution, after waiting for the specified delay.
+ */
+ this.continueCommandExecutionWithDelay = function() {
+ // Get the interval to use for this command execution, using the pauseInterval is
+ // specified. Reset the pause interval, since it's a one-off thing.
+ var interval = this.pauseInterval || this.getCommandInterval();
+ this.pauseInterval = undefined;
+
+ // Continue processing
+ if (interval >= 0) {
+ window.setTimeout("testLoop.finishCommandExecution()", interval);
+ }
+ };
+
+ /**
+ * Finishes the execution of the previous command, and continues the test
+ */
+ this.finishCommandExecution = function() {
+ this.commandComplete(this.lastCommandResult);
+ this.continueCurrentTest();
+ };
+}
+
+/** The default is not to have any interval between commands. */
+TestLoop.prototype.getCommandInterval = function() {
+ return 0;
+};
+
+TestLoop.prototype.firstCommand = noop;
+
+TestLoop.prototype.nextCommand = noop;
+
+TestLoop.prototype.commandStarted = noop;
+
+TestLoop.prototype.commandError = noop;
+
+TestLoop.prototype.commandComplete = noop;
+
+TestLoop.prototype.testComplete = noop;
+
+function noop() {
+
+};
+
+/**
+ * A selenium command that tells selenium to expect a failure on the next command
+ * execution. This command temporarily installs a new CommandFactory, that generates
+ * CommandHandlers that expect a failure.
+ */
+Selenium.prototype.assertFailureOnNext = function(message) {
+ if (!message) {
+ throw new Error("Message must be provided");
+ }
+
+ var expectFailureCommandFactory =
+ new ExpectFailureCommandFactory(testLoop.commandFactory, message);
+ expectFailureCommandFactory.baseExecutor = executeCommandAndReturnFailureMessage;
+ testLoop.commandFactory = expectFailureCommandFactory;
+};
+
+/**
+ * A selenium command that tells selenium to expect a failure on the next command
+ * execution. This command temporarily installs a new CommandFactory, that generates
+ * CommandHandlers that expect a failure.
+ */
+Selenium.prototype.assertErrorOnNext = function(message) {
+ if (!message) {
+ throw new Error("Message must be provided");
+ }
+
+ var expectFailureCommandFactory =
+ new ExpectFailureCommandFactory(testLoop.commandFactory, message);
+ expectFailureCommandFactory.baseExecutor = executeCommandAndReturnErrorMessage;
+ testLoop.commandFactory = expectFailureCommandFactory;
+};
+
+function ExpectFailureCommandFactory(originalCommandFactory, expectedErrorMessage) {
+ this.getCommandHandler = function(name) {
+ var baseHandler = originalCommandFactory.getCommandHandler(name);
+ var baseExecutor = this.baseExecutor;
+ var expectFailureCommand = {};
+ expectFailureCommand.execute = function() {
+ var baseFailureMessage = baseExecutor(baseHandler, arguments);
+ var result = new CommandResult();
+ if (!baseFailureMessage) {
+ result.failed = true;
+ result.failureMessage = "Command should have failed.";
+ }
+ else {
+ if (baseFailureMessage != expectedErrorMessage) {
+ result.failed = true;
+ result.failureMessage = "Expected failure message '" + expectedErrorMessage
+ + "' but was '" + baseFailureMessage + "'";
+ }
+ else {
+ result.passed = true;
+ result.result = baseFailureMessage;
+ }
+ }
+ testLoop.commandFactory = originalCommandFactory;
+ return result;
+ };
+ return expectFailureCommand;
+ };
+};
+
+function executeCommandAndReturnFailureMessage(baseHandler, originalArguments) {
+ var baseResult = baseHandler.execute.apply(baseHandler, originalArguments);
+ if (baseResult.passed) {
+ return null;
+ }
+ return baseResult.failureMessage;
+ };
+
+function executeCommandAndReturnErrorMessage(baseHandler, originalArguments) {
+ try {
+ baseHandler.execute.apply(baseHandler, originalArguments);
+ return null;
+ }
+ catch (expected) {
+ return expected.message;
+ }
+ };
+
=== Products/Zelenium/selenium/selenium-fitrunner.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-fitrunner.js:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium-fitrunner.js Mon May 2 23:48:16 2005
@@ -1,567 +1,656 @@
-/*
- * Copyright 2004 ThoughtWorks, Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-passColor = "#cfffcf";
-failColor = "#ffcfcf";
-workingColor = "#DEE7EC";
-
-// The current row in the list of commands (test script)
-currentCommandRow = 0;
-inputTableRows = null;
-
-// The current row in the list of tests (test suite)
-currentTestRow = 0;
-
-// Whether or not the jsFT should run all tests in the suite
-runAllTests = false;
-
-// Whether or not the current test has any errors;
-testFailed = false;
-suiteFailed = false;
-
-// Test Suite name got from query string
-testSuiteName = "";
-
-// Holds variables that are stored in a script
-storedVars = new Object();
-
-// Holds the handlers for each command.
-commandHandlers = null;
-
-// The number of tests run
-numTestPasses = 0;
-
-// The number of tests that have failed
-numTestFailures = 0;
-
-// The number of commands which have passed
-numCommandPasses = 0;
-
-// The number of commands which have failed
-numCommandFailures = 0;
-
-// The number of commands which have caused errors (element not found)
-numCommandErrors = 0;
-
-// The time that the test was started.
-startTime = null;
-
-// The current time.
-currentTime = null;
-
-// An simple enum for failureType
-ERROR = 0;
-FAILURE = 1;
-
-runInterval = 0;
-
-function setRunInterval() {
- runInterval = this.value;
-}
-
-function continueCurrentTest() {
- testLoop.finishCommandExecution()
-}
-
-function getSuiteFrame() {
- return document.getElementById('testSuiteFrame');
-}
-
-function getTestFrame(){
- return document.getElementById('testFrame');
-}
-
-function loadAndRunIfAuto() {
- loadSuiteFrame();
-}
-
-function loadSuiteFrame() {
- var testAppFrame = document.getElementById('myiframe');
- browserbot = new BrowserBot(testAppFrame);
- selenium = new Selenium(browserbot);
- registerCommandHandlers()
-
- document.getElementById("modeRun").onclick = setRunInterval;
- document.getElementById('modeWalk').onclick = setRunInterval;
- document.getElementById('modeStep').onclick = setRunInterval;
- document.getElementById('continueTest').onclick = continueCurrentTest;
-
- testSuiteName = getQueryStringTestName();
-
- if( testSuiteName != "" ) {
- addLoadListener(getSuiteFrame(), loadTestFrame);
- getSuiteFrame().src = testSuiteName;
- } else {
- loadTestFrame();
- }
-
- //testAppFrame.src = "http://selenium.thoughtworks.com";
-}
-
-function loadTestFrame() {
- removeLoadListener(getSuiteFrame(), loadTestFrame);
- suiteTable = getSuiteFrame().contentWindow.document.getElementsByTagName("table")[0];
-
- // Add an onclick function to each link in the suite table
- for(rowNum = 1;rowNum < suiteTable.rows.length; rowNum++) {
- addOnclick(suiteTable, rowNum);
- }
-
- if (isAutomatedRun())
- startTestSuite();
- else {
- testLink = suiteTable.rows[currentTestRow+1].cells[0].getElementsByTagName("a")[0];
- getTestFrame().src = testLink.href;
- }
-}
-
-// Adds an onclick function to the link in the given row in suite table.
-// This function checks whether the test has already been run and the data is
-// stored. If the data is stored, it sets the test frame to be the stored data.
-// Otherwise, it loads the fresh page.
-function addOnclick(suiteTable, rowNum) {
- aLink = suiteTable.rows[rowNum].cells[0].getElementsByTagName("a")[0];
- aLink.onclick = function(eventObj) {
- srcObj = null;
-
- // For mozilla-like browsers
- if(eventObj)
- srcObj = eventObj.target;
-
- // For IE-like browsers
- else if (getSuiteFrame().contentWindow.event)
- srcObj = getSuiteFrame().contentWindow.event.srcElement;
-
- // The target row
- row = srcObj.parentNode.parentNode.rowIndex;
-
- // If the row has a stored results table, use that
- if(suiteTable.rows[row].cells[1]) {
- getTestFrame().contentWindow.document.body.innerHTML = getText(suiteTable.rows[row].cells[1]);
- }
- // Otherwise, just open up the fresh page.
- else {
- getTestFrame().src = suiteTable.rows[row].cells[0].getElementsByTagName("a")[0].href;
- }
-
- return false;
- };
-}
-
-function getQueryStringTestName() {
- testName = "";
- myVars = location.search.substr(1).split('&');
- for (var i =0;i < myVars.length; i++) {
- nameVal = myVars[i].split('=')
- if( nameVal[0] == "test" ) {
- testName="/" + nameVal[1];
- }
- }
- return testName;
-}
-
-function isAutomatedRun() {
- myVars = location.search.substr(1).split('&');
- for (var i =0;i < myVars.length; i++) {
- nameVal = myVars[i].split('=')
- if( nameVal[0] == "auto" && nameVal[1].toLowerCase() == "true" )
- return true;
- }
-
- return false;
-}
-
-function resetMetrics() {
- numTestPasses = 0;
- numTestFailures = 0;
- numCommandPasses = 0;
- numCommandFailures = 0;
- numCommandErrors = 0;
- startTime = new Date().getTime();
-}
-
-function runSingleTest() {
- runAllTests = false;
- resetMetrics();
- startTest();
-}
-
-function startTest() {
- removeLoadListener(getTestFrame(), startTest);
- getTestFrame().contentWindow.scrollTo(0,0);
- inputTable = (getTestFrame().contentWindow.document.getElementsByTagName("table"))[0];
- inputTableRows = inputTable.rows;
- currentCommandRow = 0;
- testFailed = false;
- storedVars = new Object();
-
- clearRowColours();
-
- testLoop = initialiseTestLoop();
- testLoop.start();
-}
-
-function clearRowColours() {
- for (var i = 0; i <= inputTableRows.length - 1; i++) {
- inputTableRows[i].bgColor = "white";
- }
-}
-
-function startTestSuite() {
- resetMetrics();
- currentTestRow = 0;
- runAllTests = true;
- suiteFailed = false;
-
- runNextTest();
-}
-
-function runNextTest() {
- if (!runAllTests)
- return;
-
- // Scroll the suite frame down by 25 pixels once we get past the first cell.
- if(currentTestRow >= 1)
- getSuiteFrame().contentWindow.scrollBy(0,25);
-
- suiteTable = (getSuiteFrame().contentWindow.document.getElementsByTagName("table"))[0];
-
- // Do not change the row color of the first row
- if(currentTestRow > 0) {
- // Make the previous row green or red depending if the test passed or failed
- if(testFailed)
- setCellColor(suiteTable.rows, currentTestRow, 0, failColor);
- else
- setCellColor(suiteTable.rows, currentTestRow, 0, passColor);
-
- // Set the results from the previous test run
- setResultsData(suiteTable, currentTestRow);
- }
-
- currentTestRow++;
-
- // If we are done with all of the tests, set the title bar as pass or fail
- if(currentTestRow >= suiteTable.rows.length) {
- if(suiteFailed)
- setCellColor(suiteTable.rows, 0, 0, failColor);
- else
- setCellColor(suiteTable.rows, 0, 0, passColor);
-
- // If this is an automated run (i.e., build script), then submit
- // the test results by posting to a form
- if (isAutomatedRun())
- postTestResults(suiteFailed, suiteTable);
- }
-
- else {
- // Make the current row blue
- setCellColor(suiteTable.rows, currentTestRow, 0, workingColor);
-
- testLink = suiteTable.rows[currentTestRow].cells[0].getElementsByTagName("a")[0];
-
- addLoadListener(getTestFrame(), startTest);
- getTestFrame().src = testLink.href;
- }
-}
-
-function setCellColor(tableRows, row, col, colorStr) {
- tableRows[row].cells[col].bgColor = colorStr;
-}
-
-// Sets the results from a test into a hidden column on the suite table. So,
-// for each tests, the second column is set to the HTML from the test table.
-function setResultsData(suiteTable, row) {
- // Create a text node of the test table
- tableContents = suiteTable.ownerDocument.createTextNode(getTestFrame().contentWindow.document.body.innerHTML);
-
- new_column = suiteTable.ownerDocument.createElement("td");
- new_column.appendChild(tableContents);
-
- // Set the column to be invisible
- new_column.style.cssText = "display: none;";
-
- // Add the invisible column
- suiteTable.rows[row].appendChild(new_column);
-}
-
-// Post the results to /postResults. The parameters are:
-// result: passed/failed depending on whether the suite passed or failed
-// totalTime: the total running time in seconds for the suite.
-//
-// numTestPasses: the total number of tests which passed.
-// numTestFailures: the total number of tests which failed.
-//
-// numCommandPasses: the total number of commands which passed.
-// numCommandFailures: the total number of commands which failed.
-// numCommandErrors: the total number of commands which errored.
-//
-// suite: the suite table, including the hidden column of test results
-// testTable.1 to testTable.N: the individual test tables
-function postTestResults(suiteFailed, suiteTable) {
- form = document.createElement("form");
- form.id = "resultsForm";
- form.action = "/postResults"
- form.method="post";
- form.enctype="multipart/form-data"
-
- resultInput = createInputField("result", suiteFailed == true ? "failed" : "passed");
- form.appendChild(resultInput);
-
- timeInput = createInputField("totalTime", Math.floor((currentTime - startTime) / 1000));
- form.appendChild(timeInput);
-
- testPassesInput = createInputField("numTestPasses", numTestPasses);
- form.appendChild(testPassesInput);
-
- testFailuresInput = createInputField("numTestFailures", numTestFailures);
- form.appendChild(testFailuresInput);
-
- commandPassesInput = createInputField("numCommandPasses", numCommandPasses);
- form.appendChild(commandPassesInput);
-
- commandFailuresInput = createInputField("numCommandFailures", numCommandFailures);
- form.appendChild(commandFailuresInput);
-
- commandErrorsInput = createInputField("numCommandErrors", numCommandErrors);
- form.appendChild(commandErrorsInput);
-
- suiteInput = createInputField("suite", escape(suiteTable.parentNode.innerHTML));
- form.appendChild(suiteInput);
-
- // Create an input for each test table. The inputs are named testTable.1, testTable.2, etc.
- for (rowNum = 1;rowNum < suiteTable.rows.length;rowNum++) {
- // If there is a second column, then add a new input
- if (suiteTable.rows[rowNum].cells.length > 1) {
- testInput = createInputField("testTable." + rowNum, escape(getText(suiteTable.rows[rowNum].cells[1])));
- form.appendChild(testInput);
- }
- }
-
- document.body.appendChild(form);
-
- form.submit();
-}
-
-function createInputField(name, value) {
- input = document.createElement("input");
- input.type = "hidden";
- input.name = name;
- input.value = value;
-
- return input;
-}
-
-function printMetrics() {
- setText(document.getElementById("commandPasses"), numCommandPasses);
- setText(document.getElementById("commandFailures"), numCommandFailures);
- setText(document.getElementById("commandErrors"), numCommandErrors);
- setText(document.getElementById("testRuns"), numTestPasses);
- setText(document.getElementById("testFailures"), numTestFailures);
-
- currentTime = new Date().getTime();
-
- timeDiff = currentTime - startTime;
- totalSecs = Math.floor(timeDiff / 1000);
-
- minutes = Math.floor(totalSecs / 60);
- seconds = totalSecs % 60;
-
- setText(document.getElementById("elapsedTime"), pad(minutes)+":"+pad(seconds));
-}
-
-// Puts a leading 0 on num if it is less than 10
-function pad (num) {
- return (num > 9) ? num : "0" + num;
-}
-
-// Search through str and replace all variable references ${varName} with their
-// value in storedVars.
-function replaceVariables(str) {
-
- //handle the case of ${userid}.toUpper
- pattern = /\$\{(\w+)\}\.(.+)/
-
- var variableIndex = str;
- var variableFunction='';
-
- if(pattern.test(str)) {
- pieces = str.split('.');
-
- variableIndex = pieces[0];
- variableFunction = pieces[1];
- }
-
-
- regex = /\$\{(\w+)\}/g;
-
- var variableValue = variableIndex.replace(regex, function(match, word) {
- return storedVars[word];
- });
-
- if( variableFunction == '')
- return variableValue;
- else
- {
- return eval("variableValue."+ eval("variableFunction") + "()" )
- }
-}
- // Register all of the built-in command handlers with the CommandHandlerFactory.
-// TODO work out an easy way for people to register handlers without modifying the Selenium sources.
-function registerCommandHandlers() {
- commandFactory = new CommandHandlerFactory();
- commandFactory.registerAll(selenium);
-
- // These actions are overridden for fitrunner, as they still involve some FitRunner smarts,
- // because of the wait/nowait behaviour modification. We need a generic solution to this.
- commandFactory.registerAction("click", selenium.doClickWithOptionalWait);
-
-}
-
-function initialiseTestLoop() {
- testLoop = new TestLoop(commandFactory);
-
- testLoop.getCommandInterval = function() { return runInterval };
- testLoop.firstCommand = nextCommand;
- testLoop.nextCommand = nextCommand;
- testLoop.commandStarted = commandStarted;
- testLoop.commandComplete = commandComplete;
- testLoop.commandError = commandError;
- testLoop.testComplete = testComplete;
- return testLoop
-}
-
-function nextCommand() {
- if (currentCommandRow >= inputTableRows.length - 1) {
- return null;
- }
-
- currentCommandRow++;
-
- var commandName = getCellText(currentCommandRow, 0);
- var target = replaceVariables(getCellText(currentCommandRow, 1));
- var value = replaceVariables(getCellText(currentCommandRow, 2));
-
- var command = new SeleniumCommand(commandName, target, value);
- return command;
-}
-
-function commandStarted() {
- // Make the current row blue
- inputTableRows[currentCommandRow].bgColor = "#DEE7EC";
-
- // Scroll the test frame down by 25 pixels once we get past the first 5 cells.
- if(currentCommandRow >= 5)
- getTestFrame().contentWindow.scrollBy(0,25);
-
- printMetrics();
-}
-
-function commandComplete(result) {
- if (result.failed) {
- setRowFailed(result.failureMessage, FAILURE);
- } else if (result.passed) {
- setRowPassed();
- } else {
- setRowWhite();
- }
-}
-
-function commandError(errorMessage) {
- setRowFailed(errorMessage, ERROR);
-}
-
-function setRowWhite() {
- inputTableRows[currentCommandRow].bgColor = "white";
-}
-
-function setRowPassed() {
- numCommandPasses += 1;
-
- // Set cell background to green
- inputTableRows[currentCommandRow].bgColor = passColor;
-}
-
-function setRowFailed(errorMsg, failureType) {
- if (failureType == ERROR)
- numCommandErrors += 1;
- else if (failureType == FAILURE)
- numCommandFailures += 1;
-
- // Set cell background to red
- inputTableRows[currentCommandRow].bgColor = failColor;
-
- // Set error message
- inputTableRows[currentCommandRow].cells[2].innerHTML = errorMsg;
- inputTableRows[currentCommandRow].title = errorMsg;
- testFailed = true;
- suiteFailed = true;
-}
-
-function testComplete() {
- if(testFailed) {
- inputTableRows[0].bgColor = failColor;
- numTestFailures += 1;
- }
- else {
- inputTableRows[0].bgColor = passColor;
- numTestPasses += 1;
- }
-
- printMetrics();
-
- window.setTimeout("runNextTest()", 1);
-}
-
-function getCellText(rowNumber, columnNumber) {
- return getText(inputTableRows[rowNumber].cells[columnNumber]);
-}
-
-Selenium.prototype.doPause = function(waitTime) {
- testLoop.pauseInterval = waitTime;
-}
-
-// Store the value of a form input in a variable
-Selenium.prototype.doStoreValue = function(target, varName) {
- if (!varName) {
- // Backward compatibility mode: read the ENTIRE text of the page
- // and stores it in a variable with the name of the target
- value = this.page().bodyText();
- storedVars[target] = value;
- return;
- }
- var element = this.page().findElement(target);
- storedVars[varName] = getInputValue(element);
-}
-
-// Store the text of an element in a variable
-Selenium.prototype.doStoreText = function(target, varName) {
- var element = this.page().findElement(target);
- storedVars[varName] = getText(element);
-}
-
-Selenium.prototype.doClickWithOptionalWait = function(target, wait) {
-
- this.doClick(target);
-
- if(wait != "nowait") {
- return SELENIUM_PROCESS_WAIT;
- }
-
-}
-
-
-
+/*
+* Copyright 2004 ThoughtWorks, Inc
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+passColor = "#cfffcf";
+failColor = "#ffcfcf";
+workingColor = "#DEE7EC";
+
+// The current row in the list of commands (test script)
+currentCommandRow = 0;
+inputTableRows = null;
+
+// The current row in the list of tests (test suite)
+currentTestRow = 0;
+
+// Whether or not the jsFT should run all tests in the suite
+runAllTests = false;
+
+// Whether or not the current test has any errors;
+testFailed = false;
+suiteFailed = false;
+
+// Holds variables that are stored in a script
+storedVars = new Object();
+
+// Holds the handlers for each command.
+commandHandlers = null;
+
+// The number of tests run
+numTestPasses = 0;
+
+// The number of tests that have failed
+numTestFailures = 0;
+
+// The number of commands which have passed
+numCommandPasses = 0;
+
+// The number of commands which have failed
+numCommandFailures = 0;
+
+// The number of commands which have caused errors (element not found)
+numCommandErrors = 0;
+
+// The time that the test was started.
+startTime = null;
+
+// The current time.
+currentTime = null;
+
+// An simple enum for failureType
+ERROR = 0;
+FAILURE = 1;
+
+runInterval = 0;
+
+function setRunInterval() {
+ runInterval = this.value;
+}
+
+function continueCurrentTest() {
+ testLoop.finishCommandExecution();
+}
+
+function getApplicationFrame() {
+ return document.getElementById('myiframe');
+}
+
+function getSuiteFrame() {
+ return document.getElementById('testSuiteFrame');
+}
+
+function getTestFrame(){
+ return document.getElementById('testFrame');
+}
+
+function loadAndRunIfAuto() {
+ loadSuiteFrame();
+}
+
+function getExecutionContext() {
+ if (isNewWindow()) {
+ return getWindowExecutionContext();
+ }
+ else if (isSafari || isKonqueror) {
+ return new KonquerorIFrameExecutionContext();
+ }
+ else {
+ return new IFrameExecutionContext();
+ }
+}
+
+function start() {
+ loadSuiteFrame(getExecutionContext());
+}
+
+function loadSuiteFrame(executionContext) {
+
+ var testAppFrame = executionContext.loadFrame();
+ browserbot = createBrowserBot(testAppFrame,executionContext);
+ selenium = new Selenium(browserbot);
+ registerCommandHandlers();
+
+ //set the runInterval if there is a queryParameter for it
+ var tempRunInterval = getQueryParameter("runInterval");
+ if (tempRunInterval) {
+ runInterval = tempRunInterval;
+ }
+
+ document.getElementById("modeRun").onclick = setRunInterval;
+ document.getElementById('modeWalk').onclick = setRunInterval;
+ document.getElementById('modeStep').onclick = setRunInterval;
+ document.getElementById('continueTest').onclick = continueCurrentTest;
+
+ var testSuiteName = getQueryParameter("test");
+
+ if (testSuiteName) {
+ addLoadListener(getSuiteFrame(), onloadTestSuite);
+ getSuiteFrame().src = testSuiteName;
+ } else {
+ onloadTestSuite();
+ }
+}
+
+function startSingleTest() {
+ removeLoadListener(getApplicationFrame(), startSingleTest);
+ var singleTestName = getQueryParameter("singletest");
+ addLoadListener(getTestFrame(), startTest);
+ getTestFrame().src = singleTestName;
+}
+
+function getIframeDocument(iframe)
+{
+ if (iframe.contentDocument) {
+ return iframe.contentDocument;
+ }
+ else {
+ return iframe.contentWindow.document;
+ }
+}
+
+function onloadTestSuite() {
+ removeLoadListener(getSuiteFrame(), onloadTestSuite);
+ suiteTable = getIframeDocument(getSuiteFrame()).getElementsByTagName("table")[0];
+
+ // Add an onclick function to each link in the suite table
+ for(rowNum = 1;rowNum < suiteTable.rows.length; rowNum++) {
+ addOnclick(suiteTable, rowNum);
+ }
+
+
+ if (isAutomatedRun()) {
+ startTestSuite();
+ } else if (getQueryParameter("autoURL")) {
+
+ addLoadListener(getApplicationFrame(), startSingleTest);
+
+ getApplicationFrame().src = getQueryParameter("autoURL");
+
+ } else {
+ testLink = suiteTable.rows[currentTestRow+1].cells[0].getElementsByTagName("a")[0];
+ getTestFrame().src = testLink.href;
+ }
+}
+
+// Adds an onclick function to the link in the given row in suite table.
+// This function checks whether the test has already been run and the data is
+// stored. If the data is stored, it sets the test frame to be the stored data.
+// Otherwise, it loads the fresh page.
+function addOnclick(suiteTable, rowNum) {
+ aLink = suiteTable.rows[rowNum].cells[0].getElementsByTagName("a")[0];
+ aLink.onclick = function(eventObj) {
+ srcObj = null;
+
+ // For mozilla-like browsers
+ if(eventObj)
+ srcObj = eventObj.target;
+
+ // For IE-like browsers
+ else if (getSuiteFrame().contentWindow.event)
+ srcObj = getSuiteFrame().contentWindow.event.srcElement;
+
+ // The target row (the event source is not consistently reported by browsers)
+ row = srcObj.parentNode.parentNode.rowIndex || srcObj.parentNode.parentNode.parentNode.rowIndex;
+
+ // If the row has a stored results table, use that
+ if(suiteTable.rows[row].cells[1]) {
+ var bodyElement = getIframeDocument(getTestFrame()).body;
+
+ // Create a div element to hold the results table.
+ var tableNode = getIframeDocument(getTestFrame()).createElement("div");
+ var resultsCell = suiteTable.rows[row].cells[1];
+ tableNode.innerHTML = resultsCell.innerHTML;
+
+ // Append this text node, and remove all the preceding nodes.
+ bodyElement.appendChild(tableNode);
+ while (bodyElement.firstChild != bodyElement.lastChild) {
+ bodyElement.removeChild(bodyElement.firstChild);
+ }
+ }
+ // Otherwise, just open up the fresh page.
+ else {
+ getTestFrame().src = suiteTable.rows[row].cells[0].getElementsByTagName("a")[0].href;
+ }
+
+ return false;
+ };
+}
+
+function isQueryParameterTrue(name) {
+ parameterValue = getQueryParameter(name);
+ return (parameterValue != null && parameterValue.toLowerCase() == "true");
+}
+
+function getQueryParameter(searchKey) {
+ var clauses = location.search.substr(1).split('&');
+ for (var i = 0; i < clauses.length; i++) {
+ var keyValuePair = clauses[i].split('=',2);
+ var key = unescape(keyValuePair[0]);
+ if (key == searchKey) {
+ return unescape(keyValuePair[1]);
+ }
+ }
+ return null;
+}
+
+function isNewWindow() {
+ return isQueryParameterTrue("newWindow");
+}
+
+function isAutomatedRun() {
+ return isQueryParameterTrue("auto");
+}
+
+function resetMetrics() {
+ numTestPasses = 0;
+ numTestFailures = 0;
+ numCommandPasses = 0;
+ numCommandFailures = 0;
+ numCommandErrors = 0;
+ startTime = new Date().getTime();
+}
+
+function runSingleTest() {
+ runAllTests = false;
+ resetMetrics();
+ startTest();
+}
+
+function startTest() {
+ removeLoadListener(getTestFrame(), startTest);
+
+ // Scroll to the top of the test frame
+ if (getTestFrame().contentWindow) {
+ getTestFrame().contentWindow.scrollTo(0,0);
+ }
+ else {
+ frames['testFrame'].scrollTo(0,0);
+ }
+
+ inputTable = getIframeDocument(getTestFrame()).getElementsByTagName("table")[0];
+ inputTableRows = inputTable.rows;
+ currentCommandRow = 0;
+ testFailed = false;
+ storedVars = new Object();
+
+ clearRowColours();
+
+ testLoop = initialiseTestLoop();
+ testLoop.start();
+}
+
+function clearRowColours() {
+ for (var i = 0; i <= inputTableRows.length - 1; i++) {
+ inputTableRows[i].bgColor = "white";
+ }
+}
+
+function startTestSuite() {
+ resetMetrics();
+ currentTestRow = 0;
+ runAllTests = true;
+ suiteFailed = false;
+
+ runNextTest();
+}
+
+function runNextTest() {
+ if (!runAllTests)
+ return;
+
+ suiteTable = getIframeDocument(getSuiteFrame()).getElementsByTagName("table")[0];
+
+ // Do not change the row color of the first row
+ if(currentTestRow > 0) {
+ // Make the previous row green or red depending if the test passed or failed
+ if(testFailed)
+ setCellColor(suiteTable.rows, currentTestRow, 0, failColor);
+ else
+ setCellColor(suiteTable.rows, currentTestRow, 0, passColor);
+
+ // Set the results from the previous test run
+ setResultsData(suiteTable, currentTestRow);
+ }
+
+ currentTestRow++;
+
+ // If we are done with all of the tests, set the title bar as pass or fail
+ if(currentTestRow >= suiteTable.rows.length) {
+ if(suiteFailed)
+ setCellColor(suiteTable.rows, 0, 0, failColor);
+ else
+ setCellColor(suiteTable.rows, 0, 0, passColor);
+
+ // If this is an automated run (i.e., build script), then submit
+ // the test results by posting to a form
+ if (isAutomatedRun())
+ postTestResults(suiteFailed, suiteTable);
+ }
+
+ else {
+ // Make the current row blue
+ setCellColor(suiteTable.rows, currentTestRow, 0, workingColor);
+
+ testLink = suiteTable.rows[currentTestRow].cells[0].getElementsByTagName("a")[0];
+ testLink.focus();
+
+ addLoadListener(getTestFrame(), startTest);
+ getExecutionContext().open(testLink.href, getTestFrame());
+ }
+}
+
+function setCellColor(tableRows, row, col, colorStr) {
+ tableRows[row].cells[col].bgColor = colorStr;
+}
+
+// Sets the results from a test into a hidden column on the suite table. So,
+// for each tests, the second column is set to the HTML from the test table.
+function setResultsData(suiteTable, row) {
+ // Create a text node of the test table
+ var resultTable = getIframeDocument(getTestFrame()).body.innerHTML;
+ if (!resultTable) return;
+
+ var tableNode = suiteTable.ownerDocument.createElement("div");
+ tableNode.innerHTML = resultTable;
+
+ var new_column = suiteTable.ownerDocument.createElement("td");
+ new_column.appendChild(tableNode);
+
+ // Set the column to be invisible
+ new_column.style.cssText = "display: none;";
+
+ // Add the invisible column
+ suiteTable.rows[row].appendChild(new_column);
+}
+
+// Post the results to a servlet, CGI-script, etc. The URL of the
+// results-handler defaults to "/postResults", but an alternative location
+// can be specified by providing a "resultsUrl" query parameter.
+//
+// Parameters passed to the results-handler are:
+// result: passed/failed depending on whether the suite passed or failed
+// totalTime: the total running time in seconds for the suite.
+//
+// numTestPasses: the total number of tests which passed.
+// numTestFailures: the total number of tests which failed.
+//
+// numCommandPasses: the total number of commands which passed.
+// numCommandFailures: the total number of commands which failed.
+// numCommandErrors: the total number of commands which errored.
+//
+// suite: the suite table, including the hidden column of test results
+// testTable.1 to testTable.N: the individual test tables
+//
+function postTestResults(suiteFailed, suiteTable) {
+
+ form = document.createElement("form");
+ document.body.appendChild(form);
+
+ form.id = "resultsForm";
+ form.method="post";
+ form.target="myiframe";
+
+ var resultsUrl = getQueryParameter("resultsUrl");
+ if (!resultsUrl) {
+ resultsUrl = "./postResults";
+ }
+
+ var actionAndParameters = resultsUrl.split('?',2);
+ form.action = actionAndParameters[0];
+ var resultsUrlQueryString = actionAndParameters[1];
+
+ form.createHiddenField = function(name, value) {
+ input = document.createElement("input");
+ input.type = "hidden";
+ input.name = name;
+ input.value = value;
+ this.appendChild(input);
+ };
+
+ if (resultsUrlQueryString) {
+ var clauses = resultsUrlQueryString.split('&');
+ for (var i = 0; i < clauses.length; i++) {
+ var keyValuePair = clauses[i].split('=',2);
+ var key = unescape(keyValuePair[0]);
+ var value = unescape(keyValuePair[1]);
+ form.createHiddenField(key, value);
+ }
+ }
+
+ form.createHiddenField("result", suiteFailed == true ? "failed" : "passed");
+
+ form.createHiddenField("totalTime", Math.floor((currentTime - startTime) / 1000));
+ form.createHiddenField("numTestPasses", numTestPasses);
+ form.createHiddenField("numTestFailures", numTestFailures);
+ form.createHiddenField("numCommandPasses", numCommandPasses);
+ form.createHiddenField("numCommandFailures", numCommandFailures);
+ form.createHiddenField("numCommandErrors", numCommandErrors);
+
+ // Create an input for each test table. The inputs are named
+ // testTable.1, testTable.2, etc.
+ for (rowNum = 1; rowNum < suiteTable.rows.length;rowNum++) {
+ // If there is a second column, then add a new input
+ if (suiteTable.rows[rowNum].cells.length > 1) {
+ var resultCell = suiteTable.rows[rowNum].cells[1];
+ form.createHiddenField("testTable." + rowNum, getText(resultCell));
+ // remove the resultCell, so it's not included in the suite HTML
+ resultCell.parentNode.removeChild(resultCell);
+ }
+ }
+
+ // Add HTML for the suite itself
+ form.createHiddenField("suite", suiteTable.parentNode.innerHTML);
+
+ form.submit();
+ document.body.removeChild(form);
+
+}
+
+function printMetrics() {
+ setText(document.getElementById("commandPasses"), numCommandPasses);
+ setText(document.getElementById("commandFailures"), numCommandFailures);
+ setText(document.getElementById("commandErrors"), numCommandErrors);
+ setText(document.getElementById("testRuns"), numTestPasses + numTestFailures);
+ setText(document.getElementById("testFailures"), numTestFailures);
+
+ currentTime = new Date().getTime();
+
+ timeDiff = currentTime - startTime;
+ totalSecs = Math.floor(timeDiff / 1000);
+
+ minutes = Math.floor(totalSecs / 60);
+ seconds = totalSecs % 60;
+
+ setText(document.getElementById("elapsedTime"), pad(minutes)+":"+pad(seconds));
+}
+
+// Puts a leading 0 on num if it is less than 10
+function pad (num) {
+ return (num > 9) ? num : "0" + num;
+}
+
+/*
+ * Search through str and replace all variable references ${varName} with their
+ * value in storedVars.
+ */
+function replaceVariables(str) {
+ // We can't use a String.replace(regexp, replacementFunction) since this doesn't
+ // work in safari. So replace each match 1 at a time.
+ var stringResult = str;
+ var match;
+ while (match = stringResult.match(/\$\{(\w+)\}/)) {
+ var variable = match[0];
+ var name = match[1];
+ var replacement = storedVars[name];
+ stringResult = stringResult.replace(variable, replacement);
+ }
+ return stringResult;
+}
+
+/*
+ * Register all of the built-in command handlers with the CommandHandlerFactory.
+ * TODO work out an easy way for people to register handlers without modifying the Selenium sources.
+ */
+function registerCommandHandlers() {
+ commandFactory = new CommandHandlerFactory();
+ commandFactory.registerAll(selenium);
+
+ // These actions are overridden for fitrunner, as they still involve some FitRunner smarts,
+ // because of the wait/nowait behaviour modification. We need a generic solution to this.
+ commandFactory.registerAction("click", selenium.doClickWithOptionalWait);
+
+}
+
+function initialiseTestLoop() {
+ testLoop = new TestLoop(commandFactory, getExecutionContext());
+
+ testLoop.getCommandInterval = function() { return runInterval; };
+ testLoop.firstCommand = nextCommand;
+ testLoop.nextCommand = nextCommand;
+ testLoop.commandStarted = commandStarted;
+ testLoop.commandComplete = commandComplete;
+ testLoop.commandError = commandError;
+ testLoop.testComplete = testComplete;
+ return testLoop;
+}
+
+function nextCommand() {
+ if (currentCommandRow >= inputTableRows.length - 1) {
+ return null;
+ }
+
+ currentCommandRow++;
+
+ var commandName = getCellText(currentCommandRow, 0);
+ var target = replaceVariables(getCellText(currentCommandRow, 1));
+ var value = replaceVariables(getCellText(currentCommandRow, 2));
+
+
+ var command = new SeleniumCommand(commandName, target, removeNbsp(value));
+ return command;
+}
+
+function removeNbsp(value)
+{
+ return value.replace(/\240/g, "");
+}
+
+function focusOnElement(element) {
+ if (element.focus) {
+ element.focus();
+ return;
+ }
+ var anchor = element.ownerDocument.createElement("a");
+ anchor.innerHTML = "!CURSOR!";
+ element.appendChild(anchor, element);
+ anchor.focus();
+ element.removeChild(anchor);
+}
+
+function commandStarted() {
+ inputTableRows[currentCommandRow].bgColor = workingColor;
+ focusOnElement(inputTableRows[currentCommandRow].cells[0]);
+ printMetrics();
+}
+
+function commandComplete(result) {
+ if (result.failed) {
+ setRowFailed(result.failureMessage, FAILURE);
+ } else if (result.passed) {
+ setRowPassed();
+ } else {
+ setRowWhite();
+ }
+}
+
+function commandError(errorMessage) {
+ setRowFailed(errorMessage, ERROR);
+}
+
+function setRowWhite() {
+ inputTableRows[currentCommandRow].bgColor = "white";
+}
+
+function setRowPassed() {
+ numCommandPasses += 1;
+
+ // Set cell background to green
+ inputTableRows[currentCommandRow].bgColor = passColor;
+}
+
+function setRowFailed(errorMsg, failureType) {
+ if (failureType == ERROR)
+ numCommandErrors += 1;
+ else if (failureType == FAILURE)
+ numCommandFailures += 1;
+
+ // Set cell background to red
+ inputTableRows[currentCommandRow].bgColor = failColor;
+
+ // Set error message
+ inputTableRows[currentCommandRow].cells[2].innerHTML = errorMsg;
+ inputTableRows[currentCommandRow].title = errorMsg;
+ testFailed = true;
+ suiteFailed = true;
+}
+
+function testComplete() {
+ if(testFailed) {
+ inputTableRows[0].bgColor = failColor;
+ numTestFailures += 1;
+ }
+ else {
+ inputTableRows[0].bgColor = passColor;
+ numTestPasses += 1;
+ }
+
+ printMetrics();
+
+ window.setTimeout("runNextTest()", 1);
+}
+
+function getCellText(rowNumber, columnNumber) {
+ return getText(inputTableRows[rowNumber].cells[columnNumber]);
+}
+
+Selenium.prototype.doPause = function(waitTime) {
+ selenium.callOnNextPageLoad(null);
+ testLoop.pauseInterval = waitTime;
+};
+
+// Store the value of a form input in a variable
+Selenium.prototype.doStoreValue = function(target, varName) {
+ if (!varName) {
+ // Backward compatibility mode: read the ENTIRE text of the page
+ // and stores it in a variable with the name of the target
+ value = this.page().bodyText();
+ storedVars[target] = value;
+ return;
+ }
+ var element = this.page().findElement(target);
+ storedVars[varName] = getInputValue(element);
+};
+
+// Store the text of an element in a variable
+Selenium.prototype.doStoreText = function(target, varName) {
+ var element = this.page().findElement(target);
+ storedVars[varName] = getText(element);
+};
+
+Selenium.prototype.doSetVariable = function(varName, variableExpression) {
+ var value = eval(variableExpression);
+ storedVars[varName] = value;
+};
+
+Selenium.prototype.doClickWithOptionalWait = function(target, wait) {
+
+ this.doClick(target);
+
+ if(wait != "nowait") {
+ return SELENIUM_PROCESS_WAIT;
+ }
+
+};
=== Products/Zelenium/selenium/selenium.css 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium.css:1.1.1.1 Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/selenium.css Mon May 2 23:48:16 2005
@@ -1,92 +1,187 @@
/*
- * Copyright 2004 ThoughtWorks, Inc
- *
+ * Copyright 2005 ThoughtWorks, Inc
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
-#seleniumControlPanel {
- position: absolute;
- top: 0px;
- left: 230px;
- height: 20%;
- width: 77%;
- background-color: white;
+
+/*---( Layout )---*/
+
+body {
+ margin: 0;
+ padding: 0;
+ overflow: auto;
+}
+
+td {
+ position: static;
+}
+
+tr {
+ vertical-align: top;
+}
+
+.layout {
+ width: 100%;
+ height: 100%;
+ border-collapse: collapse;
+}
+
+.layout td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+iframe {
+ width: 100%;
+ height: 100%;
+ border: 0;
+ background: white;
+ overflow: auto;
+}
+
+/*---( Style )---*/
+
+body, html {
+ font-family: Verdana, Arial, sans-serif;
+}
+
+.selenium th, .selenium td {
+ border: 1px solid #999;
+}
+
+.header {
+ background: #ccc;
+ padding: 0;
+ font-size: 90%;
+}
+
+#controlPanel {
+ padding: 5px;
+ background: #eee;
overflow: auto;
- padding: 0px;
- margin: 5px;
- background: url(selenium-logo.jpg) no-repeat right;
-}
-#launchPanel {
- position: absolute;
- top: 10px;
- left: 2%;
- width: 10%;
-}
-#launchPanel button {
- color: white;
- background-color: green;
+}
+
+#controlPanel table {
+ font-size: 75%;
+}
+
+#controlPanel th, #controlPanel td {
+ border: 0;
+}
+
+#controls {
+ color: inherit;
+ width: 100%;
+}
+
+#controls td {
+ margin: 1px;
+ padding: 1px;
+ text-align: center;
+}
+
+h1 {
+ margin: 0.2ex;
+ font-size: 130%;
font-weight: bold;
- font-size: 12px;
- display: block;
+}
+
+h2 {
+ margin: 0.2ex;
+ font-size: 80%;
+ font-weight: normal;
+}
+
+.selenium a {
+ color: black;
+ text-decoration: none;
+}
+
+.selenium a:hover {
+ text-decoration: underline;
+}
+
+button, label {
cursor: pointer;
- margin-top:7pt;
}
-#runSpeedPanel {
- position: absolute;
- top: 10px;
- left: 19%;
- width: 15%;
-}
-#runSpeedPanel label {
- display: block;
-}
-
-table#resultsPanel {
- position: absolute;
- top: 10px;
- left: 35%;
- background-color: white;
- border: solid 1px;
- overflow: hidden;
- height: 20%;
-}
-table#resultsPanel td {
- padding:0px;
- margin:0px;
+
+#stats {
+ border-top: 1px solid #999;
+ border-bottom: 1px solid #999;
+ margin-top: 10px;
}
-table#resultsPanel th {
+
+#stats th, #stats td {
text-align: left;
+ padding-left: 2px;
+}
+
+#stats th {
+ text-decoration: underline;
+}
+
+#stats td.count {
font-weight: bold;
- padding:0px;
- margin:0px;
+ text-align: right;
}
-td#testRuns {
+
+#testRuns {
color: green;
- font-weight: bold;
}
-td#testFailures {
+
+#testFailures {
color: red;
- font-weight: bold;
}
-td#commandPasses {
+
+#commandPasses {
color: green;
- font-weight: bold;
}
-td#commandFailures {
- color: orange;
- font-weight: bold;
-}
-td#commandErrors {
+
+#commandFailures {
color: red;
- font-weight: bold;
}
+
+#commandErrors {
+ color: #f90;
+}
+
+.splash {
+ border: 1px solid black;
+ padding: 20px;
+ background: #ccc;
+}
+
+/*---( Logging Console )---*/
+#logging-console {
+ background: #FFF;
+ padding: 5px;
+ border: 1px solid #888;
+ font-size: 10px;
+}
+
+#logging-console h1 {
+ font-weight: bold;
+}
+
+#logging-console ul {
+ list-style-type: none;
+ margin: 0px;
+ padding: 0px;
+ clear: both;
+}
+
+#logging-console ul li.error {
+ font-weight: bold;
+ color: red;
+}
\ No newline at end of file
More information about the Zope-CVS
mailing list