[Zope-CVS] CVS: Products/Zelenium/selenium - user-extensions.js.sample:1.1 version.txt:1.1 xpath.js:1.1 html-xpath-patched.js:1.2 htmlutils.js:1.4 selenium-api.js:1.4 selenium-browserbot.js:1.4 selenium-executionloop.js:1.4 selenium-fitrunner.js:1.5 selenium-logging.js:1.3

Tres Seaver tseaver at palladion.com
Tue Jun 7 13:18:18 EDT 2005


Update of /cvs-repository/Products/Zelenium/selenium
In directory cvs.zope.org:/tmp/cvs-serv2774/selenium

Modified Files:
	html-xpath-patched.js htmlutils.js selenium-api.js 
	selenium-browserbot.js selenium-executionloop.js 
	selenium-fitrunner.js selenium-logging.js 
Added Files:
	user-extensions.js.sample version.txt xpath.js 
Log Message:
 - Begin using 'core application' from Selenium 0.4.0.


=== Added File Products/Zelenium/selenium/user-extensions.js.sample ===
/*
 * By default, Selenium looks for a file called "user-extensions.js", and loads and javascript
 * code found in that file. This file is a sample of what that file could look like.
 *
 * user-extensions.js provides a convenient location for adding extensions to Selenium, like
 * new actions, checks and locator-strategies.
 * By default, this file does not exist. Users can create this file and place their extension code
 * in this common location, removing the need to modify the Selenium sources, and hopefully assisting
 * with the upgrade process.
 */

// The following examples try to give an indication of how Selenium can be extended with javascript.

// All do* methods on the Selenium prototype are added as actions.
// Eg add a typeRepeated action to Selenium, which types the text twice into a text box.
// The typeTwiceAndWait command will be available automatically
Selenium.prototype.doTypeRepeated = function(locator, text) {
    // All locator-strategies are automatically handled by "findElement"
    var element = this.page().findElement(locator);

    // Create the text to type
    var valueToType = text + text;

    // Replace the element text with the new text
    this.page().replaceText(element, valueToType);
};

// All assert* methods on the Selenium prototype are added as checks.
// Eg add a assertValueRepeated check, that makes sure that the element value
// consists of the supplied text repeated.
// The verify version will be available automatically.
Selenium.prototype.assertValueRepeated = function(locator, text) {
    // All locator-strategies are automatically handled by "findElement"
    var element = this.page().findElement(locator);

    // Create the text to verify
    var expectedValue = text + text;

    // Get the actual element value
    var actualValue = element.value;

    // Make sure the actual value matches the expected
    this.assertMatches(expectedValue, actualValue);
};

// All locateElementBy* methods are added as locator-strategies.
// Eg add a "valuerepeated=" locator, that finds the first element with the supplied value, repeated.
// The "inDocument" is a the document you are searching.
PageBot.prototype.locateElementByValueRepeated = function(text, inDocument) {
    // Create the text to search for
    var expectedValue = text + text;

    // Loop through all elements, looking for ones that have a value === our expected value
    var allElements = inDocument.getElementsByTagName("*");
    for (var i = 0; i < allElements.length; i++) {
        var testElement = allElements[i];
        if (testElement.value && testElement.value === expectedValue) {
            return testElement;
        }
    }
    return null;
};


=== Added File Products/Zelenium/selenium/version.txt ===
0.4.0

=== Added File Products/Zelenium/selenium/xpath.js === (3510/3910 lines abridged)
/*
 * xpath.js
 *
 * An XPath 1.0 library for JavaScript.
 *
 * Cameron McCormack <cam (at) mcc.id.au>
 *
 * This work is licensed under the Creative Commons Attribution-ShareAlike
 * License. To view a copy of this license, visit
 * http://creativecommons.org/licenses/by-sa/2.0/ or send a letter to Creative
 * Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 *
 * Revision 13: May 3, 2005
 *   Node tests are case insensitive now if working in an HTML DOM.
 *
 * Revision 12: April 26, 2005
 *   Updated licence.  Slight code changes to enable use of Dean
 *   Edwards' script compression, http://dean.edwards.name/packer/ .
 *
 * Revision 11: April 23, 2005
 *   Fixed bug with 'and' and 'or' operators, fix thanks to
 *   Sandy McArthur <sandy (at) mcarthur.org>.
 *
 * Revision 10: April 15, 2005
 *   Added support for a virtual root node, supposedly helpful for
 *   implementing XForms.  Fixed problem with QName node tests and
 *   the parent axis.
 *
 * Revision 9: March 17, 2005
 *   Namespace resolver tweaked so using the document node as the context
 *   for namespace lookups is equivalent to using the document element.
 *
 * Revision 8: February 13, 2005
 *   Handle implicit declaration of 'xmlns' namespace prefix.
 *   Fixed bug when comparing nodesets.
 *   Instance data can now be associated with a FunctionResolver, and
 *     workaround for MSXML not supporting 'localName' and 'getElementById',
 *     thanks to Grant Gongaware.
 *   Fix a few problems when the context node is the root node.
 *   
 * Revision 7: February 11, 2005
 *   Default namespace resolver fix from Grant Gongaware
 *   <grant (at) gongaware.com>.
 *
 * Revision 6: February 10, 2005
 *   Fixed bug in 'number' function.
 *
 * Revision 5: February 9, 2005
 *   Fixed bug where text nodes not getting converted to string values.
 *
 * Revision 4: January 21, 2005
 *   Bug in 'name' function, fix thanks to Bill Edney.
 *   Fixed incorrect processing of namespace nodes.
 *   Fixed NamespaceResolver to resolve 'xml' namespace.
 *   Implemented union '|' operator.
 *
 * Revision 3: January 14, 2005
 *   Fixed bug with nodeset comparisons, bug lexing < and >.
 *
 * Revision 2: October 26, 2004
 *   QName node test namespace handling fixed.  Few other bug fixes.
 *   
 * Revision 1: August 13, 2004
 *   Bug fixes from William J. Edney <bedney (at) technicalpursuit.com>.
 *   Added minimal licence.
 *
 * Initial version: June 14, 2004
 */

