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 <[email protected]>
Newsgroups gmane.comp.web.zope.public-cvs
Message-ID <[email protected]>
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

_______________________________________________
Zope-CVS maillist  -  [email protected]
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.