How could I search an element from a repeater containing a specific text ?
I tried things like that :
element(by.repeater('item in array')).all(by.cssContainingText('.xyz','my item title')); // only gets the first element
I could search by myself using .then
after element.all
but I'm wondering if it exists something simpler like cssContainingText
but for repeaters :
element(by.repeaterContainingText('item in array','my item title'))
or a element chaining like that :
element.all(by.repeater('item in array')).element(by.cssContainingText('.xyz','my item title'));
A solution with filter (but very slow)
element.all(by.repeater('item in array')).filter(function(elem){
return elem.getText().then(function(text){
return text.indexOf('my item title') > -1;
});
}).then(function(filteredElements) {
return filteredElements[0];
})
Protractor allows adding locators.. I am using the following implementation (pure javascript) successfully in a project with 20 tests or so.
Here is a solution using lodash and jquery. Below there is also one in pure javascript.
https://gist.github.com/GuyMograbi/7a5f5e580bcf8d7da58a
by.addLocator('text',
/**
*
* @param {string} text - will be lowercased
* @param {string} selector - to get list of children
* @param {null|object} parent - protractor will provide this..
*/
function(text, selector, parent) {
return _.filter($(parent || 'body').find(selector), function(e){
return $(e).is(':visible') && $(e).text().toLowerCase().trim() === text.toLowerCase().trim();
});
});
and use it with
return $('table').all(by.text('my text', 'tr')).first().getText().then(function(text){...})
or
return element(by.text('my text', 'tr')).getText().then(function(text){...})
I just spent 2 hours breaking my brains as to why my locator does not work. please remember the following:
getOuterHtml().then..
This is how the same will look without jquery and lodash
by.addLocator('text',
/**
*
* @param text - will be lowercased
* @param selector - to get list of children
* @param parent - protractor will provide this..
*/
function(text, selector, _parent) {
return Array.prototype.filter.call( (_parent || document).querySelectorAll(selector), function(e){
return e && !!(e.offsetWidth || e.offsetHeight || e.getClientRects().length) && e.textContent && e.textContent.toLowerCase().trim() === text.toLowerCase().trim();
});
});
isVisible
part was eventually taken from jquery sources. see answer at: https://stackoverflow.com/a/33456469/1068746
Using filter
you get a promise. using this solution you get an element. So instead of having a getByText(..).then(function(e){ e.click() })
you will have getByText(...).click()
- sweeet!
in your case, the repeater locator cannot be used which is a bummer, unless you modify the location instead of text
to be textInRepeater
and then have '[ng-repeat=' + repeater + ']'
somehow added in the code.
Another thing you might want to enhance which is very useful. Sometime you want to get an element which CONTAINS text, or possibly contains a child with text, but you actually want to select the parent.
Yes you can chain elements in Protractor.
element(locator1).element(locator2);
protractor-Locators.md
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With