Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit 34f0eeb

Browse files
committed
fix(element): update to [email protected] and remove element.then
This change updates the version of WebDriverJS (selenium-webdriver node module) from 2.44 to 2.45.1. See the full changelog at https://github.com/SeleniumHQ/selenium/blob/master/javascript/node/selenium-webdriver/CHANGES.md To enable the update and remove confusion, this removes the `element().then` function unless there is an action result. This function is completely unnecessary, because it would always resolve to itself, but the removal may cause breaking changes. Before: ```js element(by.css('foo')).then(function(el) { return el.getText().then(...); }); ``` After: ```js element(by.css('foo')).getText().then(...); ``` In other words, an ElementFinder is now no longer a promise until an action has been called. Before: ```js var el = element(by.css('foo')); protractor.promise.isPromise(el); // true protractor.promise.isPromise(el.click()); // true ``` After: ```js var el = element(by.css('foo')); protractor.promise.isPromise(el); // false protractor.promise.isPromise(el.click()); // true ``` Also, fixes `filter` and `map` to work with the new WebDriverJS.
1 parent 93ccca1 commit 34f0eeb

File tree

6 files changed

+53
-84
lines changed

6 files changed

+53
-84
lines changed

lib/element.js

+39-53
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
var util = require('util');
21
var webdriver = require('selenium-webdriver');
32
var log = require('./logger.js');
43
var clientSideScripts = require('./clientsidescripts.js');
54

65
var WEB_ELEMENT_FUNCTIONS = [
76
'click', 'sendKeys', 'getTagName', 'getCssValue', 'getAttribute', 'getText',
87
'getSize', 'getLocation', 'isEnabled', 'isSelected', 'submit', 'clear',
9-
'isDisplayed', 'getOuterHtml', 'getInnerHtml', 'getId'];
8+
'isDisplayed', 'getOuterHtml', 'getInnerHtml', 'getId', 'getRawId'];
109

