Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ngUpgrade): make AoT ngUpgrade work with the testability API and resumeBootstrap() #12910

Merged
merged 1 commit into from Nov 16, 2016
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion modules/@angular/upgrade/src/aot/constants.ts
Expand Up @@ -13,8 +13,11 @@ export const $INJECTOR = '$injector';
export const $PARSE = '$parse';
export const $ROOT_SCOPE = '$rootScope';
export const $SCOPE = '$scope';
export const $PROVIDE = '$provide';
export const $DELEGATE = '$delegate';
export const $$TESTABILITY = '$$testability';

export const $COMPILE = '$compile';
export const $TEMPLATE_CACHE = '$templateCache';
export const $HTTP_BACKEND = '$httpBackend';
export const $CONTROLLER = '$controller';
export const $CONTROLLER = '$controller';
51 changes: 49 additions & 2 deletions modules/@angular/upgrade/src/aot/upgrade_module.ts
Expand Up @@ -6,13 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector, NgModule, NgZone} from '@angular/core';
import {Injector, NgModule, NgZone, Testability} from '@angular/core';

import * as angular from '../angular_js';
import {controllerKey} from '../util';

import {angular1Providers, setTempInjectorRef} from './angular1_providers';
import {$INJECTOR, INJECTOR_KEY, UPGRADE_MODULE_NAME} from './constants';
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $PROVIDE, $ROOT_SCOPE, INJECTOR_KEY, UPGRADE_MODULE_NAME} from './constants';



/**
Expand Down Expand Up @@ -40,6 +41,37 @@ export class UpgradeModule {

.value(INJECTOR_KEY, this.injector)

.config([
$PROVIDE, $INJECTOR,
($provide: angular.IProvideService, $injector: angular.IInjectorService) => {
if ($injector.has($$TESTABILITY)) {
$provide.decorator($$TESTABILITY, [
$DELEGATE,
(testabilityDelegate: angular.ITestabilityService) => {
const originalWhenStable: Function = testabilityDelegate.whenStable;
const injector = this.injector;
// Cannot use arrow function below because we need to grab the context
const newWhenStable = function(callback: Function) {
const whenStableContext: any = this;
originalWhenStable.call(this, function() {
const ng2Testability: Testability = injector.get(Testability);
if (ng2Testability.isStable()) {
callback.apply(this, arguments);
} else {
ng2Testability.whenStable(
newWhenStable.bind(whenStableContext, callback));
}
});
};

testabilityDelegate.whenStable = newWhenStable;
return testabilityDelegate;
}
]);
}
}
])

.run([
$INJECTOR,
($injector: angular.IInjectorService) => {
Expand All @@ -59,7 +91,22 @@ export class UpgradeModule {
}
]);

// Make sure resumeBootstrap() only exists if the current bootstrap is deferred
const windowAngular = (window as any /** TODO #???? */)['angular'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a valid use of any so no need for the TODO comment

windowAngular.resumeBootstrap = undefined;

// Bootstrap the angular 1 application inside our zone
this.ngZone.run(() => { angular.bootstrap(element, [upgradeModule.name], config); });

// Patch resumeBootstrap() to run inside the ngZone
if (windowAngular.resumeBootstrap) {
const originalResumeBootstrap: () => void = windowAngular.resumeBootstrap;
const ngZone = this.ngZone;
windowAngular.resumeBootstrap = function() {
let args = arguments;
windowAngular.resumeBootstrap = originalResumeBootstrap;
ngZone.run(() => { windowAngular.resumeBootstrap.apply(this, args); });
};
}
}
}
Expand Up @@ -7,6 +7,7 @@
*/

import {NgModule, Testability, destroyPlatform} from '@angular/core';
import {NgZone} from '@angular/core/src/zone/ng_zone';
import {fakeAsync, tick} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
Expand All @@ -28,7 +29,11 @@ export function main() {

it('should handle deferred bootstrap', fakeAsync(() => {
let applicationRunning = false;
const ng1Module = angular.module('ng1', []).run(() => { applicationRunning = true; });
let stayedInTheZone: boolean;
const ng1Module = angular.module('ng1', []).run(() => {
applicationRunning = true;
stayedInTheZone = NgZone.isInAngularZone();
});

const element = html('<div></div>');
window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
Expand All @@ -40,6 +45,7 @@ export function main() {
expect(applicationRunning).toEqual(false);
tick(100);
expect(applicationRunning).toEqual(true);
expect(stayedInTheZone).toEqual(true);
}));

it('should wait for ng2 testability', fakeAsync(() => {
Expand Down