Author: ajaquith
Date: Tue Feb 12 22:21:32 2008
New Revision: 627268
URL: http://svn.apache.org/viewvc?rev=627268&view=rev
Log:
Initial commit.
Added:
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/htmlutils.js
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/selenium-browserbot.js
Added:
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/htmlutils.js
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/htmlutils.js?rev=627268&view=auto
==============================================================================
---
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/htmlutils.js
(added)
+++
incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/etc/selenium/selenium-core-0.8.3-patches/core/scripts/htmlutils.js
Tue Feb 12 22:21:32 2008
@@ -0,0 +1,902 @@
+/*
+ * Copyright 2004 ThoughtWorks, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// This script contains a badly-organised collection of miscellaneous
+// functions that really better homes.
+
+function classCreate() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+}
+
+function objectExtend(destination, source) {
+ for (var property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+function sel$() {
+ var results = [], element;
+ for (var i = 0; i < arguments.length; i++) {
+ element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ results[results.length] = element;
+ }
+ return results.length < 2 ? results[0] : results;
+}
+
+function sel$A(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+function fnBind() {
+ var args = sel$A(arguments), __method = args.shift(), object = args.shift();
+ var retval = function() {
+ return __method.apply(object, args.concat(sel$A(arguments)));
+ }
+ retval.__method = __method;
+ return retval;
+}
+
+function fnBindAsEventListener(fn, object) {
+ var __method = fn;
+ return function(event) {
+ return __method.call(object, event || window.event);
+ }
+}
+
+function removeClassName(element, name) {
+ var re = new RegExp("\\b" + name + "\\b", "g");
+ element.className = element.className.replace(re, "");
+}
+
+function addClassName(element, name) {
+ element.className = element.className + ' ' + name;
+}
+
+function elementSetStyle(element, style) {
+ for (var name in style) {
+ var value = style[name];
+ if (value == null) value = "";
+ element.style[name] = value;
+ }
+}
+
+function elementGetStyle(element, style) {
+ var value = element.style[style];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+ }
+
+ /** DGF necessary?
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto'; */
+
+ return value == 'auto' ? null : value;
+ }
+
+String.prototype.trim = function() {
+ var result = this.replace(/^\s+/g, "");
+ // strip leading
+ return result.replace(/\s+$/g, "");
+ // strip trailing
+};
+String.prototype.lcfirst = function() {
+ return this.charAt(0).toLowerCase() + this.substr(1);
+};
+String.prototype.ucfirst = function() {
+ return this.charAt(0).toUpperCase() + this.substr(1);
+};
+String.prototype.startsWith = function(str) {
+ return this.indexOf(str) == 0;
+};
+
+// Returns the text in this element
+function getText(element) {
+ var text = "";
+
+ var isRecentFirefox = (browserVersion.isFirefox &&
browserVersion.firefoxVersion >= "1.5");
+ if (isRecentFirefox || browserVersion.isKonqueror ||
browserVersion.isSafari || browserVersion.isOpera) {
+ text = getTextContent(element);
+ } else if (element.textContent) {
+ text = element.textContent;
+ } else if (element.innerText) {
+ text = element.innerText;
+ }
+
+ text = normalizeNewlines(text);
+ text = normalizeSpaces(text);
+
+ return text.trim();
+}
+
+function getTextContent(element, preformatted) {
+ if (element.nodeType == 3 /*Node.TEXT_NODE*/) {
+ var text = element.data;
+ if (!preformatted) {
+ text = text.replace(/\n|\r|\t/g, " ");
+ }
+ return text;
+ }
+ if (element.nodeType == 1 /*Node.ELEMENT_NODE*/) {
+ var childrenPreformatted = preformatted || (element.tagName == "PRE");
+ var text = "";
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var child = element.childNodes.item(i);
+ text += getTextContent(child, childrenPreformatted);
+ }
+ // Handle block elements that introduce newlines
+ // -- From HTML spec:
+ //<!ENTITY % block
+ // "P | %heading; | %list; | %preformatted; | DL | DIV | NOSCRIPT |
+ // BLOCKQUOTE | F:wORM | HR | TABLE | FIELDSET | ADDRESS">
+ //
+ // TODO: should potentially introduce multiple newlines to separate
blocks
+ if (element.tagName == "P" || element.tagName == "BR" ||
element.tagName == "HR" || element.tagName == "DIV") {
+ text += "\n";
+ }
+ return text;
+ }
+ return '';
+}
+
+/**
+ * Convert all newlines to \m
+ */
+function normalizeNewlines(text)
+{
+ return text.replace(/\r\n|\r/g, "\n");
+}
+
+/**
+ * Replace multiple sequential spaces with a single space, and then convert
to space.
+ */
+function normalizeSpaces(text)
+{
+ // IE has already done this conversion, so doing it again will remove
multiple nbsp
+ if (browserVersion.isIE)
+ {
+ return text;
+ }
+
+ // Replace multiple spaces with a single space
+ // TODO - this shouldn't occur inside PRE elements
+ text = text.replace(/\ +/g, " ");
+
+ // Replace with a space
+ var nbspPattern = new RegExp(String.fromCharCode(160), "g");
+ if (browserVersion.isSafari) {
+ return replaceAll(text, String.fromCharCode(160), " ");
+ } else {
+ return text.replace(nbspPattern, " ");
+ }
+}
+
+function replaceAll(text, oldText, newText) {
+ while (text.indexOf(oldText) != -1) {
+ text = text.replace(oldText, newText);
+ }
+ return text;
+}
+
+
+function xmlDecode(text) {
+ text = text.replace(/"/g, '"');
+ text = text.replace(/'/g, "'");
+ text = text.replace(/</g, "<");
+ text = text.replace(/>/g, ">");
+ text = text.replace(/&/g, "&");
+ return text;
+}
+
+// Sets the text in this element
+function setText(element, text) {
+ if (element.textContent != null) {
+ element.textContent = text;
+ } else if (element.innerText != null) {
+ element.innerText = text;
+ }
+}
+
+// Get the value of an <input> element
+function getInputValue(inputElement) {
+ if (inputElement.type) {
+ if (inputElement.type.toUpperCase() == 'CHECKBOX' ||
+ inputElement.type.toUpperCase() == 'RADIO')
+ {
+ return (inputElement.checked ? 'on' : 'off');
+ }
+ }
+ if (inputElement.value == null) {
+ throw new SeleniumError("This element has no value; is it really a
form field?");
+ }
+ return inputElement.value;
+}
+
+/* Fire an event in a browser-compatible manner */
+function triggerEvent(element, eventType, canBubble, controlKeyDown,
altKeyDown, shiftKeyDown, metaKeyDown) {
+ canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+
+ //if (element.fireEvent) {
+ /* support for mootools patch Dirk Frederickx Dec 07*/
+ /* see http://forum.mootools.net/viewtopic.php?id=1639 */
+ if (element.ownerDocument.createEventObject) {
+ var evt = createEventObject(element, controlKeyDown, altKeyDown,
shiftKeyDown, metaKeyDown);
+ element.fireEvent('on' + eventType, evt);
+ }
+ else {
+ var evt = document.createEvent('HTMLEvents');
+
+ try {
+ evt.shiftKey = shiftKeyDown;
+ evt.metaKey = metaKeyDown;
+ evt.altKey = altKeyDown;
+ evt.ctrlKey = controlKeyDown;
+ } catch (e) {
+ // On Firefox 1.0, you can only set these during initMouseEvent or
initKeyEvent
+ // we'll have to ignore them here
+ LOG.exception(e);
+ }
+
+ evt.initEvent(eventType, canBubble, true);
+ element.dispatchEvent(evt);
+ }
+}
+
+function getKeyCodeFromKeySequence(keySequence) {
+ var match = /^\\(\d{1,3})$/.exec(keySequence);
+ if (match != null) {
+ return match[1];
+ }
+ match = /^.$/.exec(keySequence);
+ if (match != null) {
+ return match[0].charCodeAt(0);
+ }
+ // this is for backward compatibility with existing tests
+ // 1 digit ascii codes will break however because they are used for the
digit chars
+ match = /^\d{2,3}$/.exec(keySequence);
+ if (match != null) {
+ return match[0];
+ }
+ throw new SeleniumError("invalid keySequence");
+}
+
+function createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown,
metaKeyDown) {
+ var evt = element.ownerDocument.createEventObject();
+ evt.shiftKey = shiftKeyDown;
+ evt.metaKey = metaKeyDown;
+ evt.altKey = altKeyDown;
+ evt.ctrlKey = controlKeyDown;
+ return evt;
+}
+
+function triggerKeyEvent(element, eventType, keySequence, canBubble,
controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) {
+ var keycode = getKeyCodeFromKeySequence(keySequence);
+ canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
+
+ //if (element.fireEvent) {
+ /* support for mootools patch Dirk Frederickx Dec 07*/
+ /* see http://forum.mootools.net/viewtopic.php?id=1639 */
+ if (element.ownerDocument.createEventObject) {
+ var keyEvent = createEventObject(element, controlKeyDown, altKeyDown,
shiftKeyDown, metaKeyDown);
+ keyEvent.keyCode = keycode;
+ element.fireEvent('on' + eventType, keyEvent);
+ }
+ else {
+ var evt;
+ if (window.KeyEvent) {
+ evt = document.createEvent('KeyEvents');
+ evt.initKeyEvent(eventType, true, true, window, controlKeyDown,
altKeyDown, shiftKeyDown, metaKeyDown, keycode, keycode);
+ } else {
+ evt = document.createEvent('UIEvents');
+
+ evt.shiftKey = shiftKeyDown;
+ evt.metaKey = metaKeyDown;
+ evt.altKey = altKeyDown;
+ evt.ctrlKey = controlKeyDown;
+
+ evt.initUIEvent(eventType, true, true, window, 1);
+ evt.keyCode = keycode;
+ evt.which = keycode;
+ }
+
+ element.dispatchEvent(evt);
+ }
+}
+
+function removeLoadListener(element, command) {
+ LOG.debug('Removing loadListenter for ' + element + ', ' + command);
+ if (window.removeEventListener)
+ element.removeEventListener("load", command, true);
+ else if (window.detachEvent)
+ element.detachEvent("onload", command);
+}
+
+function addLoadListener(element, command) {
+ LOG.debug('Adding loadListenter for ' + element + ', ' + command);
+ var augmentedCommand = function() {
+ command.call(this, element);
+ }
+ if (window.addEventListener && !browserVersion.isOpera)
+ element.addEventListener("load", augmentedCommand, true);
+ else if (window.attachEvent)
+ element.attachEvent("onload", augmentedCommand);
+}
+
+/**
+ * Override the broken getFunctionName() method from JsUnit
+ * This file must be loaded _after_ the jsunitCore.js
+ */
+function getFunctionName(aFunction) {
+ var regexpResult = aFunction.toString().match(/function (\w*)/);
+ if (regexpResult && regexpResult[1]) {
+ return regexpResult[1];
+ }
+ return 'anonymous';
+}
+
+function getDocumentBase(doc) {
+ var bases = document.getElementsByTagName("base");
+ if (bases && bases.length && bases[0].href) {
+ return bases[0].href;
+ }
+ return "";
+}
+
+function getTagName(element) {
+ var tagName;
+ if (element && element.tagName && element.tagName.toLowerCase) {
+ tagName = element.tagName.toLowerCase();
+ }
+ return tagName;
+}
+
+function selArrayToString(a) {
+ if (isArray(a)) {
+ // DGF copying the array, because the array-like object may be a
non-modifiable nodelist
+ var retval = [];
+ for (var i = 0; i < a.length; i++) {
+ var item = a[i];
+ var replaced = new String(item).replace(/([,\\])/g, '\\$1');
+ retval[i] = replaced;
+ }
+ return retval;
+ }
+ return new String(a);
+}
+
+
+function isArray(x) {
+ return ((typeof x) == "object") && (x["length"] != null);
+}
+
+function absolutify(url, baseUrl) {
+ /** returns a relative url in its absolute form, given by baseUrl.
+ *
+ * This function is a little odd, because it can take baseUrls that
+ * aren't necessarily directories. It uses the same rules as the HTML
+ * <base> tag; if the baseUrl doesn't end with "/", we'll assume
+ * that it points to a file, and strip the filename off to find its
+ * base directory.
+ *
+ * So absolutify("foo", "http://x/bar") will return "http://x/foo"
(stripping off bar),
+ * whereas absolutify("foo", "http://x/bar/") will return
"http://x/bar/foo" (preserving bar).
+ * Naturally absolutify("foo", "http://x") will return "http://x/foo",
appropriately.
+ *
+ * @param url the url to make absolute; if this url is already absolute,
we'll just return that, unchanged
+ * @param baseUrl the baseUrl from which we'll absolutify, following the
rules above.
+ * @return 'url' if it was already absolute, or the absolutized version of
url if it was not absolute.
+ */
+
+ // DGF isn't there some library we could use for this?
+
+ if (/^\w+:/.test(url)) {
+ // it's already absolute
+ return url;
+ }
+
+ var loc;
+ try {
+ loc = parseUrl(baseUrl);
+ } catch (e) {
+ // is it an absolute windows file path? let's play the hero in that
case
+ if (/^\w:\\/.test(baseUrl)) {
+ baseUrl = "file:///" + baseUrl.replace(/\\/g, "/");
+ loc = parseUrl(baseUrl);
+ } else {
+ throw new SeleniumError("baseUrl wasn't absolute: " + baseUrl);
+ }
+ }
+ loc.search = null;
+ loc.hash = null;
+
+ // if url begins with /, then that's the whole pathname
+ if (/^\//.test(url)) {
+ loc.pathname = url;
+ var result = reassembleLocation(loc);
+ return result;
+ }
+
+ // if pathname is null, then we'll just append "/" + the url
+ if (!loc.pathname) {
+ loc.pathname = "/" + url;
+ var result = reassembleLocation(loc);
+ return result;
+ }
+
+ // if pathname ends with /, just append url
+ if (/\/$/.test(loc.pathname)) {
+ loc.pathname += url;
+ var result = reassembleLocation(loc);
+ return result;
+ }
+
+ // if we're here, then the baseUrl has a pathname, but it doesn't end with
/
+ // in that case, we replace everything after the final / with the relative
url
+ loc.pathname = loc.pathname.replace(/[^\/\\]+$/, url);
+ var result = reassembleLocation(loc);
+ return result;
+
+}
+
+var URL_REGEX = /^((\w+):\/\/)(([^:]+):?([EMAIL
PROTECTED])?@)?([^\/\?:]*):?(\d+)?(\/?[^\?#]+)?\??([^#]+)?#?(.+)?/;
+
+function parseUrl(url) {
+ var fields = ['url', null, 'protocol', null, 'username', 'password',
'host', 'port', 'pathname', 'search', 'hash'];
+ var result = URL_REGEX.exec(url);
+ if (!result) {
+ throw new SeleniumError("Invalid URL: " + url);
+ }
+ var loc = new Object();
+ for (var i = 0; i < fields.length; i++) {
+ var field = fields[i];
+ if (field == null) {
+ continue;
+ }
+ loc[field] = result[i];
+ }
+ return loc;
+}
+
+function reassembleLocation(loc) {
+ if (!loc.protocol) {
+ throw new Error("Not a valid location object: " + o2s(loc));
+ }
+ var protocol = loc.protocol;
+ protocol = protocol.replace(/:$/, "");
+ var url = protocol + "://";
+ if (loc.username) {
+ url += loc.username;
+ if (loc.password) {
+ url += ":" + loc.password;
+ }
+ url += "@";
+ }
+ if (loc.host) {
+ url += loc.host;
+ }
+
+ if (loc.port) {
+ url += ":" + loc.port;
+ }
+
+ if (loc.pathname) {
+ url += loc.pathname;
+ }
+
+ if (loc.search) {
+ url += "?" + loc.search;
+ }
+ if (loc.hash) {
+ var hash = loc.hash;
+ hash = loc.hash.replace(/^#/, "");
+ url += "#" + hash;
+ }
+ return url;
+}
+
+function canonicalize(url) {
+ var tempLink = window.document.createElement("link");
+ tempLink.href = url; // this will canonicalize the href on most browsers
+ var loc = parseUrl(tempLink.href)
+ if (!/\/\.\.\//.test(loc.pathname)) {
+ return tempLink.href;
+ }
+ // didn't work... let's try it the hard way
+ var originalParts = loc.pathname.split("/");
+ var newParts = [];
+ newParts.push(originalParts.shift());
+ for (var i = 0; i < originalParts.length; i++) {
+ var part = originalParts[i];
+ if (".." == part) {
+ newParts.pop();
+ continue;
+ }
+ newParts.push(part);
+ }
+ loc.pathname = newParts.join("/");
+ return reassembleLocation(loc);
+}
+
+function extractExceptionMessage(ex) {
+ if (ex == null) return "null exception";
+ if (ex.message != null) return ex.message;
+ if (ex.toString && ex.toString() != null) return ex.toString();
+}
+
+
+function describe(object, delimiter) {
+ var props = new Array();
+ for (var prop in object) {
+ try {
+ props.push(prop + " -> " + object[prop]);
+ } catch (e) {
+ props.push(prop + " -> [htmlutils: ack! couldn't read this
property! (Permission Denied?)]");
+ }
+ }
+ return props.join(delimiter || '\n');
+}
+
+var PatternMatcher = function(pattern) {
+ this.selectStrategy(pattern);
+};
+PatternMatcher.prototype = {
+
+ selectStrategy: function(pattern) {
+ this.pattern = pattern;
+ var strategyName = 'glob';
+ // by default
+ if (/^([a-z-]+):(.*)/.test(pattern)) {
+ var possibleNewStrategyName = RegExp.$1;
+ var possibleNewPattern = RegExp.$2;
+ if (PatternMatcher.strategies[possibleNewStrategyName]) {
+ strategyName = possibleNewStrategyName;
+ pattern = possibleNewPattern;
+ }
+ }
+ var matchStrategy = PatternMatcher.strategies[strategyName];
+ if (!matchStrategy) {
+ throw new SeleniumError("cannot find PatternMatcher.strategies." +
strategyName);
+ }
+ this.strategy = matchStrategy;
+ 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);
+ };
+ },
+
+ regex: function(regexpString) {
+ this.regexp = new RegExp(regexpString);
+ this.matches = function(actual) {
+ return this.regexp.test(actual);
+ };
+ },
+
+/**
+ * "globContains" (aka "wildmat") patterns, e.g. "glob:one,two,*",
+ * but don't require a perfect match; instead succeed if actual
+ * contains something that matches globString.
+ * Making this distinction is motivated by a bug in IE6 which
+ * leads to the browser hanging if we implement *TextPresent tests
+ * by just matching against a regular expression beginning and
+ * ending with ".*". The globcontains strategy allows us to satisfy
+ * the functional needs of the *TextPresent ops more efficiently
+ * and so avoid running into this IE6 freeze.
+ */
+ globContains: function(globString) {
+ this.regexp = new
RegExp(PatternMatcher.regexpFromGlobContains(globString));
+ 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.convertGlobMetaCharsToRegexpMetaChars = function(glob) {
+ var re = glob;
+ re = re.replace(/([.^$+(){}\[\]\\|])/g, "\\$1");
+ re = re.replace(/\?/g, "(.|[\r\n])");
+ re = re.replace(/\*/g, "(.|[\r\n])*");
+ return re;
+};
+
+PatternMatcher.regexpFromGlobContains = function(globContains) {
+ return PatternMatcher.convertGlobMetaCharsToRegexpMetaChars(globContains);
+};
+
+PatternMatcher.regexpFromGlob = function(glob) {
+ return "^" + PatternMatcher.convertGlobMetaCharsToRegexpMetaChars(glob) +
"$";
+};
+
+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.isSeleniumError = true;
+ this.message = message;
+ this.failureMessage = message;
+}
+
+function SeleniumError(message) {
+ var error = new Error(message);
+ if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
+ var result = '';
+ for (var a = arguments.caller; a != null; a = a.caller) {
+ result += '> ' + a.callee.toString() + '\n';
+ if (a.caller == a) {
+ result += '*';
+ break;
+ }
+ }
+ error.stack = result;
+ }
+ error.isSeleniumError = true;
+ return error;
+}
+
+function highlight(element) {
+ var highLightColor = "yellow";
+ if (element.originalColor == undefined) { // avoid picking up highlight
+ element.originalColor = elementGetStyle(element, "background-color");
+ }
+ elementSetStyle(element, {"backgroundColor" : highLightColor});
+ window.setTimeout(function() {
+ try {
+ //if element is orphan, probably page of it has already gone, so
ignore
+ if (!element.parentNode) {
+ return;
+ }
+ elementSetStyle(element, {"backgroundColor" :
element.originalColor});
+ } catch (e) {} // DGF unhighlighting is very dangerous and low priority
+ }, 200);
+}
+
+
+
+// for use from vs.2003 debugger
+function o2s(obj) {
+ var s = "";
+ for (key in obj) {
+ var line = key + "->" + obj[key];
+ line.replace("\n", " ");
+ s += line + "\n";
+ }
+ return s;
+}
+
+var seenReadyStateWarning = false;
+
+function openSeparateApplicationWindow(url, suppressMozillaWarning) {
+ // resize the Selenium window itself
+ window.resizeTo(1200, 500);
+ window.moveTo(window.screenX, 0);
+
+ var appWindow = window.open(url + '?start=true', 'main');
+ if (appWindow == null) {
+ var errorMessage = "Couldn't open app window; is the pop-up blocker
enabled?"
+ LOG.error(errorMessage);
+ throw new Error("Couldn't open app window; is the pop-up blocker
enabled?");
+ }
+ try {
+ var windowHeight = 500;
+ if (window.outerHeight) {
+ windowHeight = window.outerHeight;
+ } else if (document.documentElement &&
document.documentElement.offsetHeight) {
+ windowHeight = document.documentElement.offsetHeight;
+ }
+
+ if (window.screenLeft && !window.screenX) window.screenX =
window.screenLeft;
+ if (window.screenTop && !window.screenY) window.screenY =
window.screenTop;
+
+ appWindow.resizeTo(1200, screen.availHeight - windowHeight - 60);
+ appWindow.moveTo(window.screenX, window.screenY + windowHeight + 25);
+ } catch (e) {
+ LOG.error("Couldn't resize app window");
+ LOG.exception(e);
+ }
+
+
+ if (!suppressMozillaWarning && window.document.readyState == null &&
!seenReadyStateWarning) {
+ alert("Beware! Mozilla bug 300992 means that we can't always reliably
detect when a new page has loaded. Install the Selenium IDE extension or the
readyState extension available from selenium.openqa.org to make page load
detection more reliable.");
+ seenReadyStateWarning = true;
+ }
+
+ return appWindow;
+}
+
+var URLConfiguration = classCreate();
+objectExtend(URLConfiguration.prototype, {
+ initialize: function() {
+ },
+ _isQueryParameterTrue: function (name) {
+ var parameterValue = this._getQueryParameter(name);
+ if (parameterValue == null) return false;
+ if (parameterValue.toLowerCase() == "true") return true;
+ if (parameterValue.toLowerCase() == "on") return true;
+ return false;
+ },
+
+ _getQueryParameter: function(searchKey) {
+ var str = this.queryString
+ if (str == null) return null;
+ var clauses = str.split('&');
+ for (var i = 0; i < clauses.length; i++) {
+ var keyValuePair = clauses[i].split('=', 2);
+ var key = unescape(keyValuePair[0]);
+ if (key == searchKey) {
+ return unescape(keyValuePair[1]);
+ }
+ }
+ return null;
+ },
+
+ _extractArgs: function() {
+ var str = SeleniumHTARunner.commandLine;
+ if (str == null || str == "") return new Array();
+ var matches = str.match(/(?:\"([^\"]+)\"|(?!\"([^\"]+)\")(\S+))/g);
+ // We either want non quote stuff ([^"]+) surrounded by quotes
+ // or we want to look-ahead, see that the next character isn't
+ // a quoted argument, and then grab all the non-space stuff
+ // this will return for the line: "foo" bar
+ // the results "\"foo\"" and "bar"
+
+ // So, let's unquote the quoted arguments:
+ var args = new Array;
+ for (var i = 0; i < matches.length; i++) {
+ args[i] = matches[i];
+ args[i] = args[i].replace(/^"(.*)"$/, "$1");
+ }
+ return args;
+ },
+
+ isMultiWindowMode:function() {
+ return this._isQueryParameterTrue('multiWindow');
+ },
+
+ getBaseUrl:function() {
+ return this._getQueryParameter('baseUrl');
+
+ }
+});
+
+
+function safeScrollIntoView(element) {
+ if (element.scrollIntoView) {
+ element.scrollIntoView(false);
+ return;
+ }
+ // TODO: work out how to scroll browsers that don't support
+ // scrollIntoView (like Konqueror)
+}