diff --git a/modules/@angular/upgrade/src/aot/constants.ts b/modules/@angular/upgrade/src/aot/constants.ts index 2291fd3a34..5b66390208 100644 --- a/modules/@angular/upgrade/src/aot/constants.ts +++ b/modules/@angular/upgrade/src/aot/constants.ts @@ -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'; \ No newline at end of file +export const $CONTROLLER = '$controller'; diff --git a/modules/@angular/upgrade/src/aot/upgrade_module.ts b/modules/@angular/upgrade/src/aot/upgrade_module.ts index 9c3b162af7..a22af71930 100644 --- a/modules/@angular/upgrade/src/aot/upgrade_module.ts +++ b/modules/@angular/upgrade/src/aot/upgrade_module.ts @@ -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'; + /** @@ -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) => { @@ -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']; + 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); }); + }; + } } } diff --git a/modules/@angular/upgrade/test/aot/integration/testability_spec.ts b/modules/@angular/upgrade/test/aot/integration/testability_spec.ts index 11cfb065a3..c6df6a449c 100644 --- a/modules/@angular/upgrade/test/aot/integration/testability_spec.ts +++ b/modules/@angular/upgrade/test/aot/integration/testability_spec.ts @@ -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'; @@ -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('
'); window.name = 'NG_DEFER_BOOTSTRAP!' + window.name; @@ -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(() => {