UNPKG

17.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const selenium_webdriver_1 = require("selenium-webdriver");
4let clientSideScripts = require('./clientsidescripts');
5// Explicitly define webdriver.By.
6// We do this because we want to inherit the static methods of webdriver.By, as opposed to
7// inheriting from the webdriver.By class itself, which is actually analogous to ProtractorLocator.
8class WebdriverBy {
9 constructor() {
10 this.className = selenium_webdriver_1.By.className;
11 this.css = selenium_webdriver_1.By.css;
12 this.id = selenium_webdriver_1.By.id;
13 this.linkText = selenium_webdriver_1.By.linkText;
14 this.js = selenium_webdriver_1.By.js;
15 this.name = selenium_webdriver_1.By.name;
16 this.partialLinkText = selenium_webdriver_1.By.partialLinkText;
17 this.tagName = selenium_webdriver_1.By.tagName;
18 this.xpath = selenium_webdriver_1.By.xpath;
19 }
20}
21exports.WebdriverBy = WebdriverBy;
22function isProtractorLocator(x) {
23 return x && (typeof x.findElementsOverride === 'function');
24}
25exports.isProtractorLocator = isProtractorLocator;
26/**
27 * The Protractor Locators. These provide ways of finding elements in
28 * Angular applications by binding, model, etc.
29 *
30 * @alias by
31 * @extends {webdriver.By}
32 */
33class ProtractorBy extends WebdriverBy {
34 /**
35 * Add a locator to this instance of ProtractorBy. This locator can then be
36 * used with element(by.locatorName(args)).
37 *
38 * @view
39 * <button ng-click="doAddition()">Go!</button>
40 *
41 * @example
42 * // Add the custom locator.
43 * by.addLocator('buttonTextSimple',
44 * function(buttonText, opt_parentElement, opt_rootSelector) {
45 * // This function will be serialized as a string and will execute in the
46 * // browser. The first argument is the text for the button. The second
47 * // argument is the parent element, if any.
48 * var using = opt_parentElement || document,
49 * buttons = using.querySelectorAll('button');
50 *
51 * // Return an array of buttons with the text.
52 * return Array.prototype.filter.call(buttons, function(button) {
53 * return button.textContent === buttonText;
54 * });
55 * });
56 *
57 * // Use the custom locator.
58 * element(by.buttonTextSimple('Go!')).click();
59 *
60 * @alias by.addLocator(locatorName, functionOrScript)
61 * @param {string} name The name of the new locator.
62 * @param {Function|string} script A script to be run in the context of
63 * the browser. This script will be passed an array of arguments
64 * that contains any args passed into the locator followed by the
65 * element scoping the search and the css selector for the root angular
66 * element. It should return an array of elements.
67 */
68 addLocator(name, script) {
69 this[name] = (...args) => {
70 let locatorArguments = args;
71 return {
72 findElementsOverride: (driver, using, rootSelector) => {
73 let findElementArguments = [script];
74 for (let i = 0; i < locatorArguments.length; i++) {
75 findElementArguments.push(locatorArguments[i]);
76 }
77 findElementArguments.push(using);
78 findElementArguments.push(rootSelector);
79 return driver.findElements(selenium_webdriver_1.By.js.apply(selenium_webdriver_1.By, findElementArguments));
80 },
81 toString: () => {
82 return 'by.' + name + '("' + Array.prototype.join.call(locatorArguments, '", "') + '")';
83 }
84 };
85 };
86 }
87 ;
88 /**
89 * Find an element by text binding. Does a partial match, so any elements
90 * bound to variables containing the input string will be returned.
91 *
92 * Note: For AngularJS version 1.2, the interpolation brackets, (usually
93 * {{}}), are optionally allowed in the binding description string. For
94 * Angular version 1.3+, they are not allowed, and no elements will be found
95 * if they are used.
96 *
97 * @view
98 * <span>{{person.name}}</span>
99 * <span ng-bind="person.email"></span>
100 *
101 * @example
102 * var span1 = element(by.binding('person.name'));
103 * expect(span1.getText()).toBe('Foo');
104 *
105 * var span2 = element(by.binding('person.email'));
106 * expect(span2.getText()).toBe('foo@bar.com');
107 *
108 * // You can also use a substring for a partial match
109 * var span1alt = element(by.binding('name'));
110 * expect(span1alt.getText()).toBe('Foo');
111 *
112 * // This works for sites using Angular 1.2 but NOT 1.3
113 * var deprecatedSyntax = element(by.binding('{{person.name}}'));
114 *
115 * @param {string} bindingDescriptor
116 * @returns {ProtractorLocator} location strategy
117 */
118 binding(bindingDescriptor) {
119 return {
120 findElementsOverride: (driver, using, rootSelector) => {
121 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findBindings, bindingDescriptor, false, using, rootSelector));
122 },
123 toString: () => {
124 return 'by.binding("' + bindingDescriptor + '")';
125 }
126 };
127 }
128 ;
129 /**
130 * Find an element by exact binding.
131 *
132 * @view
133 * <span>{{ person.name }}</span>
134 * <span ng-bind="person-email"></span>
135 * <span>{{person_phone|uppercase}}</span>
136 *
137 * @example
138 * expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
139 * expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
140 * expect(element(by.exactBinding('person')).isPresent()).toBe(false);
141 * expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
142 * expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
143 * expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
144 *
145 * @param {string} bindingDescriptor
146 * @returns {ProtractorLocator} location strategy
147 */
148 exactBinding(bindingDescriptor) {
149 return {
150 findElementsOverride: (driver, using, rootSelector) => {
151 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findBindings, bindingDescriptor, true, using, rootSelector));
152 },
153 toString: () => {
154 return 'by.exactBinding("' + bindingDescriptor + '")';
155 }
156 };
157 }
158 ;
159 /**
160 * Find an element by ng-model expression.
161 *
162 * @alias by.model(modelName)
163 * @view
164 * <input type="text" ng-model="person.name">
165 *
166 * @example
167 * var input = element(by.model('person.name'));
168 * input.sendKeys('123');
169 * expect(input.getAttribute('value')).toBe('Foo123');
170 *
171 * @param {string} model ng-model expression.
172 * @returns {ProtractorLocator} location strategy
173 */
174 model(model) {
175 return {
176 findElementsOverride: (driver, using, rootSelector) => {
177 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findByModel, model, using, rootSelector));
178 },
179 toString: () => {
180 return 'by.model("' + model + '")';
181 }
182 };
183 }
184 ;
185 /**
186 * Find a button by text.
187 *
188 * @view
189 * <button>Save</button>
190 *
191 * @example
192 * element(by.buttonText('Save'));
193 *
194 * @param {string} searchText
195 * @returns {ProtractorLocator} location strategy
196 */
197 buttonText(searchText) {
198 return {
199 findElementsOverride: (driver, using, rootSelector) => {
200 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findByButtonText, searchText, using, rootSelector));
201 },
202 toString: () => {
203 return 'by.buttonText("' + searchText + '")';
204 }
205 };
206 }
207 ;
208 /**
209 * Find a button by partial text.
210 *
211 * @view
212 * <button>Save my file</button>
213 *
214 * @example
215 * element(by.partialButtonText('Save'));
216 *
217 * @param {string} searchText
218 * @returns {ProtractorLocator} location strategy
219 */
220 partialButtonText(searchText) {
221 return {
222 findElementsOverride: (driver, using, rootSelector) => {
223 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findByPartialButtonText, searchText, using, rootSelector));
224 },
225 toString: () => {
226 return 'by.partialButtonText("' + searchText + '")';
227 }
228 };
229 }
230 ;
231 // Generate either by.repeater or by.exactRepeater
232 byRepeaterInner(exact, repeatDescriptor) {
233 let name = 'by.' + (exact ? 'exactR' : 'r') + 'epeater';
234 return {
235 findElementsOverride: (driver, using, rootSelector) => {
236 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findAllRepeaterRows, repeatDescriptor, exact, using, rootSelector));
237 },
238 toString: () => {
239 return name + '("' + repeatDescriptor + '")';
240 },
241 row: (index) => {
242 return {
243 findElementsOverride: (driver, using, rootSelector) => {
244 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findRepeaterRows, repeatDescriptor, exact, index, using, rootSelector));
245 },
246 toString: () => {
247 return name + '(' + repeatDescriptor + '").row("' + index + '")"';
248 },
249 column: (binding) => {
250 return {
251 findElementsOverride: (driver, using, rootSelector) => {
252 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findRepeaterElement, repeatDescriptor, exact, index, binding, using, rootSelector));
253 },
254 toString: () => {
255 return name + '("' + repeatDescriptor + '").row("' + index + '").column("' +
256 binding + '")';
257 }
258 };
259 }
260 };
261 },
262 column: (binding) => {
263 return {
264 findElementsOverride: (driver, using, rootSelector) => {
265 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findRepeaterColumn, repeatDescriptor, exact, binding, using, rootSelector));
266 },
267 toString: () => {
268 return name + '("' + repeatDescriptor + '").column("' + binding + '")';
269 },
270 row: (index) => {
271 return {
272 findElementsOverride: (driver, using, rootSelector) => {
273 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findRepeaterElement, repeatDescriptor, exact, index, binding, using, rootSelector));
274 },
275 toString: () => {
276 return name + '("' + repeatDescriptor + '").column("' + binding + '").row("' +
277 index + '")';
278 }
279 };
280 }
281 };
282 }
283 };
284 }
285 /**
286 * Find elements inside an ng-repeat.
287 *
288 * @view
289 * <div ng-repeat="cat in pets">
290 * <span>{{cat.name}}</span>
291 * <span>{{cat.age}}</span>
292 * </div>
293 *
294 * <div class="book-img" ng-repeat-start="book in library">
295 * <span>{{$index}}</span>
296 * </div>
297 * <div class="book-info" ng-repeat-end>
298 * <h4>{{book.name}}</h4>
299 * <p>{{book.blurb}}</p>
300 * </div>
301 *
302 * @example
303 * // Returns the DIV for the second cat.
304 * var secondCat = element(by.repeater('cat in pets').row(1));
305 *
306 * // Returns the SPAN for the first cat's name.
307 * var firstCatName = element(by.repeater('cat in pets').
308 * row(0).column('cat.name'));
309 *
310 * // Returns a promise that resolves to an array of WebElements from a column
311 * var ages = element.all(
312 * by.repeater('cat in pets').column('cat.age'));
313 *
314 * // Returns a promise that resolves to an array of WebElements containing
315 * // all top level elements repeated by the repeater. For 2 pets rows
316 * // resolves to an array of 2 elements.
317 * var rows = element.all(by.repeater('cat in pets'));
318 *
319 * // Returns a promise that resolves to an array of WebElements containing
320 * // all the elements with a binding to the book's name.
321 * var divs = element.all(by.repeater('book in library').column('book.name'));
322 *
323 * // Returns a promise that resolves to an array of WebElements containing
324 * // the DIVs for the second book.
325 * var bookInfo = element.all(by.repeater('book in library').row(1));
326 *
327 * // Returns the H4 for the first book's name.
328 * var firstBookName = element(by.repeater('book in library').
329 * row(0).column('book.name'));
330 *
331 * // Returns a promise that resolves to an array of WebElements containing
332 * // all top level elements repeated by the repeater. For 2 books divs
333 * // resolves to an array of 4 elements.
334 * var divs = element.all(by.repeater('book in library'));
335 *
336 * @param {string} repeatDescriptor
337 * @returns {ProtractorLocator} location strategy
338 */
339 repeater(repeatDescriptor) {
340 return this.byRepeaterInner(false, repeatDescriptor);
341 }
342 /**
343 * Find an element by exact repeater.
344 *
345 * @view
346 * <li ng-repeat="person in peopleWithRedHair"></li>
347 * <li ng-repeat="car in cars | orderBy:year"></li>
348 *
349 * @example
350 * expect(element(by.exactRepeater('person in
351 * peopleWithRedHair')).isPresent())
352 * .toBe(true);
353 * expect(element(by.exactRepeater('person in
354 * people')).isPresent()).toBe(false);
355 * expect(element(by.exactRepeater('car in cars')).isPresent()).toBe(true);
356 *
357 * @param {string} repeatDescriptor
358 * @returns {ProtractorLocator} location strategy
359 */
360 exactRepeater(repeatDescriptor) {
361 return this.byRepeaterInner(true, repeatDescriptor);
362 }
363 /**
364 * Find elements by CSS which contain a certain string.
365 *
366 * @view
367 * <ul>
368 * <li class="pet">Dog</li>
369 * <li class="pet">Cat</li>
370 * </ul>
371 *
372 * @example
373 * // Returns the li for the dog, but not cat.
374 * var dog = element(by.cssContainingText('.pet', 'Dog'));
375 *
376 * @param {string} cssSelector css selector
377 * @param {string|RegExp} searchString text search
378 * @returns {ProtractorLocator} location strategy
379 */
380 cssContainingText(cssSelector, searchText) {
381 searchText = (searchText instanceof RegExp) ? '__REGEXP__' + searchText.toString() : searchText;
382 return {
383 findElementsOverride: (driver, using, rootSelector) => {
384 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findByCssContainingText, cssSelector, searchText, using, rootSelector));
385 },
386 toString: () => {
387 return 'by.cssContainingText("' + cssSelector + '", "' + searchText + '")';
388 }
389 };
390 }
391 ;
392 /**
393 * Find an element by ng-options expression.
394 *
395 * @alias by.options(optionsDescriptor)
396 * @view
397 * <select ng-model="color" ng-options="c for c in colors">
398 * <option value="0" selected="selected">red</option>
399 * <option value="1">green</option>
400 * </select>
401 *
402 * @example
403 * var allOptions = element.all(by.options('c for c in colors'));
404 * expect(allOptions.count()).toEqual(2);
405 * var firstOption = allOptions.first();
406 * expect(firstOption.getText()).toEqual('red');
407 *
408 * @param {string} optionsDescriptor ng-options expression.
409 * @returns {ProtractorLocator} location strategy
410 */
411 options(optionsDescriptor) {
412 return {
413 findElementsOverride: (driver, using, rootSelector) => {
414 return driver.findElements(selenium_webdriver_1.By.js(clientSideScripts.findByOptions, optionsDescriptor, using, rootSelector));
415 },
416 toString: () => {
417 return 'by.option("' + optionsDescriptor + '")';
418 }
419 };
420 }
421 ;
422 /**
423 * Find an element by css selector within the Shadow DOM.
424 *
425 * @alias by.deepCss(selector)
426 * @view
427 * <div>
428 * <span id="outerspan">
429 * <"shadow tree">
430 * <span id="span1"></span>
431 * <"shadow tree">
432 * <span id="span2"></span>
433 * </>
434 * </>
435 * </div>
436 * @example
437 * var spans = element.all(by.deepCss('span'));
438 * expect(spans.count()).toEqual(3);
439 *
440 * @param {string} selector a css selector within the Shadow DOM.
441 * @returns {Locator} location strategy
442 */
443 deepCss(selector) {
444 // TODO(julie): syntax will change from /deep/ to >>> at some point.
445 // When that is supported, switch it here.
446 return selenium_webdriver_1.By.css('* /deep/ ' + selector);
447 }
448 ;
449}
450exports.ProtractorBy = ProtractorBy;
451//# sourceMappingURL=locators.js.map
\No newline at end of file