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', 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', 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.