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

Commit 86fd569

Browse files
authored
feat(ngUpgrade): Auto detect ngUpgrade apps and make the ng12Hybrid flag unnecessary for most users (#3847)
1 parent 8952eab commit 86fd569

File tree

4 files changed

+81
-44
lines changed

4 files changed

+81
-44
lines changed

lib/browser.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,25 @@ export class ProtractorBrowser extends Webdriver {
303303
this.ready = null;
304304
this.plugins_ = new Plugins({});
305305
this.resetUrl = DEFAULT_RESET_URL;
306-
this.ng12Hybrid = false;
307306
this.debugHelper = new DebugHelper(this);
308307

308+
var ng12Hybrid_ = false;
309+
Object.defineProperty(this, 'ng12Hybrid', {
310+
get: function() {
311+
return ng12Hybrid_;
312+
},
313+
set: function(ng12Hybrid) {
314+
if (ng12Hybrid) {
315+
logger.warn(
316+
'You have set ng12Hybrid. As of Protractor 4.1.0, ' +
317+
'Protractor can automatically infer if you are using an ' +
318+
'ngUpgrade app (as long as ng1 is loaded before you call ' +
319+
'platformBrowserDynamic()), and this flag is no longer needed ' +
320+
'for most users');
321+
}
322+
ng12Hybrid_ = ng12Hybrid;
323+
}
324+
});
309325
this.driver.getCapabilities().then((caps: Capabilities) => {
310326
// Internet Explorer does not accept data URLs, which are the default
311327
// reset URL for Protractor.
@@ -451,7 +467,7 @@ export class ProtractorBrowser extends Webdriver {
451467
} else if (this.rootEl) {
452468
return this.executeAsyncScript_(
453469
clientSideScripts.waitForAngular, 'Protractor.waitForAngular()' + description,
454-
this.rootEl, this.ng12Hybrid);
470+
this.rootEl);
455471
} else {
456472
return this.executeAsyncScript_(
457473
clientSideScripts.waitForAllAngular2, 'Protractor.waitForAngular()' + description);

lib/clientsidescripts.js

+47-21
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,38 @@ function wrapWithHelpers(fun) {
4444
* Asynchronous.
4545
*
4646
* @param {string} rootSelector The selector housing an ng-app
47-
* @param {boolean} ng12Hybrid Flag set if app is a hybrid of angular 1 and 2
4847
* @param {function(string)} callback callback. If a failure occurs, it will
4948
* be passed as a parameter.
5049
*/
51-
functions.waitForAngular = function(rootSelector, ng12Hybrid, callback) {
50+
functions.waitForAngular = function(rootSelector, callback) {
5251
var el = document.querySelector(rootSelector);
5352

5453
try {
55-
if (!ng12Hybrid && window.getAngularTestability) {
54+
if (window.angular && !(window.angular.version &&
55+
window.angular.version.major > 1)) {
56+
if (angular.getTestability) {
57+
angular.getTestability(el).whenStable(callback);
58+
} else if (angular.element(el).injector()) {
59+
angular.element(el).injector().get('$browser').
60+
notifyWhenNoOutstandingRequests(callback);
61+
} else {
62+
throw new Error('root element (' + rootSelector + ') has no injector.' +
63+
' this may mean it is not inside ng-app.');
64+
}
65+
} else if (window.getAngularTestability) {
5666
window.getAngularTestability(el).whenStable(callback);
57-
return;
58-
}
59-
if (!window.angular) {
67+
} else if (!window.angular) {
6068
throw new Error('window.angular is undefined. This could be either ' +
6169
'because this is a non-angular page or because your test involves ' +
6270
'client-side navigation, which can interfere with Protractor\'s ' +
6371
'bootstrapping. See http://git.io/v4gXM for details');
64-
}
65-
if (angular.getTestability) {
66-
angular.getTestability(el).whenStable(callback);
72+
} else if (window.angular.version >= 2) {
73+
throw new Error('You appear to be using angular, but window.' +
74+
'getAngularTestability was never set. This may be due to bad ' +
75+
'obfuscation.');
6776
} else {
68-
if (!angular.element(el).injector()) {
69-
throw new Error('root element (' + rootSelector + ') has no injector.' +
70-
' this may mean it is not inside ng-app.');
71-
}
72-
angular.element(el).injector().get('$browser').
73-
notifyWhenNoOutstandingRequests(callback);
77+
throw new Error('Cannot get testability API for unknown angular ' +
78+
'version "' + window.angular.version + '"');
7479
}
7580
} catch (err) {
7681
callback(err.message);
@@ -599,15 +604,36 @@ functions.testForAngular = function(attempts, ng12Hybrid, asyncCallback) {
599604
asyncCallback(args);
600605
}, 0);
601606
};
607+
var definitelyNg1 = !!ng12Hybrid;
608+
var definitelyNg2OrNewer = false;
602609
var check = function(n) {
603610
try {
604-
if (!ng12Hybrid && window.getAllAngularTestabilities) {
605-
callback({ver: 2});
606-
} else if (window.angular && window.angular.resumeBootstrap) {
607-
callback({ver: 1});
608-
} else if (n < 1) {
609-
if (window.angular) {
611+
/* Figure out which version of angular we're waiting on */
612+
if (!definitelyNg1 && !definitelyNg2OrNewer) {
613+
if (window.angular && !(window.angular.version && window.angular.version.major > 1)) {
614+
definitelyNg1 = true;
615+
} else if (window.getAllAngularTestabilities) {
616+
definitelyNg2OrNewer = true;
617+
}
618+
}
619+
/* See if our version of angular is ready */
620+
if (definitelyNg1) {
621+
if (window.angular && window.angular.resumeBootstrap) {
622+
return callback({ver: 1});
623+
}
624+
} else if (definitelyNg2OrNewer) {
625+
if (true /* ng2 has no resumeBootstrap() */) {
626+
return callback({ver: 2});
627+
}
628+
}
629+
/* Try again (or fail) */
630+
if (n < 1) {
631+
if (definitelyNg1 && window.angular) {
610632
callback({message: 'angular never provided resumeBootstrap'});
633+
} else if (ng12Hybrid && !window.angular) {
634+
callback({message: 'angular 1 never loaded' +
635+
window.getAllAngularTestabilities ? ' (are you sure this app ' +
636+
'uses ngUpgrade? Try un-setting ng12Hybrid)' : ''});
611637
} else {
612638
callback({message: 'retries looking for angular exceeded'});
613639
}

spec/hybrid/async_spec.js

+15-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
describe('async angular1/2 hybrid using ngUpgrade application', function() {
22
describe('@angular/upgrade/static', function() {
3-
beforeEach(function() {
3+
it('should be able to click buttons and wait for $timeout', function() {
44
browser.get('/upgrade');
5-
});
6-
7-
it('should set browser flag via config', function() {
8-
expect(browser.ng12Hybrid).toBe(true);
9-
});
105

11-
it('should be able to click buttons and wait for $timeout', function() {
126
var rootBtn = $$('my-app button').first();
137
expect(rootBtn.getText()).toEqual('Click Count: 0');
148
rootBtn.click();
@@ -25,23 +19,26 @@ describe('async angular1/2 hybrid using ngUpgrade application', function() {
2519
expect(ng1Btn.getText()).toEqual('Click Count: 1');
2620
});
2721

28-
it('should use the flag on the browser object', function() {
29-
browser.ng12Hybrid = false;
30-
browser.get('/ng2'); // will time out if Protractor expects hybrid
31-
browser.ng12Hybrid = true;
22+
it('should be able to automatically infer ng1/ng2/ngUpgrade', function() {
23+
browser.get('/upgrade');
24+
expect($('h1').getText()).toBe('My App');
25+
browser.get('/ng1');
26+
expect($$('h4').first().getText()).toBe('Bindings');
27+
browser.get('/upgrade');
28+
expect($('h1').getText()).toBe('My App');
29+
browser.useAllAngular2AppRoots();
30+
browser.get('/ng2');
31+
expect($('h1').getText()).toBe('Test App for Angular 2');
32+
browser.rootEl = 'body';
33+
browser.get('/upgrade');
34+
expect($('h1').getText()).toBe('My App');
3235
});
3336
});
3437

3538
describe('@angular/upgrade (not static)', function() {
36-
beforeEach(function() {
39+
it('should be able to click buttons and wait for $timeout', function() {
3740
browser.get('/upgrade?no_static');
38-
});
3941

40-
it('should set browser flag via config', function() {
41-
expect(browser.ng12Hybrid).toBe(true);
42-
});
43-
44-
it('should be able to click buttons and wait for $timeout', function() {
4542
var rootBtn = $$('my-app button').first();
4643
expect(rootBtn.getText()).toEqual('Click Count: 0');
4744
rootBtn.click();

spec/hybridConf.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,5 @@ exports.config = {
1414

1515
baseUrl: env.baseUrl,
1616

17-
rootElement: 'body',
18-
19-
ng12Hybrid: true
17+
rootElement: 'body'
2018
};

0 commit comments

Comments
 (0)