diff --git a/lib/globals.d.ts b/lib/globals.d.ts
index 5cd9283d8..d2972a073 100644
--- a/lib/globals.d.ts
+++ b/lib/globals.d.ts
@@ -25,6 +25,7 @@ declare var DartObject: any;
declare namespace webdriver {
class WebDriver {
+ findElements: Function;
getSession: Function;
quit: Function;
static attachToSession: Function;
@@ -45,4 +46,8 @@ declare namespace webdriver {
isEnabled: Function;
findElements: Function;
}
+
+ interface Locator {
+ toString(): string;
+ }
}
diff --git a/lib/locators.js b/lib/locators.js
deleted file mode 100644
index 8eac442cc..000000000
--- a/lib/locators.js
+++ /dev/null
@@ -1,456 +0,0 @@
-var util = require('util');
-var webdriver = require('selenium-webdriver');
-
-var clientSideScripts = require('./clientsidescripts.js');
-
-/**
- * The Protractor Locators. These provide ways of finding elements in
- * Angular applications by binding, model, etc.
- *
- * @alias by
- * @extends {webdriver.By}
- */
-var ProtractorBy = function() {};
-var WebdriverBy = function() {};
-
-/**
- * webdriver's By is an enum of locator functions, so we must set it to
- * a prototype before inheriting from it.
- */
-WebdriverBy.prototype = webdriver.By;
-util.inherits(ProtractorBy, WebdriverBy);
-
-/**
- * Add a locator to this instance of ProtractorBy. This locator can then be
- * used with element(by.locatorName(args)).
- *
- * @view
- *
- *
- * @example
- * // Add the custom locator.
- * by.addLocator('buttonTextSimple',
- * function(buttonText, opt_parentElement, opt_rootSelector) {
- * // This function will be serialized as a string and will execute in the
- * // browser. The first argument is the text for the button. The second
- * // argument is the parent element, if any.
- * var using = opt_parentElement || document,
- * buttons = using.querySelectorAll('button');
- *
- * // Return an array of buttons with the text.
- * return Array.prototype.filter.call(buttons, function(button) {
- * return button.textContent === buttonText;
- * });
- * });
- *
- * // Use the custom locator.
- * element(by.buttonTextSimple('Go!')).click();
- *
- * @alias by.addLocator(locatorName, functionOrScript)
- * @param {string} name The name of the new locator.
- * @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 contains any args passed into the locator followed by the
- * element scoping the search and the css selector for the root angular
- * element. It should return an array of elements.
- */
-ProtractorBy.prototype.addLocator = function(name, script) {
- this[name] = function() {
- var locatorArguments = arguments;
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- var findElementArguments = [script];
- for (var i = 0; i < locatorArguments.length; i++) {
- findElementArguments.push(locatorArguments[i]);
- }
- findElementArguments.push(using);
- findElementArguments.push(rootSelector);
-
- return driver.findElements(
- webdriver.By.js.apply(webdriver.By, findElementArguments));
- },
- toString: function toString() {
- return 'by.' + name + '("' + Array.prototype.
- join.call(locatorArguments, '", "') + '")';
- }
- };
- };
-};
-
-/**
- * Find an element by text binding. Does a partial match, so any elements bound
- * to variables containing the input string will be returned.
- *
- * Note: For AngularJS version 1.2, the interpolation brackets, (usually {{}}),
- * are optionally allowed in the binding description string. For Angular version
- * 1.3+, they are not allowed, and no elements will be found if they are used.
- *
- * @view
- * {{person.name}}
- *
- *
- * @example
- * var span1 = element(by.binding('person.name'));
- * expect(span1.getText()).toBe('Foo');
- *
- * var span2 = element(by.binding('person.email'));
- * expect(span2.getText()).toBe('foo@bar.com');
- *
- * // You can also use a substring for a partial match
- * var span1alt = element(by.binding('name'));
- * expect(span1alt.getText()).toBe('Foo');
- *
- * // This works for sites using Angular 1.2 but NOT 1.3
- * var deprecatedSyntax = element(by.binding('{{person.name}}'));
- *
- * @param {string} bindingDescriptor
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.binding = function(bindingDescriptor) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findBindings,
- bindingDescriptor, false, using, rootSelector));
- },
- toString: function toString() {
- return 'by.binding("' + bindingDescriptor + '")';
- }
- };
-};
-
-/**
- * Find an element by exact binding.
- *
- * @view
- * {{ person.name }}
- *
- * {{person_phone|uppercase}}
- *
- * @example
- * expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
- * expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
- * expect(element(by.exactBinding('person')).isPresent()).toBe(false);
- * expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
- * expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
- * expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
- *
- * @param {string} bindingDescriptor
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.exactBinding = function(bindingDescriptor) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findBindings,
- bindingDescriptor, true, using, rootSelector));
- },
- toString: function toString() {
- return 'by.exactBinding("' + bindingDescriptor + '")';
- }
- };
-};
-
-/**
- * Find an element by ng-model expression.
- *
- * @alias by.model(modelName)
- * @view
- *
- *
- * @example
- * var input = element(by.model('person.name'));
- * input.sendKeys('123');
- * expect(input.getAttribute('value')).toBe('Foo123');
- *
- * @param {string} model ng-model expression.
- */
-ProtractorBy.prototype.model = function(model) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(
- clientSideScripts.findByModel, model, using, rootSelector));
- },
- toString: function toString() {
- return 'by.model("' + model + '")';
- }
- };
-};
-
-/**
- * Find a button by text.
- *
- * @view
- *
- *
- * @example
- * element(by.buttonText('Save'));
- *
- * @param {string} searchText
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.buttonText = function(searchText) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findByButtonText,
- searchText, using, rootSelector));
- },
- toString: function toString() {
- return 'by.buttonText("' + searchText + '")';
- }
- };
-};
-
-/**
- * Find a button by partial text.
- *
- * @view
- *
- *
- * @example
- * element(by.partialButtonText('Save'));
- *
- * @param {string} searchText
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.partialButtonText = function(searchText) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findByPartialButtonText,
- searchText, using, rootSelector));
- },
- toString: function toString() {
- return 'by.partialButtonText("' + searchText + '")';
- }
- };
-};
-
-// Generate either by.repeater or by.exactRepeater
-function byRepeaterInner(exact) {
- var name = 'by.' + (exact ? 'exactR' : 'r') + 'epeater';
- return function(repeatDescriptor) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findAllRepeaterRows,
- repeatDescriptor, exact, using, rootSelector));
- },
- toString: function toString() {
- return name + '("' + repeatDescriptor + '")';
- },
- row: function(index) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findRepeaterRows,
- repeatDescriptor, exact, index, using, rootSelector));
- },
- toString: function toString() {
- return name + '(' + repeatDescriptor + '").row("' + index + '")"';
- },
- column: function(binding) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findRepeaterElement,
- repeatDescriptor, exact, index, binding, using,
- rootSelector));
- },
- toString: function toString() {
- return name + '("' + repeatDescriptor + '").row("' + index +
- '").column("' + binding + '")';
- }
- };
- }
- };
- },
- column: function(binding) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findRepeaterColumn,
- repeatDescriptor, exact, binding, using, rootSelector));
- },
- toString: function toString() {
- return name + '("' + repeatDescriptor + '").column("' +
- binding + '")';
- },
- row: function(index) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findRepeaterElement,
- repeatDescriptor, exact, index, binding, using, rootSelector));
- },
- toString: function toString() {
- return name + '("' + repeatDescriptor + '").column("' +
- binding + '").row("' + index + '")';
- }
- };
- }
- };
- }
- };
- };
-}
-
-/**
- * Find elements inside an ng-repeat.
- *
- * @view
- *
- * {{cat.name}}
- * {{cat.age}}
- *
- *
- *
- * {{$index}}
- *
- *
- *
{{book.name}}
- *
{{book.blurb}}
- *
- *
- * @example
- * // Returns the DIV for the second cat.
- * var secondCat = element(by.repeater('cat in pets').row(1));
- *
- * // Returns the SPAN for the first cat's name.
- * var firstCatName = element(by.repeater('cat in pets').
- * row(0).column('cat.name'));
- *
- * // Returns a promise that resolves to an array of WebElements from a column
- * var ages = element.all(
- * by.repeater('cat in pets').column('cat.age'));
- *
- * // Returns a promise that resolves to an array of WebElements containing
- * // all top level elements repeated by the repeater. For 2 pets rows resolves
- * // to an array of 2 elements.
- * var rows = element.all(by.repeater('cat in pets'));
- *
- * // Returns a promise that resolves to an array of WebElements containing all
- * // the elements with a binding to the book's name.
- * var divs = element.all(by.repeater('book in library').column('book.name'));
- *
- * // Returns a promise that resolves to an array of WebElements containing
- * // the DIVs for the second book.
- * var bookInfo = element.all(by.repeater('book in library').row(1));
- *
- * // Returns the H4 for the first book's name.
- * var firstBookName = element(by.repeater('book in library').
- * row(0).column('book.name'));
- *
- * // Returns a promise that resolves to an array of WebElements containing
- * // all top level elements repeated by the repeater. For 2 books divs
- * // resolves to an array of 4 elements.
- * var divs = element.all(by.repeater('book in library'));
- *
- * @param {string} repeatDescriptor
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.repeater = byRepeaterInner(false);
-
-/**
- * Find an element by exact repeater.
- *
- * @view
- *
- *
- *
- * @example
- * expect(element(by.exactRepeater('person in peopleWithRedHair')).isPresent())
- * .toBe(true);
- * expect(element(by.exactRepeater('person in people')).isPresent()).toBe(false);
- * expect(element(by.exactRepeater('car in cars')).isPresent()).toBe(true);
- *
- * @param {string} repeatDescriptor
- * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
- */
-ProtractorBy.prototype.exactRepeater = byRepeaterInner(true);
-
-
-/**
- * Find elements by CSS which contain a certain string.
- *
- * @view
- *
- *
Dog
- *
Cat
- *
- *
- * @example
- * // Returns the li for the dog, but not cat.
- * var dog = element(by.cssContainingText('.pet', 'Dog'));
- */
-ProtractorBy.prototype.cssContainingText = function(cssSelector, searchText) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findByCssContainingText,
- cssSelector, searchText, using, rootSelector));
- },
- toString: function toString() {
- return 'by.cssContainingText("' + cssSelector + '", "' + searchText + '")';
- }
- };
-};
-
-/**
- * Find an element by ng-options expression.
- *
- * @alias by.options(optionsDescriptor)
- * @view
- *
- *
- * @example
- * var allOptions = element.all(by.options('c for c in colors'));
- * expect(allOptions.count()).toEqual(2);
- * var firstOption = allOptions.first();
- * expect(firstOption.getText()).toEqual('red');
- *
- * @param {string} optionsDescriptor ng-options expression.
- */
-ProtractorBy.prototype.options = function(optionsDescriptor) {
- return {
- findElementsOverride: function(driver, using, rootSelector) {
- return driver.findElements(
- webdriver.By.js(clientSideScripts.findByOptions, optionsDescriptor,
- using, rootSelector));
- },
- toString: function toString() {
- return 'by.option("' + optionsDescriptor + '")';
- }
- };
-};
-
-/**
- * Find an element by css selector within the Shadow DOM.
- *
- * @alias by.deepCss(selector)
- * @view
- *
- * @example
- * var spans = element.all(by.deepCss('span'));
- * expect(spans.count()).toEqual(3);
- */
-ProtractorBy.prototype.deepCss = function(selector) {
- // TODO(julie): syntax will change from /deep/ to >>> at some point.
- // When that is supported, switch it here.
- return webdriver.By.css('* /deep/ ' + selector);
-};
-
-exports.ProtractorBy = ProtractorBy;
diff --git a/lib/locators.ts b/lib/locators.ts
new file mode 100644
index 000000000..b6d768963
--- /dev/null
+++ b/lib/locators.ts
@@ -0,0 +1,460 @@
+import * as util from 'util';
+let webdriver: any = require('selenium-webdriver');
+let clientSideScripts: any = require('./clientsidescripts');
+
+/**
+ * webdriver's By is an enum of locator functions, so we must set it to
+ * a prototype before inheriting from it.
+ */
+export class WebdriverBy {};
+WebdriverBy.prototype = webdriver.By;
+
+export interface Locator extends webdriver.Locator {
+ findElementsOverride?:
+ (driver: webdriver.WebDriver, using: webdriver.WebElement,
+ rootSelector: string) => webdriver.WebElement;
+ row?: (index: number) => Locator;
+ column?: (index: string) => Locator;
+}
+;
+
+/**
+ * The Protractor Locators. These provide ways of finding elements in
+ * Angular applications by binding, model, etc.
+ *
+ * @alias by
+ * @extends {webdriver.By}
+ */
+export class ProtractorBy extends WebdriverBy {
+ /**
+ * Add a locator to this instance of ProtractorBy. This locator can then be
+ * used with element(by.locatorName(args)).
+ *
+ * @view
+ *
+ *
+ * @example
+ * // Add the custom locator.
+ * by.addLocator('buttonTextSimple',
+ * function(buttonText, opt_parentElement, opt_rootSelector) {
+ * // This function will be serialized as a string and will execute in the
+ * // browser. The first argument is the text for the button. The second
+ * // argument is the parent element, if any.
+ * var using = opt_parentElement || document,
+ * buttons = using.querySelectorAll('button');
+ *
+ * // Return an array of buttons with the text.
+ * return Array.prototype.filter.call(buttons, function(button) {
+ * return button.textContent === buttonText;
+ * });
+ * });
+ *
+ * // Use the custom locator.
+ * element(by.buttonTextSimple('Go!')).click();
+ *
+ * @alias by.addLocator(locatorName, functionOrScript)
+ * @param {string} name The name of the new locator.
+ * @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 contains any args passed into the locator followed by the
+ * element scoping the search and the css selector for the root angular
+ * element. It should return an array of elements.
+ */
+ addLocator(name: string, script: Function|string) {
+ this[name] = function(): Locator {
+ var locatorArguments = arguments;
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ var findElementArguments: any[] = [script];
+ for (var i = 0; i < locatorArguments.length; i++) {
+ findElementArguments.push(locatorArguments[i]);
+ }
+ findElementArguments.push(using);
+ findElementArguments.push(rootSelector);
+
+ return driver.findElements(
+ webdriver.By.js.apply(webdriver.By, findElementArguments));
+ },
+ toString: function toString() {
+ return 'by.' + name + '("' +
+ Array.prototype.join.call(locatorArguments, '", "') + '")';
+ }
+ };
+ };
+ };
+
+ /**
+ * Find an element by text binding. Does a partial match, so any elements bound
+ * to variables containing the input string will be returned.
+ *
+ * Note: For AngularJS version 1.2, the interpolation brackets, (usually {{}}),
+ * are optionally allowed in the binding description string. For Angular version
+ * 1.3+, they are not allowed, and no elements will be found if they are used.
+ *
+ * @view
+ * {{person.name}}
+ *
+ *
+ * @example
+ * var span1 = element(by.binding('person.name'));
+ * expect(span1.getText()).toBe('Foo');
+ *
+ * var span2 = element(by.binding('person.email'));
+ * expect(span2.getText()).toBe('foo@bar.com');
+ *
+ * // You can also use a substring for a partial match
+ * var span1alt = element(by.binding('name'));
+ * expect(span1alt.getText()).toBe('Foo');
+ *
+ * // This works for sites using Angular 1.2 but NOT 1.3
+ * var deprecatedSyntax = element(by.binding('{{person.name}}'));
+ *
+ * @param {string} bindingDescriptor
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ binding(bindingDescriptor: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findBindings, bindingDescriptor, false, using,
+ rootSelector));
+ },
+ toString: function toString() {
+ return 'by.binding("' + bindingDescriptor + '")';
+ }
+ };
+ };
+
+ /**
+ * Find an element by exact binding.
+ *
+ * @view
+ * {{ person.name }}
+ *
+ * {{person_phone|uppercase}}
+ *
+ * @example
+ * expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
+ * expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
+ * expect(element(by.exactBinding('person')).isPresent()).toBe(false);
+ * expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
+ * expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
+ * expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
+ *
+ * @param {string} bindingDescriptor
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ exactBinding(bindingDescriptor: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findBindings, bindingDescriptor, true, using,
+ rootSelector));
+ },
+ toString: function toString() {
+ return 'by.exactBinding("' + bindingDescriptor + '")';
+ }
+ };
+ };
+
+ /**
+ * Find an element by ng-model expression.
+ *
+ * @alias by.model(modelName)
+ * @view
+ *
+ *
+ * @example
+ * var input = element(by.model('person.name'));
+ * input.sendKeys('123');
+ * expect(input.getAttribute('value')).toBe('Foo123');
+ *
+ * @param {string} model ng-model expression.
+ */
+ model(model: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findByModel, model, using, rootSelector));
+ },
+ toString: function toString() { return 'by.model("' + model + '")'; }
+ };
+ };
+
+ /**
+ * Find a button by text.
+ *
+ * @view
+ *
+ *
+ * @example
+ * element(by.buttonText('Save'));
+ *
+ * @param {string} searchText
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ buttonText(searchText: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findByButtonText, searchText, using,
+ rootSelector));
+ },
+ toString: function toString() {
+ return 'by.buttonText("' + searchText + '")';
+ }
+ };
+ };
+
+ /**
+ * Find a button by partial text.
+ *
+ * @view
+ *
+ *
+ * @example
+ * element(by.partialButtonText('Save'));
+ *
+ * @param {string} searchText
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ partialButtonText(searchText: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findByPartialButtonText, searchText, using,
+ rootSelector));
+ },
+ toString: function toString() {
+ return 'by.partialButtonText("' + searchText + '")';
+ }
+ };
+ };
+
+ // Generate either by.repeater or by.exactRepeater
+ private byRepeaterInner(exact: boolean, repeatDescriptor: string): Locator {
+ var name = 'by.' + (exact ? 'exactR' : 'r') + 'epeater';
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findAllRepeaterRows, repeatDescriptor, exact,
+ using, rootSelector));
+ },
+ toString: function toString() {
+ return name + '("' + repeatDescriptor + '")';
+ },
+ row: function(index) {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findRepeaterRows, repeatDescriptor, exact,
+ index, using, rootSelector));
+ },
+ toString: function toString() {
+ return name + '(' + repeatDescriptor + '").row("' + index + '")"';
+ },
+ column: function(binding) {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findRepeaterElement, repeatDescriptor,
+ exact, index, binding, using, rootSelector));
+ },
+ toString: function toString() {
+ return name + '("' + repeatDescriptor + '").row("' + index +
+ '").column("' + binding + '")';
+ }
+ };
+ }
+ };
+ },
+ column: function(binding) {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findRepeaterColumn, repeatDescriptor, exact,
+ binding, using, rootSelector));
+ },
+ toString: function toString() {
+ return name + '("' + repeatDescriptor + '").column("' + binding +
+ '")';
+ },
+ row: function(index) {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findRepeaterElement, repeatDescriptor,
+ exact, index, binding, using, rootSelector));
+ },
+ toString: function toString() {
+ return name + '("' + repeatDescriptor + '").column("' +
+ binding + '").row("' + index + '")';
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Find elements inside an ng-repeat.
+ *
+ * @view
+ *
+ * {{cat.name}}
+ * {{cat.age}}
+ *
+ *
+ *
+ * {{$index}}
+ *
+ *
+ *
{{book.name}}
+ *
{{book.blurb}}
+ *
+ *
+ * @example
+ * // Returns the DIV for the second cat.
+ * var secondCat = element(by.repeater('cat in pets').row(1));
+ *
+ * // Returns the SPAN for the first cat's name.
+ * var firstCatName = element(by.repeater('cat in pets').
+ * row(0).column('cat.name'));
+ *
+ * // Returns a promise that resolves to an array of WebElements from a column
+ * var ages = element.all(
+ * by.repeater('cat in pets').column('cat.age'));
+ *
+ * // Returns a promise that resolves to an array of WebElements containing
+ * // all top level elements repeated by the repeater. For 2 pets rows resolves
+ * // to an array of 2 elements.
+ * var rows = element.all(by.repeater('cat in pets'));
+ *
+ * // Returns a promise that resolves to an array of WebElements containing all
+ * // the elements with a binding to the book's name.
+ * var divs = element.all(by.repeater('book in library').column('book.name'));
+ *
+ * // Returns a promise that resolves to an array of WebElements containing
+ * // the DIVs for the second book.
+ * var bookInfo = element.all(by.repeater('book in library').row(1));
+ *
+ * // Returns the H4 for the first book's name.
+ * var firstBookName = element(by.repeater('book in library').
+ * row(0).column('book.name'));
+ *
+ * // Returns a promise that resolves to an array of WebElements containing
+ * // all top level elements repeated by the repeater. For 2 books divs
+ * // resolves to an array of 4 elements.
+ * var divs = element.all(by.repeater('book in library'));
+ *
+ * @param {string} repeatDescriptor
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ repeater(repeatDescriptor: string): Locator {
+ return this.byRepeaterInner(false, repeatDescriptor);
+ }
+
+ /**
+ * Find an element by exact repeater.
+ *
+ * @view
+ *
+ *
+ *
+ * @example
+ * expect(element(by.exactRepeater('person in peopleWithRedHair')).isPresent())
+ * .toBe(true);
+ * expect(element(by.exactRepeater('person in people')).isPresent()).toBe(false);
+ * expect(element(by.exactRepeater('car in cars')).isPresent()).toBe(true);
+ *
+ * @param {string} repeatDescriptor
+ * @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
+ */
+ exactRepeater(repeatDescriptor: string): Locator {
+ return this.byRepeaterInner(true, repeatDescriptor);
+ }
+
+
+ /**
+ * Find elements by CSS which contain a certain string.
+ *
+ * @view
+ *
+ *
Dog
+ *
Cat
+ *
+ *
+ * @example
+ * // Returns the li for the dog, but not cat.
+ * var dog = element(by.cssContainingText('.pet', 'Dog'));
+ */
+ cssContainingText(cssSelector: string, searchText: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findByCssContainingText, cssSelector, searchText,
+ using, rootSelector));
+ },
+ toString: function toString() {
+ return 'by.cssContainingText("' + cssSelector + '", "' + searchText +
+ '")';
+ }
+ };
+ };
+
+ /**
+ * Find an element by ng-options expression.
+ *
+ * @alias by.options(optionsDescriptor)
+ * @view
+ *
+ *
+ * @example
+ * var allOptions = element.all(by.options('c for c in colors'));
+ * expect(allOptions.count()).toEqual(2);
+ * var firstOption = allOptions.first();
+ * expect(firstOption.getText()).toEqual('red');
+ *
+ * @param {string} optionsDescriptor ng-options expression.
+ */
+ options(optionsDescriptor: string): Locator {
+ return {
+ findElementsOverride: function(driver, using, rootSelector) {
+ return driver.findElements(webdriver.By.js(
+ clientSideScripts.findByOptions, optionsDescriptor, using,
+ rootSelector));
+ },
+ toString: function toString() {
+ return 'by.option("' + optionsDescriptor + '")';
+ }
+ };
+ };
+
+ /**
+ * Find an element by css selector within the Shadow DOM.
+ *
+ * @alias by.deepCss(selector)
+ * @view
+ *