, strictDi?: boolean) => angular.injector(modules, strictDi);
+
export const resumeBootstrap: typeof angular.resumeBootstrap = () => angular.resumeBootstrap();
export const getTestability: typeof angular.getTestability = e => angular.getTestability(e);
diff --git a/packages/upgrade/static/testing/BUILD.bazel b/packages/upgrade/static/testing/BUILD.bazel
new file mode 100644
index 0000000000..9cece1502f
--- /dev/null
+++ b/packages/upgrade/static/testing/BUILD.bazel
@@ -0,0 +1,19 @@
+load("//tools:defaults.bzl", "ng_module")
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(["package.json"])
+
+ng_module(
+ name = "testing",
+ srcs = glob(
+ [
+ "*.ts",
+ "src/*.ts",
+ ],
+ ),
+ deps = [
+ "//packages/core/testing",
+ "//packages/upgrade/src/common",
+ ],
+)
diff --git a/packages/upgrade/static/testing/index.ts b/packages/upgrade/static/testing/index.ts
new file mode 100755
index 0000000000..f93e7c31d5
--- /dev/null
+++ b/packages/upgrade/static/testing/index.ts
@@ -0,0 +1,9 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+export * from './public_api';
diff --git a/packages/upgrade/static/testing/package.json b/packages/upgrade/static/testing/package.json
new file mode 100644
index 0000000000..eecbcda470
--- /dev/null
+++ b/packages/upgrade/static/testing/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@angular/upgrade/static/testing",
+ "main": "../../bundles/upgrade-static-testing.umd.js",
+ "module": "../../fesm5/static/testing.js",
+ "es2015": "../../fesm2015/static/testing.js",
+ "esm5": "../../esm5/static/testing/testing.js",
+ "esm2015": "../../esm2015/static/testing/testing.js",
+ "fesm5": "../../fesm5/static/testing.js",
+ "fesm2015": "../../fesm2015/static/testing.js",
+ "typings": "./testing.d.ts"
+}
diff --git a/packages/upgrade/static/testing/public_api.ts b/packages/upgrade/static/testing/public_api.ts
new file mode 100755
index 0000000000..871ad430b1
--- /dev/null
+++ b/packages/upgrade/static/testing/public_api.ts
@@ -0,0 +1,10 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+export {createAngularTestingModule} from './src/create_angular_testing_module';
+export {createAngularJSTestingModule} from './src/create_angularjs_testing_module';
\ No newline at end of file
diff --git a/packages/upgrade/static/testing/src/create_angular_testing_module.ts b/packages/upgrade/static/testing/src/create_angular_testing_module.ts
new file mode 100644
index 0000000000..bbaa2f5c8f
--- /dev/null
+++ b/packages/upgrade/static/testing/src/create_angular_testing_module.ts
@@ -0,0 +1,99 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Injector, NgModule, Type} from '@angular/core';
+
+import * as angular from '../../../src/common/src/angular1';
+import {$INJECTOR, INJECTOR_KEY, UPGRADE_APP_TYPE_KEY} from '../../../src/common/src/constants';
+import {UpgradeAppType} from '../../../src/common/src/util';
+
+export let $injector: angular.IInjectorService|null = null;
+let injector: Injector;
+
+export function $injectorFactory() {
+ return $injector;
+}
+
+@NgModule({providers: [{provide: $INJECTOR, useFactory: $injectorFactory}]})
+export class AngularTestingModule {
+ constructor(i: Injector) { injector = i; }
+}
+
+/**
+ * A helper function to use when unit testing Angular services that depend upon upgraded AngularJS
+ * services.
+ *
+ * This function returns an `NgModule` decorated class that is configured to wire up the Angular
+ * and AngularJS injectors without the need to actually bootstrap a hybrid application.
+ * This makes it simpler and faster to unit test services.
+ *
+ * Use the returned class as an "import" when configuring the `TestBed`.
+ *
+ * In the following code snippet, we are configuring the TestBed with two imports.
+ * The `Ng2AppModule` is the Angular part of our hybrid application and the `ng1AppModule` is the
+ * AngularJS part.
+ *
+ *
+ *
+ * Once this is done we can get hold of services via the Angular `Injector` as normal.
+ * Services that are (or have dependencies on) an upgraded AngularJS service, will be instantiated
+ * as needed by the AngularJS `$injector`.
+ *
+ * In the following code snippet, `HeroesService` is an Angular service that depends upon an
+ * AngularJS service, `titleCase`.
+ *
+ *
+ *
+ *
+ *
+ * This helper is for testing services not Components.
+ * For Component testing you must still bootstrap a hybrid app. See `UpgradeModule` or
+ * `downgradeModule` for more information.
+ *
+ *
+ *
+ *
+ *
+ * The resulting configuration does not wire up AngularJS digests to Zone hooks. It is the
+ * responsibility of the test writer to call `$rootScope.$apply`, as necessary, to trigger
+ * AngularJS handlers of async events from Angular.
+ *
+ *
+ *
+ *
+ *
+ * The helper sets up global variables to hold the shared Angular and AngularJS injectors.
+ *
+ * * Only call this helper once per spec.
+ * * Do not use `createAngularTestingModule` in the same spec as `createAngularJSTestingModule`.
+ *
+ *
+ *
+ * Here is the example application and its unit tests that use `createAngularTestingModule`
+ * and `createAngularJSTestingModule`.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @param angularJSModules a collection of the names of AngularJS modules to include in the
+ * configuration.
+ * @param [strictDi] whether the AngularJS injector should have `strictDI` enabled.
+ *
+ * @publicApi
+ */
+export function createAngularTestingModule(
+ angularJSModules: string[], strictDi?: boolean): Type {
+ angular.module_('$$angularJSTestingModule', angularJSModules)
+ .constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
+ .factory(INJECTOR_KEY, () => injector);
+ $injector = angular.injector(['ng', '$$angularJSTestingModule'], strictDi);
+ return AngularTestingModule;
+}
diff --git a/packages/upgrade/static/testing/src/create_angularjs_testing_module.ts b/packages/upgrade/static/testing/src/create_angularjs_testing_module.ts
new file mode 100644
index 0000000000..85a6d9adcf
--- /dev/null
+++ b/packages/upgrade/static/testing/src/create_angularjs_testing_module.ts
@@ -0,0 +1,100 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Injector} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+
+import * as ng from '../../../src/common/src/angular1';
+import {$INJECTOR, INJECTOR_KEY, UPGRADE_APP_TYPE_KEY} from '../../../src/common/src/constants';
+import {UpgradeAppType} from '../../../src/common/src/util';
+
+
+/**
+ * A helper function to use when unit testing AngularJS services that depend upon downgraded Angular
+ * services.
+ *
+ * This function returns an AngularJS module that is configured to wire up the AngularJS and Angular
+ * injectors without the need to actually bootstrap a hybrid application.
+ * This makes it simpler and faster to unit test services.
+ *
+ * Use the returned AngularJS module in a call to
+ * [`angular.mocks.module`](https://docs.angularjs.org/api/ngMock/function/angular.mock.module) to
+ * include this module in the unit test injector.
+ *
+ * In the following code snippet, we are configuring the `$injector` with two modules:
+ * The AngularJS `ng1AppModule`, which is the AngularJS part of our hybrid application and the
+ * `Ng2AppModule`, which is the Angular part.
+ *
+ *
+ *
+ * Once this is done we can get hold of services via the AngularJS `$injector` as normal.
+ * Services that are (or have dependencies on) a downgraded Angular service, will be instantiated as
+ * needed by the Angular root `Injector`.
+ *
+ * In the following code snippet, `heroesService` is a downgraded Angular service that we are
+ * accessing from AngularJS.
+ *
+ *
+ *
+ *
+ *
+ * This helper is for testing services not components.
+ * For Component testing you must still bootstrap a hybrid app. See `UpgradeModule` or
+ * `downgradeModule` for more information.
+ *
+ *
+ *
+ *
+ *
+ * The resulting configuration does not wire up AngularJS digests to Zone hooks. It is the
+ * responsibility of the test writer to call `$rootScope.$apply`, as necessary, to trigger
+ * AngularJS handlers of async events from Angular.
+ *
+ *
+ *
+ *
+ *
+ * The helper sets up global variables to hold the shared Angular and AngularJS injectors.
+ *
+ * * Only call this helper once per spec.
+ * * Do not use `createAngularJSTestingModule` in the same spec as `createAngularTestingModule`.
+ *
+ *
+ *
+ * Here is the example application and its unit tests that use `createAngularTestingModule`
+ * and `createAngularJSTestingModule`.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @param angularModules a collection of Angular modules to include in the configuration.
+ *
+ * @publicApi
+ */
+export function createAngularJSTestingModule(angularModules: any[]): string {
+ return ng.module_('$$angularJSTestingModule', [])
+ .constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
+ .factory(
+ INJECTOR_KEY,
+ [
+ $INJECTOR,
+ ($injector: ng.IInjectorService) => {
+ TestBed.configureTestingModule({
+ imports: angularModules,
+ providers: [{provide: $INJECTOR, useValue: $injector}]
+ });
+ return TestBed.get(Injector);
+ }
+ ])
+ .name;
+}
diff --git a/packages/upgrade/static/testing/test/BUILD.bazel b/packages/upgrade/static/testing/test/BUILD.bazel
new file mode 100644
index 0000000000..96aa6c731a
--- /dev/null
+++ b/packages/upgrade/static/testing/test/BUILD.bazel
@@ -0,0 +1,29 @@
+package(default_visibility = ["//visibility:public"])
+
+load("//tools:defaults.bzl", "ts_library", "ts_web_test_suite")
+
+ts_library(
+ name = "test_lib",
+ testonly = True,
+ srcs = glob([
+ "**/*.ts",
+ ]),
+ deps = [
+ "//packages/core",
+ "//packages/core/testing",
+ "//packages/upgrade/src/common",
+ "//packages/upgrade/src/common/test/helpers",
+ "//packages/upgrade/static",
+ "//packages/upgrade/static/testing",
+ ],
+)
+
+ts_web_test_suite(
+ name = "test",
+ static_files = [
+ "//:angularjs_scripts",
+ ],
+ deps = [
+ ":test_lib",
+ ],
+)
diff --git a/packages/upgrade/static/testing/test/create_angular_testing_module_spec.ts b/packages/upgrade/static/testing/test/create_angular_testing_module_spec.ts
new file mode 100644
index 0000000000..13d3629434
--- /dev/null
+++ b/packages/upgrade/static/testing/test/create_angular_testing_module_spec.ts
@@ -0,0 +1,48 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Injector} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+
+import {$INJECTOR} from '../../../src/common/src/constants';
+import {withEachNg1Version} from '../../../src/common/test/helpers/common_test_helpers';
+import {createAngularTestingModule} from '../src/create_angular_testing_module';
+
+import {AppModule, Inventory, defineAppModule, serverRequestInstance} from './mocks';
+
+withEachNg1Version(() => {
+ describe('Angular entry point', () => {
+ it('should allow us to get an upgraded AngularJS service from an Angular service', () => {
+ defineAppModule();
+ // Configure an NgModule that has the Angular and AngularJS injectors wired up
+ TestBed.configureTestingModule({imports: [createAngularTestingModule(['app']), AppModule]});
+ const inventory = TestBed.get(Inventory) as Inventory;
+ expect(inventory.serverRequest).toBe(serverRequestInstance);
+ });
+
+ it('should create new injectors when we re-use the helper', () => {
+ defineAppModule();
+ TestBed.configureTestingModule({imports: [createAngularTestingModule(['app']), AppModule]});
+ // Check that the injectors are wired up correctly
+ TestBed.get(Inventory) as Inventory;
+
+ // Grab references to the current injectors
+ const injector = TestBed.get(Injector);
+ const $injector = TestBed.get($INJECTOR);
+
+ TestBed.resetTestingModule();
+ TestBed.configureTestingModule({imports: [createAngularTestingModule(['app']), AppModule]});
+ // Check that the injectors are wired up correctly
+ TestBed.get(Inventory) as Inventory;
+
+ // Check that the new injectors are different to the previous ones.
+ expect(TestBed.get(Injector)).not.toBe(injector);
+ expect(TestBed.get($INJECTOR)).not.toBe($injector);
+ });
+ });
+});
diff --git a/packages/upgrade/static/testing/test/create_angularjs_testing_module_spec.ts b/packages/upgrade/static/testing/test/create_angularjs_testing_module_spec.ts
new file mode 100644
index 0000000000..0e55b9e1db
--- /dev/null
+++ b/packages/upgrade/static/testing/test/create_angularjs_testing_module_spec.ts
@@ -0,0 +1,33 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {getAngularJSGlobal} from '../../../src/common/src/angular1';
+import {withEachNg1Version} from '../../../src/common/test/helpers/common_test_helpers';
+import {createAngularJSTestingModule} from '../src/create_angularjs_testing_module';
+
+import {AppModule, Inventory, defineAppModule} from './mocks';
+
+
+withEachNg1Version(() => {
+ describe('AngularJS entry point', () => {
+ it('should allow us to get a downgraded Angular service from an AngularJS service', () => {
+ defineAppModule();
+ // We have to get the `mock` object from the global `angular` variable, rather than trying to
+ // import it from `@angular/upgrade/src/common/angular1`, because that file doesn't export
+ // `ngMock` helpers.
+ const {inject, module} = getAngularJSGlobal().mock;
+ // Load the AngularJS bits of the application
+ module('app');
+ // Configure an AngularJS module that has the AngularJS and Angular injector wired up
+ module(createAngularJSTestingModule([AppModule]));
+ let inventory: any = undefined;
+ inject(function(shoppingCart: any) { inventory = shoppingCart.inventory; });
+ expect(inventory).toEqual(jasmine.any(Inventory));
+ });
+ });
+});
\ No newline at end of file
diff --git a/packages/upgrade/static/testing/test/mocks.ts b/packages/upgrade/static/testing/test/mocks.ts
new file mode 100644
index 0000000000..f563a84ab4
--- /dev/null
+++ b/packages/upgrade/static/testing/test/mocks.ts
@@ -0,0 +1,76 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Inject, Injectable, NgModule} from '@angular/core';
+import {downgradeInjectable} from '@angular/upgrade/static';
+import * as ng from '../../../src/common/src/angular1';
+/*
+ * This mock application code contains the following services and their dependencies:
+ *
+ * shoppingCart (AngularJS)
+ * -> Inventory (Angular - downgraded)
+ * -> serverRequest (AngularJS - upgraded)
+ * -> Logger (Angular - downgraded)
+ *
+ * This allows us to test two scenarios:
+ * * AngularJS -> Angular -> AngularJS
+ * * Angular -> AngularJS -> Angular
+ */
+
+/* START: Angular bits */
+@Injectable()
+export class Logger {
+ warn() {}
+}
+
+@Injectable()
+export class Inventory {
+ constructor(@Inject('serverRequest') public serverRequest: any) {}
+}
+
+export function serverRequestFactory(i: ng.IInjectorService) {
+ return i.get('serverRequest');
+}
+
+@NgModule({
+ providers: [
+ Logger,
+ Inventory,
+ {provide: 'serverRequest', useFactory: serverRequestFactory, deps: ['$injector']},
+ ]
+})
+export class AppModule {
+}
+/* END: Angular bits */
+
+/* START: AngularJS bits */
+export const serverRequestInstance: {logger?: Logger} = {};
+export const shoppingCartInstance: {inventory?: Inventory} = {};
+
+export function defineAppModule() {
+ ng.module_('app', [])
+ .factory('logger', downgradeInjectable(Logger))
+ .factory('inventory', downgradeInjectable(Inventory))
+ .factory(
+ 'serverRequest',
+ [
+ 'logger',
+ function(logger: Logger) {
+ serverRequestInstance.logger = logger;
+ return serverRequestInstance;
+ }
+ ])
+ .factory('shoppingCart', [
+ 'inventory',
+ function(inventory: Inventory) {
+ shoppingCartInstance.inventory = inventory;
+ return shoppingCartInstance;
+ }
+ ]);
+}
+/* END: AngularJS bits */
diff --git a/test-main.js b/test-main.js
index 59e8c28c02..6e8f44e400 100644
--- a/test-main.js
+++ b/test-main.js
@@ -51,6 +51,7 @@ System.config({
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
'@angular/http/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/http': {main: 'index.js', defaultExtension: 'js'},
+ '@angular/upgrade/static/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/upgrade/static': {main: 'index.js', defaultExtension: 'js'},
'@angular/upgrade': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser/animations/testing': {main: 'index.js', defaultExtension: 'js'},
diff --git a/tools/public_api_guard/upgrade/static/testing.d.ts b/tools/public_api_guard/upgrade/static/testing.d.ts
new file mode 100644
index 0000000000..f905c680b6
--- /dev/null
+++ b/tools/public_api_guard/upgrade/static/testing.d.ts
@@ -0,0 +1,3 @@
+export declare function createAngularJSTestingModule(angularModules: any[]): string;
+
+export declare function createAngularTestingModule(angularJSModules: string[], strictDi?: boolean): Type;