// XPathParser ///////////////////////////////////////////////////////////////

XPathParser.prototype = new Object();
XPathParser.prototype.constructor = XPathParser;
XPathParser.superclass = Object.prototype;

function XPathParser() {
	this.init();
}

XPathParser.prototype.init = function() {
	this.reduceActions = [];

	this.reduceActions[3] = function(rhs) {
		return new OrOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[5] = function(rhs) {
		return new AndOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[7] = function(rhs) {
		return new EqualsOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[8] = function(rhs) {
		return new NotEqualOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[10] = function(rhs) {
		return new LessThanOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[11] = function(rhs) {
		return new GreaterThanOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[12] = function(rhs) {
		return new LessThanOrEqualOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[13] = function(rhs) {
		return new GreaterThanOrEqualOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[15] = function(rhs) {
		return new PlusOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[16] = function(rhs) {
		return new MinusOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[18] = function(rhs) {
		return new MultiplyOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[19] = function(rhs) {
		return new DivOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[20] = function(rhs) {
		return new ModOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[22] = function(rhs) {
		return new UnaryMinusOperation(rhs[1]);
	};
	this.reduceActions[24] = function(rhs) {
		return new BarOperation(rhs[0], rhs[2]);
	};
	this.reduceActions[25] = function(rhs) {
		return new PathExpr(undefined, undefined, rhs[0]);
	};
	this.reduceActions[27] = function(rhs) {
		rhs[0].locationPath = rhs[2];
		return rhs[0];
	};
	this.reduceActions[28] = function(rhs) {
		rhs[0].locationPath = rhs[2];
		rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
		return rhs[0];
	};
	this.reduceActions[29] = function(rhs) {
		return new PathExpr(rhs[0], [], undefined);
	};
	this.reduceActions[30] = function(rhs) {
		if (Utilities.instance_of(rhs[0], PathExpr)) {
			if (rhs[0].filterPredicates == undefined) {
				rhs[0].filterPredicates = [];
			}
			rhs[0].filterPredicates.push(rhs[1]);
			return rhs[0];
		} else {
			return new PathExpr(rhs[0], [rhs[1]], undefined);
		}
	};
	this.reduceActions[32] = function(rhs) {
		return rhs[1];
	};
	this.reduceActions[33] = function(rhs) {
		return new XString(rhs[0]);
	};
	this.reduceActions[34] = function(rhs) {
		return new XNumber(rhs[0]);
	};
	this.reduceActions[36] = function(rhs) {
		return new FunctionCall(rhs[0], []);
	};
	this.reduceActions[37] = function(rhs) {
		return new FunctionCall(rhs[0], rhs[2]);
	};
	this.reduceActions[38] = function(rhs) {
		return [ rhs[0] ];
	};
	this.reduceActions[39] = function(rhs) {
		rhs[2].unshift(rhs[0]);
		return rhs[2];
	};
	this.reduceActions[43] = function(rhs) {
		return new LocationPath(true, []);
	};
	this.reduceActions[44] = function(rhs) {
		rhs[1].absolute = true;
		return rhs[1];
	};
	this.reduceActions[46] = function(rhs) {
		return new LocationPath(false, [ rhs[0] ]);
	};
	this.reduceActions[47] = function(rhs) {
		rhs[0].steps.push(rhs[2]);
		return rhs[0];
	};
	this.reduceActions[49] = function(rhs) {
		return new Step(rhs[0], rhs[1], []);
	};
	this.reduceActions[50] = function(rhs) {
		return new Step(Step.CHILD, rhs[0], []);
	};
	this.reduceActions[51] = function(rhs) {
		return new Step(rhs[0], rhs[1], rhs[2]);
	};
	this.reduceActions[52] = function(rhs) {
		return new Step(Step.CHILD, rhs[0], rhs[1]);

[-=- -=- -=- 3510 lines omitted -=- -=- -=-]

		c >= 0x30A1 && c <= 0x30FA ||
		c >= 0x3105 && c <= 0x312C ||
		c >= 0xAC00 && c <= 0xD7A3 ||
		c >= 0x4E00 && c <= 0x9FA5 ||
		c == 0x3007 ||
		c >= 0x3021 && c <= 0x3029;
};

Utilities.isNCNameChar = function(c) {
	return c >= 0x0030 && c <= 0x0039 
		|| c >= 0x0660 && c <= 0x0669 
		|| c >= 0x06F0 && c <= 0x06F9 
		|| c >= 0x0966 && c <= 0x096F 
		|| c >= 0x09E6 && c <= 0x09EF 
		|| c >= 0x0A66 && c <= 0x0A6F 
		|| c >= 0x0AE6 && c <= 0x0AEF 
		|| c >= 0x0B66 && c <= 0x0B6F 
		|| c >= 0x0BE7 && c <= 0x0BEF 
		|| c >= 0x0C66 && c <= 0x0C6F 
		|| c >= 0x0CE6 && c <= 0x0CEF 
		|| c >= 0x0D66 && c <= 0x0D6F 
		|| c >= 0x0E50 && c <= 0x0E59 
		|| c >= 0x0ED0 && c <= 0x0ED9 
		|| c >= 0x0F20 && c <= 0x0F29
		|| c == 0x002E
		|| c == 0x002D
		|| c == 0x005F
		|| Utilities.isLetter(c)
		|| c >= 0x0300 && c <= 0x0345 
		|| c >= 0x0360 && c <= 0x0361 
		|| c >= 0x0483 && c <= 0x0486 
		|| c >= 0x0591 && c <= 0x05A1 
		|| c >= 0x05A3 && c <= 0x05B9 
		|| c >= 0x05BB && c <= 0x05BD 
		|| c == 0x05BF 
		|| c >= 0x05C1 && c <= 0x05C2 
		|| c == 0x05C4 
		|| c >= 0x064B && c <= 0x0652 
		|| c == 0x0670 
		|| c >= 0x06D6 && c <= 0x06DC 
		|| c >= 0x06DD && c <= 0x06DF 
		|| c >= 0x06E0 && c <= 0x06E4 
		|| c >= 0x06E7 && c <= 0x06E8 
		|| c >= 0x06EA && c <= 0x06ED 
		|| c >= 0x0901 && c <= 0x0903 
		|| c == 0x093C 
		|| c >= 0x093E && c <= 0x094C 
		|| c == 0x094D 
		|| c >= 0x0951 && c <= 0x0954 
		|| c >= 0x0962 && c <= 0x0963 
		|| c >= 0x0981 && c <= 0x0983 
		|| c == 0x09BC 
		|| c == 0x09BE 
		|| c == 0x09BF 
		|| c >= 0x09C0 && c <= 0x09C4 
		|| c >= 0x09C7 && c <= 0x09C8 
		|| c >= 0x09CB && c <= 0x09CD 
		|| c == 0x09D7 
		|| c >= 0x09E2 && c <= 0x09E3 
		|| c == 0x0A02 
		|| c == 0x0A3C 
		|| c == 0x0A3E 
		|| c == 0x0A3F 
		|| c >= 0x0A40 && c <= 0x0A42 
		|| c >= 0x0A47 && c <= 0x0A48 
		|| c >= 0x0A4B && c <= 0x0A4D 
		|| c >= 0x0A70 && c <= 0x0A71 
		|| c >= 0x0A81 && c <= 0x0A83 
		|| c == 0x0ABC 
		|| c >= 0x0ABE && c <= 0x0AC5 
		|| c >= 0x0AC7 && c <= 0x0AC9 
		|| c >= 0x0ACB && c <= 0x0ACD 
		|| c >= 0x0B01 && c <= 0x0B03 
		|| c == 0x0B3C 
		|| c >= 0x0B3E && c <= 0x0B43 
		|| c >= 0x0B47 && c <= 0x0B48 
		|| c >= 0x0B4B && c <= 0x0B4D 
		|| c >= 0x0B56 && c <= 0x0B57 
		|| c >= 0x0B82 && c <= 0x0B83 
		|| c >= 0x0BBE && c <= 0x0BC2 
		|| c >= 0x0BC6 && c <= 0x0BC8 
		|| c >= 0x0BCA && c <= 0x0BCD 
		|| c == 0x0BD7 
		|| c >= 0x0C01 && c <= 0x0C03 
		|| c >= 0x0C3E && c <= 0x0C44 
		|| c >= 0x0C46 && c <= 0x0C48 
		|| c >= 0x0C4A && c <= 0x0C4D 
		|| c >= 0x0C55 && c <= 0x0C56 
		|| c >= 0x0C82 && c <= 0x0C83 
		|| c >= 0x0CBE && c <= 0x0CC4 
		|| c >= 0x0CC6 && c <= 0x0CC8 
		|| c >= 0x0CCA && c <= 0x0CCD 
		|| c >= 0x0CD5 && c <= 0x0CD6 
		|| c >= 0x0D02 && c <= 0x0D03 
		|| c >= 0x0D3E && c <= 0x0D43 
		|| c >= 0x0D46 && c <= 0x0D48 
		|| c >= 0x0D4A && c <= 0x0D4D 
		|| c == 0x0D57 
		|| c == 0x0E31 
		|| c >= 0x0E34 && c <= 0x0E3A 
		|| c >= 0x0E47 && c <= 0x0E4E 
		|| c == 0x0EB1 
		|| c >= 0x0EB4 && c <= 0x0EB9 
		|| c >= 0x0EBB && c <= 0x0EBC 
		|| c >= 0x0EC8 && c <= 0x0ECD 
		|| c >= 0x0F18 && c <= 0x0F19 
		|| c == 0x0F35 
		|| c == 0x0F37 
		|| c == 0x0F39 
		|| c == 0x0F3E 
		|| c == 0x0F3F 
		|| c >= 0x0F71 && c <= 0x0F84 
		|| c >= 0x0F86 && c <= 0x0F8B 
		|| c >= 0x0F90 && c <= 0x0F95 
		|| c == 0x0F97 
		|| c >= 0x0F99 && c <= 0x0FAD 
		|| c >= 0x0FB1 && c <= 0x0FB7 
		|| c == 0x0FB9 
		|| c >= 0x20D0 && c <= 0x20DC 
		|| c == 0x20E1 
		|| c >= 0x302A && c <= 0x302F 
		|| c == 0x3099 
		|| c == 0x309A
		|| c == 0x00B7 
		|| c == 0x02D0 
		|| c == 0x02D1 
		|| c == 0x0387 
		|| c == 0x0640 
		|| c == 0x0E46 
		|| c == 0x0EC6 
		|| c == 0x3005 
		|| c >= 0x3031 && c <= 0x3035 
		|| c >= 0x309D && c <= 0x309E 
		|| c >= 0x30FC && c <= 0x30FE;
};

Utilities.coalesceText = function(n) {
	for (var m = n.firstChild; m != null; m = m.nextSibling) {
		if (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
			var s = m.nodeValue;
			var first = m;
			m = m.nextSibling;
			while (m != null && (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/)) {
				s += m.nodeValue;
				var del = m;
				m = m.nextSibling;
				del.parentNode.removeChild(del);
			}
			if (first.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
				var p = first.parentNode;
				if (first.nextSibling == null) {
					p.removeChild(first);
					p.appendChild(p.ownerDocument.createTextNode(s));
				} else {
					var next = first.nextSibling;
					p.removeChild(first);
					p.insertBefore(p.ownerDocument.createTextNode(s), next);
				}
			} else {
				first.nodeValue = s;
			}
			if (m == null) {
				break;
			}
		} else if (m.nodeType == 1 /*Node.ELEMENT_NODE*/) {
			Utilities.coalesceText(m);
		}
	}
};

Utilities.instance_of = function(o, c) {
	while (o != null) {
		if (o.constructor === c) {
			return true;
		}
		if (o === Object) {
			return false;
		}
		o = o.constructor.superclass;
	}
	return false;
};

Utilities.getElementById = function(n, id) {
	// Note that this does not check the DTD to check for actual
	// attributes of type ID, so this may be a bit wrong.
	if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
		if (n.getAttribute("id") == id
				|| n.getAttributeNS(null, "id") == id) {
			return n;
		}
	}
	for (var m = n.firstChild; m != null; m = m.nextSibling) {
		var res = Utilities.getElementById(m, id);
		if (res != null) {
			return res;
		}
	}
	return null;
};


=== Products/Zelenium/selenium/html-xpath-patched.js 1.1.1.1 => 1.2 ===
--- Products/Zelenium/selenium/html-xpath-patched.js:1.1.1.1	Fri Apr 15 14:48:45 2005
+++ Products/Zelenium/selenium/html-xpath-patched.js	Tue Jun  7 13:17:46 2005
@@ -536,11 +536,45 @@
 		{
 			return loadNode(dom, dom, document.body, helper);
 		}
-		
+			
+
+/** SELENIUM:PATCH for loadNode() - see SEL-68 */
 		function loadNode(dom, domParentNode, node, helper)
 		{
-			if (node.nodeType == 3)
-			{			
+			// Bad node scenarios
+			// 1. If the node contains a /, it's broken HTML
+			// 2. If the node doesn't have a name (typically from broken HTML), the node can't be loaded
+			// 3. Node types we can't deal with
+			//
+			// In all scenarios, we just skip the node. We won't be able to
+			// query on these nodes, but they're broken anyway.
+			if (node.nodeName.indexOf("/") > -1
+			    || node.nodeName == ""
+			    || node.nodeName == "#document"
+			    || node.nodeName == "#document-fragment"
+			    || node.nodeName == "#cdata-section"
+			    || node.nodeName == "#xml-declaration"
+			    || node.nodeName == "#whitespace"
+			    || node.nodeName == "#significat-whitespace"
+			   )
+			{
+				return;
+			}
+			
+			// #comment is a <!-- comment -->, which must be created with createComment()
+			if (node.nodeName == "#comment")
+			{
+				try
+				{
+					domParentNode.appendChild(dom.createComment(node.nodeValue));
+				}
+				catch (ex)
+				{
+					// it's just a comment, we don't care
+				}
+			}
+			else if (node.nodeType == 3)
+			{
 				domParentNode.appendChild(dom.createTextNode(node.nodeValue));
 			}
 			else
@@ -560,6 +594,7 @@
 				node.attachEvent("onpropertychange", onPropertyChangeEventHandler);
 			}
 		}
+/** END SELENIUM:PATCH */
 
 		function loadAttributes(dom, domParentNode, node)
 		{


=== Products/Zelenium/selenium/htmlutils.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/htmlutils.js:1.3	Fri May  6 07:46:12 2005
+++ Products/Zelenium/selenium/htmlutils.js	Tue Jun  7 13:17:46 2005
@@ -44,6 +44,9 @@
     } else if(element.innerText) {
         text = element.innerText;
     }
+    // Replace &nbsp; with a space
+    // TODO - should this be in the match() code instead?
+    text = text.replace(/\240/g, " ");
     return text.trim();
 }
 
@@ -104,6 +107,13 @@
         element.addEventListener("load",command, true);
     else if (window.attachEvent)
         element.attachEvent("onload",command);
+}
+
+function addUnloadListener(element, command) {
+    if (window.addEventListener)
+        element.addEventListener("unload",command, true);
+    else if (window.attachEvent)
+        element.attachEvent("onunload",command);
 }
 
 /**


=== Products/Zelenium/selenium/selenium-api.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/selenium-api.js:1.3	Fri May  6 07:46:12 2005
+++ Products/Zelenium/selenium/selenium-api.js	Tue Jun  7 13:17:46 2005
@@ -15,6 +15,8 @@
  *
  */
 
+storedVars = new Object();
+
 var nextExecution;
 function executeNext() {
     LOG.debug("CODED - LOAD");
@@ -40,6 +42,14 @@
 }
 
 /*
+ * Reset the browserbot when an error occurs..
+ */
+Selenium.prototype.reset = function() {
+    storedVars = new Object();
+    this.browserbot.selectWindow("null");
+};
+
+/*
  * Click on the located element, and attach a callback to notify
  * when the page is reloaded.
  */
@@ -221,22 +231,26 @@
     this.assertMatches(expectedLabel, selectedLabel);
 };
 
+String.prototype.parseCSV = function() {
+    var values = this.replace(/\\,/g, "\n").split(",");
+    // Restore escaped commas
+    for (var i = 0; i < values.length; i++) {
+        values[i] = values[i].replace(/\n/g, ",").trim();
+    }
+    return values;
+};
+
 /**
  * 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);
+    var expectedOptionLabels = options.parseCSV();
+    assert.equals("Wrong number of options.", expectedOptionLabels.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);
+        this.assertMatches(expectedOptionLabels[i], element.options[i].text);
     }
 };
 
@@ -420,10 +434,77 @@
 };
 
 /*
-  * Set the context for the current Test
-  */
+ * Set the context for the current Test
+ */
 Selenium.prototype.doContext = function(context) {
         return this.page().setContext(context);
+};
+
+/*
+ * 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);
+};
+
+/*
+ * Store the result of a literal value
+ */
+Selenium.prototype.doStore = function(value, varName) {
+    storedVars[varName] = value;
+};
+
+/**
+ * Evaluate a parameter, performing javascript evaluation and variable substitution.
+ * If the string matches the pattern "javascript{ ... }", evaluate the string between the braces.
+ */
+Selenium.prototype.preprocessParameter = function(value) {
+    var match = value.match(/^javascript\{(.+)\}$/);
+    if (match && match[1]) {
+        return eval(match[1]).toString();
+    }
+    return this.replaceVariables(value);
+};
+
+/*
+ * Search through str and replace all variable references ${varName} with their
+ * value in storedVars.
+ */
+Selenium.prototype.replaceVariables = function(str) {
+    var stringResult = str;
+
+    // Find all of the matching variable references
+    var match = stringResult.match(/\$\{\w+\}/g);
+    if (!match) {
+        return stringResult;
+    }
+
+    // For each match, lookup the variable value, and replace if found
+    for (var i = 0; match && i < match.length; i++) {
+        var variable = match[i]; // The replacement variable, with ${}
+        var name = variable.substring(2, variable.length - 1); // The replacement variable without ${}
+        var replacement = storedVars[name];
+        if (replacement != undefined) {
+            stringResult = stringResult.replace(variable, replacement);
+        }
+    }
+    return stringResult;
 };
 
 function Assert() {


=== Products/Zelenium/selenium/selenium-browserbot.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/selenium-browserbot.js:1.3	Fri May  6 07:46:12 2005
+++ Products/Zelenium/selenium/selenium-browserbot.js	Tue Jun  7 13:17:46 2005
@@ -42,19 +42,19 @@
 var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
 var geckoVersion = geckoResult == null ? null : geckoResult[1];
 
-function createBrowserBot(frame, executionContext) {
+function createBrowserBot(frame) {
     if (isIE) {
-        return new IEBrowserBot(frame, executionContext);
+        return new IEBrowserBot(frame);
     }
     else if (isKonqueror) {
-        return new KonquerorBrowserBot(frame, executionContext);
+        return new KonquerorBrowserBot(frame);
     }
     else if (isSafari) {
-        return new SafariBrowserBot(frame, executionContext);
+        return new SafariBrowserBot(frame);
     }
     else {
         // Use mozilla by default
-        return new MozillaBrowserBot(frame, executionContext);
+        return new MozillaBrowserBot(frame);
     }
 }
 
@@ -74,9 +74,8 @@
     }
 }
 
-BrowserBot = function(frame, executionContext) {
+BrowserBot = function(frame) {
     this.frame = frame;
-    this.executionContext = executionContext;
     this.currentPage = null;
     this.currentWindowName = null;
 
@@ -115,16 +114,11 @@
     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 (target && target != "null") {
         // If window exists
         if (this.getTargetWindow(target)) {
             this.currentWindowName = target;
@@ -135,15 +129,15 @@
 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());
+    // Window doesn't fire onload event when setting src to the current value,
+    // so we set it to blank first.
+    this.getFrame().src = "about:blank";
+    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);
-        }
+        var testWindow = this.getCurrentWindow();
         this.modifyWindowToRecordPopUpDialogs(testWindow, this);
         this.modifyWindowToClearPageCache(testWindow, this);
         this.currentPage = createPageBot(testWindow);
@@ -178,6 +172,10 @@
     }
 };
 
+BrowserBot.prototype.getContentWindow = function() {
+    return this.getFrame().contentWindow || frames[this.getFrame().id];
+};
+
 BrowserBot.prototype.getTargetWindow = function(windowName) {
     var evalString = "this.getContentWindow().window." + windowName;
     var targetWindow = eval(evalString);
@@ -187,22 +185,89 @@
     return targetWindow;
 };
 
+BrowserBot.prototype.getCurrentWindow = function() {
+    var testWindow = this.getContentWindow().window;
+    if (this.currentWindowName != null) {
+        testWindow = this.getTargetWindow(this.currentWindowName);
+    }
+    return testWindow;
+};
+
 BrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
-    addLoadListener(this.frame, onloadCallback);
+    if (this.currentWindowName == null) {
+        this.callOnFramePageTransition(onloadCallback, this.getFrame());
+    }
+    else {
+        this.callOnWindowPageTransition(onloadCallback, this.getCurrentWindow());
+    }
+};
+
+BrowserBot.prototype.callOnFramePageTransition = function(loadFunction, frameObject) {
+    try {
+        addLoadListener(frameObject, loadFunction);
+    } catch (e) {
+        LOG.debug("Got on error adding LoadListener in BrowserBot.prototype.callOnFramePageTransition." +
+                  "This occurs on the second and all subsequent calls in Safari");
+    }
+};
+
+BrowserBot.prototype.callOnWindowPageTransition = function(loadFunction, windowObject) {
+    var unloadFunction = function() {
+        window.setTimeout(function() {addLoadListener(windowObject, loadFunction);}, 0);
+    };
+    addUnloadListener(windowObject, unloadFunction);
 };
 
-function MozillaBrowserBot(frame, executionContext) {
-    BrowserBot.call(this, frame, executionContext);
+/**
+ * Handle the initial page load in a new popup window.
+ * TODO - something like this should allow us to wait for a new popup window - currently need to pause...
+ */
+//function callOnWindowInitialLoad(loadFunction, windowObject) {
+//    if (!(isSafari || isKonqueror)) {
+//        addLoadListener(windowObject, loadFunction);
+//    }
+//    else {
+//        this.pollForLoad(loadFunction, windowObject, windowObject.document);
+//    }
+//}
+
+function MozillaBrowserBot(frame) {
+    BrowserBot.call(this, frame);
 }
 MozillaBrowserBot.prototype = new BrowserBot;
 
-function KonquerorBrowserBot(frame, executionContext) {
-    BrowserBot.call(this, frame, executionContext);
+function KonquerorBrowserBot(frame) {
+    BrowserBot.call(this, frame);
 }
 KonquerorBrowserBot.prototype = new BrowserBot;
 
-function SafariBrowserBot(frame, executionContext) {
-    BrowserBot.call(this, frame, executionContext);
+KonquerorBrowserBot.prototype.callOnWindowPageTransition = function(loadFunction, windowObject) {
+    // Since the unload event doesn't fire in Safari 1.3, we start polling immediately
+    // This works in Konqueror as well
+    this.pollForLoad(loadFunction, windowObject, windowObject.document);
+};
+
+/**
+ * For Konqueror (and Safari), we can't catch the onload event for a separate window (as opposed to an IFrame)
+ * So we set up a polling timer that will keep checking the readyState of the document until it's complete.
+ * Since we might call this before the original page is unloaded, we check to see that the completed document
+ * is different from the original one.
+ */
+KonquerorBrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument) {
+    var sameDoc = (originalDocument === windowObject.document);
+    var rs = windowObject.document.readyState;
+
+    if (!sameDoc && rs == 'complete') {
+        LOG.debug("poll: " + rs + " (" + sameDoc + ")");
+        loadFunction();
+        return;
+    }
+    var self = this;
+    window.setTimeout(function() {self.pollForLoad(loadFunction, windowObject, originalDocument);}, 100);
+};
+
+function SafariBrowserBot(frame) {
+    BrowserBot.call(this, frame);
 }
 SafariBrowserBot.prototype = new BrowserBot;
 
@@ -212,17 +277,14 @@
  */
 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");
-    }
+    BrowserBot.prototype.callOnNextPageLoad.call(this, onloadCallback);
 };
 
-function IEBrowserBot(frame, executionContext) {
-    BrowserBot.call(this, frame, executionContext);
+SafariBrowserBot.prototype.callOnWindowPageTransition = KonquerorBrowserBot.prototype.callOnWindowPageTransition;
+SafariBrowserBot.prototype.pollForLoad = KonquerorBrowserBot.prototype.pollForLoad;
+
+function IEBrowserBot(frame) {
+    BrowserBot.call(this, frame);
 }
 IEBrowserBot.prototype = new BrowserBot;
 
@@ -281,15 +343,45 @@
         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]);
+    // Register all locateElementBy* functions
+    // TODO - don't do this in the constructor - only needed once ever
+    this.locationStrategies = {};
+    for (var functionName in this) {
+        var result = /^locateElementBy([A-Z].+)$/.exec(functionName);
+        if (result != null) {
+            var locatorFunction = this[functionName];
+            if (typeof(locatorFunction) != 'function') {
+                continue;
             }
+            // Use a specified prefix in preference to one generated from
+            // the function name
+            var locatorPrefix = locatorFunction.prefix || result[1].toLowerCase();
+            this.locationStrategies[locatorPrefix] = locatorFunction;
         }
     }
+
+    /**
+     * Find a locator based on a prefix.
+     */
+    this.findElementBy = function(locatorType, locator, inDocument) {
+        var locatorFunction = this.locationStrategies[locatorType];
+        if (! locatorFunction) {
+            throw new Error("Unrecognised locator type: '" + locatorType + "'");
+        }
+        return locatorFunction.call(this, locator, inDocument);
+    };
+
+    /**
+     * The implicit locator, that is used when no prefix is supplied.
+     */
+    this.locationStrategies['implicit'] = function(locator, inDocument) {
+        return this.locateElementByIdentifier(locator, inDocument)
+               || this.locateElementByDomTraversal(locator, inDocument)
+               || this.locateElementByXPath(locator, inDocument);
+    };
+    
 };
 
 MozillaPageBot = function(pageWindow) {
@@ -316,16 +408,24 @@
 * Finds an element on the current page, using various lookup protocols
 */
 PageBot.prototype.findElement = function(locator) {
-    var element = this.findElementInDocument(locator, this.currentDocument);
+    var locatorType = 'implicit';
+    var locatorString = locator;
+    
+    // If there is a locator prefix, use the specified strategy
+    var result = locator.match(/^([a-z]+)=(.+)/);
+    if (result) {
+        locatorType = result[1];
+        locatorString = result[2];
+    }
 
+    var element = this.findElementBy(locatorType, locatorString, 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;
-            }
+    }
+    for (var i = 0; i < this.currentWindow.frames.length; i++) {
+        element = this.findElementBy(locatorType, locatorString, this.currentWindow.frames[i].document);
+        if (element != null) {
+            return element;
         }
     }
 
@@ -333,59 +433,49 @@
     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 non-IE browsers, getElementById() does not search by name.  Instead, we
+ * we search separately by id and name.
+ */
+PageBot.prototype.locateElementByIdentifier = function(identifier, inDocument) {
+    return PageBot.prototype.locateElementById(identifier, inDocument)
+            || PageBot.prototype.locateElementByName(identifier, inDocument)
+            || null;
 };
 
 /**
- * In IE, getElementById() also searches by name.
+ * In IE, getElementById() also searches by name - this is an optimisation for IE.
  */
-IEPageBot.prototype.locateElementById = function(identifier, inDocument) {
-    try {
-        return inDocument.getElementById(identifier);
-    } catch (e) {
-        return null;
-    }
+IEPageBot.prototype.locateElementByIdentifer = function(identifier, inDocument) {
+    return inDocument.getElementById(identifier);
 };
 
 /**
- * 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.
+ * Find the element with id - can't rely on getElementById, coz it returns by name as well in IE..
  */
 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) {
+    var element = inDocument.getElementById(identifier);
+    if (element && element.id === identifier) {
+        return element;
+    }
+    else {
         return null;
     }
+};
 
-    return element;
+/**
+ * In regular browsers, getElementById() does not search by name.
+ * We search by @name using XPath, or by checking every element.
+ */
+PageBot.prototype.locateElementByName = function(identifier, inDocument) {
+    var allElements = inDocument.getElementsByTagName("*");
+    for (var i = 0; i < allElements.length; i++) {
+        var testElement = allElements[i];
+        if (testElement.name && testElement.name === identifier) {
+            return testElement;
+        }
+    }
+    return null;
 };
 
 /**
@@ -408,56 +498,108 @@
 
     return element;
 };
+PageBot.prototype.locateElementByDomTraversal.prefix = "dom";
 
 /**
 * Finds an element identified by the xpath expression. Expressions _must_
 * begin with "//".
 */
 PageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
-    if (xpath.indexOf("//") != 0) {
+    if (xpath.slice(0,2) != "//") {
         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.
+    // Trim any trailing "/": not valid xpath, and remains from attribute
+    // locator.
     if (xpath.charAt(xpath.length - 1) == '/') {
-        xpath = xpath.slice(0, xpath.length - 1);
+        xpath = xpath.slice(0, -1);
     }
 
-    return inDocument.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+    // Handle //tag
+    var match = xpath.match(/^\/\/(\w+|\*)$/); 
+    if (match) {
+        var elements = inDocument.getElementsByTagName(match[1].toUpperCase()); 
+        if (elements == null) return null;
+        return elements[0];
+    }
+
+    // Handle //tag[@attr='value']
+    var match = xpath.match(/^\/\/(\w+|\*)\[@(\w+)=('([^\']+)'|"([^\"]+)")\]$/); 
+    if (match) {
+        return this.findElementByTagNameAndAttributeValue(
+            inDocument,
+            match[1].toUpperCase(),
+            match[2].toLowerCase(),
+            match[3].slice(1, -1)
+        );
+    }
+
+    // Handle //tag[text()='value']
+    var match = xpath.match(/^\/\/(\w+|\*)\[text\(\)=('([^\']+)'|"([^\"]+)")\]$/); 
+    if (match) {
+        return this.findElementByTagNameAndText(
+            inDocument,
+            match[1].toUpperCase(),
+            match[2].slice(1, -1)
+        );
+    }
+
+    return this.findElementUsingFullXPath(xpath, inDocument);
+};
+
+PageBot.prototype.findElementByTagNameAndAttributeValue = function(
+    inDocument, tagName, attributeName, attributeValue
+) {
+    if (isIE && attributeName == "class") {
+        attributeName = "className";
+    }
+    var elements = inDocument.getElementsByTagName(tagName); 
+    for (var i = 0; i < elements.length; i++) { 
+        var elementAttr = elements[i].getAttribute(attributeName); 
+        if (elementAttr == attributeValue) { 
+            return elements[i]; 
+        } 
+    } 
+    return null;
 };
 
-/**
- * For IE, we implement XPath support using the html-xpath library.
- */
-IEPageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
-    if (xpath.indexOf("//") != 0) {
-        return null;
-    }
+PageBot.prototype.findElementByTagNameAndText = function(
+    inDocument, tagName, text
+) {
+    var elements = inDocument.getElementsByTagName(tagName); 
+    for (var i = 0; i < elements.length; i++) { 
+        if (getText(elements[i]) == text) { 
+            return elements[i]; 
+        } 
+    } 
+    return null;
+};
 
-    if (!inDocument.evaluate) {
+PageBot.prototype.findElementUsingFullXPath = function(xpath, inDocument) {
+    if (isIE && !inDocument.evaluate) {
         addXPathSupport(inDocument);
     }
 
-    return PageBot.prototype.locateElementByXPath(xpath, inDocument);
+    // Use document.evaluate() if it's available
+    if (inDocument.evaluate) {
+        return inDocument.evaluate(xpath, inDocument, null, 0, null).iterateNext();
+    }
+
+    // If not, fall back to slower JavaScript implementation
+    var context = new XPathContext();
+    context.expressionContextNode = inDocument;
+    var xpathResult = new XPathParser().parse(xpath).evaluate(context);
+    if (xpathResult && xpathResult.toArray) {
+        return xpathResult.toArray()[0];
+    }
+    return null;
 };
 
 /**
 * 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);
+PageBot.prototype.locateElementByLinkText = function(linkText, inDocument) {
     var links = inDocument.getElementsByTagName('a');
     for (var i = 0; i < links.length; i++) {
         var element = links[i];
@@ -467,6 +609,7 @@
     }
     return null;
 };
+PageBot.prototype.locateElementByLinkText.prefix = "link";
 
 /**
 * Returns an attribute based on an attribute locator. This is made up of an element locator


=== Products/Zelenium/selenium/selenium-executionloop.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/selenium-executionloop.js:1.3	Fri May  6 07:46:12 2005
+++ Products/Zelenium/selenium/selenium-executionloop.js	Tue Jun  7 13:17:46 2005
@@ -20,12 +20,13 @@
 TEST_FINISHED = true;
 TEST_CONTINUE = false;
 
-function TestLoop(commandFactory, executionContext) {
+function TestLoop(commandFactory) {
     this.commandFactory = commandFactory;
 
     var self = this;
 
     this.start = function() {
+        selenium.reset();
         this.continueCurrentTest();
     };
 
@@ -35,7 +36,7 @@
         if (testStatus == TEST_FINISHED) {
             this.testComplete();
         }
-        };
+    };
 
     this.kickoffNextCommandExecution = function() {
 
@@ -58,9 +59,12 @@
         try {
             var handler = this.commandFactory.getCommandHandler(command.command);
             if(handler == null) {
-                throw new Error("Unknown command");
+                throw new Error("Unknown command: '" + command.command + "'");
             }
 
+            command.target = selenium.preprocessParameter(command.target);
+            command.value = selenium.preprocessParameter(command.value);
+
             result = handler.execute(selenium, command);
         } catch (e) {
             LOG.error(e);
@@ -77,8 +81,12 @@
         // 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.
 
-            executionContext.waitForPageLoad(this,selenium);
+            // 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
@@ -93,13 +101,17 @@
     * 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
+        // Get the interval to use for this command execution, using the pauseInterval as
         // 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) {
+        if (interval < 0) {
+            // Enable the "next/continue" button
+            this.waitingForNext();
+        }
+        else {
+            // Continue processing
             window.setTimeout("testLoop.finishCommandExecution()", interval);
         }
     };
@@ -129,6 +141,8 @@
 TestLoop.prototype.commandComplete = noop;
 
 TestLoop.prototype.testComplete = noop;
+
+TestLoop.prototype.waitingForNext = noop;
 
 function noop() {
 


=== Products/Zelenium/selenium/selenium-fitrunner.js 1.4 => 1.5 ===
--- Products/Zelenium/selenium/selenium-fitrunner.js:1.4	Fri May  6 07:47:06 2005
+++ Products/Zelenium/selenium/selenium-fitrunner.js	Tue Jun  7 13:17:46 2005
@@ -33,9 +33,6 @@
 testFailed = false;
 suiteFailed = false;
 
-// Holds variables that are stored in a script
-storedVars = new Object();
-
 // Holds the handlers for each command.
 commandHandlers = null;
 
@@ -67,10 +64,19 @@
 runInterval = 0;
 
 function setRunInterval() {
-    runInterval = this.value;
+    // Get the value of the checked runMode option.
+    // There should be a way of getting the value of the "group", but I don't know how.
+    var runModeOptions = document.forms['controlPanel'].runMode;
+    for (var i = 0; i < runModeOptions.length; i++) {
+        if (runModeOptions[i].checked) {
+            runInterval = runModeOptions[i].value;
+            break;
+        }
+    }
 }
 
 function continueCurrentTest() {
+    document.getElementById('continueTest').disabled = true;
     testLoop.finishCommandExecution();
 }
 
@@ -90,26 +96,14 @@
     loadSuiteFrame();
 }
 
-function getExecutionContext() {
-    if (isNewWindow()) {
-        return getWindowExecutionContext();
-    }
-    else if (isSafari || isKonqueror) {
-        return new KonquerorIFrameExecutionContext();
-    }
-    else {
-        return new IFrameExecutionContext();
-    }
-}
-
 function start() {
-    loadSuiteFrame(getExecutionContext());
+    setRunInterval();
+    loadSuiteFrame();
 }
 
-function loadSuiteFrame(executionContext) {
-
-    var testAppFrame = executionContext.loadFrame();
-    browserbot = createBrowserBot(testAppFrame,executionContext);
+function loadSuiteFrame() {
+    var testAppFrame = document.getElementById('myiframe');
+    browserbot = createBrowserBot(testAppFrame);
     selenium = new Selenium(browserbot);
     registerCommandHandlers();
 
@@ -337,8 +331,13 @@
         testLink = suiteTable.rows[currentTestRow].cells[0].getElementsByTagName("a")[0];
         testLink.focus();
 
-        addLoadListener(getTestFrame(), startTest);
-        getExecutionContext().open(testLink.href, getTestFrame());
+        var testFrame = getTestFrame();
+        addLoadListener(testFrame, startTest);
+
+        // Window doesn't fire onload event when setting src to the current value,
+        // so we set it to blank first.
+        testFrame.src = "about:blank";
+        testFrame.src = testLink.href;
     }
 }
 
@@ -473,24 +472,6 @@
 }
 
 /*
- * 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.
  */
@@ -498,14 +479,10 @@
     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 = new TestLoop(commandFactory);
 
     testLoop.getCommandInterval = function() { return runInterval; };
     testLoop.firstCommand = nextCommand;
@@ -514,6 +491,9 @@
     testLoop.commandComplete = commandComplete;
     testLoop.commandError = commandError;
     testLoop.testComplete = testComplete;
+    testLoop.waitingForNext = function() {
+        document.getElementById('continueTest').disabled = false;
+    };
     return testLoop;
 }
 
@@ -525,9 +505,8 @@
     currentCommandRow++;
 
     var commandName = getCellText(currentCommandRow, 0);
-    var target = replaceVariables(getCellText(currentCommandRow, 1));
-    var value = replaceVariables(getCellText(currentCommandRow, 2));
-
+    var target = getCellText(currentCommandRow, 1);
+    var value = getCellText(currentCommandRow, 2);
 
     var command = new SeleniumCommand(commandName, target, removeNbsp(value));
     return command;
@@ -538,21 +517,23 @@
     return value.replace(/\240/g, "");
 }
 
-function focusOnElement(element) {
-    if (element.focus) {
-        element.focus();
+function scrollIntoView(element) {
+    if (element.scrollIntoView) {
+        element.scrollIntoView();
         return;
     }
+
+    // For Konqueror, we have to create a remove an element.
     var anchor = element.ownerDocument.createElement("a");
     anchor.innerHTML = "!CURSOR!";
     element.appendChild(anchor, element);
-    anchor.focus();
+//    anchor.focus();
     element.removeChild(anchor);
 }
 
 function commandStarted() {
     inputTableRows[currentCommandRow].bgColor = workingColor;
-    focusOnElement(inputTableRows[currentCommandRow].cells[0]);
+    scrollIntoView(inputTableRows[currentCommandRow].cells[0]);
     printMetrics();
 }
 
@@ -619,38 +600,4 @@
 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;
-    }
-
-};
+};
\ No newline at end of file


=== Products/Zelenium/selenium/selenium-logging.js 1.2 => 1.3 ===
--- Products/Zelenium/selenium/selenium-logging.js:1.2	Fri May  6 07:46:12 2005
+++ Products/Zelenium/selenium/selenium-logging.js	Tue Jun  7 13:17:46 2005
@@ -1 +1,88 @@
-/*
* 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();
};
\ 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 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();
+};
+
+function noop() {};
+
+function DummyLogger() {
+};
+
+DummyLogger.prototype.show = noop;
+DummyLogger.prototype.hide = noop;
+DummyLogger.prototype.clear = noop;
+DummyLogger.prototype.log = noop;
+DummyLogger.prototype.debug = noop;
+DummyLogger.prototype.info = noop;
+DummyLogger.prototype.warn = noop;
+DummyLogger.prototype.error = noop;
\ No newline at end of file



More information about the Zope-CVS mailing list