Skip to content

Commit

Permalink
feat(testing): allow to pass in aot summaries also to `TestBed.config…
Browse files Browse the repository at this point in the history
…ureTestingModule`

Also adds caching for summaries.

Closes #19817.
  • Loading branch information
tbosch committed Oct 27, 2017
1 parent 394d951 commit 272c27b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 30 deletions.
44 changes: 21 additions & 23 deletions packages/compiler/src/jit/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class JitCompiler {
private _compiledDirectiveWrapperCache = new Map<Type, Type>();
private _compiledNgModuleCache = new Map<Type, object>();
private _sharedStylesheetCount = 0;
private _addedAotSummaries = new Set<() => any[]>();

constructor(
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
Expand Down Expand Up @@ -74,10 +75,25 @@ export class JitCompiler {

loadAotSummaries(summaries: () => any[]) {
this.clearCache();
flattenSummaries(summaries).forEach((summary) => {
this._summaryResolver.addSummary(
{symbol: summary.type.reference, metadata: null, type: summary});
});
this._addAotSummaries(summaries);
}

private _addAotSummaries(fn: () => any[]) {
if (this._addedAotSummaries.has(fn)) {
return;
}
this._addedAotSummaries.add(fn);
const summaries = fn();
for (let i = 0; i < summaries.length; i++) {
const entry = summaries[i];
if (typeof entry === 'function') {
this._addAotSummaries(entry);
} else {
const summary = entry as CompileTypeSummary;
this._summaryResolver.addSummary(
{symbol: summary.type.reference, metadata: null, type: summary})
}
}
}

hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); }
Expand Down Expand Up @@ -200,6 +216,7 @@ export class JitCompiler {
}

clearCache(): void {
// Note: don't clear the _addedAotSummaries, as they don't change!
this._metadataResolver.clearCache();
this._compiledTemplateCache.clear();
this._compiledHostTemplateCache.clear();
Expand Down Expand Up @@ -335,25 +352,6 @@ function assertComponent(meta: CompileDirectiveMetadata) {
}
}

function flattenSummaries(
fn: () => any[], out: CompileTypeSummary[] = [],
seen = new Set<() => any[]>()): CompileTypeSummary[] {
if (seen.has(fn)) {
return out;
}
seen.add(fn);
const summaries = fn();
for (let i = 0; i < summaries.length; i++) {
const entry = summaries[i];
if (typeof entry === 'function') {
flattenSummaries(entry, out, seen);
} else {
out.push(entry);
}
}
return out;
}

function createOutputContext(): OutputContext {
const importExpr = (symbol: any) =>
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});
Expand Down
38 changes: 35 additions & 3 deletions packages/core/test/linker/jit_summaries_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {TestBed, async, getTestBed} from '@angular/core/testing';
export function main() {
describe('Jit Summaries', () => {
let instances: Map<any, Base>;
let summaries: () => any[];

class SomeDep {}

Expand Down Expand Up @@ -69,7 +70,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),
Expand All @@ -83,10 +84,12 @@ export function main() {
metadataResolver.getInjectableSummary(SomeService)
];
clearMetadata();
resetTestEnvironmentWithSummaries(() => summaries);
TestBed.resetTestingModule();
return () => summaries;
});

resourceLoader.flush();
return summariesPromise;
}

function setMetadata(resourceLoader: MockResourceLoader) {
Expand Down Expand Up @@ -123,12 +126,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 {
}
Expand All @@ -140,6 +145,8 @@ export function main() {
});

it('should use pipe metadata from summaries', () => {
resetTestEnvironmentWithSummaries(summaries);

@Component({template: '{{1 | somePipe}}'})
class TestComp {
}
Expand All @@ -150,6 +157,8 @@ export function main() {
});

it('should use Service metadata from summaries', () => {
resetTestEnvironmentWithSummaries(summaries);

TestBed.configureTestingModule({
providers: [SomeService, SomeDep],
});
Expand All @@ -158,6 +167,8 @@ export function main() {
});

it('should use NgModule metadata from summaries', () => {
resetTestEnvironmentWithSummaries(summaries);

TestBed
.configureTestingModule(
{providers: [SomeDep], declarations: [TestComp3], imports: [SomeModule]})
Expand All @@ -170,12 +181,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(
Expand All @@ -190,5 +205,22 @@ 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);
});
});
}
16 changes: 12 additions & 4 deletions packages/core/testing/src/test_bed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type TestModuleMetadata = {
declarations?: any[],
imports?: any[],
schemas?: Array<SchemaMetadata|any[]>,
aotSummaries?: () => any[],
};

/**
Expand Down Expand Up @@ -205,7 +206,8 @@ export class TestBed implements Injector {
private _schemas: Array<SchemaMetadata|any[]> = [];
private _activeFixtures: ComponentFixture<any>[] = [];

private _aotSummaries: () => any[] = () => [];
private _testEnvAotSummaries: () => any[] = () => [];
private _aotSummaries: Array<() => any[]> = [];

platform: PlatformRef = null !;

Expand All @@ -232,7 +234,7 @@ export class TestBed implements Injector {
this.platform = platform;
this.ngModule = ngModule;
if (aotSummaries) {
this._aotSummaries = aotSummaries;
this._testEnvAotSummaries = aotSummaries;
}
}

Expand All @@ -245,11 +247,12 @@ export class TestBed implements Injector {
this.resetTestingModule();
this.platform = null !;
this.ngModule = null !;
this._aotSummaries = () => [];
this._testEnvAotSummaries = () => [];
}

resetTestingModule() {
clearProviderOverrides();
this._aotSummaries = [];
this._compiler = null !;
this._moduleOverrides = [];
this._componentOverrides = [];
Expand Down Expand Up @@ -293,6 +296,9 @@ export class TestBed implements Injector {
if (moduleDef.schemas) {
this._schemas.push(...moduleDef.schemas);
}
if (moduleDef.aotSummaries) {
this._aotSummaries.push(moduleDef.aotSummaries);
}
}

compileComponents(): Promise<any> {
Expand Down Expand Up @@ -350,7 +356,9 @@ export class TestBed implements Injector {
const compilerFactory: TestingCompilerFactory =
this.platform.injector.get(TestingCompilerFactory);
this._compiler = compilerFactory.createTestingCompiler(this._compilerOptions);
this._compiler.loadAotSummaries(this._aotSummaries);
for (const summary of [this._testEnvAotSummaries, ...this._aotSummaries]) {
this._compiler.loadAotSummaries(summary);
}
this._moduleOverrides.forEach((entry) => this._compiler.overrideModule(entry[0], entry[1]));
this._componentOverrides.forEach(
(entry) => this._compiler.overrideComponent(entry[0], entry[1]));
Expand Down

0 comments on commit 272c27b

Please sign in to comment.