Skip to content

Commit 3fb78aa

Browse files
petebacondarwinkara
authored andcommitted
feat(upgrade): provide unit test helpers for wiring up injectors (#16848)
Adds two new helper functions that can be used when unit testing Angular services that depend upon upgraded AngularJS services, or vice versa. The functions return a module (AngularJS or NgModule) that is configured to wire up the Angular and AngularJS injectors without the need to actually bootstrap a full hybrid application. This makes it simpler and faster to unit test services. PR Close #16848
1 parent 5e53956 commit 3fb78aa

File tree

20 files changed

+506
-9
lines changed

20 files changed

+506
-9
lines changed

aio/tools/transforms/angular-api-package/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ module.exports =
115115
'service-worker/index.ts',
116116
'upgrade/index.ts',
117117
'upgrade/static/index.ts',
118+
'upgrade/static/testing/index.ts',
118119
];
119120

120121
readFilesProcessor.fileReaders.push(packageContentFileReader);

aio/tools/transforms/authors-package/api-package.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const packageMap = {
2424
'platform-webworker-dynamic': ['platform-webworker-dynamic/index.ts'],
2525
router: ['router/index.ts', 'router/testing/index.ts', 'router/upgrade/index.ts'],
2626
'service-worker': ['service-worker/index.ts'],
27-
upgrade: ['upgrade/index.ts', 'upgrade/static/index.ts']
27+
upgrade: ['upgrade/index.ts', 'upgrade/static/index.ts', 'upgrade/static/testing/index.ts']
2828
};
2929

3030

integration/typings_test_ts34/include-all.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import * as routerUpgrade from '@angular/router/upgrade';
3939
import * as serviceWorker from '@angular/service-worker';
4040
import * as upgrade from '@angular/upgrade';
4141
import * as upgradeStatic from '@angular/upgrade/static';
42+
import * as upgradeTesting from '@angular/upgrade/static/testing';
4243

