feat(compiler): support sync runtime compile
Adds new abstraction `Compiler` with methods `compileComponentAsync` and `compileComponentSync`. This is in preparation of deprecating `ComponentResolver`. `compileComponentSync` is able to compile components synchronously given all components either have an inline template or they have been compiled before. Also changes `TestComponentBuilder.createSync` to take a `Type` and use the new `compileComponentSync` method. Also supports overriding the component metadata even if the component has already been compiled. Also fixes #7084 in a better way. BREAKING CHANGE: `TestComponentBuilder.createSync` now takes a component type and throws if not all templates are either inlined are compiled before via `createAsync`. Closes #9594
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompileTemplateMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {CompilerConfig} from '@angular/compiler/src/config';
|
||||
import {DirectiveNormalizer} from '@angular/compiler/src/directive_normalizer';
|
||||
import {XHR} from '@angular/compiler/src/xhr';
|
||||
@ -15,6 +15,7 @@ import {ViewEncapsulation} from '@angular/core/src/metadata/view';
|
||||
import {beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
||||
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {SpyXHR} from './spies';
|
||||
import {TEST_PROVIDERS} from './test_bindings';
|
||||
|
||||
export function main() {
|
||||
@ -30,176 +31,230 @@ export function main() {
|
||||
new CompileTypeMetadata({moduleUrl: 'http://some/module/a.js', name: 'SomeComp'});
|
||||
});
|
||||
|
||||
describe('loadTemplate', () => {
|
||||
describe('inline template', () => {
|
||||
it('should store the template',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer) => {
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: 'a',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
expect(template.templateUrl).toEqual('package:some/module/a.js');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer) => {
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer) => {
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '<style>@import test.css</style>',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should use ViewEncapsulation.Emulated by default',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer) => {
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.encapsulation).toEqual(ViewEncapsulation.Emulated);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should use default encapsulation provided by CompilerConfig',
|
||||
inject(
|
||||
[AsyncTestCompleter, CompilerConfig, DirectiveNormalizer],
|
||||
(async: AsyncTestCompleter, config: CompilerConfig,
|
||||
normalizer: DirectiveNormalizer) => {
|
||||
config.defaultEncapsulation = ViewEncapsulation.None;
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.encapsulation).toEqual(ViewEncapsulation.None);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('templateUrl', () => {
|
||||
|
||||
it('should load a template from a url that is resolved against moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('package:some/module/sometplurl.html', 'a');
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
expect(template.templateUrl).toEqual('package:some/module/sometplurl.html');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('package:some/module/tpl/sometplurl.html', '');
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the templateUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect(
|
||||
'package:some/module/tpl/sometplurl.html', '<style>@import test.css</style>');
|
||||
normalizer
|
||||
.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/tpl/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('normalizeDirective', () => {
|
||||
it('should throw if no template was specified',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
expect(
|
||||
() => normalizer.normalizeTemplate(
|
||||
dirType,
|
||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []})))
|
||||
.toThrowError('No template specified for component SomeComp');
|
||||
expect(() => normalizer.normalizeDirective(new CompileDirectiveMetadata({
|
||||
type: dirType,
|
||||
isComponent: true,
|
||||
template:
|
||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []})
|
||||
}))).toThrowError('No template specified for component SomeComp');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('normalizeTemplateSync', () => {
|
||||
it('should store the template',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
let template = normalizer.normalizeTemplateSync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: 'a',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
expect(template.template).toEqual('a');
|
||||
expect(template.templateUrl).toEqual('package:some/module/a.js');
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleUrl',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
let template = normalizer.normalizeTemplateSync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the moduleUrl',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
let template =
|
||||
normalizer.normalizeTemplateSync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '<style>@import test.css</style>',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
}));
|
||||
|
||||
it('should use ViewEncapsulation.Emulated by default',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
let template = normalizer.normalizeTemplateSync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
expect(template.encapsulation).toEqual(ViewEncapsulation.Emulated);
|
||||
}));
|
||||
|
||||
it('should use default encapsulation provided by CompilerConfig',
|
||||
inject(
|
||||
[CompilerConfig, DirectiveNormalizer],
|
||||
(config: CompilerConfig, normalizer: DirectiveNormalizer) => {
|
||||
config.defaultEncapsulation = ViewEncapsulation.None;
|
||||
let template =
|
||||
normalizer.normalizeTemplateSync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
expect(template.encapsulation).toEqual(ViewEncapsulation.None);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('templateUrl', () => {
|
||||
|
||||
it('should load a template from a url that is resolved against moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('package:some/module/sometplurl.html', 'a');
|
||||
normalizer
|
||||
.normalizeTemplateAsync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
expect(template.templateUrl).toEqual('package:some/module/sometplurl.html');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('package:some/module/tpl/sometplurl.html', '');
|
||||
normalizer
|
||||
.normalizeTemplateAsync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the templateUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect(
|
||||
'package:some/module/tpl/sometplurl.html', '<style>@import test.css</style>');
|
||||
normalizer
|
||||
.normalizeTemplateAsync(dirType, new CompileTemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl.html',
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.styleUrls).toEqual(['package:some/module/tpl/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('normalizeExternalStylesheets', () => {
|
||||
|
||||
beforeEachProviders(() => [{provide: XHR, useClass: SpyXHR}]);
|
||||
|
||||
it('should load an external stylesheet',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: SpyXHR) => {
|
||||
programXhrSpy(xhr, {'package:some/module/test.css': 'a'});
|
||||
normalizer
|
||||
.normalizeExternalStylesheets(new CompileTemplateMetadata({
|
||||
template: '',
|
||||
templateUrl: '',
|
||||
styleUrls: ['package:some/module/test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.externalStylesheets.length).toBe(1);
|
||||
expect(template.externalStylesheets[0]).toEqual(new CompileStylesheetMetadata({
|
||||
moduleUrl: 'package:some/module/test.css',
|
||||
styles: ['a'],
|
||||
styleUrls: []
|
||||
}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should load stylesheets referenced by external stylesheets',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: SpyXHR) => {
|
||||
programXhrSpy(xhr, {
|
||||
'package:some/module/test.css': 'a@import "test2.css"',
|
||||
'package:some/module/test2.css': 'b'
|
||||
});
|
||||
normalizer
|
||||
.normalizeExternalStylesheets(new CompileTemplateMetadata({
|
||||
template: '',
|
||||
templateUrl: '',
|
||||
styleUrls: ['package:some/module/test.css']
|
||||
}))
|
||||
.then((template: CompileTemplateMetadata) => {
|
||||
expect(template.externalStylesheets.length).toBe(2);
|
||||
expect(template.externalStylesheets[0]).toEqual(new CompileStylesheetMetadata({
|
||||
moduleUrl: 'package:some/module/test.css',
|
||||
styles: ['a'],
|
||||
styleUrls: ['package:some/module/test2.css']
|
||||
}));
|
||||
expect(template.externalStylesheets[1]).toEqual(new CompileStylesheetMetadata({
|
||||
moduleUrl: 'package:some/module/test2.css',
|
||||
styles: ['b'],
|
||||
styleUrls: []
|
||||
}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('caching', () => {
|
||||
it('should work for templateUrl',
|
||||
inject(
|
||||
[AsyncTestCompleter, DirectiveNormalizer, XHR],
|
||||
(async: AsyncTestCompleter, normalizer: DirectiveNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('package:some/module/cmp.html', 'a');
|
||||
var templateMeta = new CompileTemplateMetadata({
|
||||
templateUrl: 'cmp.html',
|
||||
});
|
||||
Promise
|
||||
.all([
|
||||
normalizer.normalizeTemplateAsync(dirType, templateMeta),
|
||||
normalizer.normalizeTemplateAsync(dirType, templateMeta)
|
||||
])
|
||||
.then((templates: CompileTemplateMetadata[]) => {
|
||||
expect(templates[0].template).toEqual('a');
|
||||
expect(templates[1].template).toEqual('a');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
@ -369,3 +424,14 @@ export function main() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function programXhrSpy(spy: SpyXHR, results: {[key: string]: string}) {
|
||||
spy.spy('get').andCallFake((url: string): Promise<any> => {
|
||||
var result = results[url];
|
||||
if (result) {
|
||||
return Promise.resolve(result);
|
||||
} else {
|
||||
return Promise.reject(`Unknown mock url ${url}`);
|
||||
}
|
||||
});
|
||||
}
|
@ -20,11 +20,11 @@ import {TemplateParser} from '@angular/compiler/src/template_parser';
|
||||
import {createOfflineCompileUrlResolver} from '@angular/compiler/src/url_resolver';
|
||||
import {MODULE_SUFFIX} from '@angular/compiler/src/util';
|
||||
import {ViewCompiler} from '@angular/compiler/src/view_compiler/view_compiler';
|
||||
import {XHR} from '@angular/compiler/src/xhr';
|
||||
|
||||
import {Console} from '../core_private';
|
||||
import {IS_DART, isPresent, print} from '../src/facade/lang';
|
||||
import {MockSchemaRegistry} from '../testing/schema_registry_mock';
|
||||
import {MockXHR} from '../testing/xhr_mock';
|
||||
|
||||
|
||||
export class CompA { user: string; }
|
||||
@ -44,9 +44,8 @@ export var compAMetadata = CompileDirectiveMetadata.create({
|
||||
})
|
||||
});
|
||||
|
||||
function _createOfflineCompiler(xhr: MockXHR, emitter: OutputEmitter): OfflineCompiler {
|
||||
function _createOfflineCompiler(xhr: XHR, emitter: OutputEmitter): OfflineCompiler {
|
||||
var urlResolver = createOfflineCompileUrlResolver();
|
||||
xhr.when(`${THIS_MODULE_PATH}/offline_compiler_compa.html`, 'Hello World {{user}}!');
|
||||
var htmlParser = new HtmlParser();
|
||||
var config = new CompilerConfig({genDebugInfo: true, useJit: true});
|
||||
var normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config);
|
||||
@ -54,24 +53,25 @@ function _createOfflineCompiler(xhr: MockXHR, emitter: OutputEmitter): OfflineCo
|
||||
normalizer,
|
||||
new TemplateParser(
|
||||
new Parser(new Lexer()), new MockSchemaRegistry({}, {}), htmlParser, new Console(), []),
|
||||
new StyleCompiler(urlResolver), new ViewCompiler(config), emitter, xhr);
|
||||
new StyleCompiler(urlResolver), new ViewCompiler(config), emitter);
|
||||
}
|
||||
|
||||
export function compileComp(
|
||||
emitter: OutputEmitter, comp: CompileDirectiveMetadata): Promise<string> {
|
||||
var xhr = new MockXHR();
|
||||
var xhr = new MockXhr();
|
||||
xhr.setResult(`${THIS_MODULE_PATH}/offline_compiler_compa.html`, '');
|
||||
xhr.setResult(`${THIS_MODULE_PATH}/offline_compiler_compa.css`, '');
|
||||
var compiler = _createOfflineCompiler(xhr, emitter);
|
||||
var result = compiler.normalizeDirectiveMetadata(comp).then((normComp) => {
|
||||
return compiler.compileTemplates([new NormalizedComponentWithViewDirectives(normComp, [], [])])
|
||||
return compiler
|
||||
.compileTemplates([new NormalizedComponentWithViewDirectives(normComp, [], [])])[0]
|
||||
.source;
|
||||
});
|
||||
xhr.flush();
|
||||
return result;
|
||||
}
|
||||
|
||||
export class SimpleJsImportGenerator implements ImportGenerator {
|
||||
getImportPath(moduleUrlStr: string, importedUrlStr: string): string {
|
||||
// var moduleAssetUrl = ImportGenerator.parseAssetUrl(moduleUrlStr);
|
||||
var importedAssetUrl = ImportGenerator.parseAssetUrl(importedUrlStr);
|
||||
if (isPresent(importedAssetUrl)) {
|
||||
return `${importedAssetUrl.packageName}/${importedAssetUrl.modulePath}`;
|
||||
@ -80,3 +80,15 @@ export class SimpleJsImportGenerator implements ImportGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MockXhr implements XHR {
|
||||
results: {[key: string]: string} = {};
|
||||
setResult(url: string, content: string) { this.results[url] = content; }
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
if (url in this.results) {
|
||||
return Promise.resolve(this.results[url]);
|
||||
}
|
||||
return Promise.reject<any>(`Unknown url ${url}`);
|
||||
}
|
||||
}
|
108
modules/@angular/compiler/test/runtime_compiler_spec.ts
Normal file
108
modules/@angular/compiler/test/runtime_compiler_spec.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import {beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
|
||||
import {Injectable, Component, Input, ViewMetadata, Compiler, ComponentFactory, Injector} from '@angular/core';
|
||||
import {ConcreteType, stringify} from '../src/facade/lang';
|
||||
import {fakeAsync, tick, TestComponentBuilder, ComponentFixture} from '@angular/core/testing';
|
||||
import {XHR, ViewResolver} from '@angular/compiler';
|
||||
import {MockViewResolver} from '@angular/compiler/testing';
|
||||
|
||||
import {SpyXHR} from './spies';
|
||||
|
||||
@Component({selector: 'child-cmp', template: 'childComp'})
|
||||
class ChildComp {
|
||||
}
|
||||
|
||||
@Component({selector: 'some-cmp', template: 'someComp'})
|
||||
class SomeComp {
|
||||
}
|
||||
|
||||
@Component({selector: 'some-cmp', templateUrl: './someTpl'})
|
||||
class SomeCompWithUrlTemplate {
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('RuntimeCompiler', () => {
|
||||
let compiler: Compiler;
|
||||
let xhr: SpyXHR;
|
||||
let tcb: TestComponentBuilder;
|
||||
let viewResolver: MockViewResolver;
|
||||
let injector: Injector;
|
||||
|
||||
beforeEachProviders(() => [{provide: XHR, useValue: new SpyXHR()}]);
|
||||
|
||||
beforeEach(inject(
|
||||
[Compiler, TestComponentBuilder, XHR, ViewResolver, Injector],
|
||||
(_compiler: Compiler, _tcb: TestComponentBuilder, _xhr: SpyXHR,
|
||||
_viewResolver: MockViewResolver, _injector: Injector) => {
|
||||
compiler = _compiler;
|
||||
tcb = _tcb;
|
||||
xhr = _xhr;
|
||||
viewResolver = _viewResolver;
|
||||
injector = _injector;
|
||||
}));
|
||||
|
||||
describe('clearCacheFor', () => {
|
||||
it('should support changing the content of a template referenced via templateUrl',
|
||||
fakeAsync(() => {
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve('init'));
|
||||
let compFixture =
|
||||
tcb.overrideView(SomeComp, new ViewMetadata({templateUrl: '/myComp.html'}))
|
||||
.createFakeAsync(SomeComp);
|
||||
expect(compFixture.nativeElement).toHaveText('init');
|
||||
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve('new content'));
|
||||
// Note: overrideView is calling .clearCacheFor...
|
||||
compFixture = tcb.overrideView(SomeComp, new ViewMetadata({templateUrl: '/myComp.html'}))
|
||||
.createFakeAsync(SomeComp);
|
||||
expect(compFixture.nativeElement).toHaveText('new content');
|
||||
}));
|
||||
|
||||
it('should support overwriting inline templates', () => {
|
||||
let componentFixture = tcb.createSync(SomeComp);
|
||||
expect(componentFixture.nativeElement).toHaveText('someComp');
|
||||
|
||||
componentFixture = tcb.overrideTemplate(SomeComp, 'test').createSync(SomeComp);
|
||||
expect(componentFixture.nativeElement).toHaveText('test');
|
||||
});
|
||||
|
||||
it('should not update existing compilation results', () => {
|
||||
viewResolver.setView(
|
||||
SomeComp,
|
||||
new ViewMetadata({template: '<child-cmp></child-cmp>', directives: [ChildComp]}));
|
||||
viewResolver.setInlineTemplate(ChildComp, 'oldChild');
|
||||
let compFactory = compiler.compileComponentSync(SomeComp);
|
||||
viewResolver.setInlineTemplate(ChildComp, 'newChild');
|
||||
compiler.compileComponentSync(SomeComp);
|
||||
let compRef = compFactory.create(injector);
|
||||
expect(compRef.location.nativeElement).toHaveText('oldChild');
|
||||
});
|
||||
});
|
||||
|
||||
describe('compileComponentSync', () => {
|
||||
it('should throw when using a templateUrl that has not been compiled before', () => {
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve(''));
|
||||
expect(() => tcb.createSync(SomeCompWithUrlTemplate))
|
||||
.toThrowError(
|
||||
`Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`);
|
||||
});
|
||||
|
||||
it('should throw when using a templateUrl in a nested component that has not been compiled before',
|
||||
() => {
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve(''));
|
||||
let localTcb =
|
||||
tcb.overrideView(SomeComp, new ViewMetadata({template: '', directives: [ChildComp]}))
|
||||
.overrideView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'}));
|
||||
expect(() => localTcb.createSync(SomeComp))
|
||||
.toThrowError(
|
||||
`Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`);
|
||||
});
|
||||
|
||||
it('should allow to use templateUrl components that have been loaded before',
|
||||
fakeAsync(() => {
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve('hello'));
|
||||
tcb.createFakeAsync(SomeCompWithUrlTemplate);
|
||||
let compFixture = tcb.createSync(SomeCompWithUrlTemplate);
|
||||
expect(compFixture.nativeElement).toHaveText('hello');
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
import {beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
|
||||
import {TestComponentBuilder, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone} from '@angular/compiler/testing';
|
||||
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
|
||||
import {Injectable, Component, Input, ViewMetadata, ComponentResolver} from '@angular/core';
|
||||
import {Injectable, Component, Input, ViewMetadata} from '@angular/core';
|
||||
import {NgIf} from '@angular/common';
|
||||
import {TimerWrapper} from '../src/facade/async';
|
||||
import {IS_DART} from '../src/facade/lang';
|
||||
@ -320,6 +320,15 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should create components synchronously',
|
||||
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
|
||||
let componentFixture =
|
||||
tcb.overrideTemplate(MockChildComp, '<span>Mock</span>').createSync(MockChildComp);
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('Mock');
|
||||
}));
|
||||
|
||||
if (!IS_DART) {
|
||||
describe('ComponentFixture', () => {
|
||||
it('should auto detect changes if autoDetectChanges is called',
|
||||
@ -604,27 +613,6 @@ export function main() {
|
||||
}));
|
||||
});
|
||||
|
||||
describe('createSync', () => {
|
||||
it('should create components',
|
||||
inject(
|
||||
[ComponentResolver, TestComponentBuilder, AsyncTestCompleter],
|
||||
(cr: ComponentResolver, tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
cr.resolveComponent(MyIfComp).then((cmpFactory) => {
|
||||
let componentFixture = tcb.createSync(cmpFactory);
|
||||
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('MyIf()');
|
||||
|
||||
componentFixture.componentInstance.showMore = true;
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('MyIf(More)');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -6,18 +6,19 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {beforeEach, ddescribe, describe, expect, iit, it,} from '@angular/core/testing/testing_internal';
|
||||
import {beforeEach, ddescribe, describe, expect, iit, it, inject,} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {stringify} from '../src/facade/lang';
|
||||
import {MockViewResolver} from '../testing';
|
||||
import {Component, ViewMetadata} from '@angular/core';
|
||||
import {Component, ViewMetadata, Injector} from '@angular/core';
|
||||
import {isBlank} from '../src/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe('MockViewResolver', () => {
|
||||
var viewResolver: MockViewResolver;
|
||||
|
||||
beforeEach(() => { viewResolver = new MockViewResolver(); });
|
||||
beforeEach(inject(
|
||||
[Injector], (injector: Injector) => { viewResolver = new MockViewResolver(injector); }));
|
||||
|
||||
describe('View overriding', () => {
|
||||
it('should fallback to the default ViewResolver when templates are not overridden', () => {
|
||||
@ -33,13 +34,12 @@ export function main() {
|
||||
expect(isBlank(view.directives)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow overriding a view after it has been resolved', () => {
|
||||
it('should allow overriding a view after it has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
expect(() => {
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
})
|
||||
.toThrowError(
|
||||
`The component ${stringify(SomeComponent)} has already been compiled, its configuration can not be changed`);
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
expect(isBlank(view.directives)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -58,11 +58,11 @@ export function main() {
|
||||
expect(view.template).toEqual('overridden template x 2');
|
||||
});
|
||||
|
||||
it('should not allow overriding a view after it has been resolved', () => {
|
||||
it('should allow overriding a view after it has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
expect(() => { viewResolver.setInlineTemplate(SomeComponent, 'overridden template'); })
|
||||
.toThrowError(
|
||||
`The component ${stringify(SomeComponent)} has already been compiled, its configuration can not be changed`);
|
||||
viewResolver.setInlineTemplate(SomeComponent, 'overridden template');
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
});
|
||||
});
|
||||
|
||||
@ -90,13 +90,12 @@ export function main() {
|
||||
`Overriden directive ${stringify(SomeOtherDirective)} not found in the template of ${stringify(SomeComponent)}`);
|
||||
});
|
||||
|
||||
it('should not allow overriding a directive after its view has been resolved', () => {
|
||||
it('should allow overriding a directive after its view has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
expect(() => {
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
})
|
||||
.toThrowError(
|
||||
`The component ${stringify(SomeComponent)} has already been compiled, its configuration can not be changed`);
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
expect(view.directives.length).toEqual(1);
|
||||
expect(view.directives[0]).toBe(SomeOtherDirective);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user