Reputation: 81
I'm new to AngularJS/protractor so any guidance on this is much appreciated. Since Angular JS instantiates html elements via ng- directives there are no 'id's etc that allow me to locate specific elements. (Obviously I want to do this to validate content, click them etc.) My angular js snippet looks like:
<div ng-repeat="item in myList">
<span ng-if="item.category == 'lights'">
<img src="../../../{{item.icon}}"/>
 <span id="foo">{{item.name}}</span> 
</span>
</div>
I'm trying to locate the elements {{item.name}} as I iterate over the list with this:
element.all(by.repeater('item in myList')).then(function(rows) {
noOfItems = rows.length;
for (i = 0; i < noOfItems; i++) {
row = element.all(by.repeater('item in myList')).get(i);
row.isElementPresent(By.id('foo')).then(function (isP) {
if (isP) {
console.log("foo exists?" + isP);
row.findElement(By.id('foo')).then(function (el) {
el.getText(txt).then(function (txt) {
console.log("Item name " + txt);
});
});
}
});
}
});
From inspection the 'row' element seems to be selenium object so I invoke 'isElementPresent(...) and this works great. It detects the correct number of 'foo' elements. However when row.findElement(...) runs, the test spec terminates prematurely. (No errors, it just ends)
I know that there will be multiple 'foo' elements in the document however I was hoping that since they are being queried within a sub html element, (row) this might work.
Any suggestions/workarounds?
Upvotes: 6
Views: 7358
Reputation: 1
var eleB = element(by.css('.ui-grid-render-container.ng-isolate-scope.ui-grid-render-container-body'));
eleB.element(by.repeater('(rowRenderIndex, row) in rowContainer.renderedRows track by $index').row(10)).$('.ui-grid-cell.ng-scope.ui-grid-coluiGrid-000B').getText().then(function(arr){
console.log("-------------------\n" + arr);
});
Upvotes: 0
Reputation: 2981
By the way another approach to finding the right Angular generated elements is to use the by.js
locator. This is not a Protractor specific locator but one provided by the underlying WebDriverJS so you have to look there for the docs.
Essentially by.js
lets you provide a javascript function that will be run on the browser to find the element you are looking for. The javascript in turn can interrogate DOM elements to find and inspect the Angular $scopes that have been attached to them and thereby find elements that have specific scope values. For example, you can thereby find an element associated with an actual recordId which is present in the scope but was never rendered into HTML. This is very useful because, given how angular works, you rarely need to render these sorts of ids into HTML, but tests still need to be able to find the elements that represent them!
Upvotes: 1
Reputation: 2981
Before addressing your specific question, a couple of things seem to be amiss here.
1) I don't think line 4 in the above is what you want to do. It is going to go back to the browser for every row, re-running the by.repeater query each time. All you really need to do is row = rows[i]
.
2) Better yet you could simply replace the first four lines with element.all(by.repeater('item in myList')).each(function(row){
As for the question of finding the foo span in context, you might try finding by.css(':scope #foo')
. That should give you a search for id='foo' in the scope of the current element.
Upvotes: 1