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

fix(clientSideScripts): change protractor to support waiting for hybr… #4512

Merged
merged 1 commit into from
Oct 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 83 additions & 41 deletions lib/clientsidescripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function getNg1Hooks(selector, injectorPlease) {
return {$injector: $injector};
}
}
} catch(err) {}
} catch(err) {}
}
function trySelector(selector) {
var els = document.querySelectorAll(selector);
Expand Down Expand Up @@ -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) {
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);
}

};

/**
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)' : ''});
Expand Down
15 changes: 15 additions & 0 deletions spec/hybrid/async_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,18 @@ describe('async angular1/2 hybrid using ngUpgrade application', function() {
});
});
});
describe('async angular1/2 hybrid using downgrade application', function() {
it('should be able to click buttons and wait for $timeout', function() {
browser.get('/upgrade?downgrade');

var rootBtn = $$('my-app button').first();
expect(rootBtn.getText()).toEqual('Click Count: 0');
rootBtn.click();
expect(rootBtn.getText()).toEqual('Click Count: 1');

var ng2Btn = $$('ng2 button').first();
expect(ng2Btn.getText()).toEqual('Click Count: 0');
ng2Btn.click();
expect(ng2Btn.getText()).toEqual('Click Count: 1');
});
});
15 changes: 10 additions & 5 deletions testapp/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@ li {

li.left {
left: 0;
}
}

li.left.mid {
left: 25%;
left: 20%;
}

li.right {
right: 0;
li.mid{
left : 40%;
}

li.right.mid {
right: 25%;
left: 60%;
}

li.right {
left: 80%;
}

5 changes: 4 additions & 1 deletion testapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ <h1>Choose Version</h1>
<li class='mid left'>
<a href='upgrade?no_static'>Hybrid (JIT)</a>
</li>
<li class='mid right'>
<li class='mid'>
<a href='upgrade'>Hybrid (AOT)</a>
</li>
<li class='mid right'>
<a href='upgrade?downgrade'>Hybrid (Downgrade)</a>
</li>
<li class="right">
<a href="ng2">Angular 2</a>
</li>
Expand Down
21 changes: 11 additions & 10 deletions testapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@
"tsc": "tsc"
},
"dependencies": {
"@angular/common": "2.2.1",
"@angular/compiler": "2.2.1",
"@angular/core": "2.2.1",
"@angular/http": "2.2.1",
"@angular/platform-browser": "2.2.1",
"@angular/platform-browser-dynamic": "2.2.1",
"@angular/router": "3.0.0",
"@angular/upgrade": "2.2.1",
"@angular/common": "5.0.0-beta.7",
"@angular/compiler": "5.0.0-beta.7",
"@angular/core": "5.0.0-beta.7",
"@angular/http": "5.0.0-beta.7",
"@angular/platform-browser": "5.0.0-beta.7",
"@angular/animations": "5.0.0-beta.7",
"@angular/platform-browser-dynamic": "5.0.0-beta.7",
"@angular/router": "5.0.0-beta.7",
"@angular/upgrade": "5.0.0-beta.7",
"@types/angular": "^1.5.20",
"@types/core-js": "^0.9.34",
"@types/node": "^6.0.48",
"core-js": "2.4.1",
"reflect-metadata": "0.1.3",
"rxjs": "5.0.0-beta.12",
"rxjs": "5.4.3",
"systemjs": "0.19.27",
"zone.js": "0.6.25"
"zone.js": "0.8.18"
},
"devDependencies": {
"concurrently": "2.2.0",
Expand Down
23 changes: 23 additions & 0 deletions testapp/tsconfig-aot.json
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"
]

}
9 changes: 9 additions & 0 deletions testapp/upgrade/app/downgrade/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions testapp/upgrade/app/downgrade/main.ts
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)]);
17 changes: 17 additions & 0 deletions testapp/upgrade/app/downgrade/ng1.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions testapp/upgrade/app/downgrade/ng1.metadata.json
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"}}}}]
21 changes: 21 additions & 0 deletions testapp/upgrade/app/downgrade/ng1.ts
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
});
Loading