4344
export default {
4445
animations,
@@ -71,5 +72,6 @@ export default {
7172
routerUpgrade,
7273
serviceWorker,
7374
upgrade,
74-
upgradeStatic
75+
upgradeStatic,
76+
upgradeTesting,
7577
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
// #docregion angular-setup
10+
import {TestBed} from '@angular/core/testing';
11+
import {createAngularJSTestingModule, createAngularTestingModule} from '@angular/upgrade/static/testing';
12+
13+
import {HeroesService, Ng2AppModule, ng1AppModule} from './module';
14+
15+
const {module, inject} = (window as any).angular.mock;
16+
17+
// #enddocregion angular-setup
18+
describe('HeroesService (from Angular)', () => {
19+
20+
// #docregion angular-setup
21+
beforeEach(() => {
22+
TestBed.configureTestingModule(
23+
{imports: [createAngularTestingModule([ng1AppModule.name]), Ng2AppModule]});
24+
});
25+
// #enddocregion angular-setup
26+
27+
// #docregion angular-spec
28+
it('should have access to the HeroesService', () => {
29+
const heroesService = TestBed.get(HeroesService) as HeroesService;
30+
expect(heroesService).toBeDefined();
31+
});
32+
// #enddocregion angular-spec
33+
});
34+
35+
36+
describe('HeroesService (from AngularJS)', () => {
37+
// #docregion angularjs-setup
38+
beforeEach(module(createAngularJSTestingModule([Ng2AppModule])));
39+
beforeEach(module(ng1AppModule.name));
40+
// #enddocregion angularjs-setup
41+
42+
// #docregion angularjs-spec
43+
it('should have access to the HeroesService',
44+
inject((heroesService: HeroesService) => { expect(heroesService).toBeDefined(); }));
45+
// #enddocregion angularjs-spec
46+
});

packages/examples/upgrade/static/ts/full/module.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import {UpgradeComponent, UpgradeModule, downgradeComponent, downgradeInjectable
1313

1414
declare var angular: ng.IAngularStatic;
1515

16-
interface Hero {
16+
export interface Hero {
1717
name: string;
1818
description: string;
1919
}
2020

2121
// #docregion ng1-text-formatter-service
22-
class TextFormatter {
22+
export class TextFormatter {
2323
titleCase(value: string) { return value.replace(/((^|\s)[a-z])/g, (_, c) => c.toUpperCase()); }
2424
}
2525

@@ -38,7 +38,7 @@ class TextFormatter {
3838
</div>
3939
<button (click)="addHero.emit()">Add Hero</button>`,
4040
})
41-
class Ng2HeroesComponent {
41+
export class Ng2HeroesComponent {
4242
@Input() heroes !: Hero[];
4343
@Output() addHero = new EventEmitter();
4444
@Output() removeHero = new EventEmitter();
@@ -48,7 +48,7 @@ class Ng2HeroesComponent {
4848
// #docregion ng2-heroes-service
4949
// This Angular service will be "downgraded" to be used in AngularJS
5050
@Injectable()
51-
class HeroesService {
51+
export class HeroesService {
5252
heroes: Hero[] = [
5353
{name: 'superman', description: 'The man of steel'},
5454
{name: 'wonder woman', description: 'Princess of the Amazons'},
@@ -74,7 +74,7 @@ class HeroesService {
7474
// #docregion ng1-hero-wrapper
7575
// This Angular directive will act as an interface to the "upgraded" AngularJS component
7676
@Directive({selector: 'ng1-hero'})
77-
class Ng1HeroComponentWrapper extends UpgradeComponent {
77+
export class Ng1HeroComponentWrapper extends UpgradeComponent {
7878
// The names of the input and output properties here must match the names of the
7979
// `<` and `&` bindings in the AngularJS component that is being wrapped
8080
@Input() hero !: Hero;
@@ -104,7 +104,7 @@ class Ng1HeroComponentWrapper extends UpgradeComponent {
104104
imports: [BrowserModule, UpgradeModule]
105105
})
106106
// #docregion bootstrap-ng1
107-
class Ng2AppModule {
107+
export class Ng2AppModule {
108108
// #enddocregion ng2-module
109109
constructor(private upgrade: UpgradeModule) {}
110110

@@ -122,7 +122,7 @@ class Ng2AppModule {
122122
// #docregion Angular 1 Stuff
123123
// #docregion ng1-module
124124
// This Angular 1 module represents the AngularJS pieces of the application
125-
const ng1AppModule = angular.module('ng1AppModule', []);
125+
export const ng1AppModule: ng.IModule = angular.module('ng1AppModule', []);
126126
// #enddocregion
127127

128128
// #docregion ng1-hero

packages/examples/upgrade/upgrade_example.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ def create_upgrade_example_targets(name, srcs, e2e_srcs, entry_module, assets =
1717
type_check = False,
1818
deps = [
1919
"@npm//@types/angular",
20+
"@npm//@types/jasmine",
2021
"//packages/core",
2122
"//packages/platform-browser",
2223
"//packages/platform-browser-dynamic",
2324
"//packages/upgrade/static",
25+
"//packages/core/testing",
26+
"//packages/upgrade/static/testing",
2427
],
2528
tsconfig = "//packages/examples/upgrade:tsconfig-build.json",
2629
)

packages/upgrade/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ ng_package(
2323
srcs = [
2424
"package.json",
2525
"//packages/upgrade/static:package.json",
26+
"//packages/upgrade/static/testing:package.json",
2627
],
2728
entry_point = ":index.ts",
2829
tags = [
@@ -34,5 +35,6 @@ ng_package(
3435
deps = [
3536
":upgrade",
3637
"//packages/upgrade/static",
38+
"//packages/upgrade/static/testing",
3739
],
3840
)

packages/upgrade/src/common/src/angular1.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,15 @@ let angular: {
234234
(e: string | Element | Document | IAugmentedJQuery): IAugmentedJQuery;
235235
cleanData: (nodes: Node[] | NodeList) => void;
236236
},
237+
injector: (modules: Array<string|IInjectable>, strictDi?: boolean) => IInjectorService,
237238
version: {major: number},
238239
resumeBootstrap: () => void,
239240
getTestability: (e: Element) => ITestabilityService
240241
} = {
241242
bootstrap: noNg,
242243
module: noNg,
243244
element: noNgElement,
245+
injector: noNg,
244246
version: undefined as any,
245247
resumeBootstrap: noNg,
246248
getTestability: noNg
@@ -304,6 +306,9 @@ export const module_: typeof angular.module = (prefix, dependencies?) =>
304306
export const element: typeof angular.element = (e => angular.element(e)) as typeof angular.element;
305307
element.cleanData = nodes => angular.element.cleanData(nodes);
306308

309+
export const injector: typeof angular.injector =
310+
(modules: Array<string|IInjectable>, strictDi?: boolean) => angular.injector(modules, strictDi);
311+
307312
export const resumeBootstrap: typeof angular.resumeBootstrap = () => angular.resumeBootstrap();
308313

309314
export const getTestability: typeof angular.getTestability = e => angular.getTestability(e);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
load("//tools:defaults.bzl", "ng_module")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
exports_files(["package.json"])
6+
7+
ng_module(
8+
name = "testing",
9+
srcs = glob(
10+
[
11+
"*.ts",
12+
"src/*.ts",
13+
],
14+
),
15+
deps = [
16+
"//packages/core/testing",
17+
"//packages/upgrade/src/common",
18+
],
19+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './public_api';

0 commit comments

Comments
 (0)