feat(compiler): introduce TestBed.overrideTemplateUsingTestingModule
This allows to overwrite templates for JIT and AOT components alike. In contrast to `TestBed.overrideTemplate`, the template is compiled in the context of the testing module, allowing to use other testing directives. Closes #19815
This commit is contained in:

committed by
Victor Berchet

parent
05d96dc507
commit
a460066972
@ -20,5 +20,5 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
|
||||
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
||||
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
||||
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
|
||||
export {clearProviderOverrides as ɵclearProviderOverrides, overrideProvider as ɵoverrideProvider} from './view/index';
|
||||
export {clearOverrides as ɵclearOverrides, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index';
|
||||
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
|
||||
|
@ -7,11 +7,12 @@
|
||||
*/
|
||||
|
||||
import {Injector} from '../di/injector';
|
||||
import {ComponentFactory} from '../linker/component_factory';
|
||||
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {initServicesIfNeeded} from './services';
|
||||
import {NgModuleDefinitionFactory, ProviderOverride, Services} from './types';
|
||||
import {NgModuleDefinitionFactory, ProviderOverride, Services, ViewDefinition} from './types';
|
||||
import {resolveDefinition} from './util';
|
||||
|
||||
export function overrideProvider(override: ProviderOverride) {
|
||||
@ -19,9 +20,14 @@ export function overrideProvider(override: ProviderOverride) {
|
||||
return Services.overrideProvider(override);
|
||||
}
|
||||
|
||||
export function clearProviderOverrides() {
|
||||
export function overrideComponentView(comp: Type<any>, componentFactory: ComponentFactory<any>) {
|
||||
initServicesIfNeeded();
|
||||
return Services.clearProviderOverrides();
|
||||
return Services.overrideComponentView(comp, componentFactory);
|
||||
}
|
||||
|
||||
export function clearOverrides() {
|
||||
initServicesIfNeeded();
|
||||
return Services.clearOverrides();
|
||||
}
|
||||
|
||||
// Attention: this function is called as top level function.
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
export {anchorDef, elementDef} from './element';
|
||||
export {clearProviderOverrides, createNgModuleFactory, overrideProvider} from './entrypoint';
|
||||
export {clearOverrides, createNgModuleFactory, overrideComponentView, overrideProvider} from './entrypoint';
|
||||
export {ngContentDef} from './ng_content';
|
||||
export {moduleDef, moduleProvideDef} from './ng_module';
|
||||
export {directiveDef, pipeDef, providerDef} from './provider';
|
||||
|
@ -10,6 +10,7 @@ import {isDevMode} from '../application_ref';
|
||||
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
|
||||
import {Injector} from '../di';
|
||||
import {ErrorHandler} from '../error_handler';
|
||||
import {ComponentFactory} from '../linker/component_factory';
|
||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
|
||||
import {Sanitizer} from '../security';
|
||||
@ -18,9 +19,9 @@ import {Type} from '../type';
|
||||
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
||||
import {resolveDep} from './provider';
|
||||
import {dirtyParentQueries, getQueryValue} from './query';
|
||||
import {createInjector, createNgModuleRef} from './refs';
|
||||
import {createInjector, createNgModuleRef, getComponentViewDefinitionFactory} from './refs';
|
||||
import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
|
||||
import {NOOP, isComponentView, renderNode, splitDepsDsl, viewParentEl} from './util';
|
||||
import {NOOP, isComponentView, renderNode, resolveDefinition, splitDepsDsl, viewParentEl} from './util';
|
||||
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||
|
||||
|
||||
@ -38,7 +39,8 @@ export function initServicesIfNeeded() {
|
||||
Services.createComponentView = services.createComponentView;
|
||||
Services.createNgModuleRef = services.createNgModuleRef;
|
||||
Services.overrideProvider = services.overrideProvider;
|
||||
Services.clearProviderOverrides = services.clearProviderOverrides;
|
||||
Services.overrideComponentView = services.overrideComponentView;
|
||||
Services.clearOverrides = services.clearOverrides;
|
||||
Services.checkAndUpdateView = services.checkAndUpdateView;
|
||||
Services.checkNoChangesView = services.checkNoChangesView;
|
||||
Services.destroyView = services.destroyView;
|
||||
@ -58,7 +60,8 @@ function createProdServices() {
|
||||
createComponentView: createComponentView,
|
||||
createNgModuleRef: createNgModuleRef,
|
||||
overrideProvider: NOOP,
|
||||
clearProviderOverrides: NOOP,
|
||||
overrideComponentView: NOOP,
|
||||
clearOverrides: NOOP,
|
||||
checkAndUpdateView: checkAndUpdateView,
|
||||
checkNoChangesView: checkNoChangesView,
|
||||
destroyView: destroyView,
|
||||
@ -84,7 +87,8 @@ function createDebugServices() {
|
||||
createComponentView: debugCreateComponentView,
|
||||
createNgModuleRef: debugCreateNgModuleRef,
|
||||
overrideProvider: debugOverrideProvider,
|
||||
clearProviderOverrides: debugClearProviderOverrides,
|
||||
overrideComponentView: debugOverrideComponentView,
|
||||
clearOverrides: debugClearOverrides,
|
||||
checkAndUpdateView: debugCheckAndUpdateView,
|
||||
checkNoChangesView: debugCheckNoChangesView,
|
||||
destroyView: debugDestroyView,
|
||||
@ -139,10 +143,15 @@ function debugCreateEmbeddedView(
|
||||
|
||||
function debugCreateComponentView(
|
||||
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
|
||||
const defWithOverride = applyProviderOverridesToView(viewDef);
|
||||
const overrideComponentView =
|
||||
viewDefOverrides.get(nodeDef.element !.componentProvider !.provider !.token);
|
||||
if (overrideComponentView) {
|
||||
viewDef = overrideComponentView;
|
||||
} else {
|
||||
viewDef = applyProviderOverridesToView(viewDef);
|
||||
}
|
||||
return callWithDebugContext(
|
||||
DebugAction.create, createComponentView, null,
|
||||
[parentView, nodeDef, defWithOverride, hostElement]);
|
||||
DebugAction.create, createComponentView, null, [parentView, nodeDef, viewDef, hostElement]);
|
||||
}
|
||||
|
||||
function debugCreateNgModuleRef(
|
||||
@ -153,13 +162,21 @@ function debugCreateNgModuleRef(
|
||||
}
|
||||
|
||||
const providerOverrides = new Map<any, ProviderOverride>();
|
||||
const viewDefOverrides = new Map<any, ViewDefinition>();
|
||||
|
||||
function debugOverrideProvider(override: ProviderOverride) {
|
||||
providerOverrides.set(override.token, override);
|
||||
}
|
||||
|
||||
function debugClearProviderOverrides() {
|
||||
function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any>) {
|
||||
const hostViewDef = resolveDefinition(getComponentViewDefinitionFactory(compFactory));
|
||||
const compViewDef = resolveDefinition(hostViewDef.nodes[0].element !.componentView !);
|
||||
viewDefOverrides.set(comp, compViewDef);
|
||||
}
|
||||
|
||||
function debugClearOverrides() {
|
||||
providerOverrides.clear();
|
||||
viewDefOverrides.clear();
|
||||
}
|
||||
|
||||
// Notes about the algorithm:
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import {Injector} from '../di';
|
||||
import {ErrorHandler} from '../error_handler';
|
||||
import {ComponentFactory} from '../linker/component_factory';
|
||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {QueryList} from '../linker/query_list';
|
||||
import {TemplateRef} from '../linker/template_ref';
|
||||
@ -16,6 +17,7 @@ import {Renderer2, RendererFactory2, RendererType2} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
import {Type} from '../type';
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
// Defs
|
||||
// -------------------------------------
|
||||
@ -522,7 +524,8 @@ export interface Services {
|
||||
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
|
||||
def: NgModuleDefinition): NgModuleRef<any>;
|
||||
overrideProvider(override: ProviderOverride): void;
|
||||
clearProviderOverrides(): void;
|
||||
overrideComponentView(compType: Type<any>, compFactory: ComponentFactory<any>): void;
|
||||
clearOverrides(): void;
|
||||
checkAndUpdateView(view: ViewData): void;
|
||||
checkNoChangesView(view: ViewData): void;
|
||||
destroyView(view: ViewData): void;
|
||||
@ -547,7 +550,8 @@ export const Services: Services = {
|
||||
createComponentView: undefined !,
|
||||
createNgModuleRef: undefined !,
|
||||
overrideProvider: undefined !,
|
||||
clearProviderOverrides: undefined !,
|
||||
overrideComponentView: undefined !,
|
||||
clearOverrides: undefined !,
|
||||
checkAndUpdateView: undefined !,
|
||||
checkNoChangesView: undefined !,
|
||||
destroyView: undefined !,
|
||||
|
Reference in New Issue
Block a user