1110
/**
1211
* ElementArrayFinder is used for operations on an array of elements (as opposed
@@ -78,7 +77,6 @@ var ElementArrayFinder = function(ptor, getWebElements, locator, opt_actionResul
7877
};
7978
});
8079
};
81-
util.inherits(ElementArrayFinder, webdriver.promise.Promise);
8280

8381
exports.ElementArrayFinder = ElementArrayFinder;
8482

@@ -209,18 +207,17 @@ ElementArrayFinder.prototype.filter = function(filterFn) {
209207
var elementFinder =
210208
ElementFinder.fromWebElement_(self.ptor_, parentWebElement, self.locator_);
211209

212-
var filterResults = filterFn(elementFinder, index);
213-
if (filterResults instanceof webdriver.promise.Promise) {
214-
filterResults.then(function(satisfies) {
215-
if (satisfies) {
216-
list.push(parentWebElements[index]);
217-
}
218-
});
219-
} else if (filterResults) {
220-
list.push(parentWebElements[index]);
221-
}
210+
list.push(filterFn(elementFinder, index));
211+
});
212+
return webdriver.promise.all(list).then(function(resolvedList) {
213+
var filteredElementList = [];
214+
resolvedList.forEach(function(result, index) {
215+
if (result) {
216+
filteredElementList.push(parentWebElements[index]);
217+
}
218+
});
219+
return filteredElementList;
222220
});
223-
return list;
224221
});
225222
};
226223
return new ElementArrayFinder(this.ptor_, getWebElements, this.locator_);
@@ -533,11 +530,9 @@ ElementArrayFinder.prototype.map = function(mapFn) {
533530
arr.forEach(function(elementFinder, index) {
534531
var mapResult = mapFn(elementFinder, index);
535532
// All nested arrays and objects will also be fully resolved.
536-
webdriver.promise.fullyResolved(mapResult).then(function(resolved) {
537-
list.push(resolved);
538-
});
533+
list.push(webdriver.promise.fullyResolved(mapResult));
539534
});
540-
return list;
535+
return webdriver.promise.all(list);
541536
});
542537
};
543538

@@ -637,10 +632,10 @@ ElementArrayFinder.prototype.allowAnimations = function(value) {
637632
*
638633
* The ElementFinder can be treated as a WebElement for most purposes, in
639634
* particular, you may perform actions (i.e. click, getText) on them as you
640-
* would a WebElement. ElementFinders extend Promise, and once an action
641-
* is performed on an ElementFinder, the latest result from the chain can be
642-
* accessed using then. Unlike a WebElement, an ElementFinder will wait for
643-
* angular to settle before performing finds or actions.
635+
* would a WebElement. Once an action is performed on an ElementFinder, the
636+
* latest result from the chain can be accessed using the then method.
637+
* Unlike a WebElement, an ElementFinder will wait for angular to settle before
638+
* performing finds or actions.
644639
*
645640
* ElementFinder can be used to build a chain of locators that is used to find
646641
* an element. An ElementFinder does not actually attempt to find the element
@@ -680,6 +675,28 @@ var ElementFinder = function(ptor, elementArrayFinder) {
680675
this.ptor_ = ptor;
681676
this.parentElementArrayFinder = elementArrayFinder;
682677

678+
// Only have a `then` method if the parent element array finder
679+
// has action results.
680+
if (this.parentElementArrayFinder.actionResults_) {
681+
/**
682+
* Access the underlying actionResult of ElementFinder.
683+
*
684+
* @param {function(webdriver.promise.Promise)} fn Function which takes
685+
* the value of the underlying actionResult.
686+
*
687+
* @return {webdriver.promise.Promise} Promise which contains the results of
688+
* evaluating fn.
689+
*/
690+
this.then = function(fn, errorFn) {
691+
return this.elementArrayFinder_.then(function(actionResults) {
692+
if (!fn) {
693+
return actionResults[0];
694+
}
695+
return fn(actionResults[0]);
696+
}, errorFn);
697+
};
698+
}
699+
683700
// This filter verifies that there is only 1 element returned by the
684701
// elementArrayFinder. It will warn if there are more than 1 element and
685702
// throw an error if there are no elements.
@@ -717,7 +734,6 @@ var ElementFinder = function(ptor, elementArrayFinder) {
717734
};
718735
});
719736
};
720-
util.inherits(ElementFinder, webdriver.promise.Promise);
721737

722738
exports.ElementFinder = ElementFinder;
723739

@@ -770,25 +786,6 @@ ElementFinder.prototype.getWebElement = function() {
770786
return new webdriver.WebElementPromise(this.ptor_.driver, id);
771787
};
772788

