14

I'm testing Protractor with a small AngularJS app.

This is the test:

describe('Testing Protractor', function() {
  var draftList;

  it('should count the number of drafts', function() {
    browser.get('#/');
    draftList = element.all(by.repeater('newsletter in drafts'));
    expect(draftList.count()).toEqual(2);
  });
});

Controller:

angular.module('myApp.controllers', []).
  controller('DraftsCtrl', ['$scope', 'Draft', function($scope, Draft) {
    $scope.drafts = Draft.query();
}])

Draft service:

angular.module('myApp.services', ['ngResource']).
  factory('Draft', ['$resource',
    function($resource) {
      return $resource('api/drafts/:id')
    }])

Running this test using Protractor results in the following error:

Error: Timed out waiting for Protractor to synchronize with the page after 11 seconds

However, if in the controller I change this line:

$scope.drafts = Draft.query();

to this:

$scope.drafts = [];

The test fails as expected, but more importantly: it does not time out.

With query() enabled, both when running the app manually in a browser and when looking at the browser window opened by Protractor, the data returned by the API is correctly displayed by a repeater.

Why is Protractor not able to synchronize with the page when the service is communicating with the API?

AngularJS is v1.2.0-rc3. Protractor is v0.12.0.

Joseph S.
  • 475
  • 1
  • 6
  • 11

4 Answers4

26

This is a known issue, but there is a temporary workaround. Set ptor.ignoreSynchronization = true.

For example:

describe('Testing Protractor', function() {
  var draftList;
  var ptor;

  beforeEach(function() {
    ptor = protractor.getInstance();
    ptor.ignoreSynchronization = true;
  });

  it('should count the number of drafts', function() {
    ptor.get('#/');
    draftList = element.all(by.repeater('newsletter in drafts'));
    expect(draftList.count()).toEqual(2);
  });
});
Harri Siirak
  • 1,182
  • 12
  • 15
  • 1
    Thanks, I'll try this out later and let you know whether it worked. I actually did read that GitHub issue before posting here, but I was under the impression that the workaround is only required when polling an API at regular intervals which my test app is not doing. It only sends the API request once, when the controller is initialized. – Joseph S. Nov 08 '13 at 11:19
  • 10
    This was indeed the correct solution. Since Protractor 0.12.0 exposes the instance of Protractor as `browser`, it was enough to just add `browser.ignoreSynchronization = true;` before `element.all(by.repeater(' ... '));`. – Joseph S. Nov 10 '13 at 09:57
  • protractor.getInstance() had been unused (replaced by global browser in v0.12.0) and is [now removed](https://github.com/angular/protractor/blob/master/CHANGELOG.md#breaking-changes). – orszaczky Jun 26 '17 at 19:27
3

browser.ignoreSynchronization = true; worked out for me.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Lokesh
  • 214
  • 2
  • 11
1

I'm using Protractor 3.3.0 and to get this to work in my test I had to defer the ignore synchronisation until after I had done the setup.

So in my beforeEach I call my action:

var searchBox = element(by.css('#inpt_search'));
searchBox.sendKeys('test');

I then have to wait for the mock backend to populate the view (I'm not happy about these sleep calls so if anyone has a better way of doing this please comment, I can't get expectedConditions.presenceOf to work as it's part of the same bug) using browser.sleep(500). Then in the test I set browser.ignoreSynchronization = true which unblocks whatever is blocked and sees the browser content.

describe('standard search', function (){
    beforeEach(function (){
        openApp();
        var searchBox = element(by.css('#inpt_search'));
        searchBox.sendKeys('test');
        browser.sleep(500);
    });
    it('should work or summat', function () {
        browser.ignoreSynchronization = true;
        var fileItems = element.all(by.repeater('item in list'));
        expect(fileItems.count()).toEqual(50);
    });
});
Stevo
  • 2,601
  • 3
  • 24
  • 32
1

Instead of using browser.ignoreSynchronization, use browser.waitForAngularEnabled(*boolean*). browser.waitForAngularEnabled(false) sets browser.ignoreSynchronization to true, browser.waitForAngularEnabled(true) sets browser.ignoreSynchronization to false.

you can also include this as part of your test suites' config file:

onPrepare: function () {
    'use strict';
    browser.waitForAngularEnabled(false);
}
Arets Paeglis
  • 3,856
  • 4
  • 35
  • 44