You will need a manual way to know that Angular has bootstrapped from within your specs. Here's the basic run-down of how I have this set up with Angular, RequireJS and Protractor. This works for me with jasmine2
and old jasmine.
We want to add a class of ng-app
to the element that Angular bootstraps. For example:
index.html
<html lang="en" class="ng-app">
But rather than putting this in the HTML file, we want to add the class using the same RequireJS module that is manually bootstrapping your Angular App. Eg:
ng-bootstrap.js
require(['angular'], function (angular, otherdeps) {
// Start the Angular App
angular.bootstrap(document, ['MyApp']);
// Set the ng-app class for Angular Protractor tests
var root = document.documentElement;
angular.element(root).addClass('ng-app');
});
Check that your page adds this class after bootstrapping. then set up your protractor.conf
exports to run the onprepare
test. This spec is executed each time Protractor is launched and we will use it to check for the class you added in the ng-bootstrap.js module.
protractor-conf.js
exports.config = {
// Every time protractor is launched:
onPrepare: 'onprepare.e2e.js',
};
In your onprepare.e2e.js
spec file, you can trigger the load of the home page. Then ask Protractor to wait until the class .ng-app
is found on the root element, Ie: Angular has bootstrapped and is ready to run Protractor tests.
onprepare.e2e.js
describe("On prepare", function () {
// Replace with your own URL
var baseUrl = 'http://127.0.0.1:8001/#/';
// Begin fetching the page
browser.driver.get(baseUrl);
// Wait until `.ng-app` is found on the root elem
browser.driver.wait(function () {
return browser.driver.getCurrentUrl().then(function (url) {
return browser.driver.isElementPresent(by.className('ng-app')).then(function () {
return true;
});
});
});
});
Keep in mind that if you a running lots of spec files together, your page could is being re-loaded when a new test starts. Your page also may be being reloaded if your Angular router is using a reload: true
param.
This means that the app has to bootstrap again; And you will need to wait for the bootstrap class again before you can use Protractor.
Add a helper for this and include it in your protractor-conf.js
.
helpers.js
module.exports = {
get: function (url) {
browser.driver.get(url);
browser.driver.wait(function () {
return browser.driver.getCurrentUrl().then(function (url) {
return browser.driver.isElementPresent(by.className('ng-app')).then(function () {
return true;
});
});
});
},
};
protractor-conf.js
helpers = require('helpers.js');
exports.config = {
onPrepare: 'onprepare.e2e.js',
specs: [
'my-spec.js'
]
};
Now your helper is globally visible to your specs and you can use your new helper.get(url)
method instead of browser.driver.get(url)
. Example:
my-spec.js
describe("Users", function() {
it('should login', function () {
// Wait for Angular and RequireJS to finish
helpers.get('http://127.0.0.1:8001/#/login');
// ...tests here...
});
});