773-
/**
774-
* Access the underlying actionResult of ElementFinder. Implementation allows
775-
* ElementFinder to be used as a webdriver.promise.Promise
776-
*
777-
* @param {function(webdriver.promise.Promise)} fn Function which takes
778-
* the value of the underlying actionResult.
779-
*
780-
* @return {webdriver.promise.Promise} Promise which contains the results of
781-
* evaluating fn.
782-
*/
783-
ElementFinder.prototype.then = function(fn, errorFn) {
784-
return this.elementArrayFinder_.then(function(actionResults) {
785-
if (!fn) {
786-
return actionResults[0];
787-
}
788-
return fn(actionResults[0]);
789-
}, errorFn);
790-
};
791-
792789
/**
793790
* Calls to {@code all} may be chained to find an array of elements within a
794791
* parent.
@@ -957,17 +954,6 @@ ElementFinder.prototype.allowAnimations = function(value) {
957954
return this.elementArrayFinder_.allowAnimations(value).toElementFinder_();
958955
};
959956

960-
/**
961-
* Webdriver relies on this function to be present on Promises, so adding
962-
* this dummy function as we inherited from webdriver.promise.Promise, but
963-
* this function is irrelevant to our usage
964-
*
965-
* @return {boolean} Always false as ElementFinder is never in pending state.
966-
*/
967-
ElementFinder.prototype.isPending = function() {
968-
return false;
969-
};
970-
971957
/**
972958
* Shortcut for querying the document directly with css.
973959
*

lib/protractor.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ Protractor.prototype.findElements = function(locator) {
329329
* the element is present on the page.
330330
*/
331331
Protractor.prototype.isElementPresent = function(locatorOrElement) {
332-
var element = (locatorOrElement instanceof webdriver.promise.Promise) ?
332+
var element = (locatorOrElement.isPresent) ?
333333
locatorOrElement : this.element(locatorOrElement);
334334
return element.isPresent();
335335
};

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"author": "Julie Ralph <[email protected]>",
1414
"dependencies": {
1515
"request": "~2.36.0",
16-
"selenium-webdriver": "2.44.0",
16+
"selenium-webdriver": "2.45.1",
1717
"minijasminenode": "1.1.1",
1818
"jasminewd": "1.1.0",
1919
"jasminewd2": "0.0.2",

spec/basic/elements_spec.js

+5-28
Original file line numberDiff line numberDiff line change
@@ -157,36 +157,18 @@ describe('ElementFinder', function() {
157157
expect(successful).toEqual(false);
158158
});
159159

160-
it('then function should be equivalent to itself', function() {
161-
browser.get('index.html#/form');
162-
var elem = element(by.binding('greeting'));
163-
164-
elem.then(function(elem2) {
165-
expect(elem.getId()).toEqual(elem2.getId());
166-
});
167-
});
168-
169-
it('should not resolve to itself', function() {
170-
browser.get('index.html#/form');
171-
var elem1 = element(by.binding('greeting'));
172-
173-
elem1.then(function(result) {
174-
expect(result === elem1).toBe(false);
175-
});
176-
});
177-
178160
it('should be returned from a helper without infinite loops', function() {
179161
browser.get('index.html#/form');
180-
var helperPromise = element(by.binding('greeting')).then(function(result) {
181-
return result;
162+
var helperPromise = protractor.promise.when(true).then(function() {
163+
return element(by.binding('greeting'));
182164
});
183165

184166
helperPromise.then(function(finalResult) {
185167
expect(finalResult.getText()).toEqual('Hiya');
186168
});
187169
});
188170

189-
it('should be usable in WebDriver functions', function() {
171+
it('should be usable in WebDriver functions via getWebElement', function() {
190172
// TODO(juliemr): should be able to do this without the getWebElement call
191173
browser.get('index.html#/form');
192174
var greeting = element(by.binding('greeting'));
@@ -509,16 +491,11 @@ describe('ElementArrayFinder', function() {
509491
'4/5: small cat\n');
510492
});
511493

512-
it('should always return a promise when calling then', function() {
513-
browser.get('index.html#/form');
514-
var e1 = element(by.tagName('body')).then(function() {});
515-
expect(e1 instanceof protractor.promise.Promise).toBe(true);
516-
});
517-
518494
it('should allow using protractor locator within map', function() {
519495
browser.get('index.html#/repeater');
520496

521-
var expected = [{ first: 'M', second: 'Monday' },
497+
var expected = [
498+
{ first: 'M', second: 'Monday' },
522499
{ first: 'T', second: 'Tuesday' },
523500
{ first: 'W', second: 'Wednesday' },
524501
{ first: 'Th', second: 'Thursday' },

spec/basic/locators_spec.js

+6
Original file line numberDiff line numberDiff line change
@@ -388,4 +388,10 @@ describe('locators', function() {
388388
expect(browser.isElementPresent(by.binding('greet'))).toBe(true);
389389
expect(browser.isElementPresent(by.binding('nopenopenope'))).toBe(false);
390390
});
391+
392+
it('should determine if an ElementFinder is present', function() {
393+
expect(browser.isElementPresent(element(by.binding('greet')))).toBe(true);
394+
expect(browser.isElementPresent(element(by.binding('nopenopenope'))))
395+
.toBe(false);
396+
})
391397
});

spec/withLoginConf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ exports.config = {
2828
browser.driver.wait(function() {
2929
return browser.driver.getCurrentUrl().then(function(url) {
3030
return /index/.test(url);
31-
});
31+
}, 10000);
3232
});
3333
}
3434
};

0 commit comments

Comments
 (0)