This repository has been archived by the owner on Jul 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(clientSideScripts): change protractor to support waiting for hybr…
…id app (#4512) Change protractor to wait for both angular1 hook and angular2 hook so that it can wait for hybrid app correctly. Add an aot hybrid app and testcase to test new change
- Loading branch information
Showing
19 changed files
with
469 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,7 +86,7 @@ function getNg1Hooks(selector, injectorPlease) { | |
return {$injector: $injector}; | ||
} | ||
} | ||
} catch(err) {} | ||
} catch(err) {} | ||
} | ||
function trySelector(selector) { | ||
var els = document.querySelectorAll(selector); | ||
|
@@ -133,54 +133,96 @@ function getNg1Hooks(selector, injectorPlease) { | |
* be passed as a parameter. | ||
*/ | ||
functions.waitForAngular = function(rootSelector, callback) { | ||
|
||
try { | ||
if (window.angular && !(window.angular.version && | ||
window.angular.version.major > 1)) { | ||
/* ng1 */ | ||
var hooks = getNg1Hooks(rootSelector); | ||
if (hooks.$$testability) { | ||
hooks.$$testability.whenStable(callback); | ||
} else if (hooks.$injector) { | ||
hooks.$injector.get('$browser'). | ||
notifyWhenNoOutstandingRequests(callback); | ||
} else if (!!rootSelector) { | ||
throw new Error('Could not automatically find injector on page: "' + | ||
window.location.toString() + '". Consider using config.rootEl'); | ||
} else { | ||
throw new Error('root element (' + rootSelector + ') has no injector.' + | ||
' this may mean it is not inside ng-app.'); | ||
// Wait for both angular1 testability and angular2 testability. | ||
|
||
var testCallback = callback; | ||
|
||
// Wait for angular1 testability first and run waitForAngular2 as a callback | ||
var waitForAngular1 = function(callback) { | ||
|
||
if (window.angular) { | ||
var hooks = getNg1Hooks(rootSelector); | ||
if (!hooks){ | ||
callback(); // not an angular1 app | ||
} | ||
else{ | ||
if (hooks.$$testability) { | ||
hooks.$$testability.whenStable(callback); | ||
} else if (hooks.$injector) { | ||
hooks.$injector.get('$browser') | ||
.notifyWhenNoOutstandingRequests(callback); | ||
} else if (!!rootSelector) { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
qiyigg
Author
Contributor
|
||
throw new Error( | ||
'Could not automatically find injector on page: "' + | ||
window.location.toString() + '". Consider using config.rootEl'); | ||
} else { | ||
throw new Error( | ||
'root element (' + rootSelector + ') has no injector.' + | ||
' this may mean it is not inside ng-app.'); | ||
} | ||
} | ||
} | ||
} else if (rootSelector && window.getAngularTestability) { | ||
var el = document.querySelector(rootSelector); | ||
window.getAngularTestability(el).whenStable(callback); | ||
} else if (window.getAllAngularTestabilities) { | ||
var testabilities = window.getAllAngularTestabilities(); | ||
var count = testabilities.length; | ||
var decrement = function() { | ||
count--; | ||
else {callback();} // not an angular1 app | ||
}; | ||
|
||
// Wait for Angular2 testability and then run test callback | ||
var waitForAngular2 = function() { | ||
if (window.getAngularTestability) { | ||
if (rootSelector) { | ||
var testability = null; | ||
var el = document.querySelector(rootSelector); | ||
try{ | ||
testability = window.getAngularTestability(el); | ||
} | ||
catch(e){} | ||
if (testability) { | ||
return testability.whenStable(testCallback); | ||
} | ||
} | ||
|
||
// Didn't specify root element or testability could not be found | ||
// by rootSelector. This may happen in a hybrid app, which could have | ||
// more than one root. | ||
var testabilities = window.getAllAngularTestabilities(); | ||
var count = testabilities.length; | ||
|
||
// No angular2 testability, this happens when | ||
// going to a hybrid page and going back to a pure angular1 page | ||
if (count === 0) { | ||
callback(); | ||
return testCallback(); | ||
} | ||
}; | ||
testabilities.forEach(function(testability) { | ||
testability.whenStable(decrement); | ||
}); | ||
} else if (!window.angular) { | ||
throw new Error('window.angular is undefined. This could be either ' + | ||
|
||
var decrement = function() { | ||
count--; | ||
if (count === 0) { | ||
testCallback(); | ||
} | ||
}; | ||
testabilities.forEach(function(testability) { | ||
testability.whenStable(decrement); | ||
}); | ||
|
||
} | ||
else {testCallback();} // not an angular2 app | ||
}; | ||
|
||
if (!(window.angular) && !(window.getAngularTestability)) { | ||
// no testability hook | ||
throw new Error( | ||
'both angularJS testability and angular testability are undefined.' + | ||
' This could be either ' + | ||
'because this is a non-angular page or because your test involves ' + | ||
'client-side navigation, which can interfere with Protractor\'s ' + | ||
'bootstrapping. See http://git.io/v4gXM for details'); | ||
} else if (window.angular.version >= 2) { | ||
throw new Error('You appear to be using angular, but window.' + | ||
'getAngularTestability was never set. This may be due to bad ' + | ||
'obfuscation.'); | ||
} else { | ||
throw new Error('Cannot get testability API for unknown angular ' + | ||
'version "' + window.angular.version + '"'); | ||
} | ||
} else {waitForAngular1(waitForAngular2);} // Wait for angular1 and angular2 | ||
// Testability hooks sequentially | ||
|
||
} catch (err) { | ||
callback(err.message); | ||
} | ||
|
||
}; | ||
|
||
/** | ||
|
@@ -277,7 +319,7 @@ function findRepeaterRows(repeater, exact, index, using) { | |
var row = rows[index] || [], multiRow = multiRows[index] || []; | ||
return [].concat(row, multiRow); | ||
} | ||
functions.findRepeaterRows = wrapWithHelpers(findRepeaterRows, repeaterMatch); | ||
functions.findRepeaterRows = wrapWithHelpers(findRepeaterRows, repeaterMatch); | ||
|
||
/** | ||
* Find all rows of an ng-repeat. | ||
|
@@ -697,7 +739,7 @@ functions.testForAngular = function(attempts, ng12Hybrid, asyncCallback) { | |
if (n < 1) { | ||
if (definitelyNg1 && window.angular) { | ||
callback({message: 'angular never provided resumeBootstrap'}); | ||
} else if (ng12Hybrid && !window.angular) { | ||
} else if (ng12Hybrid && !window.angular) { | ||
callback({message: 'angular 1 never loaded' + | ||
window.getAllAngularTestabilities ? ' (are you sure this app ' + | ||
'uses ngUpgrade? Try un-setting ng12Hybrid)' : ''}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"lib": ["es2015", "dom"], | ||
"noImplicitAny": true, | ||
"suppressImplicitAnyIndexErrors": true, | ||
"typeRoots": [ | ||
"./node_modules/@types/" | ||
] | ||
}, | ||
|
||
"files": [ | ||
"upgrade/app/downgrade/main.ts", | ||
"upgrade/app/downgrade/ng1.ts", | ||
"upgrade/app/downgrade/ng2.ts" | ||
] | ||
|
||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {downgradeModule} from '@angular/upgrade/static'; | ||
declare var angular: angular.IAngularStatic; | ||
|
||
import {ng1module} from './ng1'; | ||
import {AppModuleNgFactory} from './ng2.ngfactory'; | ||
|
||
// Bootstrap Ng1 app as usual, but add a downgradedModule for the Angular (2+) | ||
// part of the application. | ||
angular.bootstrap( | ||
document.body, [ng1module.name, downgradeModule(AppModuleNgFactory)]); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[{"__symbolic":"module","version":3,"metadata":{"ng1module":{"__symbolic":"error","message":"Reference to a local symbol","line":0,"character":12,"context":{"name":"angular"}}}},{"__symbolic":"module","version":1,"metadata":{"ng1module":{"__symbolic":"error","message":"Reference to a local symbol","line":0,"character":12,"context":{"name":"angular"}}}}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
declare var angular: angular.IAngularStatic; | ||
|
||
function ctrl($scope: any, $timeout: any) { | ||
$scope.callCount = 0; | ||
|
||
$scope.clickButton = function() { | ||
$timeout(() => { | ||
$scope.callCount++; | ||
}, 1000); | ||
}; | ||
} | ||
ctrl.$inject = ['$scope', '$timeout']; | ||
|
||
export const ng1module = angular.module('hybrid', []); | ||
|
||
ng1module.component('myApp', { | ||
template: `<h3>ng1</h3><button ng-click="clickButton()">Click Count: {{callCount}}</button> | ||
<ng2></ng2> | ||
`, | ||
controller: ctrl | ||
}); |
Oops, something went wrong.
Shouldn't this be
!rootSelector
?