Question

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.

Was it helpful?

Solution

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);
  });
});

OTHER TIPS

browser.ignoreSynchronization = true; worked out for me.

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);
    });
});

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top