Search for an element in a repeater containing specific text using a protractor

How can I search for an element from a repeater containing specific text?

I tried things like this:

element(by.repeater('item in array')).all(by.cssContainingText('.xyz','my item title')); // only gets the first element 

I could search on my own using .then after element.all , but I wonder if there is something simpler like cssContainingText , but for repeaters:

 element(by.repeaterContainingText('item in array','my item title')) 

or chain of elements:

 element.all(by.repeater('item in array')).element(by.cssContainingText('.xyz','my item title')); 

Filter solution (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]; }) 
+6
source share
3 answers

The protractor allows you to add locators. I successfully use the following implementation (pure javascript) in a project with 20 tests or so.

Here is a solution using lodash and jquery. Below also there is 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){...}) 

Do not forget the following about the transporter and locators

I just spent 2 hours puzzling why my locator wasn’t working. remember the following:

  • protractor "ignores" hidden elements, however your locator does not do this by default .. therefore, if you write a custom locator to make it work as expected in angular, you must filter the hidden elements
  • If you need to debug, I found it most useful using getOuterHtml().then..

Pure javascript

Here's how it would 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(); }); }); 

Important note - or - why this should be the correct answer

Using filter , you will get a promise. using this solution, you get the item. So instead of getByText(..).then(function(e){ e.click() }) you will get getByText(...).click() - sweeet!

Limitations and Possible Improvements

in your case, the repeater locator cannot be used, which is a chip, unless you change the location instead of text as textInRepeater , and then add '[ng-repeat=' + repeater + ']' to the code.

Another thing you can improve, which is very useful. Sometimes you want to get an element containing the text CONTAINS, or perhaps containing a child element with the text, but you really want to select the parent.

+2
source

Yes, you can chain items in the transporter.

 element(locator1).element(locator2); 

protractor-Locators.md

+1
source

I know that you most likely no longer need an answer, but although I would update it if someone else has a problem. you can use

 element(by.linkText('.xyz')); 
-1
source

Source: https://habr.com/ru/post/973116/


All Articles