6

Problem

Calling repeater('#myTable tr','Rows').count(); returns a Future, not an integer. I need to get the integer value so I can confirm that an additional row was added to a table.

Code

it('should add a new user when save button is clicked',function()
    {
        showModal();

        //here I'm trynig to store the row count of my table into  a local variable.
        //a future is returned who's 'value' field is undefined.
        var memberCount = repeater('#memberTable tr','Member Rows').count();

        //this outputs 'undefined'
        console.log(memberCount.value);


        input('editedMember.name').enter('John');
        input('editedMember.grade').enter(5);
        input('editedMember.ladderPosition').enter(3);

        element('#saveMemberButton').click();
        sleep(1);
        expect(element(modalId).css('display')).toBe('none');

        //here is where I want to do the comparison against the above stored memberCount
        expect(repeater('#memberTable tr', 'Member Rows').count()).toBe(memberCount.value + 1);


    });

Test Result

Chrome 25.0 e2e should add a new user when save button is clicked FAILED
    expect repeater 'Member Rows ( #memberTable tr )' count toBe null
    /Users/jgordon/learning/chessClub/web-app/test/e2e/scenarios.js:45:3: expected null but was 6
Chrome 25.0: Executed 2 of 2 (1 FAILED) (1 min 4.117 secs / 1 min 3.773 secs)
John Gordon
  • 2,181
  • 5
  • 28
  • 47

4 Answers4

4

Drilling into the source code for Angularjs' e2e support reveals that you have to call execute() on the Future to have it populate its value. Also, when you call execute you have to provide a "done" function to the execute() otherwise Testacular will (oddly enough!) skip your test.

Code

var rowCountFuture = repeater('#memberTable tr','Member Rows').count();
        
        rowCountFuture.execute(function(){
        });
        
        var memberCount = rowCountFuture.value;

While I'm jazzed to see this works, I'm concerned there may be some asynchronous bugs that could come out of this, also, I feel like this is a hack and not the right way to do it. Any ideas?

Community
  • 1
  • 1
John Gordon
  • 2,181
  • 5
  • 28
  • 47
  • I've just bumped into this problem as well, could you please elaborate more regarding your solution ? if can provide code example it'll be very helpful ! Thanks ! – Igal Mar 13 '13 at 15:57
  • Call the `count()` method like the 1st line above. That returns a `Future` -- an object that will fetch the count of your repeater when you call the `execute()` method. Pass in an empty function to satisfy it. After `execute()` has been called, you can get the count of your rows by accessing the `Future`'s `value` property. – John Gordon Mar 13 '13 at 19:46
  • I've tried it already, but then I'm getting next error : "Frame window is not accessible." – Igal Mar 14 '13 at 08:26
  • I've revisited this and find I'm getting the same error, too. I wonder if there was some update that changed this behaviour. I'm marking this as unanswered. – John Gordon Mar 18 '13 at 19:50
  • Brilliance. This is the kind of thing that makes Angular very difficult to pick up, but very exciting and powerful at the same time. – eighteyes Oct 04 '13 at 22:16
2

Based on the latest Protractor version:

it('should add a new user when save button is clicked', function() {
    var memberCount;
    element.all(by.repeater('#memberTable tr','Member Rows')).count().then(function(value) {
        memberCount = value;
    });
    ...
    // then do all your entering user info, saving etc.
    ...
    browser.refresh(); // or however you want to load new data
    expect(element.all(by.repeater('#memberTable tr','Member Rows')).count()).toEqual(memberCount + 1);
});
zewt112
  • 320
  • 5
  • 12
1

I've run into the same issue, and have seen confusing results when testing value returned after calling execute(). I've found this method works more reliably:

var getCount = repeater('ul li').count();
getCount.execute(function(value) {
    expect(value).toEqual(3);
});
David Woods
  • 648
  • 7
  • 8
1

You can do this most easily in the async promise returned by the locator

element.all(By.repeater 'thing in things').then(function(elements){
      count = elements.length;
      expect(count).toEqual(3);
});
ricick
  • 5,694
  • 3
  • 25
  • 37