Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using protractor to test an angularjs app, how do i keep a reference to one of the rows of element.all when the array changes as I work with it?

I have an ng-repeat which has a new element added to it as soon as the existing "last" element is modified in any way. My protractor test looks something like this:

var emptyPerson = this.people.last() // this gets me the last row of the ng-repeat
emptyPerson.element(by.css('.firstName')).sendKeys('first'); // this sets the firstname correctly but then the app adds a new row to the ng-repeat because of the model change here.
emptyPerson.element(by.css('.lastName')).sendKeys('last');  // this sets the lastname of the new row instead of the row that emptyPerson previously referenced

Is there any way to essentially tell emptyPerson to stick to the same element until we're done with it?

Example HTML before firstname is edited:

<div ng-repeat="person in object.People" class="student ng-scope">
  <div type="text" ng-model="person.FirstName" skip-label="true" placeholder="First" validator="svalidators[$index]" class="layout-default field field-FirstName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="First" ng-model="lModel.val" name="person-FirstName">
  </div>
  <div type="text" ng-model="person.LastName" skip-label="true" placeholder="Last" validator="svalidators[$index]" class="layout-default field field-LastName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="Last" ng-model="lModel.val" name="person-LastName">
</div>

example after firstname is edited:

<div ng-repeat="person in object.People" class="student ng-scope">
  <div type="text" ng-model="person.FirstName" skip-label="true" placeholder="First" validator="svalidators[$index]" class="layout-default field field-FirstName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="First" ng-model="lModel.val" name="person-FirstName">
  </div>
  <div type="text" ng-model="person.LastName" skip-label="true" placeholder="Last" validator="svalidators[$index]" class="layout-default field field-LastName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="Last" ng-model="lModel.val" name="person-LastName">
</div>
<div ng-repeat="person in object.People" class="student ng-scope">
  <div type="text" ng-model="person.FirstName" skip-label="true" placeholder="First" validator="svalidators[$index]" class="layout-default field field-FirstName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="First" ng-model="lModel.val" name="person-FirstName">
  </div>
  <div type="text" ng-model="person.LastName" skip-label="true" placeholder="Last" validator="svalidators[$index]" class="layout-default field field-LastName type-text">
    <input type="text" ng-focus="myFocus()" ng-blur="myBlur()" class="form-control" placeholder="Last" ng-model="lModel.val" name="person-LastName">
</div>
like image 875
Robert Avatar asked Nov 09 '22 09:11

Robert


1 Answers

This is how Protractor works internally. It searches for the element at the time an action is applied on the element. I am afraid you have to handle it "manually" and re-reference the desired repeater item.

To make things a little bit better in terms of coding, I would hide the first interaction with the repeater item part in a function - basically, touching the input for repeater to have one more item, then returning the item before last. Something along the lines:

var MyPageObject = function () {
    this.people = element(by.repeater("person in object.People"));

    this.touch = function () {
        var emptyPerson = this.people.last();
        emptyPerson.element(by.css('.firstName')).sendKeys('smth');

        var newEmptyPerson = this.people.get(-2);  // I think -1 would be the last
        emptyPerson.element(by.css('.firstName')).clear();

        return newEmptyPerson;
    }

    this.fillForm = function () {
        var emptyPerson = this.touch();

        emptyPerson.element(by.css('.firstName')).sendKeys('first');
        emptyPerson.element(by.css('.lastName')).sendKeys('last');    
    }
}
like image 94
alecxe Avatar answered Nov 26 '22 01:11

alecxe