selenium-webdriver
Advanced tools
Comparing version 2.33.0 to 2.34.0
@@ -38,3 +38,3 @@ // Copyright 2012 Selenium committers | ||
* If this script was loaded from the Selenium project repo, it will operate in | ||
* development, adjusting how it loads Closure-based dependencies. | ||
* development mode, adjusting how it loads Closure-based dependencies. | ||
* @type {boolean} | ||
@@ -99,3 +99,3 @@ */ | ||
return closure.goog.getObjectByName(symbol); | ||
}; | ||
} | ||
@@ -102,0 +102,0 @@ |
@@ -16,32 +16,38 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
var base = require('./_base'), | ||
HttpClient = require('./http').HttpClient; | ||
executors = require('./executors'); | ||
var goog = base.require('goog'), | ||
AbstractBuilder = base.require('webdriver.AbstractBuilder'), | ||
Browser = base.require('webdriver.Browser'), | ||
Capability = base.require('webdriver.Capability'), | ||
WebDriver = base.require('webdriver.WebDriver'), | ||
HttpExecutor = base.require('webdriver.http.Executor'), | ||
promise = base.require('webdriver.promise'); | ||
/** | ||
* Wraps a promised {@link webdriver.CommandExecutor}, ensuring no commands | ||
* are executed until the wrapped executor has been fully built. | ||
* @param {!webdriver.promise.Promise.<!webdriver.CommandExecutor>} delegate The | ||
* promised delegate. | ||
* @constructor | ||
* @implements {webdriver.CommandExecutor} | ||
* @param {!webdriver.Capabilities} capabilities The desired capabilities. | ||
* @return {webdriver.WebDriver} A new WebDriver instance or {@code null} | ||
* if the requested browser is not natively supported in Node. | ||
*/ | ||
var DeferredExecutor = function(delegate) { | ||
function createNativeDriver(capabilities) { | ||
switch (capabilities.get(Capability.BROWSER_NAME)) { | ||
case Browser.CHROME: | ||
// Requiring 'chrome' above would create a cycle: | ||
// index -> builder -> chrome -> index | ||
var chrome = require('./chrome'); | ||
return chrome.createDriver(capabilities); | ||
/** @override */ | ||
this.execute = function(command, callback) { | ||
delegate.then(function(executor) { | ||
executor.execute(command, callback); | ||
}, callback); | ||
}; | ||
}; | ||
case Browser.PHANTOM_JS: | ||
// Requiring 'phantomjs' would create a cycle: | ||
// index -> builder -> phantomjs -> index | ||
var phantomjs = require('./phantomjs'); | ||
return phantomjs.createDriver(capabilities); | ||
default: | ||
return null; | ||
} | ||
} | ||
/** | ||
@@ -57,18 +63,46 @@ * @constructor | ||
/** | ||
* Sets the proxy configuration to use for WebDriver clients created by this | ||
* builder. Any calls to {@link #withCapabilities} after this function will | ||
* overwrite these settings. | ||
* @param {!ProxyConfig} config The configuration to use. | ||
* @return {!Builder} A self reference. | ||
*/ | ||
Builder.prototype.setProxy = function(config) { | ||
this.getCapabilities().set(Capability.PROXY, config); | ||
return this; | ||
}; | ||
/** | ||
* Sets Chrome-specific options for drivers created by this builder. | ||
* @param {!chrome.Options} options The ChromeDriver options to use. | ||
* @return {!Builder} A self reference. | ||
*/ | ||
Builder.prototype.setChromeOptions = function(options) { | ||
var newCapabilities = options.toCapabilities(this.getCapabilities()); | ||
return /** @type {!Builder} */(this.withCapabilities(newCapabilities)); | ||
}; | ||
/** | ||
* @override | ||
*/ | ||
Builder.prototype.build = function() { | ||
var serverUrl = this.getServerUrl(); | ||
var executor = new DeferredExecutor(promise.when(serverUrl, function(url) { | ||
var client = new HttpClient(url); | ||
return new HttpExecutor(client); | ||
})); | ||
var url = this.getServerUrl(); | ||
if (this.getSession()) { | ||
return WebDriver.attachToSession(executor, this.getSession()); | ||
} else { | ||
return WebDriver.createSession(executor, this.getCapabilities()); | ||
// If a remote server wasn't specified, check for browsers we support | ||
// natively in node before falling back to using the java Selenium server. | ||
if (!url) { | ||
var driver = createNativeDriver(this.getCapabilities()); | ||
if (driver) { | ||
return driver; | ||
} | ||
// Nope, fall-back to using the default java server. | ||
url = AbstractBuilder.DEFAULT_SERVER_URL; | ||
} | ||
var executor = executors.createExecutor(url); | ||
return WebDriver.createSession(executor, this.getCapabilities()); | ||
}; | ||
@@ -75,0 +109,0 @@ |
@@ -0,1 +1,35 @@ | ||
## v2.34.0 | ||
* Added the `selenium-webdriver/testing/assert` module. This module | ||
simplifies writing assertions against promised values (see | ||
example in module documentation). | ||
* Added the `webdriver.Capabilities` class. | ||
* Added native support for the ChromeDriver. When using the `Builder`, | ||
requesting chrome without specifying a remote server URL will default to | ||
the native ChromeDriver implementation. The | ||
[ChromeDriver server](https://code.google.com/p/chromedriver/downloads/list) | ||
must be downloaded separately. | ||
// Will start ChromeDriver locally. | ||
var driver = new webdriver.Builder(). | ||
withCapabilities(webdriver.Capabilities.chrome()). | ||
build(); | ||
// Will start ChromeDriver using the remote server. | ||
var driver = new webdriver.Builder(). | ||
withCapabilities(webdriver.Capabilities.chrome()). | ||
usingServer('http://server:1234/wd/hub'). | ||
build(); | ||
* Added support for configuring proxies through the builder. For examples, see | ||
`selenium-webdriver/test/proxy_test`. | ||
* Added native support for PhantomJS. | ||
* Changed signature of `SeleniumServer` to `SeleniumServer(jar, options)`. | ||
* Tests are now included in the npm published package. See `README.md` for | ||
execution instructions | ||
* Removed the deprecated `webdriver.Deferred#resolve` and | ||
`webdriver.promise.resolved` functions. | ||
* Removed the ability to connect to an existing session from the Builder. This | ||
feature is intended for use with the browser-based client. | ||
## v2.33.0 | ||
@@ -2,0 +36,0 @@ |
19
index.js
@@ -27,4 +27,4 @@ // Copyright 2012 Selenium committers | ||
exports.By = base.require('webdriver.Locator.Strategy'); | ||
exports.Capabilities = base.require('webdriver.Capabilities'); | ||
exports.Command = base.require('webdriver.Command'); | ||
exports.CommandName = base.require('webdriver.CommandName'); | ||
exports.EventEmitter = base.require('webdriver.EventEmitter'); | ||
@@ -35,8 +35,7 @@ exports.Session = base.require('webdriver.Session'); | ||
exports.__defineGetter__('Key', function() { | ||
return base.require('webdriver.Key'); | ||
}); | ||
var submodules = { | ||
var closureModules = { | ||
Browser: base.require('webdriver.Browser'), | ||
Capability: base.require('webdriver.Capability'), | ||
CommandName: base.require('webdriver.CommandName'), | ||
Key: base.require('webdriver.Key'), | ||
command: { | ||
@@ -53,3 +52,2 @@ Command: base.require('webdriver.Command'), | ||
}, | ||
http: require('./http'), | ||
logging: base.exportPublicApi('webdriver.logging'), | ||
@@ -61,7 +59,6 @@ promise: base.exportPublicApi('webdriver.promise'), | ||
Object.keys(submodules).forEach(function(key) { | ||
Object.keys(closureModules).forEach(function(key) { | ||
exports.__defineGetter__(key, function() { | ||
return submodules[key]; | ||
return closureModules[key]; | ||
}); | ||
}); | ||
@@ -98,2 +98,3 @@ // Copyright 2010 WebDriver committers | ||
}); | ||
var l = name.length - 'Error'.length; | ||
@@ -100,0 +101,0 @@ if (l < 0 || name.indexOf('Error', l) != l) { |
@@ -30,3 +30,3 @@ // Copyright 2012 WebDriver committers | ||
* @define {boolean} NATIVE_JSON indicates whether the code should rely on the | ||
* native {@ocde JSON} functions, if available. | ||
* native {@code JSON} functions, if available. | ||
* | ||
@@ -33,0 +33,0 @@ * <p>The JSON functions can be defined by external libraries like Prototype |
@@ -51,3 +51,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
if (bot.response.isResponseObject(value)) { | ||
return (/** @type {!bot.response.ResponseObject} */value); | ||
return /** @type {!bot.response.ResponseObject} */ (value); | ||
} | ||
@@ -69,3 +69,3 @@ return { | ||
if (bot.response.isResponseObject(error)) { | ||
return (/** @type {!bot.response.ResponseObject} */error); | ||
return /** @type {!bot.response.ResponseObject} */ (error); | ||
} | ||
@@ -76,3 +76,3 @@ | ||
return { | ||
'status': (/** @type {bot.ErrorCode} */statusCode), | ||
'status': /** @type {bot.ErrorCode} */ (statusCode), | ||
'value': { | ||
@@ -79,0 +79,0 @@ 'message': (error && error.message || error) + '' |
@@ -49,3 +49,3 @@ // Copyright 2011 WebDriver committers | ||
} else { | ||
return goog.userAgent.isVersion(version); | ||
return goog.userAgent.isVersionOrHigher(version); | ||
} | ||
@@ -85,3 +85,2 @@ }; | ||
* than the given version. When we are not in a Firefox extension, this is null. | ||
* | ||
* @private {(undefined|function((string|number)): boolean)} | ||
@@ -96,3 +95,2 @@ */ | ||
* than the given version. When we are not in a Firefox extension, this is null. | ||
* | ||
* @private {(undefined|function((string|number)): boolean)} | ||
@@ -170,5 +168,4 @@ */ | ||
* Android Operating System Version. | ||
* | ||
* @private {string} | ||
* @const | ||
* @private {string} | ||
*/ | ||
@@ -192,3 +189,3 @@ bot.userAgent.ANDROID_VERSION_ = (function() { | ||
bot.userAgent.IE_DOC_PRE8 = goog.userAgent.IE && | ||
!goog.userAgent.isDocumentMode(8); | ||
!goog.userAgent.isDocumentModeOrHigher(8); | ||
@@ -201,3 +198,3 @@ | ||
*/ | ||
bot.userAgent.IE_DOC_9 = goog.userAgent.isDocumentMode(9); | ||
bot.userAgent.IE_DOC_9 = goog.userAgent.isDocumentModeOrHigher(9); | ||
@@ -211,3 +208,3 @@ | ||
bot.userAgent.IE_DOC_PRE9 = goog.userAgent.IE && | ||
!goog.userAgent.isDocumentMode(9); | ||
!goog.userAgent.isDocumentModeOrHigher(9); | ||
@@ -220,3 +217,3 @@ | ||
*/ | ||
bot.userAgent.IE_DOC_10 = goog.userAgent.isDocumentMode(10); | ||
bot.userAgent.IE_DOC_10 = goog.userAgent.isDocumentModeOrHigher(10); | ||
@@ -230,3 +227,3 @@ | ||
bot.userAgent.IE_DOC_PRE10 = goog.userAgent.IE && | ||
!goog.userAgent.isDocumentMode(10); | ||
!goog.userAgent.isDocumentModeOrHigher(10); | ||
@@ -233,0 +230,0 @@ |
// This file has been auto-generated; do not edit by hand | ||
goog.addDependency("../atoms/error.js", ["bot.Error","bot.ErrorCode"], []); | ||
goog.addDependency("../atoms/response.js", ["bot.response","bot.response.ResponseObject"], ["bot.Error","bot.ErrorCode"]); | ||
goog.addDependency("../atoms/json.js", ["bot.json"], ["bot.userAgent","goog.json","goog.userAgent"]); | ||
goog.addDependency("../atoms/userAgent.js", ["bot.userAgent"], ["goog.string","goog.userAgent","goog.userAgent.product","goog.userAgent.product.isVersion"]); | ||
@@ -9,31 +11,39 @@ goog.addDependency("string/string.js", ["goog.string","goog.string.Unicode"], []); | ||
goog.addDependency("json/json.js", ["goog.json","goog.json.Serializer"], []); | ||
goog.addDependency("../webdriver/process.js", ["webdriver.process"], ["goog.Uri","goog.array","goog.json"]); | ||
goog.addDependency("uri/uri.js", ["goog.Uri","goog.Uri.QueryData"], ["goog.array","goog.string","goog.structs","goog.structs.Map","goog.uri.utils","goog.uri.utils.ComponentIndex"]); | ||
goog.addDependency("../webdriver/capabilities.js", ["webdriver.Browser","webdriver.Capability","webdriver.Capabilities"], []); | ||
goog.addDependency("../webdriver/logging.js", ["webdriver.logging"], ["goog.object"]); | ||
goog.addDependency("object/object.js", ["goog.object"], []); | ||
goog.addDependency("../webdriver/actionsequence.js", ["webdriver.ActionSequence"], ["goog.array","webdriver.Button","webdriver.Command","webdriver.CommandName","webdriver.Key"]); | ||
goog.addDependency("array/array.js", ["goog.array","goog.array.ArrayLike"], ["goog.asserts"]); | ||
goog.addDependency("asserts/asserts.js", ["goog.asserts","goog.asserts.AssertionError"], ["goog.debug.Error","goog.string"]); | ||
goog.addDependency("debug/error.js", ["goog.debug.Error"], []); | ||
goog.addDependency("structs/structs.js", ["goog.structs"], ["goog.array","goog.object"]); | ||
goog.addDependency("object/object.js", ["goog.object"], []); | ||
goog.addDependency("structs/map.js", ["goog.structs.Map"], ["goog.iter.Iterator","goog.iter.StopIteration","goog.object","goog.structs"]); | ||
goog.addDependency("iter/iter.js", ["goog.iter","goog.iter.Iterator","goog.iter.StopIteration"], ["goog.array","goog.asserts"]); | ||
goog.addDependency("uri/utils.js", ["goog.uri.utils","goog.uri.utils.ComponentIndex","goog.uri.utils.QueryArray","goog.uri.utils.QueryValue","goog.uri.utils.StandardQueryParam"], ["goog.asserts","goog.string","goog.userAgent"]); | ||
goog.addDependency("../webdriver/button.js", ["webdriver.Button"], []); | ||
goog.addDependency("../webdriver/command.js", ["webdriver.Command","webdriver.CommandExecutor","webdriver.CommandName"], []); | ||
goog.addDependency("../webdriver/key.js", ["webdriver.Key"], []); | ||
goog.addDependency("../webdriver/abstractbuilder.js", ["webdriver.AbstractBuilder"], ["webdriver.process"]); | ||
goog.addDependency("../webdriver/firefoxdomexecutor.js", ["webdriver.FirefoxDomExecutor"], ["bot.response","goog.json","goog.userAgent.product","webdriver.Command","webdriver.CommandName"]); | ||
goog.addDependency("../atoms/response.js", ["bot.response","bot.response.ResponseObject"], ["bot.Error","bot.ErrorCode"]); | ||
goog.addDependency("../webdriver/webdriver.js", ["webdriver.Alert","webdriver.UnhandledAlertError","webdriver.WebDriver","webdriver.WebElement"], ["bot.Error","bot.ErrorCode","bot.response","goog.array","goog.object","webdriver.ActionSequence","webdriver.Command","webdriver.CommandName","webdriver.Key","webdriver.Locator","webdriver.Session","webdriver.logging","webdriver.promise"]); | ||
goog.addDependency("../webdriver/actionsequence.js", ["webdriver.ActionSequence"], ["goog.array","webdriver.Button","webdriver.Command","webdriver.CommandName","webdriver.Key"]); | ||
goog.addDependency("../webdriver/stacktrace.js", ["webdriver.stacktrace","webdriver.stacktrace.Snapshot"], ["goog.array","goog.string","goog.userAgent"]); | ||
goog.addDependency("../webdriver/locators.js", ["webdriver.Locator","webdriver.Locator.Strategy"], ["bot.json","goog.object"]); | ||
goog.addDependency("../atoms/json.js", ["bot.json"], ["bot.userAgent","goog.json","goog.userAgent"]); | ||
goog.addDependency("../webdriver/session.js", ["webdriver.Session"], []); | ||
goog.addDependency("../webdriver/logging.js", ["webdriver.logging"], ["goog.object"]); | ||
goog.addDependency("../webdriver/promise.js", ["webdriver.promise","webdriver.promise.ControlFlow","webdriver.promise.Deferred","webdriver.promise.Promise"], ["goog.array","goog.object","webdriver.EventEmitter","webdriver.stacktrace.Snapshot"]); | ||
goog.addDependency("../webdriver/promise.js", ["webdriver.promise","webdriver.promise.ControlFlow","webdriver.promise.ControlFlow.Timer","webdriver.promise.Deferred","webdriver.promise.Promise"], ["goog.array","goog.debug.Error","goog.object","webdriver.EventEmitter","webdriver.stacktrace.Snapshot"]); | ||
goog.addDependency("../webdriver/events.js", ["webdriver.EventEmitter"], []); | ||
goog.addDependency("../webdriver/stacktrace.js", ["webdriver.stacktrace","webdriver.stacktrace.Snapshot"], ["goog.array","goog.string"]); | ||
goog.addDependency("../webdriver/process.js", ["webdriver.process"], ["goog.Uri","goog.array","goog.json"]); | ||
goog.addDependency("uri/uri.js", ["goog.Uri","goog.Uri.QueryData"], ["goog.array","goog.string","goog.structs","goog.structs.Map","goog.uri.utils","goog.uri.utils.ComponentIndex","goog.uri.utils.StandardQueryParam"]); | ||
goog.addDependency("structs/structs.js", ["goog.structs"], ["goog.array","goog.object"]); | ||
goog.addDependency("structs/map.js", ["goog.structs.Map"], ["goog.iter.Iterator","goog.iter.StopIteration","goog.object"]); | ||
goog.addDependency("iter/iter.js", ["goog.iter","goog.iter.Iterator","goog.iter.StopIteration"], ["goog.array","goog.asserts"]); | ||
goog.addDependency("uri/utils.js", ["goog.uri.utils","goog.uri.utils.ComponentIndex","goog.uri.utils.QueryArray","goog.uri.utils.QueryValue","goog.uri.utils.StandardQueryParam"], ["goog.asserts","goog.string","goog.userAgent"]); | ||
goog.addDependency("../webdriver/webdriver.js", ["webdriver.Alert","webdriver.UnhandledAlertError","webdriver.WebDriver","webdriver.WebElement"], ["bot.Error","bot.ErrorCode","bot.response","goog.array","goog.object","webdriver.ActionSequence","webdriver.Command","webdriver.CommandName","webdriver.Key","webdriver.Locator","webdriver.Session","webdriver.logging","webdriver.promise"]); | ||
goog.addDependency("../webdriver/session.js", ["webdriver.Session"], ["webdriver.Capabilities"]); | ||
goog.addDependency("../webdriver/builder.js", ["webdriver.Builder"], ["webdriver.AbstractBuilder","webdriver.FirefoxDomExecutor","webdriver.WebDriver","webdriver.http.CorsClient","webdriver.http.Executor","webdriver.process"]); | ||
goog.addDependency("../webdriver/abstractbuilder.js", ["webdriver.AbstractBuilder"], ["webdriver.Capabilities","webdriver.process"]); | ||
goog.addDependency("../webdriver/firefoxdomexecutor.js", ["webdriver.FirefoxDomExecutor"], ["bot.response","goog.json","goog.userAgent.product","webdriver.Command","webdriver.CommandName"]); | ||
goog.addDependency("../webdriver/http/corsclient.js", ["webdriver.http.CorsClient"], ["goog.json","webdriver.http.Response"]); | ||
goog.addDependency("../webdriver/http/http.js", ["webdriver.http.Client","webdriver.http.Executor","webdriver.http.Request","webdriver.http.Response"], ["bot.ErrorCode","goog.array","goog.json","webdriver.CommandName","webdriver.promise.Deferred"]); | ||
goog.addDependency("../webdriver/http/xhrclient.js", ["webdriver.http.XhrClient"], ["goog.json","goog.net.XmlHttp","webdriver.http.Response"]); | ||
goog.addDependency("net/xmlhttp.js", ["goog.net.DefaultXmlHttpFactory","goog.net.XmlHttp","goog.net.XmlHttp.OptionType","goog.net.XmlHttp.ReadyState"], ["goog.net.WrapperXmlHttpFactory","goog.net.XmlHttpFactory"]); | ||
goog.addDependency("net/wrapperxmlhttpfactory.js", ["goog.net.WrapperXmlHttpFactory"], ["goog.net.XmlHttpFactory"]); | ||
goog.addDependency("net/xmlhttpfactory.js", ["goog.net.XmlHttpFactory"], []); | ||
goog.addDependency("../webdriver/testing/asserts.js", ["webdriver.testing.Assertion","webdriver.testing.ContainsMatcher","webdriver.testing.NegatedAssertion","webdriver.testing.assert","webdriver.testing.asserts"], ["goog.array","goog.string","goog.labs.testing.AnyOfMatcher","goog.labs.testing.CloseToMatcher","goog.labs.testing.ContainsStringMatcher","goog.labs.testing.EndsWithMatcher","goog.labs.testing.EqualsMatcher","goog.labs.testing.EqualToMatcher","goog.labs.testing.GreaterThanEqualToMatcher","goog.labs.testing.GreaterThanMatcher","goog.labs.testing.LessThanEqualToMatcher","goog.labs.testing.LessThanMatcher","goog.labs.testing.InstanceOfMatcher","goog.labs.testing.IsNotMatcher","goog.labs.testing.IsNullMatcher","goog.labs.testing.IsNullOrUndefinedMatcher","goog.labs.testing.IsUndefinedMatcher","goog.labs.testing.ObjectEqualsMatcher","goog.labs.testing.Matcher","goog.labs.testing.RegexMatcher","goog.labs.testing.StartsWithMatcher","goog.labs.testing.assertThat","webdriver.promise"]); | ||
goog.addDependency("labs/testing/logicmatcher.js", ["goog.labs.testing.AllOfMatcher","goog.labs.testing.AnyOfMatcher","goog.labs.testing.IsNotMatcher"], ["goog.array","goog.labs.testing.Matcher"]); | ||
goog.addDependency("labs/testing/matcher.js", ["goog.labs.testing.Matcher"], []); | ||
goog.addDependency("labs/testing/numbermatcher.js", ["goog.labs.testing.CloseToMatcher","goog.labs.testing.EqualToMatcher","goog.labs.testing.GreaterThanEqualToMatcher","goog.labs.testing.GreaterThanMatcher","goog.labs.testing.LessThanEqualToMatcher","goog.labs.testing.LessThanMatcher"], ["goog.asserts","goog.labs.testing.Matcher"]); | ||
goog.addDependency("labs/testing/stringmatcher.js", ["goog.labs.testing.ContainsStringMatcher","goog.labs.testing.EndsWithMatcher","goog.labs.testing.EqualToIgnoringCaseMatcher","goog.labs.testing.EqualToIgnoringWhitespaceMatcher","goog.labs.testing.EqualsMatcher","goog.labs.testing.RegexMatcher","goog.labs.testing.StartsWithMatcher","goog.labs.testing.StringContainsInOrderMatcher"], ["goog.asserts","goog.labs.testing.Matcher","goog.string"]); | ||
goog.addDependency("labs/testing/objectmatcher.js", ["goog.labs.testing.HasPropertyMatcher","goog.labs.testing.InstanceOfMatcher","goog.labs.testing.IsNullMatcher","goog.labs.testing.IsNullOrUndefinedMatcher","goog.labs.testing.IsUndefinedMatcher","goog.labs.testing.ObjectEqualsMatcher"], ["goog.labs.testing.Matcher","goog.string"]); | ||
goog.addDependency("labs/testing/assertthat.js", ["goog.labs.testing.MatcherError","goog.labs.testing.assertThat"], ["goog.asserts","goog.debug.Error","goog.labs.testing.Matcher"]); |
@@ -38,4 +38,7 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
* "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler. | ||
* | ||
* Setting goog.TRUSTED_SITE to false will automatically set | ||
* NATIVE_ARRAY_PROTOTYPES to false. | ||
*/ | ||
goog.NATIVE_ARRAY_PROTOTYPES = true; | ||
goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE); | ||
@@ -159,16 +162,11 @@ | ||
/** | ||
* Calls a function for each element in an array. | ||
* | ||
* Calls a function for each element in an array. Skips holes in the array. | ||
* See {@link http://tinyurl.com/developer-mozilla-org-array-foreach} | ||
* | ||
* @param {Array.<T>|goog.array.ArrayLike} arr Array or array | ||
* like object over which to iterate. | ||
* @param {Array.<T>|goog.array.ArrayLike} arr Array or array like object over | ||
* which to iterate. | ||
* @param {?function(this: S, T, number, ?): ?} f The function to call for every | ||
* element. | ||
* This function takes 3 arguments (the element, the index and the array). | ||
* The return value is ignored. The function is called only for indexes of | ||
* the array which have assigned values; it is not called for indexes which | ||
* have been deleted or which have never been assigned values. | ||
* @param {S=} opt_obj The object to be used as the value of 'this' | ||
* within f. | ||
* element. This function takes 3 arguments (the element, the index and the | ||
* array). The return value is ignored. | ||
* @param {S=} opt_obj The object to be used as the value of 'this' within f. | ||
* @template T,S | ||
@@ -454,2 +452,25 @@ */ | ||
/** | ||
* Counts the array elements that fulfill the predicate, i.e. for which the | ||
* callback function returns true. Skips holes in the array. | ||
* | ||
* @param {!(Array.<T>|goog.array.ArrayLike)} arr Array or array like object | ||
* over which to iterate. | ||
* @param {function(this: S, T, number, ?): boolean} f The function to call for | ||
* every element. Takes 3 arguments (the element, the index and the array). | ||
* @param {S=} opt_obj The object to be used as the value of 'this' within f. | ||
* @return {number} The number of the matching elements. | ||
* @template T,S | ||
*/ | ||
goog.array.count = function(arr, f, opt_obj) { | ||
var count = 0; | ||
goog.array.forEach(arr, function(element, index, arr) { | ||
if (f.call(opt_obj, element, index, arr)) { | ||
++count; | ||
} | ||
}, opt_obj); | ||
return count; | ||
}; | ||
/** | ||
* Search an array for the first element that satisfies a given condition and | ||
@@ -786,5 +807,4 @@ * return that element. | ||
// according to section 10.6 in ES5 so check for presence instead. | ||
arr2.hasOwnProperty('callee')) { | ||
Object.prototype.hasOwnProperty.call(arr2, 'callee')) { | ||
arr1.push.apply(arr1, arr2); | ||
} else if (isArrayLike) { | ||
@@ -1245,13 +1265,14 @@ // Otherwise loop over arr2 to prevent copying the object. | ||
* @param {Array.<T>} array The array. | ||
* @param {function(T,number,Array.<T>):?} sorter Function to call for every | ||
* element. This | ||
* takes 3 arguments (the element, the index and the array) and must | ||
* return a valid object key (a string, number, etc), or undefined, if | ||
* that object should not be placed in a bucket. | ||
* @param {function(this:S, T,number,Array.<T>):?} sorter Function to call for | ||
* every element. This takes 3 arguments (the element, the index and the | ||
* array) and must return a valid object key (a string, number, etc), or | ||
* undefined, if that object should not be placed in a bucket. | ||
* @param {S=} opt_obj The object to be used as the value of 'this' within | ||
* sorter. | ||
* @return {!Object} An object, with keys being all of the unique return values | ||
* of sorter, and values being arrays containing the items for | ||
* which the splitter returned that key. | ||
* @template T | ||
* @template T,S | ||
*/ | ||
goog.array.bucket = function(array, sorter) { | ||
goog.array.bucket = function(array, sorter, opt_obj) { | ||
var buckets = {}; | ||
@@ -1261,3 +1282,3 @@ | ||
var value = array[i]; | ||
var key = sorter(value, i, array); | ||
var key = sorter.call(opt_obj, value, i, array); | ||
if (goog.isDef(key)) { | ||
@@ -1285,3 +1306,3 @@ // Push the value to the right bucket, creating it if necessary. | ||
* implementation-defined. | ||
* @param {S=} opt_obj The object to be used as the value of 'this' | ||
* @param {S=} opt_obj The object to be used as the value of 'this' | ||
* within keyFunc. | ||
@@ -1301,2 +1322,50 @@ * @return {!Object.<T>} The new object. | ||
/** | ||
* Creates a range of numbers in an arithmetic progression. | ||
* | ||
* Range takes 1, 2, or 3 arguments: | ||
* <pre> | ||
* range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4] | ||
* range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4] | ||
* range(-2, -5, -1) produces [-2, -3, -4] | ||
* range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5. | ||
* </pre> | ||
* | ||
* @param {number} startOrEnd The starting value of the range if an end argument | ||
* is provided. Otherwise, the start value is 0, and this is the end value. | ||
* @param {number=} opt_end The optional end value of the range. | ||
* @param {number=} opt_step The step size between range values. Defaults to 1 | ||
* if opt_step is undefined or 0. | ||
* @return {!Array.<number>} An array of numbers for the requested range. May be | ||
* an empty array if adding the step would not converge toward the end | ||
* value. | ||
*/ | ||
goog.array.range = function(startOrEnd, opt_end, opt_step) { | ||
var array = []; | ||
var start = 0; | ||
var end = startOrEnd; | ||
var step = opt_step || 1; | ||
if (opt_end !== undefined) { | ||
start = startOrEnd; | ||
end = opt_end; | ||
} | ||
if (step * (end - start) < 0) { | ||
// Sign mismatch: start + step will never reach the end value. | ||
return []; | ||
} | ||
if (step > 0) { | ||
for (var i = start; i < end; i += step) { | ||
array.push(i); | ||
} | ||
} else { | ||
for (var i = start; i > end; i += step) { | ||
array.push(i); | ||
} | ||
} | ||
return array; | ||
}; | ||
/** | ||
* Returns an array consisting of the given value repeated N times. | ||
@@ -1303,0 +1372,0 @@ * |
@@ -46,3 +46,3 @@ // Copyright 2008 The Closure Library Authors. All Rights Reserved. | ||
*/ | ||
goog.asserts.ENABLE_ASSERTS = goog.DEBUG; | ||
goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG); | ||
@@ -269,3 +269,3 @@ | ||
* @param {*} value The value to check. | ||
* @param {!Function} type A user-defined constructor. | ||
* @param {function(new: T, ...)} type A user-defined constructor. | ||
* @param {string=} opt_message Error message in case of failure. | ||
@@ -275,3 +275,4 @@ * @param {...*} var_args The items to substitute into the failure message. | ||
* type. | ||
* @return {!Object} | ||
* @return {!T} | ||
* @template T | ||
*/ | ||
@@ -283,4 +284,4 @@ goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) { | ||
} | ||
return /** @type {!Object} */(value); | ||
return value; | ||
}; | ||
@@ -41,3 +41,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
*/ | ||
var goog = goog || {}; // Identifies this file as the Closure base. | ||
var goog = goog || {}; | ||
@@ -52,2 +52,84 @@ | ||
/** | ||
* A hook for overriding the define values in uncompiled mode. | ||
* | ||
* In uncompiled mode, {@code CLOSURE_DEFINES} may be defined before loading | ||
* base.js. If a key is defined in {@code CLOSURE_DEFINES}, {@code goog.define} | ||
* will use the value instead of the default value. This allows flags to be | ||
* overwritten without compilation (this is normally accomplished with the | ||
* compiler's "define" flag). | ||
* | ||
* Example: | ||
* <pre> | ||
* var CLOSURE_DEFINES = {'goog.DEBUG', false}; | ||
* </pre> | ||
* | ||
* @type {Object.<string, (string|number|boolean)>|undefined} | ||
*/ | ||
goog.global.CLOSURE_DEFINES; | ||
/** | ||
* Builds an object structure for the provided namespace path, | ||
* ensuring that names that already exist are not overwritten. For | ||
* example: | ||
* "a.b.c" -> a = {};a.b={};a.b.c={}; | ||
* Used by goog.provide and goog.exportSymbol. | ||
* @param {string} name name of the object that this file defines. | ||
* @param {*=} opt_object the object to expose at the end of the path. | ||
* @param {Object=} opt_objectToExportTo The object to add the path to; default | ||
* is |goog.global|. | ||
* @private | ||
*/ | ||
goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { | ||
var parts = name.split('.'); | ||
var cur = opt_objectToExportTo || goog.global; | ||
// Internet Explorer exhibits strange behavior when throwing errors from | ||
// methods externed in this manner. See the testExportSymbolExceptions in | ||
// base_test.html for an example. | ||
if (!(parts[0] in cur) && cur.execScript) { | ||
cur.execScript('var ' + parts[0]); | ||
} | ||
// Certain browsers cannot parse code in the form for((a in b); c;); | ||
// This pattern is produced by the JSCompiler when it collapses the | ||
// statement above into the conditional loop below. To prevent this from | ||
// happening, use a for-loop and reserve the init logic as below. | ||
// Parentheses added to eliminate strict JS warning in Firefox. | ||
for (var part; parts.length && (part = parts.shift());) { | ||
if (!parts.length && opt_object !== undefined) { | ||
// last part and we have an object; use it | ||
cur[part] = opt_object; | ||
} else if (cur[part]) { | ||
cur = cur[part]; | ||
} else { | ||
cur = cur[part] = {}; | ||
} | ||
} | ||
}; | ||
/** | ||
* Defines a named value. In uncompiled mode, the value is retreived from | ||
* CLOSURE_DEFINES if the object is defined and has the property specified, | ||
* and otherwise used the defined defaultValue. When compiled, the default | ||
* can be overridden using compiler command-line options. | ||
* | ||
* @param {string} name The distinguished name to provide. | ||
* @param {string|number|boolean} defaultValue | ||
*/ | ||
goog.define = function(name, defaultValue) { | ||
var value = defaultValue; | ||
if (!COMPILED) { | ||
if (goog.global.CLOSURE_DEFINES && Object.prototype.hasOwnProperty.call( | ||
goog.global.CLOSURE_DEFINES, name)) { | ||
value = goog.global.CLOSURE_DEFINES[name]; | ||
} | ||
} | ||
goog.exportPath_(name, value); | ||
}; | ||
/** | ||
* @define {boolean} DEBUG is provided as a convenience so that debugging code | ||
@@ -82,6 +164,20 @@ * that should not be included in a production js_binary can be easily stripped | ||
*/ | ||
goog.LOCALE = 'en'; // default to en | ||
goog.define('goog.LOCALE', 'en'); // default to en | ||
/** | ||
* @define {boolean} Whether this code is running on trusted sites. | ||
* | ||
* On untrusted sites, several native functions can be defined or overridden by | ||
* external libraries like Prototype, Datejs, and JQuery and setting this flag | ||
* to false forces closure to use its own implementations when possible. | ||
* | ||
* If your javascript can be loaded by a third party site and you are wary about | ||
* relying on non-standard implementations, specify | ||
* "--define goog.TRUSTED_SITE=false" to the JSCompiler. | ||
*/ | ||
goog.define('goog.TRUSTED_SITE', true); | ||
/** | ||
* Creates object stubs for a namespace. The presence of one or more | ||
@@ -123,2 +219,7 @@ * goog.provide() calls indicate that the file defines the given | ||
* live code in production. | ||
* | ||
* In the case of unit tests, the message may optionally be an exact | ||
* namespace for the test (e.g. 'goog.stringTest'). The linter will then | ||
* ignore the extra provide (if not explicitly defined in the code). | ||
* | ||
* @param {string=} opt_message Optional message to add to the error that's | ||
@@ -162,44 +263,2 @@ * raised when used in production code. | ||
/** | ||
* Builds an object structure for the provided namespace path, | ||
* ensuring that names that already exist are not overwritten. For | ||
* example: | ||
* "a.b.c" -> a = {};a.b={};a.b.c={}; | ||
* Used by goog.provide and goog.exportSymbol. | ||
* @param {string} name name of the object that this file defines. | ||
* @param {*=} opt_object the object to expose at the end of the path. | ||
* @param {Object=} opt_objectToExportTo The object to add the path to; default | ||
* is |goog.global|. | ||
* @private | ||
*/ | ||
goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { | ||
var parts = name.split('.'); | ||
var cur = opt_objectToExportTo || goog.global; | ||
// Internet Explorer exhibits strange behavior when throwing errors from | ||
// methods externed in this manner. See the testExportSymbolExceptions in | ||
// base_test.html for an example. | ||
if (!(parts[0] in cur) && cur.execScript) { | ||
cur.execScript('var ' + parts[0]); | ||
} | ||
// Certain browsers cannot parse code in the form for((a in b); c;); | ||
// This pattern is produced by the JSCompiler when it collapses the | ||
// statement above into the conditional loop below. To prevent this from | ||
// happening, use a for-loop and reserve the init logic as below. | ||
// Parentheses added to eliminate strict JS warning in Firefox. | ||
for (var part; parts.length && (part = parts.shift());) { | ||
if (!parts.length && goog.isDef(opt_object)) { | ||
// last part and we have an object; use it | ||
cur[part] = opt_object; | ||
} else if (cur[part]) { | ||
cur = cur[part]; | ||
} else { | ||
cur = cur[part] = {}; | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns an object based on its fully qualified external name. If you are | ||
@@ -253,3 +312,3 @@ * using a compilation pass that renames property names beware that using this | ||
goog.addDependency = function(relPath, provides, requires) { | ||
if (!COMPILED) { | ||
if (goog.DEPENDENCIES_ENABLED) { | ||
var provide, require; | ||
@@ -305,3 +364,3 @@ var path = relPath.replace(/\\/g, '/'); | ||
*/ | ||
goog.ENABLE_DEBUG_LOADER = true; | ||
goog.define('goog.ENABLE_DEBUG_LOADER', true); | ||
@@ -458,3 +517,10 @@ | ||
if (!COMPILED && goog.ENABLE_DEBUG_LOADER) { | ||
/** | ||
* True if goog.dependencies_ is available. | ||
* @const {boolean} | ||
*/ | ||
goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; | ||
if (goog.DEPENDENCIES_ENABLED) { | ||
/** | ||
@@ -944,4 +1010,3 @@ * Object used to keep track of urls that have already been added. This | ||
*/ | ||
goog.UID_PROPERTY_ = 'closure_uid_' + | ||
Math.floor(Math.random() * 2147483648).toString(36); | ||
goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0); | ||
@@ -1073,4 +1138,4 @@ | ||
* | ||
* @param {Function} fn A function to partially apply. | ||
* @param {Object|undefined} selfObj Specifies the object which |this| should | ||
* @param {?function(this:T, ...)} fn A function to partially apply. | ||
* @param {T} selfObj Specifies the object which |this| should | ||
* point to when the function is run. | ||
@@ -1081,2 +1146,3 @@ * @param {...*} var_args Additional arguments that are partially | ||
* invoked as a method of. | ||
* @template T | ||
* @suppress {deprecated} See above. | ||
@@ -1152,3 +1218,3 @@ */ | ||
*/ | ||
goog.now = Date.now || (function() { | ||
goog.now = (goog.TRUSTED_SITE && Date.now) || (function() { | ||
// Unary plus operator converts its operand to a number which in the case of | ||
@@ -1503,2 +1569,11 @@ // a date is done by calling getTime(). | ||
var caller = arguments.callee.caller; | ||
if (goog.DEBUG) { | ||
if (!caller) { | ||
throw Error('arguments.caller not defined. goog.base() expects not ' + | ||
'to be running in strict mode. See ' + | ||
'http://www.ecma-international.org/ecma-262/5.1/#sec-C'); | ||
} | ||
} | ||
if (caller.superClass_) { | ||
@@ -1505,0 +1580,0 @@ // This is a constructor. Call the superclass constructor. |
@@ -191,6 +191,6 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
case 'string': | ||
this.serializeString_((/** @type {string} */ object), sb); | ||
this.serializeString_(/** @type {string} */ (object), sb); | ||
break; | ||
case 'number': | ||
this.serializeNumber_((/** @type {number} */ object), sb); | ||
this.serializeNumber_(/** @type {number} */ (object), sb); | ||
break; | ||
@@ -209,3 +209,3 @@ case 'boolean': | ||
if (goog.isArray(object)) { | ||
this.serializeArray((/** @type {!Array} */ object), sb); | ||
this.serializeArray(/** @type {!Array} */ (object), sb); | ||
break; | ||
@@ -216,3 +216,3 @@ } | ||
// need is not very big | ||
this.serializeObject_((/** @type {Object} */ object), sb); | ||
this.serializeObject_(/** @type {Object} */ (object), sb); | ||
break; | ||
@@ -219,0 +219,0 @@ case 'function': |
@@ -43,3 +43,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
*/ | ||
goog.net.XmlHttp.ASSUME_NATIVE_XHR = false; | ||
goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false); | ||
@@ -127,4 +127,4 @@ | ||
goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( | ||
(/** @type {function() : !(XMLHttpRequest|GearsHttpRequest)} */ factory), | ||
(/** @type {function() : !Object}*/ optionsFactory))); | ||
/** @type {function() : !(XMLHttpRequest|GearsHttpRequest)} */ (factory), | ||
/** @type {function() : !Object}*/ (optionsFactory))); | ||
}; | ||
@@ -131,0 +131,0 @@ |
@@ -44,3 +44,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
* @param {Object.<K,V>} obj The object over which to iterate. | ||
* @param {function(this:T,K,?,Object.<K,V>):boolean} f The function to call | ||
* @param {function(this:T,V,?,Object.<K,V>):boolean} f The function to call | ||
* for every element. This | ||
@@ -78,3 +78,3 @@ * function takes 3 arguments (the element, the index and the object) | ||
* @param {T=} opt_obj This is used as the 'this' object within f. | ||
* @return {!Object.<T,R>} a new object with the results from f. | ||
* @return {!Object.<K,R>} a new object with the results from f. | ||
* @template T,K,V,R | ||
@@ -97,3 +97,3 @@ */ | ||
* @param {Object.<K,V>} obj The object to check. | ||
* @param {function(this:T,K,?,Object.<K,V>):boolean} f The function to | ||
* @param {function(this:T,V,?,Object.<K,V>):boolean} f The function to | ||
* call for every element. This function | ||
@@ -244,3 +244,3 @@ * takes 3 arguments (the element, the index and the object) and should | ||
* @param {...(string|number|!Array.<number|string>)} var_args A number of keys | ||
* (as strings, or nubmers, for array-like objects). Can also be | ||
* (as strings, or numbers, for array-like objects). Can also be | ||
* specified as a single array of keys. | ||
@@ -418,3 +418,3 @@ * @return {*} The resulting value. If, at any point, the value for a key | ||
* @param {string} key The key to add. | ||
* @param {K} value The value to add. | ||
* @param {V} value The value to add. | ||
* @template K,V | ||
@@ -421,0 +421,0 @@ */ |
@@ -86,2 +86,14 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
/** | ||
* Case-insensitive equality checker. | ||
* @param {string} str1 First string to check. | ||
* @param {string} str2 Second string to check. | ||
* @return {boolean} True if {@code str1} and {@code str2} are the same string, | ||
* ignoring case. | ||
*/ | ||
goog.string.caseInsensitiveEquals = function(str1, str2) { | ||
return str1.toLowerCase() == str2.toLowerCase(); | ||
}; | ||
/** | ||
* Does simple python-style string substitution. | ||
@@ -95,14 +107,14 @@ * subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog". | ||
goog.string.subs = function(str, var_args) { | ||
// This appears to be slow, but testing shows it compares more or less | ||
// equivalent to the regex.exec method. | ||
for (var i = 1; i < arguments.length; i++) { | ||
// We cast to String in case an argument is a Function. Replacing $&, for | ||
// example, with $$$& stops the replace from subsituting the whole match | ||
// into the resultant string. $$$& in the first replace becomes $$& in the | ||
// second, which leaves $& in the resultant string. Also: | ||
// $$, $`, $', $n $nn | ||
var replacement = String(arguments[i]).replace(/\$/g, '$$$$'); | ||
str = str.replace(/\%s/, replacement); | ||
var splitParts = str.split('%s'); | ||
var returnString = ''; | ||
var subsArguments = Array.prototype.slice.call(arguments, 1); | ||
while (subsArguments.length && | ||
// Replace up to the last split part. We are inserting in the | ||
// positions between split parts. | ||
splitParts.length > 1) { | ||
returnString += splitParts.shift() + subsArguments.shift(); | ||
} | ||
return str; | ||
return returnString + splitParts.join('%s'); // Join unused '%s' | ||
}; | ||
@@ -1199,2 +1211,30 @@ | ||
/** | ||
* Returns whether the given string is lower camel case (e.g. "isFooBar"). | ||
* | ||
* Note that this assumes the string is entirely letters. | ||
* @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms | ||
* | ||
* @param {string} str String to test. | ||
* @return {boolean} Whether the string is lower camel case. | ||
*/ | ||
goog.string.isLowerCamelCase = function(str) { | ||
return /^[a-z]+([A-Z][a-z]*)*$/.test(str); | ||
}; | ||
/** | ||
* Returns whether the given string is upper camel case (e.g. "FooBarBaz"). | ||
* | ||
* Note that this assumes the string is entirely letters. | ||
* @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms | ||
* | ||
* @param {string} str String to test. | ||
* @return {boolean} Whether the string is upper camel case. | ||
*/ | ||
goog.string.isUpperCamelCase = function(str) { | ||
return /^([A-Z][a-z]*)+$/.test(str); | ||
}; | ||
/** | ||
* Converts a string from selector-case to camelCase (e.g. from | ||
@@ -1302,1 +1342,41 @@ * "multi-part-string" to "multiPartString"), useful for converting | ||
}; | ||
/** | ||
* Splits a string on a separator a limited number of times. | ||
* | ||
* This implementation is more similar to Python or Java, where the limit | ||
* parameter specifies the maximum number of splits rather than truncating | ||
* the number of results. | ||
* | ||
* See http://docs.python.org/2/library/stdtypes.html#str.split | ||
* See JavaDoc: http://goo.gl/F2AsY | ||
* See Mozilla reference: http://goo.gl/dZdZs | ||
* | ||
* @param {string} str String to split. | ||
* @param {string} separator The separator. | ||
* @param {number} limit The limit to the number of splits. The resulting array | ||
* will have a maximum length of limit+1. Negative numbers are the same | ||
* as zero. | ||
* @return {!Array.<string>} The string, split. | ||
*/ | ||
goog.string.splitLimit = function(str, separator, limit) { | ||
var parts = str.split(separator); | ||
var returnVal = []; | ||
// Only continue doing this while we haven't hit the limit and we have | ||
// parts left. | ||
while (limit > 0 && parts.length) { | ||
returnVal.push(parts.shift()); | ||
limit--; | ||
} | ||
// If there are remaining parts, append them to the end. | ||
if (parts.length) { | ||
returnVal.push(parts.join(separator)); | ||
} | ||
return returnVal; | ||
}; | ||
@@ -22,5 +22,6 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
* This file contains an implementation of a Map structure. It implements a lot | ||
* of the methods used in goog.structs so those functions work on hashes. For | ||
* convenience with common usage the methods accept any type for the key, though | ||
* internally they will be cast to strings. | ||
* of the methods used in goog.structs so those functions work on hashes. This | ||
* is best suited for complex key types. For simple keys such as numbers and | ||
* strings, and where special names like __proto__ are not a concern, consider | ||
* using the lighter-weight utilities in goog.object. | ||
*/ | ||
@@ -34,3 +35,2 @@ | ||
goog.require('goog.object'); | ||
goog.require('goog.structs'); | ||
@@ -37,0 +37,0 @@ |
@@ -153,3 +153,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
} else if (goog.isArrayLike(col)) { | ||
goog.array.clear((/** @type {goog.array.ArrayLike} */ col)); | ||
goog.array.clear(/** @type {goog.array.ArrayLike} */ (col)); | ||
} else { | ||
@@ -156,0 +156,0 @@ goog.object.clear(col); |
@@ -24,3 +24,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
* Implements RFC 3986 for parsing/formatting URIs. | ||
* http://gbiv.com/protocols/uri/rfc/rfc3986.html | ||
* http://www.ietf.org/rfc/rfc3986.txt | ||
* | ||
@@ -42,2 +42,3 @@ * Some changes have been made to the interface (more like .NETs), though the | ||
goog.require('goog.uri.utils.ComponentIndex'); | ||
goog.require('goog.uri.utils.StandardQueryParam'); | ||
@@ -254,5 +255,6 @@ | ||
/** | ||
* Resolves a relative url string to a this base uri. | ||
* Resolves the given relative URI (a goog.Uri object), using the URI | ||
* represented by this instance as the base URI. | ||
* | ||
* There are several kinds of relative urls:<br> | ||
* There are several kinds of relative URIs:<br> | ||
* 1. foo - replaces the last part of the path, the whole query and fragment<br> | ||
@@ -264,6 +266,6 @@ * 2. /foo - replaces the the path, the query and fragment<br> | ||
* | ||
* Additionally, if relative url has a non-empty path, all ".." and "." | ||
* Additionally, if relative URI has a non-empty path, all ".." and "." | ||
* segments will be resolved, as described in RFC 3986. | ||
* | ||
* @param {goog.Uri} relativeUri The relative url to resolve. | ||
* @param {goog.Uri} relativeUri The relative URI to resolve. | ||
* @return {!goog.Uri} The resolved URI. | ||
@@ -1254,3 +1256,3 @@ */ | ||
* it will be included multiple times in the returned array | ||
* @return {!Array} All the keys of the parameters. | ||
* @return {!Array.<string>} All the keys of the parameters. | ||
*/ | ||
@@ -1257,0 +1259,0 @@ goog.Uri.QueryData.prototype.getKeys = function() { |
@@ -42,3 +42,3 @@ // Copyright 2008 The Closure Library Authors. All Rights Reserved. | ||
* Uses features of RFC 3986 for parsing/formatting URIs: | ||
* http://gbiv.com/protocols/uri/rfc/rfc3986.html | ||
* http://www.ietf.org/rfc/rfc3986.txt | ||
* | ||
@@ -131,3 +131,3 @@ * @author gboyer@google.com (Garrett Boyer) - The "lightened" design. | ||
* | ||
* {@link http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#RFC2234} says | ||
* {@link http://www.ietf.org/rfc/rfc3986.txt} says in Appendix B | ||
* As the "first-match-wins" algorithm is identical to the "greedy" | ||
@@ -200,6 +200,5 @@ * disambiguation method used by POSIX regular expressions, it is natural and | ||
'(?:([^/?#]*)@)?' + // userInfo | ||
'([\\w\\d\\-\\u0100-\\uffff.%]*)' + // domain - restrict to letters, | ||
// digits, dashes, dots, percent | ||
// escapes, and unicode characters. | ||
'([^/#?]*?)' + // domain | ||
'(?::([0-9]+))?' + // port | ||
'(?=[/#?]|$)' + // authority-terminating character | ||
')?' + | ||
@@ -243,2 +242,3 @@ '([^?#]+)?' + // path | ||
goog.uri.utils.split = function(uri) { | ||
goog.uri.utils.phishingProtection_(); | ||
@@ -251,5 +251,55 @@ // See @return comment -- never null. | ||
/** | ||
* Safari has a nasty bug where if you have an http URL with a username, e.g., | ||
* http://evil.com%2F@google.com/ | ||
* Safari will report that window.location.href is | ||
* http://evil.com/google.com/ | ||
* so that anyone who tries to parse the domain of that URL will get | ||
* the wrong domain. We've seen exploits where people use this to trick | ||
* Safari into loading resources from evil domains. | ||
* | ||
* To work around this, we run a little "Safari phishing check", and throw | ||
* an exception if we see this happening. | ||
* | ||
* There is no convenient place to put this check. We apply it to | ||
* anyone doing URI parsing on Webkit. We're not happy about this, but | ||
* it fixes the problem. | ||
* | ||
* This should be removed once Safari fixes their bug. | ||
* | ||
* Exploit reported by Masato Kinugawa. | ||
* | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
goog.uri.utils.needsPhishingProtection_ = goog.userAgent.WEBKIT; | ||
/** | ||
* Check to see if the user is being phished. | ||
* @private | ||
*/ | ||
goog.uri.utils.phishingProtection_ = function() { | ||
if (goog.uri.utils.needsPhishingProtection_) { | ||
// Turn protection off, so that we don't recurse. | ||
goog.uri.utils.needsPhishingProtection_ = false; | ||
// Use quoted access, just in case the user isn't using location externs. | ||
var location = goog.global['location']; | ||
if (location) { | ||
var href = location['href']; | ||
if (href) { | ||
var domain = goog.uri.utils.getDomain(href); | ||
if (domain && domain != location['hostname']) { | ||
// Phishing attack | ||
goog.uri.utils.needsPhishingProtection_ = true; | ||
throw Error(); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* @param {?string} uri A possibly null string. | ||
@@ -754,9 +804,13 @@ * @return {?string} The string URI-decoded, or null if uri is null. | ||
* @param {string} key The key, which must already be URI encoded. | ||
* @param {*} value The value, which will be stringized and encoded (assumed | ||
* not already to be encoded). | ||
* @param {*=} opt_value The value, which will be stringized and encoded | ||
* (assumed not already to be encoded). If omitted, undefined, or null, the | ||
* key will be added as a valueless parameter. | ||
* @return {string} The URI with the query parameter added. | ||
*/ | ||
goog.uri.utils.appendParam = function(uri, key, value) { | ||
return goog.uri.utils.appendQueryData_( | ||
[uri, '&', key, '=', goog.string.urlEncode(value)]); | ||
goog.uri.utils.appendParam = function(uri, key, opt_value) { | ||
var paramArr = [uri, '&', key]; | ||
if (goog.isDefAndNotNull(opt_value)) { | ||
paramArr.push('=', goog.string.urlEncode(opt_value)); | ||
} | ||
return goog.uri.utils.appendQueryData_(paramArr); | ||
}; | ||
@@ -763,0 +817,0 @@ |
@@ -28,3 +28,3 @@ // Copyright 2008 The Closure Library Authors. All Rights Reserved. | ||
*/ | ||
goog.userAgent.product.ASSUME_FIREFOX = false; | ||
goog.define('goog.userAgent.product.ASSUME_FIREFOX', false); | ||
@@ -35,3 +35,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_CAMINO = false; | ||
goog.define('goog.userAgent.product.ASSUME_CAMINO', false); | ||
@@ -43,3 +43,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_IPHONE = false; | ||
goog.define('goog.userAgent.product.ASSUME_IPHONE', false); | ||
@@ -51,3 +51,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_IPAD = false; | ||
goog.define('goog.userAgent.product.ASSUME_IPAD', false); | ||
@@ -59,3 +59,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_ANDROID = false; | ||
goog.define('goog.userAgent.product.ASSUME_ANDROID', false); | ||
@@ -66,3 +66,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_CHROME = false; | ||
goog.define('goog.userAgent.product.ASSUME_CHROME', false); | ||
@@ -73,3 +73,3 @@ | ||
*/ | ||
goog.userAgent.product.ASSUME_SAFARI = false; | ||
goog.define('goog.userAgent.product.ASSUME_SAFARI', false); | ||
@@ -76,0 +76,0 @@ |
@@ -31,3 +31,3 @@ // Copyright 2006 The Closure Library Authors. All Rights Reserved. | ||
*/ | ||
goog.userAgent.ASSUME_IE = false; | ||
goog.define('goog.userAgent.ASSUME_IE', false); | ||
@@ -38,3 +38,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_GECKO = false; | ||
goog.define('goog.userAgent.ASSUME_GECKO', false); | ||
@@ -45,3 +45,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_WEBKIT = false; | ||
goog.define('goog.userAgent.ASSUME_WEBKIT', false); | ||
@@ -53,3 +53,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_MOBILE_WEBKIT = false; | ||
goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false); | ||
@@ -60,10 +60,11 @@ | ||
*/ | ||
goog.userAgent.ASSUME_OPERA = false; | ||
goog.define('goog.userAgent.ASSUME_OPERA', false); | ||
/** | ||
* @define {boolean} Whether the {@code goog.userAgent.isVersion} function will | ||
* return true for any version. | ||
* @define {boolean} Whether the | ||
* {@code goog.userAgent.isVersionOrHigher} | ||
* function will return true for any version. | ||
*/ | ||
goog.userAgent.ASSUME_ANY_VERSION = false; | ||
goog.define('goog.userAgent.ASSUME_ANY_VERSION', false); | ||
@@ -256,3 +257,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_MAC = false; | ||
goog.define('goog.userAgent.ASSUME_MAC', false); | ||
@@ -264,3 +265,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_WINDOWS = false; | ||
goog.define('goog.userAgent.ASSUME_WINDOWS', false); | ||
@@ -272,3 +273,3 @@ | ||
*/ | ||
goog.userAgent.ASSUME_LINUX = false; | ||
goog.define('goog.userAgent.ASSUME_LINUX', false); | ||
@@ -280,6 +281,24 @@ | ||
*/ | ||
goog.userAgent.ASSUME_X11 = false; | ||
goog.define('goog.userAgent.ASSUME_X11', false); | ||
/** | ||
* @define {boolean} Whether the user agent is running on Android. | ||
*/ | ||
goog.define('goog.userAgent.ASSUME_ANDROID', false); | ||
/** | ||
* @define {boolean} Whether the user agent is running on an iPhone. | ||
*/ | ||
goog.define('goog.userAgent.ASSUME_IPHONE', false); | ||
/** | ||
* @define {boolean} Whether the user agent is running on an iPad. | ||
*/ | ||
goog.define('goog.userAgent.ASSUME_IPAD', false); | ||
/** | ||
* @type {boolean} | ||
@@ -292,3 +311,6 @@ * @private | ||
goog.userAgent.ASSUME_LINUX || | ||
goog.userAgent.ASSUME_X11; | ||
goog.userAgent.ASSUME_X11 || | ||
goog.userAgent.ASSUME_ANDROID || | ||
goog.userAgent.ASSUME_IPHONE || | ||
goog.userAgent.ASSUME_IPAD; | ||
@@ -334,2 +356,26 @@ | ||
'X11'); | ||
// Need user agent string for Android/IOS detection | ||
var ua = goog.userAgent.getUserAgentString(); | ||
/** | ||
* Whether the user agent is running on Android. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
goog.userAgent.detectedAndroid_ = !!ua && ua.indexOf('Android') >= 0; | ||
/** | ||
* Whether the user agent is running on an iPhone. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
goog.userAgent.detectedIPhone_ = !!ua && ua.indexOf('iPhone') >= 0; | ||
/** | ||
* Whether the user agent is running on an iPad. | ||
* @type {boolean} | ||
* @private | ||
*/ | ||
goog.userAgent.detectedIPad_ = !!ua && ua.indexOf('iPad') >= 0; | ||
}; | ||
@@ -376,2 +422,26 @@ | ||
/** | ||
* Whether the user agent is running on Android. | ||
* @type {boolean} | ||
*/ | ||
goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ? | ||
goog.userAgent.ASSUME_ANDROID : goog.userAgent.detectedAndroid_; | ||
/** | ||
* Whether the user agent is running on an iPhone. | ||
* @type {boolean} | ||
*/ | ||
goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ? | ||
goog.userAgent.ASSUME_IPHONE : goog.userAgent.detectedIPhone_; | ||
/** | ||
* Whether the user agent is running on an iPad. | ||
* @type {boolean} | ||
*/ | ||
goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ? | ||
goog.userAgent.ASSUME_IPAD : goog.userAgent.detectedIPad_; | ||
/** | ||
* @return {string} The string that describes the version number of the user | ||
@@ -457,9 +527,9 @@ * agent. | ||
/** | ||
* Cache for {@link goog.userAgent.isVersion}. Calls to compareVersions are | ||
* surprisingly expensive and as a browsers version number is unlikely to change | ||
* during a session we cache the results. | ||
* @type {Object} | ||
* Cache for {@link goog.userAgent.isVersionOrHigher}. | ||
* Calls to compareVersions are surprisingly expensive and, as a browser's | ||
* version number is unlikely to change during a session, we cache the results. | ||
* @const | ||
* @private | ||
*/ | ||
goog.userAgent.isVersionCache_ = {}; | ||
goog.userAgent.isVersionOrHigherCache_ = {}; | ||
@@ -481,6 +551,6 @@ | ||
*/ | ||
goog.userAgent.isVersion = function(version) { | ||
goog.userAgent.isVersionOrHigher = function(version) { | ||
return goog.userAgent.ASSUME_ANY_VERSION || | ||
goog.userAgent.isVersionCache_[version] || | ||
(goog.userAgent.isVersionCache_[version] = | ||
goog.userAgent.isVersionOrHigherCache_[version] || | ||
(goog.userAgent.isVersionOrHigherCache_[version] = | ||
goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0); | ||
@@ -491,2 +561,12 @@ }; | ||
/** | ||
* Deprecated alias to {@code goog.userAgent.isVersionOrHigher}. | ||
* @param {string|number} version The version to check. | ||
* @return {boolean} Whether the user agent version is higher or the same as | ||
* the given version. | ||
* @deprecated Use goog.userAgent.isVersionOrHigher(). | ||
*/ | ||
goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher; | ||
/** | ||
* Whether the IE effective document mode is higher or the same as the given | ||
@@ -500,3 +580,3 @@ * document mode version. | ||
*/ | ||
goog.userAgent.isDocumentMode = function(documentMode) { | ||
goog.userAgent.isDocumentModeOrHigher = function(documentMode) { | ||
return goog.userAgent.IE && goog.userAgent.DOCUMENT_MODE >= documentMode; | ||
@@ -507,2 +587,11 @@ }; | ||
/** | ||
* Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}. | ||
* @param {number} version The version to check. | ||
* @return {boolean} Whether the IE effective document mode is higher or the | ||
* same as the given version. | ||
*/ | ||
goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher; | ||
/** | ||
* For IE version < 7, documentMode is undefined, so attempt to use the | ||
@@ -509,0 +598,0 @@ * CSS1Compat property to see if we are in standards mode. If we are in |
@@ -17,2 +17,3 @@ // Copyright 2012 Software Freedom Conservancy. All Rights Reserved. | ||
goog.require('webdriver.Capabilities'); | ||
goog.require('webdriver.process'); | ||
@@ -48,21 +49,9 @@ | ||
this.serverUrl_ = webdriver.process.getEnv( | ||
webdriver.AbstractBuilder.SERVER_URL_ENV, | ||
webdriver.AbstractBuilder.DEFAULT_SERVER_URL); | ||
webdriver.AbstractBuilder.SERVER_URL_ENV); | ||
/** | ||
* ID of an existing WebDriver session that new clients should use. | ||
* Initialized from the value of the | ||
* {@link webdriver.AbstractBuilder.SESSION_ID_ENV} environment variable, but | ||
* may be overridden using | ||
* {@link webdriver.AbstractBuilder#usingSession}. | ||
* @private {string} | ||
*/ | ||
this.sessionId_ = | ||
webdriver.process.getEnv(webdriver.AbstractBuilder.SESSION_ID_ENV); | ||
/** | ||
* The desired capabilities to use when creating a new session. | ||
* @private {!Object.<*>} | ||
* @private {!webdriver.Capabilities} | ||
*/ | ||
this.capabilities_ = {}; | ||
this.capabilities_ = new webdriver.Capabilities(); | ||
}; | ||
@@ -72,16 +61,2 @@ | ||
/** | ||
* Environment variable that defines the session ID of an existing WebDriver | ||
* session to use when creating clients. If set, all new Builder instances will | ||
* default to creating clients that use this session. To create a new session, | ||
* use {@code #useExistingSession(boolean)}. The use of this environment | ||
* variable requires that {@link webdriver.AbstractBuilder.SERVER_URL_ENV} also | ||
* be set. | ||
* @type {string} | ||
* @const | ||
* @see webdriver.process.getEnv | ||
*/ | ||
webdriver.AbstractBuilder.SESSION_ID_ENV = 'wdsid'; | ||
/** | ||
* Environment variable that defines the URL of the WebDriver server that | ||
@@ -129,30 +104,10 @@ * should be used for all new WebDriver clients. This setting may be overridden | ||
/** | ||
* Configures the builder to create a client that will use an existing WebDriver | ||
* session. | ||
* @param {string} id The existing session ID to use. | ||
* Sets the desired capabilities when requesting a new session. This will | ||
* overwrite any previously set desired capabilities. | ||
* @param {!(Object|webdriver.Capabilities)} capabilities The desired | ||
* capabilities for a new session. | ||
* @return {!webdriver.AbstractBuilder} This Builder instance for chain calling. | ||
*/ | ||
webdriver.AbstractBuilder.prototype.usingSession = function(id) { | ||
this.sessionId_ = id; | ||
return this; | ||
}; | ||
/** | ||
* @return {string} The ID of the session, if any, this builder is configured | ||
* to reuse. | ||
*/ | ||
webdriver.AbstractBuilder.prototype.getSession = function() { | ||
return this.sessionId_; | ||
}; | ||
/** | ||
* Sets the desired capabilities when requesting a new session. | ||
* @param {!Object.<*>} capabilities The desired capabilities for a new | ||
* session. | ||
* @return {!webdriver.AbstractBuilder} This Builder instance for chain calling. | ||
*/ | ||
webdriver.AbstractBuilder.prototype.withCapabilities = function(capabilities) { | ||
this.capabilities_ = capabilities; | ||
this.capabilities_ = new webdriver.Capabilities(capabilities); | ||
return this; | ||
@@ -163,3 +118,4 @@ }; | ||
/** | ||
* @return {!Object.<*>} The current desired capabilities for this builder. | ||
* @return {!webdriver.Capabilities} The current desired capabilities for this | ||
* builder. | ||
*/ | ||
@@ -166,0 +122,0 @@ webdriver.AbstractBuilder.prototype.getCapabilities = function() { |
@@ -48,5 +48,3 @@ // Copyright 2012 Selenium comitters | ||
/** | ||
* @private {!Array.<{description: string, command: !webdriver.Command}>} | ||
*/ | ||
/** @private {!Array.<{description: string, command: !webdriver.Command}>} */ | ||
this.actions_ = []; | ||
@@ -111,3 +109,3 @@ }; | ||
// string, not the usual JSON object. | ||
var id = (/** @type {!webdriver.WebElement} */location).toWireValue(). | ||
var id = /** @type {!webdriver.WebElement} */ (location).toWireValue(). | ||
then(function(value) { | ||
@@ -149,3 +147,4 @@ return value['ELEMENT']; | ||
if (opt_elementOrButton) { | ||
this.mouseMove((/** @type {!webdriver.WebElement} */opt_elementOrButton)); | ||
this.mouseMove( | ||
/** @type {!webdriver.WebElement} */ (opt_elementOrButton)); | ||
} | ||
@@ -152,0 +151,0 @@ button = goog.isDef(opt_button) ? opt_button : webdriver.Button.LEFT; |
@@ -158,3 +158,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
var response = bot.response.checkResponse( | ||
(/** @type {!bot.response.ResponseObject} */goog.json.parse(json))); | ||
/** @type {!bot.response.ResponseObject} */ (goog.json.parse(json))); | ||
} catch (ex) { | ||
@@ -161,0 +161,0 @@ command.callback(ex); |
@@ -104,3 +104,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
callback(null, webdriver.http.Response.fromXmlHttpRequest( | ||
(/** @type {!XMLHttpRequest} */xhr))); | ||
/** @type {!XMLHttpRequest} */ (xhr))); | ||
}; | ||
@@ -107,0 +107,0 @@ |
@@ -91,3 +91,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
responseObj = webdriver.http.Executor.parseHttpResponse_( | ||
(/** @type {!webdriver.http.Response} */response)); | ||
/** @type {!webdriver.http.Response} */ (response)); | ||
} catch (ex) { | ||
@@ -148,3 +148,3 @@ e = ex; | ||
try { | ||
return (/** @type {!bot.response.ResponseObject} */goog.json.parse( | ||
return /** @type {!bot.response.ResponseObject} */ (goog.json.parse( | ||
httpResponse.body)); | ||
@@ -151,0 +151,0 @@ } catch (ex) { |
@@ -113,3 +113,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
} | ||
return (/**@type {!webdriver.Locator} */locator); | ||
return /**@type {!webdriver.Locator} */ (locator); | ||
}; | ||
@@ -116,0 +116,0 @@ |
@@ -22,12 +22,26 @@ // Copyright 2013 Selenium comitters | ||
/** | ||
* Log level names from WebDriver's JSON wire protocol. | ||
* @enum {string} | ||
*/ | ||
webdriver.logging.LevelName = { | ||
ALL: 'ALL', | ||
DEBUG: 'DEBUG', | ||
INFO: 'INFO', | ||
WARNING: 'WARNING', | ||
SEVERE: 'SEVERE', | ||
OFF: 'OFF' | ||
}; | ||
/** | ||
* Logging levels. | ||
* @enum {{value: number, name: string}} | ||
* @enum {{value: number, name: webdriver.logging.LevelName}} | ||
*/ | ||
webdriver.logging.Level = { | ||
ALL: {value: Number.MIN_VALUE, name: 'ALL'}, | ||
DEBUG: {value: 700, name: 'DEBUG'}, | ||
INFO: {value: 800, name: 'INFO'}, | ||
WARNING: {value: 900, name: 'WARNING'}, | ||
SEVERE: {value: 1000, name: 'SEVERE'}, | ||
OFF: {value: Number.MAX_VALUE, name: 'OFF'} | ||
ALL: {value: Number.MIN_VALUE, name: webdriver.logging.LevelName.ALL}, | ||
DEBUG: {value: 700, name: webdriver.logging.LevelName.DEBUG}, | ||
INFO: {value: 800, name: webdriver.logging.LevelName.INFO}, | ||
WARNING: {value: 900, name: webdriver.logging.LevelName.WARNING}, | ||
SEVERE: {value: 1000, name: webdriver.logging.LevelName.SEVERE}, | ||
OFF: {value: Number.MAX_VALUE, name: webdriver.logging.LevelName.OFF} | ||
}; | ||
@@ -59,6 +73,11 @@ | ||
webdriver.logging.Type = { | ||
/** Logs originating from the browser. */ | ||
BROWSER: 'browser', | ||
/** Logs from a WebDriver client. */ | ||
CLIENT: 'client', | ||
/** Logs from a WebDriver implementation. */ | ||
DRIVER: 'driver', | ||
PROFILER: 'profiler', | ||
/** Logs related to performance. */ | ||
PERFORMANCE: 'performance', | ||
/** Logs from the remote server. */ | ||
SERVER: 'server' | ||
@@ -69,2 +88,9 @@ }; | ||
/** | ||
* A hash describing log preferences. | ||
* @typedef {Object.<webdriver.logging.Type, webdriver.logging.LevelName>} | ||
*/ | ||
webdriver.logging.Preferences; | ||
/** | ||
* A single log entry. | ||
@@ -71,0 +97,0 @@ * @param {(!webdriver.logging.Level|string)} level The entry level. |
@@ -51,2 +51,3 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
goog.provide('webdriver.promise.ControlFlow'); | ||
goog.provide('webdriver.promise.ControlFlow.Timer'); | ||
goog.provide('webdriver.promise.Deferred'); | ||
@@ -56,2 +57,3 @@ goog.provide('webdriver.promise.Promise'); | ||
goog.require('goog.array'); | ||
goog.require('goog.debug.Error'); | ||
goog.require('goog.object'); | ||
@@ -271,2 +273,13 @@ goog.require('webdriver.EventEmitter'); | ||
/** | ||
* Removes all of the listeners previously registered on this deferred. | ||
* @throws {Error} If this deferred has already been resolved. | ||
*/ | ||
function removeAll() { | ||
if (!isPending()) { | ||
throw new Error('This Deferred has already been resolved.'); | ||
} | ||
listeners = []; | ||
} | ||
/** | ||
* Notifies all of the listeners registered with this Deferred that its state | ||
@@ -447,6 +460,10 @@ * has changed. Will throw an error if this Deferred has already been | ||
this.fulfill = fulfill; | ||
/** @deprecated Use fulfill instead. This will be removed in 2.34.0 */ | ||
this.resolve = this.callback = fulfill; | ||
this.reject = this.errback = reject; | ||
// Only expose this function to our internal classes. | ||
// TODO: find a cleaner way of handling this. | ||
if (this instanceof webdriver.promise.Task_) { | ||
this.removeAll = removeAll; | ||
} | ||
// Export symbols necessary for the contract on this object to work in | ||
@@ -565,15 +582,5 @@ // compiled mode. | ||
/** | ||
* Creates a promise that has been resolved with the given value. | ||
* @param {*=} opt_value The fulfilled promises's value. | ||
* @return {!webdriver.promise.Promise} A fulfilled promise. | ||
* @deprecated Use webdriver.promise.fulfilled(). This will be removed in | ||
* Selenium 2.34.0. | ||
*/ | ||
webdriver.promise.resolved = webdriver.promise.fulfilled; | ||
/** | ||
* Creates a promise that has been rejected with the given reason. | ||
* @param {*=} opt_reason The rejection reason; may be any value, but is usually an | ||
* Error or a string. | ||
* @param {*=} opt_reason The rejection reason; may be any value, but is | ||
* usually an Error or a string. | ||
* @return {!webdriver.promise.Promise} The rejected promise. | ||
@@ -837,7 +844,4 @@ */ | ||
* | ||
* @param {{clearInterval: function(number), | ||
* clearTimeout: function(number), | ||
* setInterval: function(!Function, number): number, | ||
* setTimeout: function(!Function, number): number}=} opt_timer | ||
* The timer object to use. Should only be set for testing. | ||
* @param {webdriver.promise.ControlFlow.Timer=} opt_timer The timer object | ||
* to use. Should only be set for testing. | ||
* @constructor | ||
@@ -851,6 +855,3 @@ * @extends {webdriver.EventEmitter} | ||
* The timer used by this instance. | ||
* @type {{clearInterval: function(number), | ||
* clearTimeout: function(number), | ||
* setInterval: function(!Function, number): number, | ||
* setTimeout: function(!Function, number): number}} | ||
* @type {webdriver.promise.ControlFlow.Timer} | ||
*/ | ||
@@ -872,7 +873,13 @@ this.timer = opt_timer || webdriver.promise.ControlFlow.defaultTimer; | ||
/** | ||
* @typedef {{clearInterval: function(number), | ||
* clearTimeout: function(number), | ||
* setInterval: function(!Function, number): number, | ||
* setTimeout: function(!Function, number): number}} | ||
*/ | ||
webdriver.promise.ControlFlow.Timer; | ||
/** | ||
* The default timer object, which uses the global timer functions. | ||
* @type {{clearInterval: function(number), | ||
* clearTimeout: function(number), | ||
* setInterval: function(!Function, number): number, | ||
* setTimeout: function(!Function, number): number}} | ||
* @type {webdriver.promise.ControlFlow.Timer} | ||
*/ | ||
@@ -1096,3 +1103,3 @@ webdriver.promise.ControlFlow.defaultTimer = (function() { | ||
/** @type {!Error} */(e).stack = (e.stack || e.stackTrace || '') + [ | ||
/** @type {!Error} */(e).stack += [ | ||
'\n==== async task ====\n', | ||
@@ -1299,3 +1306,3 @@ history.join('\n==== async task ====\n') | ||
var markTaskComplete = goog.bind(function() { | ||
this.history_.push(task); | ||
this.history_.push(/** @type {!webdriver.promise.Task_} */ (task)); | ||
activeFrame.setPendingTask(null); | ||
@@ -1355,3 +1362,3 @@ }, this); | ||
this.activeFrame_ = | ||
(/** @type {webdriver.promise.Frame_} */frame.getParent()); | ||
/** @type {webdriver.promise.Frame_} */ (frame.getParent()); | ||
} | ||
@@ -1393,3 +1400,3 @@ | ||
// enough to recognize this. | ||
var parent = (/** @type {webdriver.promise.Frame_} */ | ||
var parent = /** @type {webdriver.promise.Frame_} */ ( | ||
this.activeFrame_.getParent()); | ||
@@ -1468,7 +1475,11 @@ if (parent) { | ||
} catch (ex) { | ||
removeNewFrame(); | ||
removeNewFrame(new webdriver.promise.CanceledTaskError_(ex)); | ||
errback(ex); | ||
} | ||
function removeNewFrame() { | ||
/** | ||
* @param {webdriver.promise.CanceledTaskError_=} opt_err If provided, the | ||
* error that triggered the removal of this frame. | ||
*/ | ||
function removeNewFrame(opt_err) { | ||
var parent = newFrame.getParent(); | ||
@@ -1478,2 +1489,6 @@ if (parent) { | ||
} | ||
if (opt_err) { | ||
newFrame.cancelRemainingTasks(opt_err); | ||
} | ||
self.activeFrame_ = oldFrame; | ||
@@ -1617,2 +1632,11 @@ } | ||
var reject = goog.bind(this.reject, this); | ||
var cancelRemainingTasks = goog.bind(this.cancelRemainingTasks, this); | ||
/** @override */ | ||
this.reject = function(e) { | ||
cancelRemainingTasks(new webdriver.promise.CanceledTaskError_(e)); | ||
reject(e); | ||
}; | ||
/** | ||
@@ -1675,2 +1699,42 @@ * @private {!Array.<!(webdriver.promise.Frame_|webdriver.promise.Task_)>} | ||
/** | ||
* Marks all of the tasks that are descendants of this frame in the execution | ||
* tree as cancelled. This is necessary for callbacks scheduled asynchronous. | ||
* For example: | ||
* | ||
* var someResult; | ||
* webdriver.promise.createFlow(function(flow) { | ||
* someResult = flow.execute(function() {}); | ||
* throw Error(); | ||
* }).addErrback(function(err) { | ||
* console.log('flow failed: ' + err); | ||
* someResult.then(function() { | ||
* console.log('task succeeded!'); | ||
* }, function(err) { | ||
* console.log('task failed! ' + err); | ||
* }); | ||
* }); | ||
* // flow failed: Error: boom | ||
* // task failed! CanceledTaskError: Task discarded due to a previous | ||
* // task failure: Error: boom | ||
* | ||
* @param {!webdriver.promise.CanceledTaskError_} error The cancellation | ||
* error. | ||
*/ | ||
webdriver.promise.Frame_.prototype.cancelRemainingTasks = function(error) { | ||
goog.array.forEach(this.children_, function(child) { | ||
if (child instanceof webdriver.promise.Frame_) { | ||
child.cancelRemainingTasks(error); | ||
} else { | ||
// None of the previously registered listeners should be notified that | ||
// the task is being canceled, however, we need at least one errback | ||
// to prevent the cancellation from bubbling up. | ||
child.removeAll(); | ||
child.addErrback(goog.nullFunction); | ||
child.cancel(error); | ||
} | ||
}); | ||
}; | ||
/** | ||
* @return {webdriver.promise.Task_} The task currently executing | ||
@@ -1808,3 +1872,3 @@ * within this frame, if any. | ||
var ret = this.description_; | ||
if (stack) { | ||
if (stack.length) { | ||
if (this.description_) { | ||
@@ -1819,3 +1883,23 @@ ret += '\n'; | ||
/** | ||
* Special error used to signal when a task is canceled because a previous | ||
* task in the same frame failed. | ||
* @param {*} err The error that caused the task cancellation. | ||
* @constructor | ||
* @extends {goog.debug.Error} | ||
* @private | ||
*/ | ||
webdriver.promise.CanceledTaskError_ = function(err) { | ||
goog.base(this, 'Task discarded due to a previous task failure: ' + err); | ||
}; | ||
goog.inherits(webdriver.promise.CanceledTaskError_, goog.debug.Error); | ||
/** @override */ | ||
webdriver.promise.CanceledTaskError_.prototype.name = 'CanceledTaskError'; | ||
/** | ||
* The default flow to use if no others are active. | ||
@@ -1822,0 +1906,0 @@ * @private {!webdriver.promise.ControlFlow} |
@@ -17,9 +17,11 @@ // Copyright 2011 Software Freedom Conservancy. All Rights Reserved. | ||
goog.require('webdriver.Capabilities'); | ||
/** | ||
* Contains information about a WebDriver session. | ||
* @param {string} id The session ID. | ||
* @param {!Object.<*>} capabilities A map describing the capabilities | ||
* of this session. | ||
* @param {!(Object|webdriver.Capabilities)} capabilities The session | ||
* capabilities. | ||
* @constructor | ||
@@ -29,13 +31,7 @@ */ | ||
/** | ||
* The session ID. | ||
* @type {string} | ||
*/ | ||
this.id = id; | ||
/** @private {string} */ | ||
this.id_ = id; | ||
/** | ||
* A map describing the capabilities of this session. | ||
* @type {!Object.<*>} | ||
*/ | ||
this.capabilities = capabilities; | ||
/** @private {!webdriver.Capabilities} */ | ||
this.caps_ = new webdriver.Capabilities().merge(capabilities); | ||
}; | ||
@@ -48,3 +44,3 @@ | ||
webdriver.Session.prototype.getId = function() { | ||
return this.id; | ||
return this.id_; | ||
}; | ||
@@ -54,6 +50,6 @@ | ||
/** | ||
* @return {!Object.<*>} This session's capabilities. | ||
* @return {!webdriver.Capabilities} This session's capabilities. | ||
*/ | ||
webdriver.Session.prototype.getCapabilities = function() { | ||
return this.capabilities; | ||
return this.caps_; | ||
}; | ||
@@ -68,3 +64,3 @@ | ||
webdriver.Session.prototype.getCapability = function(key) { | ||
return this.capabilities[key]; | ||
return this.caps_.get(key); | ||
}; | ||
@@ -79,3 +75,3 @@ | ||
webdriver.Session.prototype.toJSON = function() { | ||
return this.id; | ||
return this.getId(); | ||
}; |
@@ -27,2 +27,3 @@ // Copyright 2009 The Closure Library Authors. All Rights Reserved. | ||
goog.require('goog.string'); | ||
goog.require('goog.userAgent'); | ||
@@ -43,11 +44,19 @@ | ||
/** @private {!Error} */ | ||
this.error_ = Error(); | ||
var error; | ||
if (webdriver.stacktrace.CAN_CAPTURE_STACK_TRACE_) { | ||
Error.captureStackTrace(this.error_, webdriver.stacktrace.Snapshot); | ||
error = Error(); | ||
Error.captureStackTrace(error, webdriver.stacktrace.Snapshot); | ||
} else { | ||
// Opera and Firefox do not generate a stack frame for calls to Error(), | ||
// so just remove 1 extra for the call to this constructor. | ||
// Remove 1 extra frame for the call to this constructor. | ||
this.slice_ += 1; | ||
// IE will only create a stack trace when the Error is thrown. | ||
// We use null.x() to throw an exception instead of throw this.error_ | ||
// because the closure compiler may optimize throws to a function call | ||
// in an attempt to minimize the binary size which in turn has the side | ||
// effect of adding an unwanted stack frame. | ||
try { | ||
null.x(); | ||
} catch (e) { | ||
error = e; | ||
} | ||
} | ||
@@ -60,3 +69,3 @@ | ||
*/ | ||
this.stack_ = this.error_.stack; | ||
this.stack_ = webdriver.stacktrace.getStack_(error); | ||
}; | ||
@@ -76,5 +85,20 @@ | ||
/** | ||
* Whether the current browser supports stack traces. | ||
* | ||
* @type {boolean} | ||
* @const | ||
*/ | ||
webdriver.stacktrace.BROWSER_SUPPORTED = (function() { | ||
try { | ||
throw Error(); | ||
} catch (e) { | ||
return !!e.stack; | ||
} | ||
})(); | ||
/** | ||
* The parsed stack trace. This list is lazily generated the first time it is | ||
* accessed. | ||
* @private {?string} | ||
* @private {Array.<!webdriver.stacktrace.Frame>} | ||
*/ | ||
@@ -85,12 +109,10 @@ webdriver.stacktrace.Snapshot.prototype.parsedStack_ = null; | ||
/** | ||
* @return {string} The parsed stack trace. | ||
* @return {!Array.<!webdriver.stacktrace.Frame>} The parsed stack trace. | ||
*/ | ||
webdriver.stacktrace.Snapshot.prototype.getStacktrace = function() { | ||
if (goog.isNull(this.parsedStack_)) { | ||
var stack = webdriver.stacktrace.parse(this.error_); | ||
this.parsedStack_ = webdriver.stacktrace.parse_(this.stack_); | ||
if (this.slice_) { | ||
stack = goog.array.slice(stack, this.slice_); | ||
this.parsedStack_ = goog.array.slice(this.parsedStack_, this.slice_); | ||
} | ||
this.parsedStack_ = stack.join('\n'); | ||
delete this.error_; | ||
delete this.slice_; | ||
@@ -116,5 +138,4 @@ delete this.stack_; | ||
* @constructor | ||
* @private | ||
*/ | ||
webdriver.stacktrace.Frame_ = function(context, name, alias, path) { | ||
webdriver.stacktrace.Frame = function(context, name, alias, path) { | ||
@@ -132,2 +153,20 @@ /** @private {string} */ | ||
this.path_ = path || ''; | ||
/** @private {string} */ | ||
this.url_ = this.path_; | ||
/** @private {number} */ | ||
this.line_ = -1; | ||
/** @private {number} */ | ||
this.column_ = -1; | ||
if (path) { | ||
var match = /:(\d+)(?::(\d+))?$/.exec(path); | ||
if (match) { | ||
this.line_ = Number(match[1]); | ||
this.column = Number(match[2] || -1); | ||
this.url_ = path.substr(0, match.index); | ||
} | ||
} | ||
}; | ||
@@ -138,7 +177,7 @@ | ||
* Constant for an anonymous frame. | ||
* @private {!webdriver.stacktrace.Frame_} | ||
* @private {!webdriver.stacktrace.Frame} | ||
* @const | ||
*/ | ||
webdriver.stacktrace.ANONYMOUS_FRAME_ = | ||
new webdriver.stacktrace.Frame_('', '', '', ''); | ||
new webdriver.stacktrace.Frame('', '', '', ''); | ||
@@ -150,3 +189,3 @@ | ||
*/ | ||
webdriver.stacktrace.Frame_.prototype.getName = function() { | ||
webdriver.stacktrace.Frame.prototype.getName = function() { | ||
return this.name_; | ||
@@ -157,5 +196,29 @@ }; | ||
/** | ||
* @return {string} The url or empty string if it is unknown. | ||
*/ | ||
webdriver.stacktrace.Frame.prototype.getUrl = function() { | ||
return this.url_; | ||
}; | ||
/** | ||
* @return {number} The line number if known or -1 if it is unknown. | ||
*/ | ||
webdriver.stacktrace.Frame.prototype.getLine = function() { | ||
return this.line_; | ||
}; | ||
/** | ||
* @return {number} The column number if known and -1 if it is unknown. | ||
*/ | ||
webdriver.stacktrace.Frame.prototype.getColumn = function() { | ||
return this.column_; | ||
}; | ||
/** | ||
* @return {boolean} Whether the stack frame contains an anonymous function. | ||
*/ | ||
webdriver.stacktrace.Frame_.prototype.isAnonymous = function() { | ||
webdriver.stacktrace.Frame.prototype.isAnonymous = function() { | ||
return !this.name_ || this.context_ == '[object Object]'; | ||
@@ -171,3 +234,3 @@ }; | ||
*/ | ||
webdriver.stacktrace.Frame_.prototype.toString = function() { | ||
webdriver.stacktrace.Frame.prototype.toString = function() { | ||
var context = this.context_; | ||
@@ -283,3 +346,3 @@ if (context && context !== 'new ') { | ||
webdriver.stacktrace.URL_PATTERN_ = | ||
'((?:http|https|file)://[^\\s)]+|javascript:.*)'; | ||
'((?:http|https|file)://[^\\s]+|javascript:.*)'; | ||
@@ -310,2 +373,13 @@ | ||
/** | ||
* RegExp pattern for function names in the Firefox stack trace. | ||
* Firefox has extended identifiers to deal with inner functions and anonymous | ||
* functions: https://bugzilla.mozilla.org/show_bug.cgi?id=433529#c9 | ||
* @private {string} | ||
* @const | ||
*/ | ||
webdriver.stacktrace.FIREFOX_FUNCTION_NAME_PATTERN_ = | ||
webdriver.stacktrace.IDENTIFIER_PATTERN_ + '[\\w./<$]*'; | ||
/** | ||
* RegExp pattern for function call in the Firefox stack trace. | ||
@@ -317,3 +391,3 @@ * Creates a submatch for the function name. | ||
webdriver.stacktrace.FIREFOX_FUNCTION_CALL_PATTERN_ = | ||
'(' + webdriver.stacktrace.IDENTIFIER_PATTERN_ + ')?' + | ||
'(' + webdriver.stacktrace.FIREFOX_FUNCTION_NAME_PATTERN_ + ')?' + | ||
'(?:\\(.*\\))?@'; | ||
@@ -367,2 +441,23 @@ | ||
/** | ||
* RegExp pattern for function call in a Chakra (IE) stack trace. This | ||
* expression allows for identifiers like 'Anonymous function', 'eval code', | ||
* and 'Global code'. | ||
* @private {string} | ||
* @const | ||
*/ | ||
webdriver.stacktrace.CHAKRA_FUNCTION_CALL_PATTERN_ = '(' + | ||
webdriver.stacktrace.IDENTIFIER_PATTERN_ + '(?:\\s+\\w+)*)'; | ||
/** | ||
* Regular expression for parsing on stack frame in Chakra (IE). | ||
* @private {!RegExp} | ||
* @const | ||
*/ | ||
webdriver.stacktrace.CHAKRA_STACK_FRAME_REGEXP_ = new RegExp('^ at ' + | ||
webdriver.stacktrace.CHAKRA_FUNCTION_CALL_PATTERN_ + | ||
'\\s*(?:\\((.*)\\))$'); | ||
/** | ||
* Placeholder for an unparsable frame in a stack trace generated by | ||
@@ -412,3 +507,3 @@ * {@link goog.testing.stacktrace}. | ||
* @param {string} frameStr The stack frame as string. | ||
* @return {webdriver.stacktrace.Frame_} Stack frame object or null if the | ||
* @return {webdriver.stacktrace.Frame} Stack frame object or null if the | ||
* parsing failed. | ||
@@ -420,3 +515,3 @@ * @private | ||
if (m) { | ||
return new webdriver.stacktrace.Frame_( | ||
return new webdriver.stacktrace.Frame( | ||
m[1] || m[2], m[3], m[4], m[5] || m[6]); | ||
@@ -432,3 +527,3 @@ } | ||
if (m) { | ||
return new webdriver.stacktrace.Frame_('', m[1], '', m[2]); | ||
return new webdriver.stacktrace.Frame('', m[1], '', m[2]); | ||
} | ||
@@ -438,5 +533,10 @@ | ||
if (m) { | ||
return new webdriver.stacktrace.Frame_(m[2], m[1] || m[3], '', m[4]); | ||
return new webdriver.stacktrace.Frame(m[2], m[1] || m[3], '', m[4]); | ||
} | ||
m = frameStr.match(webdriver.stacktrace.CHAKRA_STACK_FRAME_REGEXP_); | ||
if (m) { | ||
return new webdriver.stacktrace.Frame('', m[1], '', m[2]); | ||
} | ||
if (frameStr == webdriver.stacktrace.UNKNOWN_CLOSURE_FRAME_ || | ||
@@ -449,3 +549,3 @@ frameStr == webdriver.stacktrace.ANONYMOUS_CLOSURE_FRAME_) { | ||
if (m) { | ||
return new webdriver.stacktrace.Frame_(m[1], m[2], m[3], m[4] || m[5]); | ||
return new webdriver.stacktrace.Frame(m[1], m[2], m[3], m[4] || m[5]); | ||
} | ||
@@ -460,3 +560,3 @@ | ||
* @param {string} frameStr The stack frame as string. | ||
* @return {!webdriver.stacktrace.Frame_} Stack frame object. | ||
* @return {!webdriver.stacktrace.Frame} Stack frame object. | ||
* @private | ||
@@ -476,3 +576,3 @@ */ | ||
} | ||
return new webdriver.stacktrace.Frame_('', functionName, '', loc); | ||
return new webdriver.stacktrace.Frame('', functionName, '', loc); | ||
}; | ||
@@ -482,2 +582,21 @@ | ||
/** | ||
* Get an error's stack trace with the error string trimmed. | ||
* V8 prepends the string representation of an error to its stack trace. | ||
* This function trims the string so that the stack trace can be parsed | ||
* consistently with the other JS engines. | ||
* @param {!(Error|goog.testing.JsUnitException)} error The error. | ||
* @return {string} The stack trace string. | ||
* @private | ||
*/ | ||
webdriver.stacktrace.getStack_ = function(error) { | ||
var stack = error.stack || error.stackTrace || ''; | ||
var errorStr = error + '\n'; | ||
if (goog.string.startsWith(stack, errorStr)) { | ||
stack = stack.substring(errorStr.length); | ||
} | ||
return stack; | ||
}; | ||
/** | ||
* Formats an error's stack trace. | ||
@@ -488,7 +607,17 @@ * @param {!(Error|goog.testing.JsUnitException)} error The error to format. | ||
webdriver.stacktrace.format = function(error) { | ||
var stack = webdriver.stacktrace.parse(error).join('\n'); | ||
var stack = webdriver.stacktrace.getStack_(error); | ||
var frames = webdriver.stacktrace.parse_(stack); | ||
// Older versions of IE simply return [object Error] for toString(), so | ||
// only use that as a last resort. | ||
var errorStr = ''; | ||
if (error.message) { | ||
errorStr = (error.name ? error.name + ': ' : '') + error.message; | ||
} else { | ||
errorStr = error.toString(); | ||
} | ||
// Ensure the error is in the V8 style with the error's string representation | ||
// prepended to the stack. | ||
error.stack = error.toString() + '\n' + stack; | ||
error.stack = errorStr + '\n' + frames.join('\n'); | ||
return error; | ||
@@ -500,9 +629,8 @@ }; | ||
* Parses an Error object's stack trace. | ||
* @param {!(Error|goog.testing.JsUnitException)} error The error. | ||
* @return {!Array.<webdriver.stacktrace.Frame_>} Stack frames. The | ||
* @param {string} stack The stack trace. | ||
* @return {!Array.<!webdriver.stacktrace.Frame>} Stack frames. The | ||
* unrecognized frames will be nulled out. | ||
* @private | ||
*/ | ||
webdriver.stacktrace.parse = function(error) { | ||
var stack = error.stack || error.stackTrace; | ||
webdriver.stacktrace.parse_ = function(stack) { | ||
if (!stack) { | ||
@@ -512,11 +640,2 @@ return []; | ||
// V8 prepends the string representation of an error to its stack trace. | ||
// Remove this so the stack trace is parsed consistently with the other JS | ||
// engines. | ||
var errorStr = error + '\n'; | ||
if (goog.string.startsWith(stack, errorStr)) { | ||
stack = stack.substring(errorStr.length); | ||
} | ||
var lines = stack. | ||
@@ -528,3 +647,11 @@ replace(/\s*$/, ''). | ||
var frame = webdriver.stacktrace.parseStackFrame_(lines[i]); | ||
frames.push(frame || webdriver.stacktrace.ANONYMOUS_FRAME_); | ||
// The first two frames will be: | ||
// webdriver.stacktrace.Snapshot() | ||
// webdriver.stacktrace.get() | ||
// In the case of Opera, sometimes an extra frame is injected in the next | ||
// frame with a reported line number of zero. The next line detects that | ||
// case and skips that frame. | ||
if (!(goog.userAgent.OPERA && i == 2 && frame.getLine() == 0)) { | ||
frames.push(frame || webdriver.stacktrace.ANONYMOUS_FRAME_); | ||
} | ||
} | ||
@@ -539,3 +666,3 @@ return frames; | ||
* this function. | ||
* @return {string} The stack trace in canonical format. | ||
* @return {!Array.<!webdriver.stacktrace.Frame>} The frames of the stack trace. | ||
*/ | ||
@@ -542,0 +669,0 @@ webdriver.stacktrace.get = function() { |
@@ -64,3 +64,3 @@ // Copyright 2013 Selenium committers | ||
* Retrieves the external IP address for this host. | ||
* @param {string} opt_family The IP family to retrieve. Defaults to "IPv4". | ||
* @param {string=} opt_family The IP family to retrieve. Defaults to "IPv4". | ||
* @return {string} The IP address or undefined if not available. | ||
@@ -75,3 +75,3 @@ */ | ||
* Retrieves a loopback address for this machine. | ||
* @param {string} opt_family The IP family to retrieve. Defaults to "IPv4". | ||
* @param {string=} opt_family The IP family to retrieve. Defaults to "IPv4". | ||
* @return {string} The IP address or undefined if not available. | ||
@@ -78,0 +78,0 @@ */ |
@@ -55,3 +55,3 @@ // Copyright 2013 Selenium committers | ||
return systemRange = range.addErrback(function() { | ||
DEFAULT_IANA_RANGE; | ||
return DEFAULT_IANA_RANGE; | ||
}); | ||
@@ -73,3 +73,3 @@ } | ||
} else { | ||
result.resolve(stdout); | ||
result.fulfill(stdout); | ||
} | ||
@@ -96,3 +96,3 @@ }); | ||
cmd = 'sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last' + | ||
' | sed -e "s/.*:\s*//"'; | ||
' | sed -e "s/.*:\\s*//"'; | ||
} | ||
@@ -159,3 +159,3 @@ | ||
if (e.code === 'EADDRINUSE') { | ||
result.resolve(false); | ||
result.fulfill(false); | ||
} else { | ||
@@ -168,3 +168,3 @@ result.reject(e); | ||
server.close(function() { | ||
result.resolve(true); | ||
result.fulfill(true); | ||
}); | ||
@@ -174,3 +174,3 @@ }); | ||
return result.promise; | ||
}; | ||
} | ||
@@ -200,3 +200,3 @@ | ||
if (isFree) { | ||
deferredPort.resolve(port); | ||
deferredPort.fulfill(port); | ||
} else { | ||
@@ -208,3 +208,3 @@ findPort(); | ||
}); | ||
}; | ||
} | ||
@@ -211,0 +211,0 @@ |
{ | ||
"name": "selenium-webdriver", | ||
"version": "2.33.0", | ||
"version": "2.34.0", | ||
"description": "The official WebDriver JavaScript bindings from the Selenium project", | ||
"keywords": [ | ||
"automation", | ||
"selenium", | ||
"testing", | ||
"webdriver", | ||
"webdriverjs" | ||
"automation", | ||
"selenium", | ||
"testing", | ||
"webdriver", | ||
"webdriverjs" | ||
], | ||
@@ -18,8 +18,14 @@ "homepage": "https://code.google.com/p/selenium/", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://code.google.com/p/selenium/" | ||
"type": "git", | ||
"url": "https://code.google.com/p/selenium/" | ||
}, | ||
"engines": { | ||
"node": ">= 0.8.x" | ||
"node": ">= 0.8.x" | ||
}, | ||
"devDependencies" : { | ||
"mocha" : "~1.10.0" | ||
}, | ||
"scripts": { | ||
"test": "node_modules/mocha/bin/mocha -R list --recursive test" | ||
} | ||
} |
# selenium-webdriver | ||
## Installation | ||
Install the latest published version using `npm`: | ||
npm install selenium-webdriver | ||
In addition to the npm package, you will to download the WebDriver | ||
implementations you wish to utilize. As of 2.34.0, `selenium-webdriver` | ||
natively supports the [ChromeDriver](https://code.google.com/p/chromedriver/downloads/list). | ||
Simply download a copy and make sure it can be found on your `PATH`. The other | ||
drivers (e.g. Firefox, Internet Explorer, and Safari), still require the | ||
[standalone Selenium server](https://code.google.com/p/selenium/downloads/list). | ||
### Running the tests | ||
_(New in 2.34.0)_ To run the tests, you will need to download a copy of the | ||
[ChromeDriver](https://code.google.com/p/chromedriver/downloads/list) and make | ||
sure it can be found on your `PATH`. | ||
npm test selenium-webdriver | ||
To run the tests against multiple browsers, download the | ||
[Selenium server](https://code.google.com/p/selenium/downloads/list) and | ||
specify its location through the `SELENIUM_SERVER_JAR` environment variable. | ||
You can use the `SELENIUM_BROWSER` environment variable to define a | ||
comma-separated list of browsers you wish to test against. For example: | ||
export SELENIUM_SERVER_JAR=path/to/selenium-server-standalone-2.33.0.jar | ||
SELENIUM_BROWSER=chrome,firefox npm test selenium-webdriver | ||
## Usage | ||
var webdriver = require('selenium-webdriver'); | ||
var driver = new webdriver.Builder(). | ||
withCapabilities({'browserName': 'firefox'}). | ||
withCapabilities(webdriver.Capabilities.chrome()). | ||
build(); | ||
@@ -8,0 +41,0 @@ |
@@ -1,2 +0,1 @@ | ||
// Copyright 2013 Selenium committers | ||
// Copyright 2013 Software Freedom Conservancy | ||
@@ -20,3 +19,5 @@ // | ||
os = require('os'), | ||
url = require('url'); | ||
path = require('path'), | ||
url = require('url'), | ||
util = require('util'); | ||
@@ -31,46 +32,63 @@ var promise = require('../').promise, | ||
/** | ||
* Manages the life and death of the Selenium standalone server. The server | ||
* may be obtained from https://code.google.com/p/selenium/downloads/list. | ||
* Configuration options for a DriverService instance. | ||
* - port: The port to start the server on (must be > 0). If the port is | ||
* provided as a promise, the service will wait for the promise to | ||
* resolve before starting. | ||
* - args: The arguments to pass to the service. If a promise is provided, | ||
* the service will wait for it to resolve before starting. | ||
* - path: The base path on the server for the WebDriver wire protocol | ||
* (e.g. '/wd/hub'). Defaults to '/'. | ||
* - env: The environment variables that should be visible to the server | ||
* process. Defaults to inheriting the current process's environment. | ||
* - stdio: IO configuration for the spawned server process. For more | ||
* information, refer to the documentation of | ||
* {@code child_process.spawn}. | ||
* | ||
* <p>The options argument accepts the following properties: | ||
* <dl> | ||
* <dt>jar | ||
* <dd>Path to the Selenium server jar. | ||
* <dt>port | ||
* <dd>The port to start the server on, or 0 for any free port. | ||
* Defaults to 0. | ||
* <dt>jvmArgs | ||
* <dd>Arguments to pass to the JVM. | ||
* <dt>args | ||
* <dd>Arguments to pass to the server. | ||
* <dt>env | ||
* <dd>Environment to run the server in. Defaults to the current environment. | ||
* <dt>stdio | ||
* <dd>The fd configuration for the child process, as defined by | ||
* child_process.spawn. Defaults to 'ignore'. | ||
* <dt> | ||
* </dl> | ||
* @typedef {{ | ||
* port: (number|!webdriver.promise.Promise.<number>), | ||
* args: !(Array.<string>|webdriver.promise.Promise.<!Array.<string>>), | ||
* path: (string|undefined), | ||
* env: (!Object.<string, string>|undefined), | ||
* stdio: (string|!Array.<string|number|!Stream|null|undefined>|undefined) | ||
* }} | ||
*/ | ||
var ServiceOptions; | ||
/** | ||
* Manages the life and death of a native executable WebDriver server. | ||
* | ||
* @param {!Object} options A hash describing the server parameters. | ||
* @throws {Error} If the port is < 0. | ||
* <p>It is expected that the driver server implements the | ||
* <a href="http://code.google.com/p/selenium/wiki/JsonWireProtocol">WebDriver | ||
* Wire Protocol</a>. Furthermore, the managed server should support multiple | ||
* concurrent sessions, so that this class may be reused for multiple clients. | ||
* | ||
* @param {string} executable Path to the executable to run. | ||
* @param {!ServiceOptions} options Configuration options for the service. | ||
* @constructor | ||
*/ | ||
function SeleniumServer(options) { | ||
this.jar_ = options.jar; | ||
this.port_ = options.port || 0; | ||
this.jvmArgs_ = options.jvmArgs || []; | ||
this.args_ = options.args || []; | ||
this.env_ = options.env; | ||
this.stdio_ = options.stdio || 'ignore'; | ||
function DriverService(executable, options) { | ||
if (!this.jar_) { | ||
throw Error('Path to the Selenium jar must be provided'); | ||
} | ||
/** @private {string} */ | ||
this.executable_ = executable; | ||
if (this.port_ < 0) { | ||
throw Error('Port must be > 0: ' + this.port_); | ||
} | ||
}; | ||
/** @private {(number|!webdriver.promise.Promise.<number>)} */ | ||
this.port_ = options.port; | ||
/** | ||
* @private {!(Array.<string>|webdriver.promise.Promise.<!Array.<string>>)} | ||
*/ | ||
this.args_ = options.args; | ||
/** @private {string} */ | ||
this.path_ = options.path || '/'; | ||
/** @private {!Object.<string, string>} */ | ||
this.env_ = options.env || process.env; | ||
/** @private {(string|!Array.<string|number|!Stream|null|undefined>)} */ | ||
this.stdio_ = options.stdio || 'ignore'; | ||
} | ||
/** | ||
@@ -81,7 +99,7 @@ * The default amount of time, in milliseconds, to wait for the server to | ||
*/ | ||
SeleniumServer.DEFAULT_START_TIMEOUT_MS = 30 * 1000; | ||
DriverService.DEFAULT_START_TIMEOUT_MS = 30 * 1000; | ||
/** @private {child_process.ChildProcess} */ | ||
SeleniumServer.prototype.process_ = null; | ||
DriverService.prototype.process_ = null; | ||
@@ -94,3 +112,3 @@ | ||
*/ | ||
SeleniumServer.prototype.address_ = null; | ||
DriverService.prototype.address_ = null; | ||
@@ -103,3 +121,3 @@ | ||
*/ | ||
SeleniumServer.prototype.shutdownHook_ = null; | ||
DriverService.prototype.shutdownHook_ = null; | ||
@@ -110,5 +128,5 @@ | ||
* the server's address. | ||
* @throws {Error} If the SeleniumServer has not been started. | ||
* @throws {Error} If the server has not been started. | ||
*/ | ||
SeleniumServer.prototype.address = function() { | ||
DriverService.prototype.address = function() { | ||
if (this.address_) { | ||
@@ -122,2 +140,10 @@ return this.address_; | ||
/** | ||
* @return {boolean} Whether the underlying service process is running. | ||
*/ | ||
DriverService.prototype.isRunning = function() { | ||
return !!this.address_; | ||
}; | ||
/** | ||
* Starts the server if it is not already running. | ||
@@ -131,3 +157,3 @@ * @param {number=} opt_timeoutMs How long to wait, in milliseconds, for the | ||
*/ | ||
SeleniumServer.prototype.start = function(opt_timeoutMs) { | ||
DriverService.prototype.start = function(opt_timeoutMs) { | ||
if (this.address_) { | ||
@@ -137,47 +163,49 @@ return this.address_; | ||
var timeout = opt_timeoutMs || SeleniumServer.DEFAULT_START_TIMEOUT_MS; | ||
var port = this.port_ || portprober.findFreePort(); | ||
var timeout = opt_timeoutMs || DriverService.DEFAULT_START_TIMEOUT_MS; | ||
var self = this; | ||
this.address_ = promise.defer(); // TODO(jleyba): handle cancellation. | ||
this.address_.resolve(promise.when(port, function(port) { | ||
var args = self.jvmArgs_.concat( | ||
'-jar', self.jar_, '-port', port, self.args_); | ||
this.address_ = promise.defer(); | ||
this.address_.fulfill(promise.when(this.port_, function(port) { | ||
if (port <= 0) { | ||
throw Error('Port must be > 0: ' + port); | ||
} | ||
return promise.when(self.args_, function(args) { | ||
self.process_ = spawn(self.executable_, args, { | ||
env: self.env_, | ||
stdio: self.stdio_ | ||
}).once('exit', onServerExit); | ||
self.process_ = spawn('java', args, { | ||
env: self.env_ || process.env, | ||
stdio: self.stdio_ | ||
}).once('exit', function(code, signal) { | ||
if (self.address_.isPending()) { | ||
var error = Error(code == null ? | ||
('Server was killed with ' + signal) : | ||
('Server exited with ' + code)); | ||
self.address_.reject(error); | ||
} | ||
process.once('exit', killServer); | ||
if (self.shutdownHook_ && self.shutdownHook_.isPending()) { | ||
self.shutdownHook_.resolve(); | ||
} | ||
var serverUrl = url.format({ | ||
protocol: 'http', | ||
hostname: net.getAddress() || net.getLoopbackAddress(), | ||
port: port, | ||
pathname: self.path_ | ||
}); | ||
self.shutdownHook_ = null; | ||
self.address_ = null; | ||
self.process_ = null; | ||
process.removeListener('exit', killServer); | ||
return httpUtil.waitForServer(serverUrl, timeout).then(function() { | ||
return serverUrl; | ||
}); | ||
}); | ||
})); | ||
process.once('exit', killServer); | ||
return this.address_; | ||
var serverUrl = url.format({ | ||
protocol: 'http', | ||
hostname: net.getAddress(), | ||
port: port, | ||
pathname: '/wd/hub' | ||
}); | ||
function onServerExit(code, signal) { | ||
if (self.address_.isPending()) { | ||
self.address_.reject(code == null ? | ||
Error('Server was killed with ' + signal) : | ||
Error('Server exited with ' + code)); | ||
} | ||
return httpUtil.waitForServer(serverUrl, timeout).then(function() { | ||
return serverUrl; | ||
}); | ||
})); | ||
if (self.shutdownHook_ && self.shutdownHook_.isPending()) { | ||
self.shutdownHook_.fulfill(); | ||
} | ||
return this.address_; | ||
self.shutdownHook_ = null; | ||
self.address_ = null; | ||
self.process_ = null; | ||
process.removeListener('exit', killServer); | ||
} | ||
@@ -192,11 +220,11 @@ function killServer() { | ||
/** | ||
* Stops the server if it is currently running. This function will kill the | ||
* server immediately. To synchronize with the active control flow, use | ||
* {@link #stop}. | ||
* Stops the service if it is not currently running. This function will kill | ||
* the server immediately. To synchronize with the active control flow, use | ||
* {@link #stop()}. | ||
* @return {!webdriver.promise.Promise} A promise that will be resolved when | ||
* the server has been stopped. | ||
*/ | ||
SeleniumServer.prototype.kill = function() { | ||
DriverService.prototype.kill = function() { | ||
if (!this.address_) { | ||
return promise.resolved(); // Not currently running. | ||
return promise.fulfilled(); // Not currently running. | ||
} | ||
@@ -206,3 +234,4 @@ | ||
// No process: still starting; wait on address. | ||
// Otherwise, kill process now. Exit handler will resolve shutdown hook. | ||
// Otherwise, kill the process now. Exit handler will resolve the | ||
// shutdown hook. | ||
if (this.process_) { | ||
@@ -228,9 +257,47 @@ this.shutdownHook_ = promise.defer(); | ||
*/ | ||
SeleniumServer.prototype.stop = function() { | ||
DriverService.prototype.stop = function() { | ||
return promise.controlFlow().execute(this.kill.bind(this)); | ||
}; | ||
/** | ||
* Manages the life and death of the Selenium standalone server. The server | ||
* may be obtained from https://code.google.com/p/selenium/downloads/list. | ||
* @param {string} jar Path to the Selenium server jar. | ||
* @param {!ServiceOptions} options Configuration options for the server. | ||
* @throws {Error} If an invalid port is specified. | ||
* @constructor | ||
* @extends {DriverService} | ||
*/ | ||
function SeleniumServer(jar, options) { | ||
if (options.port < 0) | ||
throw Error('Port must be >= 0: ' + options.port); | ||
var port = options.port || portprober.findFreePort(); | ||
var args = promise.when(options.args || [], function(args) { | ||
return promise.when(port, function(port) { | ||
return args.concat('-jar', jar, '-port', port); | ||
}); | ||
}); | ||
DriverService.call(this, 'java', { | ||
port: port, | ||
args: args, | ||
path: '/wd/hub', | ||
env: options.env, | ||
stdio: options.stdio | ||
}); | ||
} | ||
util.inherits(SeleniumServer, DriverService); | ||
// PUBLIC API | ||
/** @constructor */ | ||
exports.DriverService = DriverService; | ||
/** @constructor */ | ||
exports.SeleniumServer = SeleniumServer; |
@@ -78,4 +78,2 @@ // Copyright 2013 Selenium committers | ||
var assert = require('assert'); | ||
var flow = require('..').promise.controlFlow(); | ||
@@ -133,24 +131,27 @@ | ||
* if the test should be suppressed. This function MUST be synchronous. | ||
* @return {!Object} A wrapped version of exports.it that ignores tests as | ||
* indicated by the predicate. | ||
* @return {!Object} An object with wrapped versions of exports.it and | ||
* exports.describe that ignore tests as indicated by the predicate. | ||
*/ | ||
function ignore(predicateFn) { | ||
var it = function(title, fn) { | ||
if (predicateFn()) { | ||
exports.xit(title, fn); | ||
} else { | ||
exports.it(title, fn); | ||
} | ||
}; | ||
var describe = wrap(exports.xdescribe, exports.describe); | ||
describe.only = wrap(exports.xdescribe, exports.describe.only); | ||
it.only = function(title, fn) { | ||
if (predicateFn()) { | ||
exports.xit(title, fn); | ||
} else { | ||
exports.it(title, fn); | ||
} | ||
var it = wrap(exports.xit, exports.it); | ||
it.only = wrap(exports.xit, exports.it.only); | ||
return { | ||
describe: describe, | ||
it: it | ||
}; | ||
return {it: it}; | ||
}; | ||
function wrap(onSkip, onRun) { | ||
return function(title, fn) { | ||
if (predicateFn()) { | ||
onSkip(title, fn); | ||
} else { | ||
onRun(title, fn); | ||
} | ||
}; | ||
} | ||
} | ||
@@ -163,2 +164,3 @@ | ||
exports.xdescribe = global.xdescribe; | ||
exports.describe.skip = global.describe.skip; | ||
@@ -165,0 +167,0 @@ exports.after = wrapped(global.after); |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1769464
281
28223
64
1
21
10