1

I am attempting to set up end-to-end tests for our angular app but am coming across a few hurdles.

One is bootstrapping. We are using this library: angular-deferred-bootstrap to bootstrap our application. This library allows us to make http calls the result of which is then injected into our app (as angular value()). Then it calls the bootstrap function to actually bootstrap the app with angular. I want the tests to run after this boostrapping is complete.

This is what I have done so far

describe('navigation should', function () {
    beforeEach(function () {
        // load homepage
        browser.get('/');
    }, 10000);

    it('show side navigation', function () {
        browser.wait(function () {
            var deferred = protractor.promise.defer();

            element(by.css('body.deferred-bootstrap-loading')).isPresent()
                .then(function (isPresent) {
                    deferred.fulfill(!isPresent);
                });

            return deferred.promise;
        });
    });
});

The library conveniently puts a deferred-bootstrap-loading class on the body. I am waiting until this is removed.

Problem is sometimes I am getting the error Error while waiting for Protractor to sync with the page: "[ng:test] no injector found for element argument to getTestability\nhttp://errors.angularjs.org/1.4.8/ng/test".

It seems to produce this error more often than it (the test) passing.

I don't understand what the issue is here? Is protractor running before angular has had a chance to run?

Would I have to run all my tests inside a callback as browser.wait returns a promise?

Also I would want this code to run for every test (wait for bootstrapping to finish). What is the best way to organize this?

BrTkCa
  • 4,703
  • 3
  • 24
  • 45
Umair
  • 3,063
  • 1
  • 29
  • 50

2 Answers2

2

What I would try to do is to turn the synchronization off until the expected condition is met:

beforeEach(function () {
    var EC = protractor.ExpectedConditions;

    browser.ignoreSynchronization = true;
    browser.get('/');

    // wait for deferred bootstrap body to not be present
    var body = $("body.deferred-bootstrap-loading");
    browser.wait(EC.stalenessOf(body), 10000).then(function () {
        browser.ignoreSynchronization = false;
    });
    browser.waitForAngular();  // might not be needed
});

Also I would want this code to run for every test (wait for bootstrapping to finish). What is the best way to organize this?

Please see:

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
0

As you use a manual/semi-manual bootstrap mechanism I would not use browser.get() as this waits for Angular to be loaded. Instead use browser.driver.get() and add a wait on the deferred-bootstrap-loading class afterwards. See Setting Up the System Under Test from Angular.

So something like the following should do the trick:

describe('navigation should', function () {
    beforeEach(function (done) {
        // load homepage
        browser.driver.get('/');
        browser.driver.wait(function () {
            return browser.driver.isElementPresent(by.class('body.deferred-bootstrap-loading'))
                .then(function (el) {
                    return el === false;
                });
        }).then(done);
    }, 10000);

    it('show side navigation', function () {
        // normal test here
    });
});

I have not tested the above, but you should get the picture. By making beforeEach async and wait for the class to disappear from the body tag you can expect everything to be running when you run your it blocks.

Bjørn Sørensen
  • 901
  • 1
  • 6
  • 14