Repository navigation
Improve AOT unit tests #19996
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve AOT unit tests #19996
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. override+n+CV ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we already have |
||
| 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: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,10 +11,12 @@ import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver'; | |
| import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock'; | ||
| import {Component, Directive, Injectable, NgModule, Pipe, Type} from '@angular/core'; | ||
| import {TestBed, async, getTestBed} from '@angular/core/testing'; | ||
| import {expect} from '@angular/platform-browser/testing/src/matchers'; | ||
|
|
||
| export function main() { | ||
| describe('Jit Summaries', () => { | ||
| let instances: Map<any, Base>; | ||
| let summaries: () => any[]; | ||
|
|
||
| class SomeDep {} | ||
|
|
||
|
|
@@ -69,7 +71,7 @@ export function main() { | |
| TestBed.configureCompiler({providers: [{provide: ResourceLoader, useValue: resourceLoader}]}); | ||
| TestBed.configureTestingModule({imports: [SomeModule], providers: [SomeDep]}); | ||
|
|
||
| TestBed.compileComponents().then(() => { | ||
| let summariesPromise = TestBed.compileComponents().then(() => { | ||
| const metadataResolver = TestBed.get(CompileMetadataResolver) as CompileMetadataResolver; | ||
| const summaries = [ | ||
| metadataResolver.getNgModuleSummary(SomeModule), | ||
|
|
@@ -83,10 +85,12 @@ export function main() { | |
| metadataResolver.getInjectableSummary(SomeService) | ||
| ]; | ||
| clearMetadata(); | ||
| resetTestEnvironmentWithSummaries(() => summaries); | ||
| TestBed.resetTestingModule(); | ||
| return () => summaries; | ||
| }); | ||
|
|
||
| resourceLoader.flush(); | ||
| return summariesPromise; | ||
| } | ||
|
|
||
| function setMetadata(resourceLoader: MockResourceLoader) { | ||
|
|
@@ -123,12 +127,14 @@ export function main() { | |
|
|
||
| beforeEach(async(() => { | ||
| instances = new Map<any, any>(); | ||
| createSummaries(); | ||
| createSummaries().then(s => summaries = s); | ||
| })); | ||
|
|
||
| afterEach(() => { resetTestEnvironmentWithSummaries(); }); | ||
|
|
||
| it('should use directive metadata from summaries', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| @Component({template: '<div someDir></div>'}) | ||
| class TestComp { | ||
| } | ||
|
|
@@ -140,6 +146,8 @@ export function main() { | |
| }); | ||
|
|
||
| it('should use pipe metadata from summaries', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| @Component({template: '{{1 | somePipe}}'}) | ||
| class TestComp { | ||
| } | ||
|
|
@@ -150,6 +158,8 @@ export function main() { | |
| }); | ||
|
|
||
| it('should use Service metadata from summaries', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| TestBed.configureTestingModule({ | ||
| providers: [SomeService, SomeDep], | ||
| }); | ||
|
|
@@ -158,6 +168,8 @@ export function main() { | |
| }); | ||
|
|
||
| it('should use NgModule metadata from summaries', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| TestBed | ||
| .configureTestingModule( | ||
| {providers: [SomeDep], declarations: [TestComp3], imports: [SomeModule]}) | ||
|
|
@@ -170,12 +182,16 @@ export function main() { | |
| }); | ||
|
|
||
| it('should allow to create private components from imported NgModule summaries', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| TestBed.configureTestingModule({providers: [SomeDep], imports: [SomeModule]}) | ||
| .createComponent(SomePrivateComponent); | ||
| expectInstanceCreated(SomePrivateComponent); | ||
| }); | ||
|
|
||
| it('should throw when trying to mock a type with a summary', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| TestBed.resetTestingModule(); | ||
| expect(() => TestBed.overrideComponent(SomePrivateComponent, {add: {}}).compileComponents()) | ||
| .toThrowError( | ||
|
|
@@ -190,5 +206,46 @@ export function main() { | |
| expect(() => TestBed.overrideModule(SomeModule, {add: {}}).compileComponents()) | ||
| .toThrowError('SomeModule was AOT compiled, so its metadata cannot be changed.'); | ||
| }); | ||
|
|
||
| it('should allow to add summaries via configureTestingModule', () => { | ||
| resetTestEnvironmentWithSummaries(); | ||
|
|
||
| @Component({template: '<div someDir></div>'}) | ||
| class TestComp { | ||
| } | ||
|
|
||
| TestBed | ||
| .configureTestingModule({ | ||
| providers: [SomeDep], | ||
| declarations: [TestComp, SomeDirective], | ||
| aotSummaries: summaries | ||
| }) | ||
| .createComponent(TestComp); | ||
| expectInstanceCreated(SomeDirective); | ||
| }); | ||
|
|
||
| it('should allow to override a provider', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| const overwrittenValue = {}; | ||
|
|
||
| TestBed.overrideProvider(SomeDep, {useFactory: () => overwrittenValue, deps: []}); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. chain call (or assert the type of the return value) ? |
||
|
|
||
| const fixture = TestBed.configureTestingModule({providers: [SomeDep], imports: [SomeModule]}) | ||
| .createComponent(SomePublicComponent); | ||
| expect(fixture.componentInstance.dep).toBe(overwrittenValue); | ||
| }); | ||
|
|
||
| it('should allow to override a template', () => { | ||
| resetTestEnvironmentWithSummaries(summaries); | ||
|
|
||
| TestBed.overrideTemplateUsingTestingModule(SomePublicComponent, 'overwritten'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't this test work the same with |
||
|
|
||
| const fixture = TestBed.configureTestingModule({providers: [SomeDep], imports: [SomeModule]}) | ||
| .createComponent(SomePublicComponent); | ||
| expectInstanceCreated(SomePublicComponent); | ||
|
|
||
| expect(fixture.nativeElement).toHaveText('overwritten'); | ||
| }); | ||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to marked only non-functions as visited ?
Could help with stateful functions ? (not sure about the exact use case for fns)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this was existing code... so probably not worth changing the behavior