Skip to content

Commit 39b92f7

Browse files
tboschjasonaden
authored andcommitted
feat: introduce TestBed.overrideProvider (#16725)
This allows to overwrite all providers for a token, not matter where they were defined. This can be used to test JIT and AOT’ed code in the same way. Design doc: https://docs.google.com/document/d/1VmTkz0EbEVSWfEEWEvQ5sXyQXSCvtMOw4t7pKU-jOwc/edit?usp=sharing
1 parent 1eba623 commit 39b92f7

20 files changed

+735
-121
lines changed

packages/core/src/application_module.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
9+
import {ApplicationInitStatus} from './application_init';
1010
import {ApplicationRef, ApplicationRef_} from './application_ref';
1111
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
1212
import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection';
1313
import {Inject, Optional, SkipSelf} from './di/metadata';
1414
import {LOCALE_ID} from './i18n/tokens';
1515
import {Compiler} from './linker/compiler';
1616
import {NgModule} from './metadata';
17-
import {initServicesIfNeeded} from './view/index';
1817

1918
export function _iterableDiffersFactory() {
2019
return defaultIterableDiffers;
@@ -28,10 +27,6 @@ export function _localeFactory(locale?: string): string {
2827
return locale || 'en-US';
2928
}
3029

31-
export function _initViewEngine() {
32-
initServicesIfNeeded();
33-
}
34-
3530
/**
3631
* This module includes the providers of @angular/core that are needed
3732
* to bootstrap components via `ApplicationRef`.
@@ -52,7 +47,6 @@ export function _initViewEngine() {
5247
useFactory: _localeFactory,
5348
deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]
5449
},
55-
{provide: APP_INITIALIZER, useValue: _initViewEngine, multi: true},
5650
]
5751
})
5852
export class ApplicationModule {

packages/core/src/core_private_export.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
2626
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
2727
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
2828
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
29+
export {clearProviderOverrides as ɵclearProviderOverrides, overrideProvider as ɵoverrideProvider} from './view/index';
2930
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';

packages/core/src/view/entrypoint.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
import {Injector} from '../di/injector';
10+
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
11+
import {Type} from '../type';
12+
13+
import {initServicesIfNeeded} from './services';
14+
import {NgModuleDefinitionFactory, ProviderOverride, Services} from './types';
15+
import {resolveDefinition} from './util';
16+
17+
export function overrideProvider(override: ProviderOverride) {
18+
initServicesIfNeeded();
19+
return Services.overrideProvider(override);
20+
}
21+
22+
export function clearProviderOverrides() {
23+
initServicesIfNeeded();
24+
return Services.clearProviderOverrides();
25+
}
26+
27+
// Attention: this function is called as top level function.
28+
// Putting any logic in here will destroy closure tree shaking!
29+
export function createNgModuleFactory(
30+
ngModuleType: Type<any>, bootstrapComponents: Type<any>[],
31+
defFactory: NgModuleDefinitionFactory): NgModuleFactory<any> {
32+
return new NgModuleFactory_(ngModuleType, bootstrapComponents, defFactory);
33+
}
34+
35+
class NgModuleFactory_ extends NgModuleFactory<any> {
36+
constructor(
37+
public readonly moduleType: Type<any>, private _bootstrapComponents: Type<any>[],
38+
private _ngModuleDefFactory: NgModuleDefinitionFactory) {
39+
// Attention: this ctor is called as top level function.
40+
// Putting any logic in here will destroy closure tree shaking!
41+
super();
42+
}
43+
44+
create(parentInjector: Injector|null): NgModuleRef<any> {
45+
initServicesIfNeeded();
46+
const def = resolveDefinition(this._ngModuleDefFactory);
47+
return Services.createNgModuleRef(
48+
this.moduleType, parentInjector || Injector.NULL, this._bootstrapComponents, def);
49+
}
50+
}

packages/core/src/view/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
*/
88

99
export {anchorDef, elementDef} from './element';
10+
export {clearProviderOverrides, createNgModuleFactory, overrideProvider} from './entrypoint';
1011
export {ngContentDef} from './ng_content';
1112
export {moduleDef, moduleProvideDef} from './ng_module';
1213
export {directiveDef, pipeDef, providerDef} from './provider';
1314
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
1415
export {queryDef} from './query';
1516
export {ViewRef_, createComponentFactory, getComponentViewDefinitionFactory, nodeValue} from './refs';
16-
export {createNgModuleFactory} from './refs';
1717
export {initServicesIfNeeded} from './services';
1818
export {textDef} from './text';
1919
export {EMPTY_ARRAY, EMPTY_MAP, createRendererType2, elementEventFullName, inlineInterpolate, interpolate, rootRenderNodes, tokenKey, unwrapValue} from './util';

packages/core/src/view/ng_module.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
1010
import {NgModuleRef} from '../linker/ng_module_factory';
1111

1212
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleDefinitionFactory, NgModuleProviderDef, NodeFlags} from './types';
13-
import {tokenKey} from './util';
13+
import {splitDepsDsl, tokenKey} from './util';
1414

1515
const NOT_CREATED = new Object();
1616

@@ -20,17 +20,7 @@ const NgModuleRefTokenKey = tokenKey(NgModuleRef);
2020
export function moduleProvideDef(
2121
flags: NodeFlags, token: any, value: any,
2222
deps: ([DepFlags, any] | any)[]): NgModuleProviderDef {
23-
const depDefs: DepDef[] = deps.map(value => {
24-
let token: any;
25-
let flags: DepFlags;
26-
if (Array.isArray(value)) {
27-
[flags, token] = value;
28-
} else {
29-
flags = DepFlags.None;
30-
token = value;
31-
}
32-
return {flags, token, tokenKey: tokenKey(token)};
33-
});
23+
const depDefs = splitDepsDsl(deps);
3424
return {
3525
// will bet set by the module definition
3626
index: -1,
@@ -97,16 +87,16 @@ function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModulePr
9787
let injectable: any;
9888
switch (providerDef.flags & NodeFlags.Types) {
9989
case NodeFlags.TypeClassProvider:
100-
injectable = _createClass(ngModule, providerDef !.value, providerDef !.deps);
90+
injectable = _createClass(ngModule, providerDef.value, providerDef.deps);
10191
break;
10292
case NodeFlags.TypeFactoryProvider:
103-
injectable = _callFactory(ngModule, providerDef !.value, providerDef !.deps);
93+
injectable = _callFactory(ngModule, providerDef.value, providerDef.deps);
10494
break;
10595
case NodeFlags.TypeUseExistingProvider:
106-
injectable = resolveNgModuleDep(ngModule, providerDef !.deps[0]);
96+
injectable = resolveNgModuleDep(ngModule, providerDef.deps[0]);
10797
break;
10898
case NodeFlags.TypeValueProvider:
109-
injectable = providerDef !.value;
99+
injectable = providerDef.value;
110100
break;
111101
}
112102
return injectable;

packages/core/src/view/provider.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {Renderer as RendererV1, Renderer2} from '../render/api';
1515

1616
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
1717
import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData} from './types';
18-
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
18+
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
1919

2020
const RendererV1TokenKey = tokenKey(RendererV1);
2121
const Renderer2TokenKey = tokenKey(Renderer2);
@@ -78,17 +78,7 @@ export function _def(
7878
bindings = [];
7979
}
8080

81-
const depDefs: DepDef[] = deps.map(value => {
82-
let token: any;
83-
let flags: DepFlags;
84-
if (Array.isArray(value)) {
85-
[flags, token] = value;
86-
} else {
87-
flags = DepFlags.None;
88-
token = value;
89-
}
90-
return {flags, token, tokenKey: tokenKey(token)};
91-
});
81+
const depDefs = splitDepsDsl(deps);
9282

9383
return {
9484
// will bet set by the view definition

packages/core/src/view/refs.ts

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {Injector} from '../di/injector';
1212
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
1313
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from '../linker/component_factory_resolver';
1414
import {ElementRef} from '../linker/element_ref';
15-
import {InternalNgModuleRef, NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
15+
import {InternalNgModuleRef, NgModuleRef} from '../linker/ng_module_factory';
1616
import {TemplateRef} from '../linker/template_ref';
1717
import {ViewContainerRef} from '../linker/view_container_ref';
1818
import {EmbeddedViewRef, InternalViewRef, ViewRef} from '../linker/view_ref';
@@ -22,7 +22,7 @@ import {stringify} from '../util';
2222
import {VERSION} from '../version';
2323

2424
import {callNgModuleLifecycle, initNgModule, resolveNgModuleDep} from './ng_module';
25-
import {DepFlags, ElementData, NgModuleData, NgModuleDefinition, NgModuleDefinitionFactory, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
25+
import {DepFlags, ElementData, NgModuleData, NgModuleDefinition, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
2626
import {markParentViewsForCheck, resolveDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util';
2727
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView, renderDetachView} from './view_attach';
2828

@@ -43,14 +43,6 @@ export function getComponentViewDefinitionFactory(componentFactory: ComponentFac
4343
return (componentFactory as ComponentFactory_).viewDefFactory;
4444
}
4545

46-
// Attention: this function is called as top level function.
47-
// Putting any logic in here will destroy closure tree shaking!
48-
export function createNgModuleFactory(
49-
ngModuleType: Type<any>, bootstrapComponents: Type<any>[],
50-
defFactory: NgModuleDefinitionFactory): NgModuleFactory<any> {
51-
return new NgModuleFactory_(ngModuleType, bootstrapComponents, defFactory);
52-
}
53-
5446
class ComponentFactory_ extends ComponentFactory<any> {
5547
/**
5648
* @internal
@@ -312,7 +304,8 @@ class TemplateRef_ extends TemplateRef<any> implements TemplateData {
312304
constructor(private _parentView: ViewData, private _def: NodeDef) { super(); }
313305

314306
createEmbeddedView(context: any): EmbeddedViewRef<any> {
315-
return new ViewRef_(Services.createEmbeddedView(this._parentView, this._def, context));
307+
return new ViewRef_(Services.createEmbeddedView(
308+
this._parentView, this._def, this._def.element !.template !, context));
316309
}
317310

318311
get elementRef(): ElementRef {
@@ -464,22 +457,10 @@ class RendererAdapter implements RendererV1 {
464457
}
465458

466459

467-
class NgModuleFactory_ extends NgModuleFactory<any> {
468-
constructor(
469-
private _moduleType: Type<any>, private _bootstrapComponents: Type<any>[],
470-
private _ngModuleDefFactory: NgModuleDefinitionFactory, ) {
471-
// Attention: this ctor is called as top level function.
472-
// Putting any logic in here will destroy closure tree shaking!
473-
super();
474-
}
475-
476-
get moduleType(): Type<any> { return this._moduleType; }
477-
478-
create(parentInjector: Injector|null): NgModuleRef<any> {
479-
const def = resolveDefinition(this._ngModuleDefFactory);
480-
return new NgModuleRef_(
481-
this._moduleType, parentInjector || Injector.NULL, this._bootstrapComponents, def);
482-
}
460+
export function createNgModuleRef(
461+
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
462+
def: NgModuleDefinition): NgModuleRef<any> {
463+
return new NgModuleRef_(moduleType, parent, bootstrapComponents, def);
483464
}
484465

485466
class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
@@ -488,8 +469,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
488469
public _providers: any[];
489470

490471
constructor(
491-
private _moduleType: any, public _parent: Injector, public _bootstrapComponents: Type<any>[],
492-
public _def: NgModuleDefinition) {
472+
private _moduleType: Type<any>, public _parent: Injector,
473+
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
493474
initNgModule(this);
494475
}
495476

0 commit comments

Comments
 (0)