Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit f246880

Browse files
committed
feat(lib): add support for waiting for angular2
Use Angular2's testability API, if present, when waiting for stability or loading a page. Closes #2396
1 parent 04e5bfb commit f246880

File tree

4 files changed

+136
-30
lines changed

4 files changed

+136
-30
lines changed

lib/clientsidescripts.js

+13-5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ functions.waitForAngular = function(rootSelector, callback) {
5050
var el = document.querySelector(rootSelector);
5151

5252
try {
53+
if (window.getAngularTestability) {
54+
window.getAngularTestability(el).whenStable(callback);
55+
return;
56+
}
5357
if (!window.angular) {
5458
throw new Error('angular could not be found on the window');
5559
}
@@ -555,6 +559,8 @@ functions.findByCssContainingText = function(cssSelector, searchText, using) {
555559
*
556560
* @param {number} attempts Number of times to retry.
557561
* @param {function} asyncCallback callback
562+
*
563+
* @return {{version: ?number, message: ?string}}
558564
*/
559565
functions.testForAngular = function(attempts, asyncCallback) {
560566
var callback = function(args) {
@@ -564,19 +570,21 @@ functions.testForAngular = function(attempts, asyncCallback) {
564570
};
565571
var check = function(n) {
566572
try {
567-
if (window.angular && window.angular.resumeBootstrap) {
568-
callback([true, null]);
573+
if (window.getAllAngularTestabilities) {
574+
callback({ver: 2});
575+
} else if (window.angular && window.angular.resumeBootstrap) {
576+
callback({ver: 1});
569577
} else if (n < 1) {
570578
if (window.angular) {
571-
callback([false, 'angular never provided resumeBootstrap']);
579+
callback({message: 'angular never provided resumeBootstrap'});
572580
} else {
573-
callback([false, 'retries looking for angular exceeded']);
581+
callback({message: 'retries looking for angular exceeded'});
574582
}
575583
} else {
576584
window.setTimeout(function() {check(n - 1);}, 1000);
577585
}
578586
} catch (e) {
579-
callback([false, e]);
587+
callback({message: e});
580588
}
581589
};
582590
check(attempts);

lib/protractor.js

+37-25
Original file line numberDiff line numberDiff line change
@@ -621,40 +621,52 @@ Protractor.prototype.get = function(destination, opt_timeout) {
621621
msg('test for angular'),
622622
Math.floor(timeout / 1000)).
623623
then(function(angularTestResult) {
624-
var hasAngular = angularTestResult[0];
625-
if (!hasAngular) {
626-
var message = angularTestResult[1];
624+
var angularVersion = angularTestResult.ver;
625+
if (!angularVersion) {
626+
var message = angularTestResult.message;
627627
throw new Error('Angular could not be found on the page ' +
628628
destination + ' : ' + message);
629629
}
630+
return angularVersion;
630631
}, function(err) {
631632
throw 'Error while running testForAngular: ' + err.message;
632633
})
633-
.then(null, deferred.reject);
634+
.then(loadMocks, deferred.reject);
635+
636+
function loadMocks(angularVersion) {
637+
if (angularVersion === 1) {
638+
// At this point, Angular will pause for us until angular.resumeBootstrap
639+
// is called.
640+
var moduleNames = [];
641+
for (var i = 0; i < self.mockModules_.length; ++i) {
642+
var mockModule = self.mockModules_[i];
643+
var name = mockModule.name;
644+
moduleNames.push(name);
645+
var executeScriptArgs = [mockModule.script, msg('add mock module ' + name)].
646+
concat(mockModule.args);
647+
self.executeScript_.apply(self, executeScriptArgs).
648+
then(null, function(err) {
649+
throw 'Error while running module script ' + name +
650+
': ' + err.message;
651+
})
652+
.then(null, deferred.reject);
653+
}
634654

635-
// At this point, Angular will pause for us until angular.resumeBootstrap
636-
// is called.
637-
var moduleNames = [];
638-
for (var i = 0; i < this.mockModules_.length; ++i) {
639-
var mockModule = this.mockModules_[i];
640-
var name = mockModule.name;
641-
moduleNames.push(name);
642-
var executeScriptArgs = [mockModule.script, msg('add mock module ' + name)].
643-
concat(mockModule.args);
644-
this.executeScript_.apply(this, executeScriptArgs).
645-
then(null, function(err) {
646-
throw 'Error while running module script ' + name +
647-
': ' + err.message;
648-
})
649-
.then(null, deferred.reject);
655+
self.executeScript_(
656+
'angular.resumeBootstrap(arguments[0]);',
657+
msg('resume bootstrap'),
658+
moduleNames)
659+
.then(null, deferred.reject);
660+
} else {
661+
// TODO: support mock modules in Angular2. For now, error if someone
662+
// has tried to use one.
663+
if (self.mockModules_.length > 1) {
664+
deferred.reject('Trying to load mock modules on an Angular2 app ' +
665+
'is not yet supported.');
666+
}
667+
}
650668
}
651669

652-
this.executeScript_(
653-
'angular.resumeBootstrap(arguments[0]);',
654-
msg('resume bootstrap'),
655-
moduleNames)
656-
.then(null, deferred.reject);
657-
658670
this.driver.controlFlow().execute(function() {
659671
return self.plugins_.onPageStable().then(function() {
660672
deferred.fulfill();

spec/angular2Conf.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
var env = require('./environment.js');
2+
3+
// This is the configuration for a smoke test for an Angular2 application.
4+
//
5+
// *** NOTE ***
6+
// As Angular2 is in rapid development, the test application that ships with
7+
// the Protractor repository does not yet contain an Angular2 section. This
8+
// configuration assumes that you are serving the examples from the
9+
// angular/angular repository at localhost:8000.
10+
// See https://github.com/angular/angular/blob/master/DEVELOPER.md for
11+
// setup instructions.
12+
//
13+
// TODO: when Angular2 is beta, include a test application in the
14+
// Protractor repository.
15+
exports.config = {
16+
seleniumAddress: env.seleniumAddress,
17+
18+
framework: 'jasmine2',
19+
20+
specs: [
21+
'ng2/async_spec.js'
22+
],
23+
24+
capabilities: env.capabilities,
25+
26+
baseUrl: 'http://localhost:8000',
27+
28+
rootElement: 'async-app'
29+
};

spec/ng2/async_spec.js

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
describe('async angular2 application', function() {
2+
var URL = 'examples/src/async/index.html';
3+
4+
beforeEach(function() {
5+
browser.get(URL);
6+
});
7+
8+
it('should work with synchronous actions', function() {
9+
var increment = $('#increment');
10+
increment.$('.action').click();
11+
12+
expect(increment.$('.val').getText()).toEqual('1');
13+
});
14+
15+
it('should wait for asynchronous actions', function() {
16+
var timeout = $('#delayedIncrement');
17+
18+
// At this point, the async action is still pending, so the count should
19+
// still be 0.
20+
expect(timeout.$('.val').getText()).toEqual('0');
21+
22+
timeout.$('.action').click();
23+
24+
expect(timeout.$('.val').getText()).toEqual('1');
25+
});
26+
27+
it('should turn off when ignoreSynchronization is true', function() {
28+
var timeout = $('#delayedIncrement');
29+
30+
// At this point, the async action is still pending, so the count should
31+
// still be 0.
32+
expect(timeout.$('.val').getText()).toEqual('0');
33+
34+
browser.ignoreSynchronization = true;
35+
36+
timeout.$('.action').click();
37+
timeout.$('.cancel').click();
38+
39+
browser.ignoreSynchronization = false;
40+
41+
// whenStable should be called since the async action is cancelled. The
42+
// count should still be 0;
43+
expect(timeout.$('.val').getText()).toEqual('0');
44+
});
45+
46+
it('should wait for a series of asynchronous actions', function() {
47+
var timeout = $('#multiDelayedIncrements');
48+
49+
// At this point, the async action is still pending, so the count should
50+
// still be 0.
51+
expect(timeout.$('.val').getText()).toEqual('0');
52+
53+
timeout.$('.action').click();
54+
55+
expect(timeout.$('.val').getText()).toEqual('10');
56+
});
57+
});

0 commit comments

Comments
 (0)