[Zope-CVS] CVS: Products/Zelenium/selenium - SeleniumLog.html:1.1
domviewer.html:1.3 htmlutils.js:1.5 selenium-api.js:1.5
selenium-browserbot.js:1.5 selenium-commandhandlers.js:1.4
selenium-domviewer.js:1.2 selenium-executionloop.js:1.5
selenium-fitrunner.js:1.6 selenium-logging.js:1.4
selenium.css:1.3 version.txt:1.2
Jens Vagelpohl
jens at dataflake.org
Wed Oct 12 06:38:54 EDT 2005
Update of /cvs-repository/Products/Zelenium/selenium
In directory cvs.zope.org:/tmp/cvs-serv7171/selenium
Modified Files:
domviewer.html htmlutils.js selenium-api.js
selenium-browserbot.js selenium-commandhandlers.js
selenium-domviewer.js selenium-executionloop.js
selenium-fitrunner.js selenium-logging.js selenium.css
version.txt
Added Files:
SeleniumLog.html
Log Message:
- Upgrade to selenium version 0.6
=== Added File Products/Zelenium/selenium/SeleniumLog.html ===
<html>
<head>
<title>Selenium Log Console</title>
<link id="cssLink" rel="stylesheet" href="selenium.css" />
</head>
<body id="logging-console">
<script language="JavaScript">
var logLevels = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
function getThresholdLevel() {
var buttons = document.getElementById('logLevelChooser').level;
for (var i = 0; i < buttons.length; i++) {
if (buttons[i].checked) {
return buttons[i].value;
}
}
}
function append(message, logLevel) {
if (logLevels[logLevel] < logLevels[getThresholdLevel()]) {
return;
}
var log = document.getElementById('log');
var newEntry = document.createElement('li');
newEntry.className = logLevel;
newEntry.appendChild(document.createTextNode(message));
log.appendChild(newEntry);
if (newEntry.scrollIntoView) {
newEntry.scrollIntoView();
}
}
</script>
<div id="banner">
<form id="logLevelChooser">
<input id="level-error" type="radio" name="level"
value="error" /><label for="level-error">Error</label>
<input id="level-warn" type="radio" name="level"
value="warn" /><label for="level-warn">Warn</label>
<input id="level-info" type="radio" name="level" checked="yes"
value="info" /><label for="level-info">Info</label>
<input id="level-debug" type="radio" name="level"
value="debug" /><label for="level-debug">Debug</label>
</form>
<h1>Selenium Log Console</h1>
</div>
<ul id="log"></ul>
</body>
</html>
=== Products/Zelenium/selenium/domviewer.html 1.2 => 1.3 ===
--- Products/Zelenium/selenium/domviewer.html:1.2 Fri May 6 07:46:12 2005
+++ Products/Zelenium/selenium/domviewer.html Wed Oct 12 06:38:23 2005
@@ -4,9 +4,8 @@
<head>
<title>DOM Viewer</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
- <link href="/styles/default.css" rel="dom-styles/stylesheet"
- type="text/css" />
- <script type="text/javascript" src="selenium-domviewer.js" />
+ <link rel="stylesheet" type="text/css" href="dom-styles/default.css"/>
+ <script type="text/javascript" src="selenium-domviewer.js"></script>
</head>
<body onload="loadDomViewer();">
<h3>DOM Viewer</h3>
=== Products/Zelenium/selenium/htmlutils.js 1.4 => 1.5 ===
--- Products/Zelenium/selenium/htmlutils.js:1.4 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/htmlutils.js Wed Oct 12 06:38:23 2005
@@ -19,21 +19,19 @@
// make it possible to handle elements in a way that is
// compatible with both IE-like and Mozilla-like browsers
-function trim() {
+String.prototype.trim = function() {
var result = this.replace( /^\s+/g, "" );// strip leading
return result.replace( /\s+$/g, "" );// strip trailing
-}
-String.prototype.trim = trim;
-
-function toCamelCase() {
+};
+String.prototype.lcfirst = function() {
return this.charAt(0).toLowerCase() + this.substr(1);
-}
-String.prototype.toCamelCase = toCamelCase;
-
-function startsWith(str) {
+};
+String.prototype.ucfirst = function() {
+ return this.charAt(0).toUpperCase() + this.substr(1);
+};
+String.prototype.startsWith = function(str) {
return this.indexOf(str) == 0;
-}
-String.prototype.startsWith = startsWith;
+};
// Returns the text in this element
function getText(element) {
@@ -128,10 +126,158 @@
return 'anonymous';
}
-function describe(object) {
+function describe(object, delimiter) {
var props = new Array();
for (var prop in object) {
props.push(prop + " -> " + object[prop]);
}
- return props.join('\n');
+ return props.join(delimiter || '\n');
}
+
+PatternMatcher = function(pattern) {
+ this.selectStrategy(pattern);
+};
+PatternMatcher.prototype = {
+
+ selectStrategy: function(pattern) {
+ this.pattern = pattern;
+ var strategyName = 'glob'; // by default
+ if (/^([a-zA-Z]+):(.*)/.test(pattern)) {
+ strategyName = RegExp.$1;
+ pattern = RegExp.$2;
+ }
+ var matchStrategy = PatternMatcher.strategies[strategyName];
+ if (!matchStrategy) {
+ throw new SeleniumError("cannot find PatternMatcher.strategies." + strategyName);
+ }
+ this.matcher = new matchStrategy(pattern);
+ },
+
+ matches: function(actual) {
+ return this.matcher.matches(actual + '');
+ // Note: appending an empty string avoids a Konqueror bug
+ }
+
+};
+
+/**
+ * A "static" convenience method for easy matching
+ */
+PatternMatcher.matches = function(pattern, actual) {
+ return new PatternMatcher(pattern).matches(actual);
+};
+
+PatternMatcher.strategies = {
+
+ /**
+ * Exact matching, e.g. "exact:***"
+ */
+ exact: function(expected) {
+ this.expected = expected;
+ this.matches = function(actual) {
+ return actual == this.expected;
+ };
+ },
+
+ /**
+ * Match by regular expression, e.g. "regexp:^[0-9]+$"
+ */
+ regexp: function(regexpString) {
+ this.regexp = new RegExp(regexpString);
+ this.matches = function(actual) {
+ return this.regexp.test(actual);
+ };
+ },
+
+ /**
+ * "glob" (aka "wildmat") patterns, e.g. "glob:one,two,*"
+ */
+ glob: function(globString) {
+ this.regexp = new RegExp(PatternMatcher.regexpFromGlob(globString));
+ this.matches = function(actual) {
+ return this.regexp.test(actual);
+ };
+ }
+
+};
+
+PatternMatcher.regexpFromGlob = function(glob) {
+ var re = glob;
+ re = re.replace(/([.^$+(){}\[\]\\|])/g, "\\$1");
+ re = re.replace(/\?/g, "(.|[\r\n])");
+ re = re.replace(/\*/g, "(.|[\r\n])*");
+ return "^" + re + "$";
+};
+
+var Assert = {
+
+ fail: function(message) {
+ throw new AssertionFailedError(message);
+ },
+
+ /*
+ * Assert.equals(comment?, expected, actual)
+ */
+ equals: function() {
+ var args = new AssertionArguments(arguments);
+ if (args.expected === args.actual) {
+ return;
+ }
+ Assert.fail(args.comment +
+ "Expected '" + args.expected +
+ "' but was '" + args.actual + "'");
+ },
+
+ /*
+ * Assert.matches(comment?, pattern, actual)
+ */
+ matches: function() {
+ var args = new AssertionArguments(arguments);
+ if (PatternMatcher.matches(args.expected, args.actual)) {
+ return;
+ }
+ Assert.fail(args.comment +
+ "Actual value '" + args.actual +
+ "' did not match '" + args.expected + "'");
+ },
+
+ /*
+ * Assert.notMtches(comment?, pattern, actual)
+ */
+ notMatches: function() {
+ var args = new AssertionArguments(arguments);
+ if (!PatternMatcher.matches(args.expected, args.actual)) {
+ return;
+ }
+ Assert.fail(args.comment +
+ "Actual value '" + args.actual +
+ "' did match '" + args.expected + "'");
+ }
+
+};
+
+// Preprocess the arguments to allow for an optional comment.
+function AssertionArguments(args) {
+ if (args.length == 2) {
+ this.comment = "";
+ this.expected = args[0];
+ this.actual = args[1];
+ } else {
+ this.comment = args[0] + "; ";
+ this.expected = args[1];
+ this.actual = args[2];
+ }
+}
+
+
+
+function AssertionFailedError(message) {
+ this.isAssertionFailedError = true;
+ this.failureMessage = message;
+}
+
+function SeleniumError(message) {
+ var error = new Error(message);
+ error.isSeleniumError = true;
+ return error;
+};
=== Products/Zelenium/selenium/selenium-api.js 1.4 => 1.5 ===
--- Products/Zelenium/selenium/selenium-api.js:1.4 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/selenium-api.js Wed Oct 12 06:38:23 2005
@@ -17,30 +17,18 @@
storedVars = new Object();
-var nextExecution;
-function executeNext() {
- LOG.debug("CODED - LOAD");
- if (nextExecution) {
- nextExecution();
- }
- nextExecution = null;
-}
-
-var assert = new Assert();
function Selenium(browserbot) {
this.browserbot = browserbot;
+ this.optionLocatorFactory = new OptionLocatorFactory();
this.page = function() {
return browserbot.getCurrentPage();
};
-
- var self = this;
-
- this.callOnNextPageLoad = function(callback) {
- nextExecution = callback;
- self.browserbot.callOnNextPageLoad(executeNext);
- };
}
+Selenium.createForFrame = function(frame) {
+ return new Selenium(BrowserBot.createForFrame(frame));
+};
+
/*
* Reset the browserbot when an error occurs..
*/
@@ -76,12 +64,16 @@
};
/**
- * Select the option by label from the located select element.
- * TODO fail if it's not a select.
+ * Select the option from the located select element.
*/
-Selenium.prototype.doSelect = function(locator, optionText) {
+Selenium.prototype.doSelect = function(locator, optionLocator) {
var element = this.page().findElement(locator);
- this.page().selectOptionWithLabel(element, optionText);
+ if (!("options" in element)) {
+ throw new SeleniumError("Specified element is not a Select (has no options)");
+ }
+ var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
+ var option = locator.findOption(element);
+ this.page().selectOption(element, option);
};
/*
@@ -107,6 +99,13 @@
};
/*
+ * Instruct Selenium what to answear on the next prompt dialog it encounters
+ */
+Selenium.prototype.doAnswerOnNextPrompt = function(answer) {
+ this.browserbot.setNextPromptResult(answer);
+};
+
+/*
* Simulate the browser back button
*/
Selenium.prototype.doGoBack = function() {
@@ -114,93 +113,114 @@
};
/*
- * Asserts that the supplied message was received as an alert
+ * Close the browser window or tab
*/
- Selenium.prototype.assertAlert = function(expectedAlert) {
- if ( this.browserbot.hasAlerts()) {
-
- receivedAlert = this.browserbot.getNextAlert();
- if ( receivedAlert != expectedAlert ) {
- assert.fail("The alert was [" + receivedAlert + "]");
- }
-
- } else {
- assert.fail("There were no alerts");
+Selenium.prototype.doClose = function() {
+ this.page().close();
+};
+
+/*
+ * Explicitly fire an event
+ */
+Selenium.prototype.doFireEvent = function(locator, event) {
+ var element = this.page().findElement(locator);
+ triggerEvent(element, event, false);
+};
+
+/*
+ * Get an alert message, or fail if there were no alerts.
+ */
+Selenium.prototype.getAlert = function() {
+ if (!this.browserbot.hasAlerts()) {
+ Assert.fail("There were no alerts");
}
- };
+ return this.browserbot.getNextAlert();
+};
- /*
- * Asserts that the supplied message was received as a confirmation
- */
- Selenium.prototype.assertConfirmation = function(expectedConfirmation) {
- if ( this.browserbot.hasConfirmations()) {
-
- receivedConfirmation = this.browserbot.getNextConfirmation();
- if ( receivedConfirmation != expectedConfirmation ) {
- assert.fail("The confirmation message was [" + receivedConfirmation + "]");
- }
-
- } else {
- assert.fail("There were no confirmations");
- }
- };
+/*
+ * Get a confirmation message, or fail if there were no confirmations.
+ */
+Selenium.prototype.getConfirmation = function() {
+ if (!this.browserbot.hasConfirmations()) {
+ Assert.fail("There were no confirmations");
+ }
+ return this.browserbot.getNextConfirmation();
+};
/*
- * Verify the location of the current page.
+ * Get a prompt message, or fail if there were no prompts.
*/
-Selenium.prototype.assertAbsoluteLocation = function(expectedLocation) {
- this.assertMatches(expectedLocation, this.page().location);
+Selenium.prototype.getPrompt = function() {
+ if (! this.browserbot.hasPrompts()) {
+ Assert.fail("There were no prompts");
+ }
+ return this.browserbot.getNextPrompt();
};
+/*
+ * Get the location of the current page.
+ */
+Selenium.prototype.getAbsoluteLocation = function() {
+ return this.page().location;
+};
/*
- * Verify the location of the current page ends with the expected location
+ * Verify the location of the current page ends with the expected location.
+ * If a querystring is provided, this is checked as well.
*/
Selenium.prototype.assertLocation = function(expectedLocation) {
- var docLocation = this.page().location.toString();
- if (docLocation.length != docLocation.indexOf(expectedLocation) + expectedLocation.length)
- {
- assert.fail("Expected location to end with '" + expectedLocation
- + "' but was '" + docLocation + "'");
+ var docLocation = this.page().location;
+ var searchPos = expectedLocation.lastIndexOf('?');
+
+ if (searchPos == -1) {
+ Assert.matches('*' + expectedLocation, docLocation.pathname);
+ }
+ else {
+ var expectedPath = expectedLocation.substring(0, searchPos);
+ Assert.matches('*' + expectedPath, docLocation.pathname);
+
+ var expectedQueryString = expectedLocation.substring(searchPos);
+ Assert.equals(expectedQueryString, docLocation.search);
}
};
/*
- * Verify the title of the current page.
+ * Get the title of the current page.
*/
-Selenium.prototype.assertTitle = function(expectedTitle) {
- this.assertMatches(expectedTitle, this.page().title());
+Selenium.prototype.getTitle = function() {
+ return this.page().title();
};
+
/*
- * Verify the value of a form element.
+ * Get the (trimmed) value of a form element.
+ * This is used to generate assertValue, verifyValue, ...
*/
-Selenium.prototype.assertValue = function(locator, expectedValue) {
- var element = this.page().findElement(locator);
- var actualValue = getInputValue(element);
- this.assertMatches(expectedValue, actualValue.trim());
-};
+Selenium.prototype.getValue = function(locator) {
+ var element = this.page().findElement(locator)
+ return getInputValue(element).trim();
+}
-/*
- * Verifies that the text of the located element matches the expected content.
+/**
+ * Get the (trimmed) text of a form element.
+ * This is used to generate assertText, verifyText, ...
*/
-Selenium.prototype.assertText = function(locator, expectedContent) {
+Selenium.prototype.getText = function(locator) {
var element = this.page().findElement(locator);
- var actualText = getText(element);
- this.assertMatches(expectedContent, actualText.trim());
+ return getText(element).trim();
};
/*
- * Asserts that the text for a single cell within and HTML table matches the expected content.
+ * Return the text for a single cell within an HTML table.
* The table locator syntax is table.row.column.
*/
-Selenium.prototype.assertTable = function(tableLocator, expectedContent) {
+Selenium.prototype.getTable = function(tableLocator) {
// This regular expression matches "tableName.row.column"
// For example, "mytable.3.4"
pattern = /(.*)\.(\d+)\.(\d+)/;
if(!pattern.test(tableLocator)) {
- assert.fail("Invalid target format. Correct format is tableName.rowNum.columnNum");
+ throw new SeleniumError("Invalid target format. Correct format is tableName.rowNum.columnNum");
}
pieces = tableLocator.match(pattern);
@@ -211,24 +231,24 @@
var table = this.page().findElement(tableName);
if (row > table.rows.length) {
- assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
+ Assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
}
else if (col > table.rows[row].cells.length) {
- assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
+ Assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
}
else {
actualContent = getText(table.rows[row].cells[col]);
- this.assertMatches(expectedContent, actualContent.trim());
+ return actualContent.trim();
}
};
/**
- * Verify the label of the option that is selected.
+ * Verify that the selected option satisfies the option locator.
*/
-Selenium.prototype.assertSelected = function(target, expectedLabel) {
+Selenium.prototype.assertSelected = function(target, optionLocator) {
var element = this.page().findElement(target);
- var selectedLabel = element.options[element.selectedIndex].text;
- this.assertMatches(expectedLabel, selectedLabel);
+ var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
+ locator.assertSelected(element);
};
String.prototype.parseCSV = function() {
@@ -247,20 +267,19 @@
var element = this.page().findElement(target);
var expectedOptionLabels = options.parseCSV();
- assert.equals("Wrong number of options.", expectedOptionLabels.length, element.options.length);
+ Assert.equals("Wrong number of options", expectedOptionLabels.length, element.options.length);
for (var i = 0; i < element.options.length; i++) {
- this.assertMatches(expectedOptionLabels[i], element.options[i].text);
+ Assert.matches(expectedOptionLabels[i], element.options[i].text);
}
};
/**
- * Verify the value of an element attribute. The syntax for returning an element attribute
- * is <element-locator>@attribute-name
+ * Get the value of an element attribute. The syntax for returning an element attribute
+ * is <element-locator>@attribute-name. Used to generate assert, verify, assertNot...
*/
-Selenium.prototype.assertAttribute = function(target, expected) {
- var attributeValue = this.page().findAttribute(target);
- this.assertMatches(expected, attributeValue);
+Selenium.prototype.getAttribute = function(target) {
+ return this.page().findAttribute(target);
};
/*
@@ -270,9 +289,9 @@
var allText = this.page().bodyText();
if(allText == "") {
- assert.fail("Page text not found");
+ Assert.fail("Page text not found");
} else if(allText.indexOf(expectedText) == -1) {
- assert.fail("'" + expectedText + "' not found in page text.");
+ Assert.fail("'" + expectedText + "' not found in page text.");
}
};
@@ -283,9 +302,9 @@
var allText = this.page().bodyText();
if(allText == "") {
- assert.fail("Page text not found");
+ Assert.fail("Page text not found");
} else if(allText.indexOf(unexpectedText) != -1) {
- assert.fail("'" + unexpectedText + "' was found in page text.");
+ Assert.fail("'" + unexpectedText + "' was found in page text.");
}
};
@@ -296,7 +315,7 @@
try {
this.page().findElement(locator);
} catch (e) {
- assert.fail("Element " + locator + " not found.");
+ Assert.fail("Element " + locator + " not found.");
}
};
@@ -310,7 +329,7 @@
catch (e) {
return;
}
- assert.fail("Element " + locator + " found.");
+ Assert.fail("Element " + locator + " found.");
};
/*
@@ -321,10 +340,10 @@
try {
element = this.page().findElement(locator);
} catch (e) {
- assert.fail("Element " + locator + " not present.");
+ Assert.fail("Element " + locator + " not present.");
}
if (! this.isVisible(element)) {
- assert.fail("Element " + locator + " not visible.");
+ Assert.fail("Element " + locator + " not visible.");
}
};
@@ -339,7 +358,7 @@
return;
}
if (this.isVisible(element)) {
- assert.fail("Element " + locator + " is visible.");
+ Assert.fail("Element " + locator + " is visible.");
}
};
@@ -383,7 +402,7 @@
// currentStyle is not identical to getComputedStyle()
// ... but it's good enough for "visibility"
}
- throw new Error("cannot determine effective stylesheet in this browser");
+ throw new SeleniumError("cannot determine effective stylesheet in this browser");
};
/**
@@ -392,10 +411,10 @@
Selenium.prototype.assertEditable = function(locator) {
var element = this.page().findElement(locator);
if (element.value == undefined) {
- assert.fail("Element " + locator + " is not an input.");
+ Assert.fail("Element " + locator + " is not an input.");
}
if (element.disabled) {
- assert.fail("Element " + locator + " is disabled.");
+ Assert.fail("Element " + locator + " is disabled.");
}
};
@@ -408,7 +427,7 @@
return; // not an input
}
if (element.disabled == false) {
- assert.fail("Element " + locator + " is editable.");
+ Assert.fail("Element " + locator + " is editable.");
}
};
@@ -464,12 +483,31 @@
};
/*
+ * Store the value of an element attribute in a variable
+ */
+Selenium.prototype.doStoreAttribute = function(target, varName) {
+ storedVars[varName] = this.page().findAttribute(target);
+};
+
+/*
* Store the result of a literal value
*/
Selenium.prototype.doStore = function(value, varName) {
storedVars[varName] = value;
};
+
+/*
+ * Wait for the target to have the specified value by polling.
+ * The polling is done in TestLoop.kickoffNextCommandExecution()
+ */
+Selenium.prototype.doWaitForValue = function (target, value) {
+ var e = this.page().findElement(target);
+ testLoop.waitForCondition = function () {
+ return (e.value == value);
+ };
+};
+
/**
* Evaluate a parameter, performing javascript evaluation and variable substitution.
* If the string matches the pattern "javascript{ ... }", evaluate the string between the braces.
@@ -507,76 +545,139 @@
return stringResult;
};
-function Assert() {
- this.equals = function()
- {
- if (arguments.length == 2)
- {
- var comment = "";
- var expected = arguments[0];
- var actual = arguments[1];
- }
- else {
- var comment = arguments[0] + " ";
- var expected = arguments[1];
- var actual = arguments[2];
- }
- if (expected === actual) {
- return;
+/**
+ * Factory for creating "Option Locators".
+ * An OptionLocator is an object for dealing with Select options (e.g. for
+ * finding a specified option, or asserting that the selected option of
+ * Select element matches some condition.
+ * The type of locator returned by the factory depends on the locator string:
+ * label=<exp> (OptionLocatorByLabel)
+ * value=<exp> (OptionLocatorByValue)
+ * index=<exp> (OptionLocatorByIndex)
+ * id=<exp> (OptionLocatorById)
+ * <exp> (default is OptionLocatorByLabel).
+ */
+function OptionLocatorFactory() {
+}
+
+OptionLocatorFactory.prototype.fromLocatorString = function(locatorString) {
+ var locatorType = 'label';
+ var locatorValue = locatorString;
+ // If there is a locator prefix, use the specified strategy
+ var result = locatorString.match(/^([a-zA-Z]+)=(.*)/);
+ if (result) {
+ locatorType = result[1];
+ locatorValue = result[2];
+ }
+ if (this.optionLocators == undefined) {
+ this.registerOptionLocators();
+ }
+ if (this.optionLocators[locatorType]) {
+ return new this.optionLocators[locatorType](locatorValue);
+ }
+ throw new SeleniumError("Unkown option locator type: " + locatorType);
+};
+
+/**
+ * To allow for easy extension, all of the option locators are found by
+ * searching for all methods of OptionLocatorFactory.prototype that start
+ * with "OptionLocatorBy".
+ * TODO: Consider using the term "Option Specifier" instead of "Option Locator".
+ */
+OptionLocatorFactory.prototype.registerOptionLocators = function() {
+ this.optionLocators={};
+ for (var functionName in this) {
+ var result = /OptionLocatorBy([A-Z].+)$/.exec(functionName);
+ if (result != null) {
+ var locatorName = result[1].lcfirst();
+ this.optionLocators[locatorName] = this[functionName];
+ }
+ }
+};
+
+/**
+ * OptionLocator for options identified by their labels.
+ */
+OptionLocatorFactory.prototype.OptionLocatorByLabel = function(label) {
+ this.label = label;
+ this.labelMatcher = new PatternMatcher(this.label);
+ this.findOption = function(element) {
+ for (var i = 0; i < element.options.length; i++) {
+ if (this.labelMatcher.matches(element.options[i].text)) {
+ return element.options[i];
+ }
}
- var errorMessage = comment + "Expected '" + expected + "' but was '" + actual + "'";
+ throw new SeleniumError("Option with label '" + this.label + "' not found");
+ };
- throw new AssertionFailedError(errorMessage);
+ this.assertSelected = function(element) {
+ var selectedLabel = element.options[element.selectedIndex].text;
+ Assert.matches(this.label, selectedLabel);
};
+};
- this.fail = function(message)
- {
- throw new AssertionFailedError(message);
+/**
+ * OptionLocator for options identified by their values.
+ */
+OptionLocatorFactory.prototype.OptionLocatorByValue = function(value) {
+ this.value = value;
+ this.valueMatcher = new PatternMatcher(this.value);
+ this.findOption = function(element) {
+ for (var i = 0; i < element.options.length; i++) {
+ if (this.valueMatcher.matches(element.options[i].value)) {
+ return element.options[i];
+ }
+ }
+ throw new SeleniumError("Option with value '" + this.value + "' not found");
};
-}
-function AssertionFailedError(message) {
- this.isAssertionFailedError = true;
- this.failureMessage = message;
-}
+ this.assertSelected = function(element) {
+ var selectedValue = element.options[element.selectedIndex].value;
+ Assert.matches(this.value, selectedValue);
+ };
+};
-/*
- * assertMatches(comment?, pattern, actual)
+/**
+ * OptionLocator for options identified by their index.
*/
-Selenium.prototype.assertMatches = function() {
- if (arguments.length == 2)
- {
- var comment = "";
- var pattern = arguments[0];
- var actual = arguments[1];
- }
- else {
- var comment = arguments[0] + "; ";
- var pattern = arguments[1];
- var actual = arguments[2];
+OptionLocatorFactory.prototype.OptionLocatorByIndex = function(index) {
+ this.index = Number(index);
+ if (isNaN(this.index) || this.index < 0) {
+ throw new SeleniumError("Illegal Index: " + index);
}
- if (this.matches(pattern, actual)) {
- return;
- }
+ this.findOption = function(element) {
+ if (element.options.length <= this.index) {
+ throw new SeleniumError("Index out of range. Only " + element.options.length + " options available");
+ }
+ return element.options[this.index];
+ };
+
+ this.assertSelected = function(element) {
+ Assert.equals(this.index, element.selectedIndex);
+ };
+};
+
+/**
+ * OptionLocator for options identified by their id.
+ */
+OptionLocatorFactory.prototype.OptionLocatorById = function(id) {
+ this.id = id;
+ this.idMatcher = new PatternMatcher(this.id);
+ this.findOption = function(element) {
+ for (var i = 0; i < element.options.length; i++) {
+ if (this.idMatcher.matches(element.options[i].id)) {
+ return element.options[i];
+ }
+ }
+ throw new SeleniumError("Option with id '" + this.id + "' not found");
+ };
- var errorMessage = comment +
- "Actual value '" + actual + "' did not match '" + pattern + "'";
- assert.fail(errorMessage);
-};
-
-Selenium.prototype.globToRegexp = function(glob) {
- var pattern = glob;
- pattern = pattern.replace(/([.^$+(){}[\]\\|])/g, "\\$1");
- pattern = pattern.replace(/\?/g, ".");
- pattern = pattern.replace(/\*/g, ".*");
- return "^" + pattern + "$";
-};
-
-Selenium.prototype.matches = function(pattern, actual) {
- var regexp = new RegExp(this.globToRegexp(pattern));
- // Work around Konqueror bug when matching empty strings.
- var testString = '' + actual;
- return regexp.test(testString);
+ this.assertSelected = function(element) {
+ var selectedId = element.options[element.selectedIndex].id;
+ Assert.matches(this.id, selectedId);
+ };
};
+
+
=== Products/Zelenium/selenium/selenium-browserbot.js 1.4 => 1.5 ===
--- Products/Zelenium/selenium/selenium-browserbot.js:1.4 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/selenium-browserbot.js Wed Oct 12 06:38:23 2005
@@ -42,47 +42,51 @@
var geckoResult = /^Mozilla\/5\.0 .*Gecko\/(\d{8}).*$/.exec(navigator.userAgent);
var geckoVersion = geckoResult == null ? null : geckoResult[1];
-function createBrowserBot(frame) {
- if (isIE) {
- return new IEBrowserBot(frame);
- }
- else if (isKonqueror) {
- return new KonquerorBrowserBot(frame);
- }
- else if (isSafari) {
- return new SafariBrowserBot(frame);
- }
- else {
- // Use mozilla by default
- return new MozillaBrowserBot(frame);
- }
-}
+BrowserBot = function(frame) {
+ this.frame = frame;
+ this.currentPage = null;
+ this.currentWindowName = null;
+
+ this.modalDialogTest = null;
+ this.recordedAlerts = new Array();
+ this.recordedConfirmations = new Array();
+ this.recordedPrompts = new Array();
+ this.openedWindows = {};
+ this.nextConfirmResult = true;
+ this.nextPromptResult = '';
+ this.newPageLoaded = false;
-function createPageBot(windowObject) {
+ var self = this;
+ this.recordPageLoad = function() {
+ LOG.debug("Page load detected, location=" + self.getCurrentWindow().location);
+ self.currentPage = null;
+ self.newPageLoaded = true;
+ };
+
+ this.isNewPageLoaded = function() {
+ return self.newPageLoaded;
+ };
+};
+
+BrowserBot.createForFrame = function(frame) {
+ var browserbot;
if (isIE) {
- return new IEPageBot(windowObject);
+ browserbot = new IEBrowserBot(frame);
}
else if (isKonqueror) {
- return new KonquerorPageBot(windowObject);
+ browserbot = new KonquerorBrowserBot(frame);
}
else if (isSafari) {
- return new SafariPageBot(windowObject);
+ browserbot = new SafariBrowserBot(frame);
}
else {
// Use mozilla by default
- return new MozillaPageBot(windowObject);
+ browserbot = new MozillaBrowserBot(frame);
}
-}
-BrowserBot = function(frame) {
- this.frame = frame;
- this.currentPage = null;
- this.currentWindowName = null;
-
- this.modalDialogTest = null;
- this.recordedAlerts = new Array();
- this.recordedConfirmations = new Array();
- this.nextConfirmResult = true;
+ // Modify the test IFrame so that page loads are detected.
+ addLoadListener(browserbot.getFrame(), browserbot.recordPageLoad);
+ return browserbot;
};
BrowserBot.prototype.doModalDialogTest = function(test) {
@@ -93,6 +97,10 @@
this.nextConfirmResult = false;
};
+BrowserBot.prototype.setNextPromptResult = function(result) {
+ this.nextPromptResult = result;
+};
+
BrowserBot.prototype.hasAlerts = function() {
return (this.recordedAlerts.length > 0) ;
};
@@ -109,6 +117,13 @@
return this.recordedConfirmations.shift();
};
+BrowserBot.prototype.hasPrompts = function() {
+ return (this.recordedPrompts.length > 0) ;
+};
+
+BrowserBot.prototype.getNextPrompt = function() {
+ return this.recordedPrompts.shift();
+};
BrowserBot.prototype.getFrame = function() {
return this.frame;
@@ -126,21 +141,25 @@
}
};
-BrowserBot.prototype.openLocation = function(target, onloadCallback) {
+BrowserBot.prototype.openLocation = function(target) {
// We're moving to a new page - clear the current one
this.currentPage = null;
- // 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;
+ this.newPageLoaded = false;
+
+ this.setIFrameLocation(this.getFrame(), target);
+};
+
+BrowserBot.prototype.setIFrameLocation = function(iframe, location) {
+ iframe.src = location;
};
BrowserBot.prototype.getCurrentPage = function() {
if (this.currentPage == null) {
var testWindow = this.getCurrentWindow();
this.modifyWindowToRecordPopUpDialogs(testWindow, this);
- this.modifyWindowToClearPageCache(testWindow, this);
- this.currentPage = createPageBot(testWindow);
+ this.modifySeparateTestWindowToDetectPageLoads(testWindow);
+ this.currentPage = PageBot.createForWindow(testWindow);
+ this.newPageLoaded = false;
}
return this.currentPage;
@@ -157,30 +176,69 @@
browserBot.nextConfirmResult = true;
return result;
};
-};
-BrowserBot.prototype.modifyWindowToClearPageCache = function(windowToModify, browserBot) {
- var clearCachedPage = function() {
- LOG.debug("UNLOAD: clearCachedPage()");
- browserbot.currentPage = null;
+ windowToModify.prompt = function(message) {
+ browserBot.recordedPrompts.push(message);
+ var result = !browserBot.nextConfirmResult ? null : browserBot.nextPromptResult;
+ browserBot.nextConfirmResult = true;
+ browserBot.nextPromptResult = '';
+ return result;
};
- if (window.addEventListener) {
- windowToModify.addEventListener("unload", clearCachedPage, true);
- } else if (window.attachEvent) {
- windowToModify.attachEvent("onunload", clearCachedPage);
+ // Keep a reference to all popup windows by name
+ // note that in IE the "windowName" argument must be a valid javascript identifier, it seems.
+ var originalOpen = windowToModify.open;
+ windowToModify.open = function(url, windowName, windowFeatures, replaceFlag) {
+ var openedWindow = originalOpen(url, windowName, windowFeatures, replaceFlag);
+ selenium.browserbot.openedWindows[windowName] = openedWindow;
+ return openedWindow;
+ };
+};
+
+/**
+ * The main IFrame has a single, long-lived onload handler that clears
+ * Browserbot.currentPage and sets the "newPageLoaded" flag. For separate
+ * windows, we need to attach a handler each time. This uses the
+ * "callOnWindowPageTransition" mechanism, which is implemented differently
+ * for different browsers.
+ */
+BrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads = function(windowToModify) {
+ if (this.currentWindowName != null) {
+ this.callOnWindowPageTransition(this.recordPageLoad, windowToModify);
}
};
+/**
+ * Call the supplied function when a the current page unloads and a new one loads.
+ * This is done with an "unload" handler which attaches a "load" handler.
+ */
+BrowserBot.prototype.callOnWindowPageTransition = function(loadFunction, windowObject) {
+ var attachLoadListener = function() {
+ if (windowObject && !windowObject.closed) {
+ addLoadListener(windowObject, loadFunction);
+ }
+ };
+
+ var unloadFunction = function() {
+ window.setTimeout(attachLoadListener, 0);
+ };
+ addUnloadListener(windowObject, unloadFunction);
+};
+
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);
+ LOG.debug("getTargetWindow(" + windowName + ")");
+ // First look in the map of opened windows
+ var targetWindow = this.openedWindows[windowName];
if (!targetWindow) {
- throw new Error("Window does not exist");
+ var evalString = "this.getContentWindow().window." + windowName;
+ targetWindow = eval(evalString);
+ }
+ if (!targetWindow) {
+ throw new SeleniumError("Window does not exist");
}
return targetWindow;
};
@@ -193,44 +251,6 @@
return testWindow;
};
-BrowserBot.prototype.callOnNextPageLoad = function(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);
-};
-
-/**
- * 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);
}
@@ -241,10 +261,24 @@
}
KonquerorBrowserBot.prototype = new BrowserBot;
+KonquerorBrowserBot.prototype.setIFrameLocation = function(iframe, location) {
+ // Window doesn't fire onload event when setting src to the current value,
+ // so we set it to blank first.
+ iframe.src = "about:blank";
+ iframe.src = location;
+};
+
+/**
+ * Call the supplied function when a the current page unloads and a new one loads.
+ * This is done by polling continuously until the document changes and is fully loaded.
+ */
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);
+ if (windowObject && !windowObject.closed) {
+ LOG.debug("Starting pollForLoad");
+ this.pollForLoad(loadFunction, windowObject, windowObject.document);
+ }
};
/**
@@ -254,16 +288,21 @@
* is different from the original one.
*/
KonquerorBrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument) {
+ if (windowObject.closed) {
+ return;
+ }
+
var sameDoc = (originalDocument === windowObject.document);
var rs = windowObject.document.readyState;
if (!sameDoc && rs == 'complete') {
- LOG.debug("poll: " + rs + " (" + sameDoc + ")");
+ LOG.debug("pollForLoad complete: " + rs + " (" + sameDoc + ")");
loadFunction();
return;
}
var self = this;
- window.setTimeout(function() {self.pollForLoad(loadFunction, windowObject, originalDocument);}, 100);
+ LOG.debug("pollForLoad continue");
+ window.setTimeout(function() {self.pollForLoad(loadFunction, windowObject, originalDocument);}, 500);
};
function SafariBrowserBot(frame) {
@@ -271,15 +310,7 @@
}
SafariBrowserBot.prototype = new BrowserBot;
-/**
- * Since Safari 1.3 doesn't trigger unload, we clear cached page as soon as
- * we know that we're expecting a new page.
- */
-SafariBrowserBot.prototype.callOnNextPageLoad = function(onloadCallback) {
- this.currentPage = null;
- BrowserBot.prototype.callOnNextPageLoad.call(this, onloadCallback);
-};
-
+SafariBrowserBot.prototype.setIFrameLocation = KonquerorBrowserBot.prototype.setIFrameLocation;
SafariBrowserBot.prototype.callOnWindowPageTransition = KonquerorBrowserBot.prototype.callOnWindowPageTransition;
SafariBrowserBot.prototype.pollForLoad = KonquerorBrowserBot.prototype.pollForLoad;
@@ -287,6 +318,8 @@
BrowserBot.call(this, frame);
}
IEBrowserBot.prototype = new BrowserBot;
+IEBrowserBot.prototype.callOnWindowPageTransition = KonquerorBrowserBot.prototype.callOnWindowPageTransition;
+IEBrowserBot.prototype.pollForLoad = KonquerorBrowserBot.prototype.pollForLoad;
IEBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
@@ -341,7 +374,7 @@
if (pageWindow) {
this.currentWindow = pageWindow;
this.currentDocument = pageWindow.document;
- this.location = pageWindow.location.pathname;
+ this.location = pageWindow.location;
this.title = function() {return this.currentDocument.title;};
}
@@ -368,7 +401,7 @@
this.findElementBy = function(locatorType, locator, inDocument) {
var locatorFunction = this.locationStrategies[locatorType];
if (! locatorFunction) {
- throw new Error("Unrecognised locator type: '" + locatorType + "'");
+ throw new SeleniumError("Unrecognised locator type: '" + locatorType + "'");
}
return locatorFunction.call(this, locator, inDocument);
};
@@ -377,13 +410,33 @@
* 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);
+ if (locator.startsWith('//')) {
+ return this.locateElementByXPath(locator, inDocument);
+ }
+ if (locator.startsWith('document.')) {
+ return this.locateElementByDomTraversal(locator, inDocument);
+ }
+ return this.locateElementByIdentifier(locator, inDocument);
};
};
+PageBot.createForWindow = function(windowObject) {
+ if (isIE) {
+ return new IEPageBot(windowObject);
+ }
+ else if (isKonqueror) {
+ return new KonquerorPageBot(windowObject);
+ }
+ else if (isSafari) {
+ return new SafariPageBot(windowObject);
+ }
+ else {
+ // Use mozilla by default
+ return new MozillaPageBot(windowObject);
+ }
+};
+
MozillaPageBot = function(pageWindow) {
PageBot.call(this, pageWindow);
};
@@ -412,9 +465,9 @@
var locatorString = locator;
// If there is a locator prefix, use the specified strategy
- var result = locator.match(/^([a-z]+)=(.+)/);
+ var result = locator.match(/^([A-Za-z]+)=(.+)/);
if (result) {
- locatorType = result[1];
+ locatorType = result[1].toLowerCase();
locatorString = result[2];
}
@@ -430,7 +483,7 @@
}
// Element was not found by any locator function.
- throw new Error("Element " + locator + " not found");
+ throw new SeleniumError("Element " + locator + " not found");
};
/**
@@ -505,9 +558,6 @@
* begin with "//".
*/
PageBot.prototype.locateElementByXPath = function(xpath, inDocument) {
- if (xpath.slice(0,2) != "//") {
- return null;
- }
// Trim any trailing "/": not valid xpath, and remains from attribute
// locator.
@@ -603,7 +653,7 @@
var links = inDocument.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
var element = links[i];
- if (getText(element) == linkText) {
+ if (PatternMatcher.matches(linkText, getText(element))) {
return element;
}
}
@@ -636,32 +686,22 @@
};
/*
-* Selects the first option with a matching label from the select box element
-* provided. If no matching element is found, nothing happens.
+* Select the specified option and trigger the relevant events of the element.
*/
-PageBot.prototype.selectOptionWithLabel = function(element, stringValue) {
+PageBot.prototype.selectOption = function(element, option) {
triggerEvent(element, 'focus', false);
- for (var i = 0; i < element.options.length; i++) {
- var option = element.options[i];
- if (option.text == stringValue) {
- if (!option.selected) {
- option.selected = true;
- triggerEvent(element, 'change', true);
- }
- triggerEvent(element, 'blur', false);
- return;
- }
+ if (!option.selected) {
+ option.selected = true;
+ triggerEvent(element, 'change', true);
}
- throw new Error("Option with label '" + stringValue + "' not found");
+ triggerEvent(element, 'blur', false);
};
PageBot.prototype.replaceText = function(element, stringValue) {
triggerEvent(element, 'focus', false);
triggerEvent(element, 'select', true);
element.value=stringValue;
- if (isIE || isKonqueror || isSafari) {
- triggerEvent(element, 'change', true);
- }
+ triggerEvent(element, 'change', true);
triggerEvent(element, 'blur', false);
};
@@ -780,17 +820,40 @@
triggerEvent(element, 'focus', false);
var wasChecked = element.checked;
+
+ // Set a flag that records if the page will unload - this isn't always accurate, because
+ // <a href="javascript:alert('foo'):"> triggers the onbeforeunload event, even thought the page won't unload
+ var pageUnloading = false;
+ var pageUnloadDetector = function() {pageUnloading = true;};
+ this.currentWindow.attachEvent("onbeforeunload", pageUnloadDetector);
+
element.click();
- if (this.windowClosed()) {
- return;
- }
- // Onchange event is not triggered automatically in IE.
- if (isDefined(element.checked) && wasChecked != element.checked) {
- triggerEvent(element, 'change', true);
- }
+ // If the page is going to unload - still attempt to fire any subsequent events.
+ // However, we can't guarantee that the page won't unload half way through, so we need to handle exceptions.
+ try {
+ this.currentWindow.detachEvent("onbeforeunload", pageUnloadDetector);
- triggerEvent(element, 'blur', false);
+ if (this.windowClosed()) {
+ return;
+ }
+
+ // Onchange event is not triggered automatically in IE.
+ if (isDefined(element.checked) && wasChecked != element.checked) {
+ triggerEvent(element, 'change', true);
+ }
+
+ triggerEvent(element, 'blur', false);
+ }
+ catch (e) {
+ // If the page is unloading, we may get a "Permission denied" or "Unspecified error".
+ // Just ignore it, because the document may have unloaded.
+ if (pageUnloading) {
+ LOG.warn("Caught exception when firing events on unloading page: " + e.message);
+ return;
+ }
+ throw e;
+ }
};
PageBot.prototype.windowClosed = function(element) {
@@ -860,4 +923,8 @@
PageBot.prototype.goForward = function() {
this.currentWindow.history.forward();
+};
+
+PageBot.prototype.close = function() {
+ this.currentWindow.close();
};
=== Products/Zelenium/selenium/selenium-commandhandlers.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/selenium-commandhandlers.js:1.3 Fri May 6 07:46:12 2005
+++ Products/Zelenium/selenium/selenium-commandhandlers.js Wed Oct 12 06:38:23 2005
@@ -35,6 +35,11 @@
var handler = new AssertHandler(assertion, haltOnFailure);
this.asserts[name] = handler;
};
+
+ self.registerAssertUsingMatcherHandler = function(name, matcherHandler, haltOnFailure) {
+ var handler = new AssertUsingMatcherHandler(matcherHandler, haltOnFailure);
+ this.asserts[name] = handler;
+ }
this.getCommandHandler = function(name) {
return this.actions[name] || this.accessors[name] || this.asserts[name] || null;
@@ -50,7 +55,7 @@
for (var functionName in commandObject) {
var result = /^do([A-Z].+)$/.exec(functionName);
if (result != null) {
- var actionName = toCamelCase(result[1]);
+ var actionName = result[1].lcfirst();
// Register the action without the wait flag.
var action = commandObject[functionName];
@@ -80,20 +85,85 @@
}
};
+ // Given an accessor function, return a function that matches against the command.value
+ // the value returned by the accessor when applied to a command.target.
+ // Used by commands that take a target and a value (e.g. assertValue | target | value)
+ this.createMatcherHandlerFromSingleArgAccessor = function(accessor) {
+ return function(seleniumApi, command) {
+ var accessorResult = accessor.call(seleniumApi, command.target);
+ if (PatternMatcher.matches(command.value, accessorResult)) {
+ return new MatcherHandlerResult(true, "Actual value '" + accessorResult + "' did match '" + command.value + "'");
+ } else {
+ return new MatcherHandlerResult(false, "Actual value '" + accessorResult + "' did not match '" + command.value + "'");
+ }
+ };
+ };
+
+ // Given an accessor function, return a function that matches against the command.target
+ // the value returned by the (no-arg) accessor returns a value that matches against the command.target
+ // Used by commands that only take a target (e.g. assertTitle | target | )
+ this.createMatcherHandlerFromNoArgAccessor = function(accessor) {
+ return function(seleniumApi, command) {
+ var accessorResult = accessor.call(seleniumApi);
+ if (PatternMatcher.matches(command.target, accessorResult)) {
+ return new MatcherHandlerResult(true, "Actual value '" + accessorResult + "' did match '" + command.target + "'");
+ } else {
+ return new MatcherHandlerResult(false, "Actual value '" + accessorResult + "' did not match '" + command.target + "'");
+ }
+ };
+ };
+
+ // Given a matcherHandler function, return a function that returns the same result
+ // as the matcherHandler, but with the result negated.
+ // Used to create assertNot and verifyNot commands (and soon hopefully waitForNot commands).
+ this.createMatcherHandlerNegator = function(matcherHandler) {
+ return function(seleniumApi, command) {
+ var result = matcherHandler(seleniumApi, command);
+ result.didMatch = ! result.didMatch;
+ return result;
+ };
+ };
+
+
+ // Methods of the form getFoo(target) result in commands:
+ // getFoo, assertFoo, verifyFoo, assertNotFoo, verifyNotFoo
var registerAllAccessors = function(commandObject) {
for (var functionName in commandObject) {
- if (/^get[A-Z].+$/.exec(functionName) != null) {
+ var match = /^get([A-Z].+)$/.exec(functionName);
+ if (match != null) {
var accessor = commandObject[functionName];
+ var baseName = match[1];
self.registerAccessor(functionName, accessor);
+
+ if (accessor.length > 1) {
+ continue;
+ }
+ var matcherHandler;
+ if (accessor.length == 1) {
+ matcherHandler = self.createMatcherHandlerFromSingleArgAccessor(accessor);
+ } else {
+ matcherHandler = self.createMatcherHandlerFromNoArgAccessor(accessor);
+ }
+ // Register an assert with the "assert" prefix, and halt on failure.
+ self.registerAssertUsingMatcherHandler("assert" + baseName, matcherHandler, true);
+ // Register a verify with the "verify" prefix, and do not halt on failure.
+ self.registerAssertUsingMatcherHandler("verify" + baseName, matcherHandler, false);
+
+ var negativeMatcherHandler = self.createMatcherHandlerNegator(matcherHandler);
+ // Register an assertNot with the "assertNot" prefix, and halt on failure.
+ self.registerAssertUsingMatcherHandler("assertNot"+baseName, negativeMatcherHandler, true);
+ // Register a verifyNot with the "verifyNot" prefix, and do not halt on failure.
+ self.registerAssertUsingMatcherHandler("verifyNot"+baseName, negativeMatcherHandler, false);
}
}
};
-
- function toCamelCase(aString) {
- return aString.charAt(0).toLowerCase() + aString.substr(1);
- }
+
}
+function MatcherHandlerResult(didMatch, message) {
+ this.didMatch = didMatch;
+ this.message = message;
+}
// NOTE: The CommandHandler is effectively an abstract base for ActionHandler,
// AccessorHandler and AssertHandler.
@@ -115,10 +185,10 @@
ActionHandler.prototype = new CommandHandler;
ActionHandler.prototype.execute = function(seleniumApi, command) {
if ( seleniumApi.browserbot.hasAlerts() ) {
- throw new Error("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
+ throw new SeleniumCommandError("There was an unexpected Alert! [" + seleniumApi.browserbot.getNextAlert() + "]");
}
if ( seleniumApi.browserbot.hasConfirmations() ) {
- throw new Error("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
+ throw new SeleniumCommandError("There was an unexpected Confirmation! [" + seleniumApi.browserbot.getNextConfirmation() + "]");
}
var processState = this.executor.call(seleniumApi, command.target, command.value);
// If the handler didn't return a wait flag, check to see if the
@@ -140,14 +210,19 @@
return result;
};
-function AssertHandler(assertion, haltOnFailure) {
+/**
+ * Abstract handler for assertions and verifications.
+ * Subclasses need to override executeAssertion() which in turn
+ * should throw an AssertFailedError if the assertion is to fail.
+ */
+function AbstractAssertHandler(assertion, haltOnFailure) {
CommandHandler.call(this, "assert", haltOnFailure || false, assertion);
}
-AssertHandler.prototype = new CommandHandler;
-AssertHandler.prototype.execute = function(seleniumApi, command) {
+AbstractAssertHandler.prototype = new CommandHandler;
+AbstractAssertHandler.prototype.execute = function(seleniumApi, command) {
var result = new CommandResult();
try {
- var processState = this.executor.call(seleniumApi, command.target, command.value);
+ this.executeAssertion(seleniumApi, command);
result.passed = true;
} catch (e) {
// If this is not a AssertionFailedError, or we should haltOnFailure, rethrow.
@@ -155,8 +230,7 @@
throw e;
}
if (this.haltOnFailure) {
- var error = new Error(e.failureMessage);
- error.message = e.failureMessage;
+ var error = new SeleniumCommandError(e.failureMessage);
throw error;
}
result.failed = true;
@@ -165,6 +239,32 @@
return result;
};
+/**
+ * Simple assertion handler whose command is expected to do the actual assertion.
+ */
+function AssertHandler(assertion, haltOnFailure) {
+ CommandHandler.call(this, "assert", haltOnFailure || false, assertion);
+};
+AssertHandler.prototype = new AbstractAssertHandler;
+AssertHandler.prototype.executeAssertion = function(seleniumApi, command) {
+ this.executor.call(seleniumApi, command.target, command.value);
+};
+
+/**
+ * Assertion handler whose command is expected to be a matcher-handler
+ */
+function AssertUsingMatcherHandler(matcherHandler, haltOnFailure) {
+ CommandHandler.call(this, "assert", haltOnFailure || false, matcherHandler);
+};
+AssertUsingMatcherHandler.prototype = new AbstractAssertHandler;
+AssertUsingMatcherHandler.prototype.executeAssertion = function(seleniumApi, command) {
+ var matcherResult = this.executor(seleniumApi, command);
+ if (!matcherResult.didMatch) {
+ Assert.fail(matcherResult.message);
+ }
+};
+
+
function CommandResult(processState) {
this.processState = processState;
this.result = "OK";
@@ -174,4 +274,13 @@
this.command = command;
this.target = target;
this.value = value;
-}
\ No newline at end of file
+}
+
+// TODO: dkemp - This is the same as SeleniumError as defined in selenium-browserbot.js
+// I defined a new error simply to avoid creating a new dependency.
+// Need to revisit to avoid this duplication.
+function SeleniumCommandError(message) {
+ var error = new Error(message);
+ error.isSeleniumError = true;
+ return error;
+};
=== Products/Zelenium/selenium/selenium-domviewer.js 1.1 => 1.2 ===
--- Products/Zelenium/selenium/selenium-domviewer.js:1.1 Mon May 2 23:48:16 2005
+++ Products/Zelenium/selenium/selenium-domviewer.js Wed Oct 12 06:38:23 2005
@@ -1,193 +1,188 @@
var HIDDEN="hidden";
var LEVEL = "level";
-var PLUS_SRC="dom-images/butplus.gif"
-var MIN_SRC="dom-images/butmin.gif"
+var PLUS_SRC="dom-images/butplus.gif";
+var MIN_SRC="dom-images/butmin.gif";
var newRoot;
var maxColumns=1;
-function loadDomViewer(){
- if(window.opener != null){
- //Open in a new window.
- // Start with specified root object.
- // It should be defined as a "newRoot" variable
- // in the tested page. Could be any element in
- // the DOM structure of the page that opened it.
- // Default to document if no object is specified.
- newRoot = window.opener.newRoot;
-
- if (newRoot==null)
- newRoot = window.opener.document;
-
- document.writeln(displayDOM(newRoot));
- document.close();
- }else{
- newRoot = parent.document.all['myiframe'].contentWindow.document;
- newRoot.writeln(displayDOM(newRoot));
- newRoot.close();
- }
+function loadDomViewer() {
+ // See if the rootDocument variable has been set on this window.
+ var rootDocument = window.rootDocument;
+
+ // If not look to the opener for an explicity rootDocument variable, otherwise, use the opener document
+ if (!rootDocument && window.opener) {
+ rootDocument = window.opener.rootDocument || window.opener.document;
+ }
+
+ if (rootDocument) {
+ document.body.innerHTML = displayDOM(rootDocument);
+ }
+ else {
+ document.body.innerHTML = "<b>Must specify rootDocument for window. This can be done by setting the rootDocument variable on this window, or on the opener window for a popup window.</b>";
+ }
}
function displayDOM(root){
- var str = "<html><head><title>DOM Viewerr</title><script type='text/javascript' src='domviewer.js'><!-- comments --> </script><link href='dom-styles/default.css' rel='stylesheet' type='text/css' /></head><body>";
- str+="<table>";
- str += treeTraversal(root,0);
- // to make table columns work well.
- str += "<tr>";
- for (var i=0; i < maxColumns; i++) {
- str+= "<td> </td>";
- }
- str += "</tr>";
- str += "</table></body></html>";
- return str;
+ var str = "";
+ str+="<table>";
+ str += treeTraversal(root,0);
+ // to make table columns work well.
+ str += "<tr>";
+ for (var i=0; i < maxColumns; i++) {
+ str+= "<td> </td>";
+ }
+ str += "</tr>";
+ str += "</table>";
+ return str;
}
function checkForChildren(element){
- if(!element.hasChildNodes())
- return false;
-
- var nodes = element.childNodes;
- var size = nodes.length;
- var count=0;
-
- for(var i=0; i< size; i++){
- var node = nodes.item(i);
- //if(node.toString()=="[object Text]"){
- //this is equalent to the above
- //but will work with more browsers
- if(node.nodeType!=1){
- count++;
- }
- }
-
- if(count == size)
- return false;
- else
- return true;
+ if(!element.hasChildNodes())
+ return false;
+
+ var nodes = element.childNodes;
+ var size = nodes.length;
+ var count=0;
+
+ for(var i=0; i< size; i++){
+ var node = nodes.item(i);
+ //if(node.toString()=="[object Text]"){
+ //this is equalent to the above
+ //but will work with more browsers
+ if(node.nodeType!=1){
+ count++;
+ }
+ }
+
+ if(count == size)
+ return false;
+ else
+ return true;
}
function treeTraversal(root, level){
- var str = "";
- var nodes= null;
- var size = null;
- //it is supposed to show the last node,
- //but the last node is always nodeText type
- //and we don't show it
- if(!root.hasChildNodes())
- return "";//displayNode(root,level,false);
-
- nodes = root.childNodes;
- size = nodes.length;
-
- for(var i=0; i< size; i++){
- var element = nodes.item(i);
- //if the node is textNode, don't display
- if(element.nodeType==1){
- str+= displayNode(element,level,checkForChildren(element));
- str+=treeTraversal(element, level+1);
- }
- }
- return str;
+ var str = "";
+ var nodes= null;
+ var size = null;
+ //it is supposed to show the last node,
+ //but the last node is always nodeText type
+ //and we don't show it
+ if(!root.hasChildNodes())
+ return "";//displayNode(root,level,false);
+
+ nodes = root.childNodes;
+ size = nodes.length;
+
+ for(var i=0; i< size; i++){
+ var element = nodes.item(i);
+ //if the node is textNode, don't display
+ if(element.nodeType==1){
+ str+= displayNode(element,level,checkForChildren(element));
+ str+=treeTraversal(element, level+1);
+ }
+ }
+ return str;
}
-
function displayNode(element, level, isLink){
- nodeContent = getNodeContent(element);
- columns = Math.round((nodeContent.length / 12) + 0.5);
- if (columns + level > maxColumns) {
- maxColumns = columns + level;
- }
- var str ="<tr class='"+LEVEL+level+"'>";
- for (var i=0; i < level; i++)
- str+= "<td> </td>";
- str+="<td colspan='"+ columns +"' class='box"+" boxlevel"+level+"' >";
- if(isLink){
- str+='<a onclick="hide(this);" href="javascript:void(this);">';
- str+='<img src="'+MIN_SRC+'" />';
- }
- str += nodeContent;
- if(isLink)
- str+="</a></td></tr>";
- return str;
+ nodeContent = getNodeContent(element);
+ columns = Math.round((nodeContent.length / 12) + 0.5);
+ if (columns + level > maxColumns) {
+ maxColumns = columns + level;
+ }
+ var str ="<tr class='"+LEVEL+level+"'>";
+ for (var i=0; i < level; i++)
+ str+= "<td> </td>";
+ str+="<td colspan='"+ columns +"' class='box"+" boxlevel"+level+"' >";
+ if(isLink){
+ str+='<a onclick="hide(this);return false;" href="javascript:void();">';
+ str+='<img src="'+MIN_SRC+'" />';
+ }
+ str += nodeContent;
+ if(isLink)
+ str+="</a></td></tr>";
+ return str;
}
function getNodeContent(element) {
- str = "";
- id ="";
- if (element.id != null && element.id != "") {
- id = " ID(" + element.id +")";
- }
- name ="";
- if (element.name != null && element.name != "") {
- name = " NAME(" + element.name + ")";
- }
- value ="";
- if (element.value != null && element.value != "") {
- value = " VALUE(" + element.value + ")";
- }
- href ="";
- if (element.href != null && element.href != "") {
- href = " HREF(" + element.href + ")";
- }
- text ="";
- if (element.text != null && element.text != "" && element.text != "undefined") {
- text = " #TEXT(" + trim(element.text) +")";
- }
- str+=" <b>"+ element.nodeName + id + name + value + href + text + "</b>";
- return str;
+ str = "";
+ id ="";
+ if (element.id != null && element.id != "") {
+ id = " ID(" + element.id +")";
+ }
+ name ="";
+ if (element.name != null && element.name != "") {
+ name = " NAME(" + element.name + ")";
+ }
+ value ="";
+ if (element.value != null && element.value != "") {
+ value = " VALUE(" + element.value + ")";
+ }
+ href ="";
+ if (element.href != null && element.href != "") {
+ href = " HREF(" + element.href + ")";
+ }
+ text ="";
+ if (element.text != null && element.text != "" && element.text != "undefined") {
+ text = " #TEXT(" + trim(element.text) +")";
+ }
+ str+=" <b>"+ element.nodeName + id + name + value + href + text + "</b>";
+ return str;
}
function trim(val) {
- val2 = val.substring(0,20) + " ";
- var spaceChr = String.fromCharCode(32);
- var length = val2.length;
- var retVal = "";
- var ix = length -1;
-
- while(ix > -1){
- if(val2.charAt(ix) == spaceChr) {
- } else {
- retVal = val2.substring(0, ix +1);
- break;
- }
- ix = ix-1;
- }
- if (val.length > 20) {
- retVal += "...";
+ val2 = val.substring(0,20) + " ";
+ var spaceChr = String.fromCharCode(32);
+ var length = val2.length;
+ var retVal = "";
+ var ix = length -1;
+
+ while(ix > -1){
+ if(val2.charAt(ix) == spaceChr) {
+ } else {
+ retVal = val2.substring(0, ix +1);
+ break;
}
- return retVal;
+ ix = ix-1;
+ }
+ if (val.length > 20) {
+ retVal += "...";
+ }
+ return retVal;
}
function hide(hlink){
- var isHidden = false;
- var image = hlink.firstChild;
- if(image.src.toString().indexOf(MIN_SRC)!=-1){
- image.src=PLUS_SRC;
- isHidden=true;
- }else{
- image.src=MIN_SRC;
- }
- var rowObj= hlink.parentNode.parentNode;
- var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));
-
- var sibling = rowObj.nextSibling;
- var siblingLevel = sibling.className.substring(LEVEL.length);
- if(siblingLevel.indexOf(HIDDEN)!=-1){
- siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
- }
- siblingLevel=parseInt(siblingLevel);
- while(sibling!=null && rowLevel<siblingLevel){
- if(isHidden){
- sibling.className += " "+ HIDDEN;
- }else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
- var str = sibling.className;
- sibling.className=str.substring(0, str.length - HIDDEN.length-1);
- }
- sibling = sibling.nextSibling;
- siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
- }
+ var isHidden = false;
+ var image = hlink.firstChild;
+ if(image.src.toString().indexOf(MIN_SRC)!=-1){
+ image.src=PLUS_SRC;
+ isHidden=true;
+ }else{
+ image.src=MIN_SRC;
+ }
+ var rowObj= hlink.parentNode.parentNode;
+ var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));
+
+ var sibling = rowObj.nextSibling;
+ var siblingLevel = sibling.className.substring(LEVEL.length);
+ if(siblingLevel.indexOf(HIDDEN)!=-1){
+ siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);
+ }
+ siblingLevel=parseInt(siblingLevel);
+ while(sibling!=null && rowLevel<siblingLevel){
+ if(isHidden){
+ sibling.className += " "+ HIDDEN;
+ }else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){
+ var str = sibling.className;
+ sibling.className=str.substring(0, str.length - HIDDEN.length-1);
+ }
+ sibling = sibling.nextSibling;
+ siblingLevel = parseInt(sibling.className.substring(LEVEL.length));
+ }
}
-
-
+function LOG(message) {
+ window.opener.LOG.warn(message);
+}
=== Products/Zelenium/selenium/selenium-executionloop.js 1.4 => 1.5 ===
--- Products/Zelenium/selenium/selenium-executionloop.js:1.4 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/selenium-executionloop.js Wed Oct 12 06:38:23 2005
@@ -23,8 +23,6 @@
function TestLoop(commandFactory) {
this.commandFactory = commandFactory;
- var self = this;
-
this.start = function() {
selenium.reset();
this.continueCurrentTest();
@@ -50,10 +48,9 @@
if (!command) return TEST_FINISHED;
- // Make the current row blue
this.commandStarted(command);
- LOG.debug("Executing: |" + command.command + " | " + command.target + " | " + command.value + " |");
+ LOG.info("Executing: |" + command.command + " | " + command.target + " | " + command.value + " |");
var result;
try {
@@ -67,27 +64,21 @@
result = handler.execute(selenium, command);
} catch (e) {
- LOG.error(e);
- // TODO: only throw typed errors from commands so that we can perform better error handling
- // to differentiate between expected command errors and unexpected javascript errors.
- if (e instanceof TypeError) {
- // Not a command error.
- throw e;
- }
- this.commandError(e.message);
+ this.handleCommandError(e);
return TEST_FINISHED;
}
- // Record the result so that we can continue the execution using window.setTimeout()
+ // Record the result so that we can continue the execution using
+ // window.setTimeout()
this.lastCommandResult = result;
if (result.processState == SELENIUM_PROCESS_WAIT) {
- // Since we're waiting for page to reload, we can't continue command execution
- // directly, we need use a page load listener.
-
- // TODO there is a potential race condition by attaching a load listener after
- // the command has completed execution.
- selenium.callOnNextPageLoad(function() {eval("testLoop.continueCommandExecutionWithDelay()");});
+ this.waitForCondition = function() {
+ return selenium.browserbot.isNewPageLoaded();
+ };
+ }
+ if (this.waitForCondition) {
+ this.pollUntilConditionIsTrue();
} else {
// Continue processing
this.continueCommandExecutionWithDelay();
@@ -97,9 +88,38 @@
return TEST_CONTINUE;
};
+ this.handleCommandError = function(e) {
+ if (!e.isSeleniumError) {
+ LOG.exception(e);
+ var msg = "Selenium failure. Please report to selenium-devel at lists.public.thoughtworks.org, with details from the logs at the base of the page.";
+ if (e.message) {
+ msg += " The error message is: " + e.message;
+ }
+ this.commandError(msg);
+ } else {
+ LOG.error(e.message);
+ this.commandError(e.message);
+ }
+ };
+
+ /**
+ * Busy wait for waitForCondition() to become true, and then continue
+ * command execution.
+ */
+ this.pollUntilConditionIsTrue = function () {
+ if (this.waitForCondition()) {
+ this.waitForCondition = null;
+ this.continueCommandExecutionWithDelay();
+ } else {
+ window.setTimeout("testLoop.pollUntilConditionIsTrue()", 10);
+ }
+ };
+
+
/**
- * Continues the command execution, after waiting for the specified delay.
- */
+ * Continue the command execution, after waiting for the specified
+ * delay.
+ */
this.continueCommandExecutionWithDelay = function() {
// 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.
@@ -108,7 +128,7 @@
if (interval < 0) {
// Enable the "next/continue" button
- this.waitingForNext();
+ this.pause();
}
else {
// Continue processing
@@ -117,8 +137,8 @@
};
/**
- * Finishes the execution of the previous command, and continues the test
- */
+ * Finish the execution of the previous command, and continue the test.
+ */
this.finishCommandExecution = function() {
this.commandComplete(this.lastCommandResult);
this.continueCurrentTest();
@@ -142,15 +162,15 @@
TestLoop.prototype.testComplete = noop;
-TestLoop.prototype.waitingForNext = noop;
+TestLoop.prototype.pause = noop;
function noop() {
};
/**
- * A selenium command that tells selenium to expect a failure on the next command
- * execution. This command temporarily installs a new CommandFactory, that generates
+ * Tell Selenium to expect a failure on the next command execution. This
+ * command temporarily installs a CommandFactory that generates
* CommandHandlers that expect a failure.
*/
Selenium.prototype.assertFailureOnNext = function(message) {
@@ -165,8 +185,8 @@
};
/**
- * A selenium command that tells selenium to expect a failure on the next command
- * execution. This command temporarily installs a new CommandFactory, that generates
+ * Tell Selenium to expect an error on the next command execution. This
+ * command temporarily installs a CommandFactory that generates
* CommandHandlers that expect a failure.
*/
Selenium.prototype.assertErrorOnNext = function(message) {
@@ -193,7 +213,7 @@
result.failureMessage = "Command should have failed.";
}
else {
- if (baseFailureMessage != expectedErrorMessage) {
+ if (! PatternMatcher.matches(expectedErrorMessage, baseFailureMessage)) {
result.failed = true;
result.failureMessage = "Expected failure message '" + expectedErrorMessage
+ "' but was '" + baseFailureMessage + "'";
@@ -216,7 +236,7 @@
return null;
}
return baseResult.failureMessage;
- };
+};
function executeCommandAndReturnErrorMessage(baseHandler, originalArguments) {
try {
@@ -226,5 +246,5 @@
catch (expected) {
return expected.message;
}
- };
+};
=== Products/Zelenium/selenium/selenium-fitrunner.js 1.5 => 1.6 ===
--- Products/Zelenium/selenium/selenium-fitrunner.js:1.5 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/selenium-fitrunner.js Wed Oct 12 06:38:23 2005
@@ -103,8 +103,7 @@
function loadSuiteFrame() {
var testAppFrame = document.getElementById('myiframe');
- browserbot = createBrowserBot(testAppFrame);
- selenium = new Selenium(browserbot);
+ selenium = Selenium.createForFrame(testAppFrame);
registerCommandHandlers();
//set the runInterval if there is a queryParameter for it
@@ -334,10 +333,7 @@
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;
+ selenium.browserbot.setIFrameLocation(testFrame, testLink.href);
}
}
@@ -491,7 +487,7 @@
testLoop.commandComplete = commandComplete;
testLoop.commandError = commandError;
testLoop.testComplete = testComplete;
- testLoop.waitingForNext = function() {
+ testLoop.pause = function() {
document.getElementById('continueTest').disabled = false;
};
return testLoop;
@@ -519,16 +515,11 @@
function scrollIntoView(element) {
if (element.scrollIntoView) {
- element.scrollIntoView();
+ element.scrollIntoView(false);
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();
- element.removeChild(anchor);
+ // TODO: work out how to scroll browsers that don't support
+ // scrollIntoView (like Konqueror)
}
function commandStarted() {
@@ -594,10 +585,13 @@
}
function getCellText(rowNumber, columnNumber) {
- return getText(inputTableRows[rowNumber].cells[columnNumber]);
+ var cell = inputTableRows[rowNumber].cells[columnNumber];
+ if (! cell.cachedText) {
+ cell.cachedText = getText(cell);
+ }
+ return cell.cachedText;
}
Selenium.prototype.doPause = function(waitTime) {
- selenium.callOnNextPageLoad(null);
testLoop.pauseInterval = waitTime;
-};
\ No newline at end of file
+};
=== Products/Zelenium/selenium/selenium-logging.js 1.3 => 1.4 ===
--- Products/Zelenium/selenium/selenium-logging.js:1.3 Tue Jun 7 13:17:46 2005
+++ Products/Zelenium/selenium/selenium-logging.js Wed Oct 12 06:38:23 2005
@@ -14,75 +14,75 @@
* 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();
+var Logger = function() {
+ this.logWindow = null;
}
+Logger.prototype = {
-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);
- }
-};
+ getLogWindow: function() {
+ if (this.logWindow && this.logWindow.closed) {
+ this.logWindow = null;
+ }
+ return this.logWindow;
+ },
+
+ openLogWindow: function() {
+ this.logWindow = window.open(
+ "SeleniumLog.html", "SeleniumLog",
+ "width=600,height=250,bottom=0,right=0,status,scrollbars,resizable"
+ );
+ return this.logWindow;
+ },
+
+ show: function() {
+ if (! this.getLogWindow()) {
+ this.openLogWindow();
+ }
+ },
+
+ log: function(message, className) {
+ var logWindow = this.getLogWindow();
+ if (logWindow) {
+ if (logWindow.append) {
+ logWindow.append(message, className);
+ }
+ }
+ },
-Logger.prototype.debug = function(message) {
- if (this.level <= LEVEL_DEBUG) {
+ debug: function(message) {
this.log(message, "debug");
- }
-};
+ },
-Logger.prototype.info = function(message) {
- if (this.level <= LEVEL_INFO) {
+ info: function(message) {
this.log(message, "info");
- }
-};
+ },
-Logger.prototype.warn = function(message) {
- if (this.level <= LEVEL_WARN) {
+ warn: function(message) {
this.log(message, "warn");
- }
-};
+ },
-Logger.prototype.error = function(message) {
- if (this.level <= LEVEL_ERROR) {
+ error: function(message) {
this.log(message, "error");
- }
-};
+ },
-Logger.prototype.log = function(message, className) {
- var loggingNode = document.createElement('li');
- loggingNode.className = className;
- loggingNode.appendChild(document.createTextNode(message));
+ exception: function(exception) {
+ var msg = "Unexpected Exception: " + describe(exception, ', ');
+ this.error(msg);
+ }
- this.logList.appendChild(loggingNode);
- this.show();
};
+var LOG = new Logger();
+
function noop() {};
-function DummyLogger() {
+var DummyLogger = function() {};
+DummyLogger.prototype = {
+ show: noop,
+ log: noop,
+ debug: noop,
+ info: noop,
+ warn: noop,
+ error: noop
};
-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
=== Products/Zelenium/selenium/selenium.css 1.2 => 1.3 ===
--- Products/Zelenium/selenium/selenium.css:1.2 Mon May 2 23:48:16 2005
+++ Products/Zelenium/selenium/selenium.css Wed Oct 12 06:38:23 2005
@@ -67,28 +67,32 @@
}
#controlPanel {
- padding: 5px;
+ padding: 0.5ex;
background: #eee;
overflow: auto;
+ font-size: 75%;
+ text-align: center;
}
-#controlPanel table {
- font-size: 75%;
+#controlPanel fieldset {
+ margin: 0.3ex;
+ padding: 0.3ex;
}
-#controlPanel th, #controlPanel td {
- border: 0;
+#controlPanel fieldset legend {
+ color: black;
}
-#controls {
- color: inherit;
- width: 100%;
+#controlPanel button {
+ margin: 0.5ex;
}
-#controls td {
- margin: 1px;
- padding: 1px;
- text-align: center;
+#controlPanel table {
+ font-size: 100%;
+}
+
+#controlPanel th, #controlPanel td {
+ border: 0;
}
h1 {
@@ -117,9 +121,7 @@
}
#stats {
- border-top: 1px solid #999;
- border-bottom: 1px solid #999;
- margin-top: 10px;
+ margin: 0.5em auto 0.5em auto;
}
#stats th, #stats td {
@@ -163,25 +165,47 @@
}
/*---( Logging Console )---*/
+
#logging-console {
- background: #FFF;
- padding: 5px;
- border: 1px solid #888;
- font-size: 10px;
+ background: #fff;
+ font-size: 75%;
+}
+
+#logging-console #banner {
+ display: block;
+ width: 100%;
+ position: fixed;
+ top: 0;
+ background: #ddd;
+ border-bottom: 1px solid #666;
}
-#logging-console h1 {
- font-weight: bold;
+#logging-console #logLevelChooser {
+ float: right;
+ margin: 3px;
}
#logging-console ul {
- list-style-type: none;
- margin: 0px;
- padding: 0px;
- clear: both;
+ list-style-type: none;
+ margin: 0px;
+ margin-top: 3em;
+ padding-left: 5px;
}
-#logging-console ul li.error {
- font-weight: bold;
- color: red;
-}
\ No newline at end of file
+#logging-console li {
+ margin: 2px;
+ border-top: 1px solid #ccc;
+}
+
+#logging-console li.error {
+ font-weight: bold;
+ color: red;
+}
+
+#logging-console li.warn {
+ color: red;
+}
+
+#logging-console li.debug {
+ color: green;
+}
=== Products/Zelenium/selenium/version.txt 1.1 => 1.2 ===
--- Products/Zelenium/selenium/version.txt:1.1 Tue Jun 7 13:17:47 2005
+++ Products/Zelenium/selenium/version.txt Wed Oct 12 06:38:23 2005
@@ -1 +1 @@
-0.4.0
\ No newline at end of file
+0.6.0
\ No newline at end of file
More information about the Zope-CVS
mailing list