protractor
Advanced tools
Comparing version 0.12.1 to 0.13.0
@@ -0,1 +1,46 @@ | ||
# 0.13.0 | ||
_Note: Major version 0 releases are for initial development, and backwards compatible changes may be introduced at any time._ | ||
## Features | ||
- ([ce5f494](https://github.com/angular/protractor/commit/ce5f494289c3750b84c6783339a14342a1b74f3d)) feat(element): element.all now has 'first' and 'last' methods | ||
- ([ef61662](https://github.com/angular/protractor/commit/ef6166232186b3385769f63430819a722052cc44)) feat(runner): allow bypassing the selenium standalone server if running only chrome | ||
Using the config option `chromeOnly` now enables running ChromeDriver directly, | ||
without going through the Selenium Standalone. The chromedriver binary should be | ||
available in your PATH, or should be specified with the config option | ||
`chromeDriver`. | ||
- ([76c094a](https://github.com/angular/protractor/commit/76c094a3fa69511b0311011b0ef2c7343b8e655b)) feat(getLocationAbsUrl) - allows current url to be obtained on IE (and Chrome/Firefox) | ||
- ([6a1c918](https://github.com/angular/protractor/commit/6a1c91848858453d0af712588b51c0bdaa0c9445)) feat(runner): add error message for bad jar path | ||
- ([98bce7e](https://github.com/angular/protractor/commit/98bce7e2ac1e659faf2d8727e1fda210b796525e)) feat(locators): add the ability to add custom element locators with by.addLocator | ||
Custom locators can now be added using by.addLocator(name, script), where | ||
script is a self-contained snippet to be executed on the browser which returns | ||
an array of elements. Closes #236. | ||
- ([c7bcc20](https://github.com/angular/protractor/commit/c7bcc20c07416237f69f7934d257b5ba5bfe8c1f)) chore(angular): update to angular 1.2 | ||
## Bug Fixes | ||
- ([a24eeee](https://github.com/angular/protractor/commit/a24eeee4f08e973ffcecd107b6610ce1c2c5e3f6)) fix(runner): do not error out if only one spec pattern does not match any files | ||
Previously, the runner would throw an error if any one of the spec patterns did not | ||
match any files. Now it logs a warning in that case, and errors out only if there | ||
are no found files in any spec patterns. Closes #260 | ||
- ([f3b3fdb](https://github.com/angular/protractor/commit/f3b3fdbcbc8fe4f3c5915ef0f6eb7c89e339a62e)) fix(element): fix an error where all.then() wasn't calling callbacks. | ||
Closes #267 | ||
- ([137d804](https://github.com/angular/protractor/commit/137d8040778215fd841654d3ca465b71f8719ea5)) fix(jasminewd): patched matcher should understand 'not' | ||
Closes #139. | ||
# 0.12.1 | ||
@@ -2,0 +47,0 @@ |
@@ -18,3 +18,3 @@ Debugging Protractor Tests | ||
``` | ||
protractor debugging/failure_conf.js | ||
protractor debugging/failureConf.js | ||
``` | ||
@@ -45,3 +45,3 @@ | ||
// Run this statement before the line which fails. If protractor is run | ||
// with the debugger (protractor debug debugging/conf.js), the test | ||
// with the debugger (protractor debug <...>), the test | ||
// will pause after loading the webpage but before trying to find the | ||
@@ -59,3 +59,3 @@ // element. | ||
``` | ||
protractor debug debugging/failure_conf.js | ||
protractor debug debugging/failureConf.js | ||
``` | ||
@@ -79,5 +79,5 @@ | ||
```javascript | ||
// In the browser console | ||
> window.clientSideScripts.findInput('user.name'); | ||
// Should return the input element with model 'user.name'. | ||
// In the browser console (e.g. from Chrome Dev Tools) | ||
> window.clientSideScripts.findInputs('username'); | ||
// Should return the input element with model 'username'. | ||
``` | ||
@@ -146,3 +146,3 @@ | ||
``` | ||
protractor debugging/timeout_conf.js | ||
protractor debugging/timeoutConf.js | ||
``` | ||
@@ -149,0 +149,0 @@ |
@@ -43,2 +43,9 @@ FAQ | ||
Angular can't be found on my page | ||
--------------------------------- | ||
Protractor supports angular 1.0.6/1.1.4 and higher - check that your version of Angular is upgraded. | ||
The `angular` variable is expected to be available in the global context. Try opening chrome devtools or firefox and see if `angular` is defined. | ||
How do I deal with my log-in page? | ||
@@ -45,0 +52,0 @@ ---------------------------------- |
@@ -23,3 +23,3 @@ Getting Started | ||
- WebDriver commands are scheduled on a control flow and return promises, not | ||
primitive values. See the [control flow doc](/control-flow.md) for more | ||
primitive values. See the [control flow doc](/docs/control-flow.md) for more | ||
info. | ||
@@ -26,0 +26,0 @@ - To run tests, WebDriverJS needs to talk to a selenium standalone server |
@@ -70,4 +70,5 @@ /** | ||
* resolve to the actual value being tested. | ||
* @param {boolean} not Whether this is being called with 'not' active. | ||
*/ | ||
function wrapMatcher(matcher, actualPromise) { | ||
function wrapMatcher(matcher, actualPromise, not) { | ||
return function(expected) { | ||
@@ -77,6 +78,14 @@ actualPromise.then(function(actual) { | ||
expected.then(function(exp) { | ||
expect(actual)[matcher](exp); | ||
if (not) { | ||
expect(actual).not[matcher](exp) | ||
} else { | ||
expect(actual)[matcher](exp); | ||
} | ||
}); | ||
} else { | ||
expect(actual)[matcher](expected); | ||
if (not) { | ||
expect(actual).not[matcher](expected) | ||
} else { | ||
expect(actual)[matcher](expected); | ||
} | ||
} | ||
@@ -94,3 +103,3 @@ }); | ||
function promiseMatchers(actualPromise) { | ||
var promises = {}; | ||
var promises = {not: {}}; | ||
var env = jasmine.getEnv(); | ||
@@ -100,3 +109,4 @@ var matchersClass = env.currentSpec.matchersClass || env.matchersClass; | ||
for (matcher in matchersClass.prototype) { | ||
promises[matcher] = wrapMatcher(matcher, actualPromise); | ||
promises[matcher] = wrapMatcher(matcher, actualPromise, false); | ||
promises.not[matcher] = wrapMatcher(matcher, actualPromise, true); | ||
}; | ||
@@ -103,0 +113,0 @@ |
@@ -114,2 +114,16 @@ require('../index.js'); | ||
describe('not', function() { | ||
it('should still pass normal synchronous tests', function() { | ||
expect(4).not.toEqual(5); | ||
}); | ||
it('should compare a promise to a primitive', function() { | ||
expect(fakeDriver.getValueA()).not.toEqual('b'); | ||
}); | ||
it('should compare a promise to a promise', function() { | ||
expect(fakeDriver.getValueA()).not.toEqual(fakeDriver.getValueB()); | ||
}); | ||
}); | ||
it('should throw an error with a WebElement actual value', function() { | ||
@@ -116,0 +130,0 @@ var webElement = new webdriver.WebElement(fakeDriver, 'idstring'); |
@@ -31,28 +31,2 @@ /** | ||
/** | ||
* Find an element in the page by their angular binding. | ||
* | ||
* arguments[0] {Element} The scope of the search. | ||
* arguments[1] {string} The binding, e.g. {{cat.name}}. | ||
* | ||
* @return {WebElement} The element containing the binding. | ||
*/ | ||
clientSideScripts.findBinding = function() { | ||
var using = arguments[0] || document; | ||
var binding = arguments[1]; | ||
var bindings = using.getElementsByClassName('ng-binding'); | ||
var matches = []; | ||
for (var i = 0; i < bindings.length; ++i) { | ||
var elemData = angular.element(bindings[i]).data(); | ||
if (!elemData || !elemData.$binding) { | ||
continue; | ||
} | ||
var bindingName = elemData.$binding[0].exp || elemData.$binding; | ||
if (bindingName.indexOf(binding) != -1) { | ||
matches.push(bindings[i]); | ||
} | ||
} | ||
return matches[0]; // We can only return one with webdriver.findElement. | ||
}; | ||
/** | ||
* Find a list of elements in the page by their angular binding. | ||
@@ -84,3 +58,4 @@ * | ||
/** | ||
* Find a row within an ng-repeat. | ||
* Find an array of elements matching a row within an ng-repeat. Always returns | ||
* an array of only one element. | ||
* | ||
@@ -91,32 +66,2 @@ * arguments[0] {Element} The scope of the search. | ||
* | ||
* @return {Element} The row element. | ||
*/ | ||
clientSideScripts.findRepeaterRow = function() { | ||
var using = arguments[0] || document; | ||
var repeater = arguments[1]; | ||
var index = arguments[2]; | ||
var rows = []; | ||
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:']; | ||
for (var p = 0; p < prefixes.length; ++p) { | ||
var attr = prefixes[p] + 'repeat'; | ||
var repeatElems = using.querySelectorAll('[' + attr + ']'); | ||
attr = attr.replace(/\\/g, ''); | ||
for (var i = 0; i < repeatElems.length; ++i) { | ||
if (repeatElems[i].getAttribute(attr).indexOf(repeater) != -1) { | ||
rows.push(repeatElems[i]); | ||
} | ||
} | ||
} | ||
return rows[index]; | ||
}; | ||
/** | ||
* Find an array of elements matching a row within an ng-repeat. There | ||
* will only be one element, but this is necessary for isElementPresent. | ||
* | ||
* arguments[0] {Element} The scope of the search. | ||
* arguments[1] {string} The text of the repeater, e.g. 'cat in cats'. | ||
* arguments[2] {number} The row index. | ||
* | ||
* @return {Array.<Element>} An array of a single element, the row of the | ||
@@ -180,3 +125,3 @@ * repeater. | ||
* | ||
* @return {Element} The element. | ||
* @return {Array.<Element>} The element in an array. | ||
*/ | ||
@@ -221,4 +166,3 @@ clientSideScripts.findRepeaterElement = function() { | ||
} | ||
// We can only return one with webdriver.findElement. | ||
return matches[0]; | ||
return matches; | ||
}; | ||
@@ -277,23 +221,2 @@ | ||
/** | ||
* Find input element by model name. | ||
* | ||
* arguments[0] {Element} The scope of the search. | ||
* arguments[1] {string} The model name. | ||
* | ||
* @return {Element} The first matching input element. | ||
*/ | ||
clientSideScripts.findInput = function() { | ||
var using = arguments[0] || document; | ||
var model = arguments[1]; | ||
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:']; | ||
for (var p = 0; p < prefixes.length; ++p) { | ||
var selector = 'input[' + prefixes[p] + 'model="' + model + '"]'; | ||
var inputs = using.querySelectorAll(selector); | ||
if (inputs.length) { | ||
return inputs[0]; | ||
} | ||
} | ||
}; | ||
/** | ||
* Find an input elements by model name. | ||
@@ -305,3 +228,3 @@ * | ||
* @return {Array.<Element>} The matching input elements. | ||
*/ | ||
*/ | ||
clientSideScripts.findInputs = function() { | ||
@@ -320,23 +243,2 @@ var using = arguments[0] || document; | ||
/** | ||
* Find an select element by model name. | ||
* | ||
* arguments[0] {Element} The scope of the search. | ||
* arguments[1] {string} The model name. | ||
* | ||
* @return {Element} The first matching select element. | ||
*/ | ||
clientSideScripts.findSelect = function() { | ||
var using = arguments[0] || document; | ||
var model = arguments[1]; | ||
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:']; | ||
for (var p = 0; p < prefixes.length; ++p) { | ||
var selector = 'select[' + prefixes[p] + 'model="' + model + '"]'; | ||
var inputs = using.querySelectorAll(selector); | ||
if (inputs.length) { | ||
return inputs[0]; | ||
} | ||
} | ||
}; | ||
/** | ||
@@ -349,3 +251,3 @@ * Find multiple select elements by model name. | ||
* @return {Array.<Element>} The matching select elements. | ||
*/ | ||
*/ | ||
clientSideScripts.findSelects = function() { | ||
@@ -365,24 +267,2 @@ var using = arguments[0] || document; | ||
/** | ||
* Find an selected option element by model name. | ||
* | ||
* arguments[0] {Element} The scope of the search. | ||
* arguments[1] {string} The model name. | ||
* | ||
* @return {Element} The first matching input element. | ||
*/ | ||
clientSideScripts.findSelectedOption = function() { | ||
var using = arguments[0] || document; | ||
var model = arguments[1]; | ||
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:']; | ||
for (var p = 0; p < prefixes.length; ++p) { | ||
var selector = | ||
'select[' + prefixes[p] + 'model="' + model + '"] option:checked'; | ||
var inputs = using.querySelectorAll(selector); | ||
if (inputs.length) { | ||
return inputs[0]; | ||
} | ||
} | ||
}; | ||
/** | ||
* Find selected option elements by model name. | ||
@@ -409,3 +289,3 @@ * | ||
/** | ||
* Find a textarea element by model name. | ||
* Find textarea elements by model name. | ||
* | ||
@@ -415,7 +295,8 @@ * arguments[0] {Element} The scope of the search. | ||
* | ||
* @return {Element} The first matching textarea element. | ||
* @return {Array.<Element>} An array of matching textarea elements. | ||
*/ | ||
clientSideScripts.findTextarea = function() { | ||
clientSideScripts.findTextareas = function() { | ||
var using = arguments[0] || document; | ||
var model = arguments[1]; | ||
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:']; | ||
@@ -426,3 +307,3 @@ for (var p = 0; p < prefixes.length; ++p) { | ||
if (textareas.length) { | ||
return textareas[0]; | ||
return textareas; | ||
} | ||
@@ -477,1 +358,11 @@ } | ||
}; | ||
/** | ||
* Return the current url using $location.absUrl(). | ||
* | ||
* arguments[0] {string} The selector housing an ng-app | ||
*/ | ||
clientSideScripts.getLocationAbsUrl = function() { | ||
var el = document.querySelector(arguments[0]); | ||
return angular.element(el).injector().get('$location').absUrl(); | ||
}; |
@@ -23,20 +23,37 @@ var util = require('util'); | ||
/** | ||
* Add a locator to this instance of ProtractorBy. This locator can then be | ||
* used with element(by.<name>(<args>)). | ||
* | ||
* @param {string} name | ||
* @param {function|string} script A script to be run in the context of | ||
* the browser. This script will be passed an array of arguments | ||
* that begins with the element scoping the search, and then | ||
* contains any args passed into the locator. It should return | ||
* an array of elements. | ||
*/ | ||
ProtractorBy.prototype.addLocator = function(name, script) { | ||
this[name] = function(varArgs) { | ||
return { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(script), using, varArgs); | ||
}, | ||
message: 'by.' + name + '("' + varArgs + '")' | ||
} | ||
}; | ||
}; | ||
/** | ||
* Usage: | ||
* <span>{{status}}</span> | ||
* var status = element(by.binding('{{status}}')); | ||
* | ||
* Note: This ignores parent element restrictions if called with | ||
* WebElement.findElement. | ||
*/ | ||
ProtractorBy.prototype.binding = function(bindingDescriptor) { | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement(webdriver.By.js(clientSideScripts.findBinding), | ||
using, bindingDescriptor); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findBindings), | ||
using, bindingDescriptor); | ||
} | ||
}, | ||
message: 'by.binding("' + bindingDescriptor + '")' | ||
}; | ||
@@ -52,10 +69,7 @@ }; | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findSelect), using, model); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findSelects), using, model); | ||
} | ||
}, | ||
message: 'by.select("' + model + '")' | ||
}; | ||
@@ -71,10 +85,7 @@ }; | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findSelectedOption), using, model); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findSelectedOptions), using, model); | ||
} | ||
}, | ||
message: 'by.selectedOption("' + model + '")' | ||
}; | ||
@@ -91,10 +102,7 @@ }; | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findInput), using, model); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findInputs), using, model); | ||
} | ||
}, | ||
message: 'by.input("' + model + '")' | ||
}; | ||
@@ -110,10 +118,7 @@ }; | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findInput), using, model); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findInputs), using, model); | ||
} | ||
}, | ||
message: 'by.model("' + model + '")' | ||
}; | ||
@@ -129,6 +134,7 @@ }; | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findTextarea), using, model); | ||
} | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findTextareas), using, model); | ||
}, | ||
message: 'by.textarea("' + model + '")' | ||
}; | ||
@@ -158,3 +164,3 @@ }; | ||
return { | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
@@ -164,10 +170,6 @@ webdriver.By.js(clientSideScripts.findAllRepeaterRows), | ||
}, | ||
message: 'by.repeater("' + repeatDescriptor + '")', | ||
row: function(index) { | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
webdriver.By.js(clientSideScripts.findRepeaterRow), | ||
using, repeatDescriptor, index); | ||
}, | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
@@ -177,9 +179,12 @@ webdriver.By.js(clientSideScripts.findRepeaterRows), | ||
}, | ||
message: 'by.repeater(' + repeatDescriptor + '").row("' + index + '")"', | ||
column: function(binding) { | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findRepeaterElement), | ||
using, repeatDescriptor, index, binding); | ||
} | ||
}, | ||
message: 'by.repeater("' + repeatDescriptor + '").row("' + index + | ||
'").column("' + binding + '")' | ||
}; | ||
@@ -191,3 +196,3 @@ } | ||
return { | ||
findArrayOverride: function(driver, using) { | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
@@ -197,9 +202,13 @@ webdriver.By.js(clientSideScripts.findRepeaterColumn), | ||
}, | ||
message: 'by.repeater("' + repeatDescriptor + '").column("' + binding + | ||
'")', | ||
row: function(index) { | ||
return { | ||
findOverride: function(driver, using) { | ||
return driver.findElement( | ||
findElementsOverride: function(driver, using) { | ||
return driver.findElements( | ||
webdriver.By.js(clientSideScripts.findRepeaterElement), | ||
using, repeatDescriptor, index, binding); | ||
} | ||
}, | ||
message: 'by.repeater("' + repeatDescriptor + '").column("' + | ||
binding + '").row("' + index + '")' | ||
}; | ||
@@ -206,0 +215,0 @@ } |
@@ -23,2 +23,7 @@ var url = require('url'); | ||
/** | ||
* @type {ProtractorBy} | ||
*/ | ||
exports.By = new ProtractorBy(); | ||
/** | ||
* Mix a function from one object onto another. The function will still be | ||
@@ -108,6 +113,23 @@ * called in the context of the original object. | ||
elementArrayFinder.then = function() { | ||
return ptor.findElements(locator); | ||
elementArrayFinder.first = function() { | ||
var id = ptor.findElements(locator).then(function(arr) { | ||
if (!arr.length) { | ||
throw new Error('No element found using locator: ' + locator.message); | ||
} | ||
return arr[0]; | ||
}); | ||
return new webdriver.WebElement(ptor.driver, id); | ||
}; | ||
elementArrayFinder.last = function() { | ||
var id = ptor.findElements(locator).then(function(arr) { | ||
return arr[arr.length - 1]; | ||
}); | ||
return new webdriver.WebElement(ptor.driver, id); | ||
}; | ||
elementArrayFinder.then = function(fn) { | ||
return ptor.findElements(locator).then(fn); | ||
}; | ||
return elementArrayFinder; | ||
@@ -271,2 +293,3 @@ } | ||
* @param {webdriver.WebElement} element | ||
* @return {webdriver.WebElement} the wrapped web element. | ||
*/ | ||
@@ -310,4 +333,4 @@ Protractor.prototype.wrapWebElement = function(element) { | ||
var found; | ||
if (locator.findOverride) { | ||
found = locator.findOverride(element.getDriver(), element); | ||
if (locator.findElementsOverride) { | ||
found = thisPtor.findElementsOverrideHelper_(element, locator); | ||
} else { | ||
@@ -342,4 +365,4 @@ found = originalFindElement.apply(element, arguments); | ||
var found; | ||
if (locator.findArrayOverride) { | ||
found = locator.findArrayOverride(element.getDriver(), element); | ||
if (locator.findElementsOverride) { | ||
found = locator.findElementsOverride(element.getDriver(), element); | ||
} else { | ||
@@ -365,4 +388,4 @@ found = originalFindElements.apply(element, arguments); | ||
thisPtor.waitForAngular(); | ||
if (locator.findArrayOverride) { | ||
return locator.findArrayOverride(element.getDriver(), element). | ||
if (locator.findElementsOverride) { | ||
return locator.findElementsOverride(element.getDriver(), element). | ||
then(function (arr) { | ||
@@ -403,4 +426,4 @@ return !!arr.length; | ||
if (locator.findOverride) { | ||
found = locator.findOverride(this.driver); | ||
if (locator.findElementsOverride) { | ||
found = this.findElementsOverrideHelper_(null, locator); | ||
} else { | ||
@@ -423,4 +446,4 @@ found = this.driver.findElement(locator, varArgs); | ||
if (locator.findArrayOverride) { | ||
found = locator.findArrayOverride(this.driver); | ||
if (locator.findElementsOverride) { | ||
found = locator.findElementsOverride(this.driver); | ||
} else { | ||
@@ -447,4 +470,4 @@ found = this.driver.findElements(locator, varArgs); | ||
this.waitForAngular(); | ||
if (locatorOrElement.findArrayOverride) { | ||
return locatorOrElement.findArrayOverride(this.driver).then(function(arr) { | ||
if (locatorOrElement.findElementsOverride) { | ||
return locatorOrElement.findElementsOverride(this.driver).then(function(arr) { | ||
return !!arr.length; | ||
@@ -546,2 +569,10 @@ }); | ||
/** | ||
* Returns the current absolute url from AngularJS. | ||
*/ | ||
Protractor.prototype.getLocationAbsUrl = function() { | ||
this.waitForAngular(); | ||
return this.driver.executeScript(clientSideScripts.getLocationAbsUrl, this.rootEl); | ||
}; | ||
/** | ||
* Pauses the test and injects some helper functions into the browser, so that | ||
@@ -581,2 +612,31 @@ * debugging may be done in the browser console. | ||
/** | ||
* Builds a single web element from a locator with a findElementsOverride. | ||
* Throws an error if an element is not found, and issues a warning | ||
* if more than one element is described by the selector. | ||
* | ||
* @private | ||
* @param {webdriver.WebElement} using A WebElement to scope the find, | ||
* or null. | ||
* @param {webdriver.Locator} locator | ||
* @return {webdriver.WebElement} | ||
*/ | ||
Protractor.prototype.findElementsOverrideHelper_ = function(using, locator) { | ||
// We need to return a WebElement, so we construct one using a promise | ||
// which will resolve to a WebElement. | ||
return new webdriver.WebElement( | ||
this.driver, | ||
locator.findElementsOverride(this.driver, using).then(function(arr) { | ||
if (!arr.length) { | ||
throw new Error('No element found using locator: ' + locator.message); | ||
} | ||
if (arr.length > 1) { | ||
util.puts('warning: more than one element found for locator ' + | ||
locator.message + | ||
'- you may need to be more specific'); | ||
} | ||
return arr[0]; | ||
})); | ||
}; | ||
/** | ||
* Create a new instance of Protractor by wrapping a webdriver instance. | ||
@@ -612,7 +672,1 @@ * | ||
} | ||
/** | ||
* @type {ProtractorBy} | ||
*/ | ||
exports.By = new ProtractorBy(); |
@@ -6,2 +6,3 @@ var util = require('util'); | ||
var remote = require('selenium-webdriver/remote'); | ||
var chrome = require('selenium-webdriver/chrome'); | ||
var minijn = require('minijasminenode'); | ||
@@ -114,3 +115,6 @@ var protractor = require('./protractor.js'); | ||
if (config.seleniumAddress) { | ||
if (config.chromeOnly) { | ||
util.puts('Using ChromeDriver directly...'); | ||
deferred.fulfill(null); | ||
} else if (config.seleniumAddress) { | ||
util.puts('Using the selenium server at ' + config.seleniumAddress); | ||
@@ -142,2 +146,8 @@ deferred.fulfill(config.seleniumAddress); | ||
} | ||
if (config.seleniumServerJar && !fs.existsSync(config.seleniumServerJar)) { | ||
throw new Error('there\'s no selenium server jar at the specified location.'+ | ||
'Do you have the correct version?'); | ||
} | ||
server = new remote.SeleniumServer(config.seleniumServerJar, { | ||
@@ -181,3 +191,3 @@ args: config.seleniumArgs, | ||
if (!matches.length) { | ||
throw new Error('Test file ' + specs[i] + ' did not match any files.'); | ||
util.puts('Warning: pattern ' + specs[i] + ' did not match any files.'); | ||
} | ||
@@ -188,2 +198,5 @@ for (var j = 0; j < matches.length; ++j) { | ||
} | ||
if (!resolvedSpecs.length) { | ||
throw new Error('Spec patterns did not match any files.'); | ||
} | ||
@@ -194,6 +207,13 @@ minijn.addSpecs(resolvedSpecs); | ||
var runDeferred = webdriver.promise.defer(); | ||
driver = new webdriver.Builder(). | ||
usingServer(config.seleniumAddress). | ||
withCapabilities(config.capabilities).build(); | ||
if (config.chromeOnly) { | ||
var service = new chrome.ServiceBuilder(config.chromeDriver).build(); | ||
driver = chrome.createDriver( | ||
new webdriver.Capabilities(config.capabilities), service); | ||
} else { | ||
driver = new webdriver.Builder(). | ||
usingServer(config.seleniumAddress). | ||
withCapabilities(config.capabilities).build(); | ||
} | ||
driver.getSession().then(function(session) { | ||
@@ -200,0 +220,0 @@ driver.manage().timeouts().setScriptTimeout(config.allScriptsTimeout); |
@@ -39,3 +39,3 @@ { | ||
"license" : "MIT", | ||
"version": "0.12.1" | ||
"version": "0.13.0" | ||
} |
@@ -12,2 +12,6 @@ // A reference configuration file. | ||
// 3. sauceUser/sauceKey - to use remote Selenium servers via SauceLabs. | ||
// | ||
// If the chromeOnly option is specified, no Selenium server will be started, | ||
// and chromeDriver will be used directly (from the location specified in | ||
// chromeDriver) | ||
@@ -24,2 +28,5 @@ // The location of the selenium standalone server .jar file. | ||
chromeDriver: './selenium/chromedriver', | ||
// If true, only chromedriver will be started, not a standalone selenium. | ||
// Tests for browsers other than chrome will not run. | ||
chromeOnly: false, | ||
// Additional command line options to pass to selenium. For example, | ||
@@ -26,0 +33,0 @@ // if you need to change the browser timeout, use |
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
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
141050
2189