Reputation: 3091
Durring some experiments with protractorJS i noticed that there is no easy way to extend (inherit) ElementFinder object from protractor to add own functions.
For example, i want to create object Checkbox, that would have additional method - check() - should switch checkbox depending on result of isSelected().
I come up with the code -
var ElementFinder = require('protractor/lib/element.js').ElementFinder;
var ElementArrayFinder = require('protractor/lib/element.js').ElementArrayFinder;
class CheckBox extends ElementFinder {
constructor(loc) {
var getWebElements = function () {
var ptor = browser;
var locator = loc;
return ptor.waitForAngular().then(function() {
if (locator.findElementsOverride) {
return locator.findElementsOverride(ptor.driver, null, ptor.rootEl);
} else {
return ptor.driver.findElements(locator);
}
});
}
var ArrayFinderFull = new ElementArrayFinder(browser, getWebElements, loc);
super(browser, ArrayFinderFull);
}
check() {
return this.isSelected().then(selected => selected? this.click() : null)
}
}
But getWebElements is copy-paste from protractor/element.js - https://github.com/angular/protractor/blob/3.1.0/lib/element.js#L131
This copy-paste flustrating me. I think there should be more proper way to extend ElementFinder.
Does anyone inherited ElementFinder in protractorJS?
Upvotes: 6
Views: 1555
Reputation: 3091
Now it is much simplier to extend ElementFinder, i calling this - page fragments.
I even created lib to solve this issue (PRs welcome!) - https://github.com/Xotabu4/protractor-element-extend
For now it only works with ElementFinder, but i want to be able to extend ElementArrayFinders as well (planned for 2.0.0 version)
Support for ElementArrayFinder inheritance is added.
Upvotes: 2
Reputation: 474003
I'm not sure this would help, but here is something we did recently to have a takewhile()
method available on an ElementArrayFinder
. We've put the following into onPrepare()
:
protractor.ElementArrayFinder.prototype.takewhile = function(whileFn) {
var self = this;
var getWebElements = function() {
return self.getWebElements().then(function(parentWebElements) {
var list = [];
parentWebElements.forEach(function(parentWebElement, index) {
var elementFinder =
protractor.ElementFinder.fromWebElement_(self.ptor_, parentWebElement, self.locator_);
list.push(whileFn(elementFinder, index));
});
return protractor.promise.all(list).then(function(resolvedList) {
var filteredElementList = [];
for (var index = 0; index < resolvedList.length; index++) {
if (!resolvedList[index]) {
break;
}
filteredElementList.push(parentWebElements[index])
}
return filteredElementList;
});
});
};
return new protractor.ElementArrayFinder(this.ptor_, getWebElements, this.locator_);
};
And now we can use takewhile
on the result of element.all()
:
element.all(by.repeater("row in rows")).takewhile(function (elm) {
return elm.getText().then(function (text) {
return some_condition_to_be_true;
});
});
Upvotes: 5