Protractor times out waiting for sync with page when using $resource
Asked Answered
M

4

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.

Monegasque answered 2/11, 2013 at 12:28 Comment(0)
T
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);
  });
});
Testee answered 7/11, 2013 at 22:55 Comment(3)
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.Monegasque
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(' ... '));.Monegasque
protractor.getInstance() had been unused (replaced by global browser in v0.12.0) and is now removed.Marna
C
3

browser.ignoreSynchronization = true; worked out for me.

Capitol answered 30/10, 2015 at 7:35 Comment(0)
S
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);
    });
});
Smoothshaven answered 4/6, 2016 at 10:27 Comment(0)
C
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);
}
Cyclic answered 26/9, 2017 at 21:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.