feat(compiler): add TemplateCompiler
TemplateCompiler is the entry point to the new compiler Related to #3605 Closes #4220
This commit is contained in:
@ -9,12 +9,15 @@ import {
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
TestComponentBuilder
|
||||
TestComponentBuilder,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {DirectiveMetadata, TypeMetadata, ChangeDetectionMetadata} from 'angular2/src/compiler/api';
|
||||
import {MockSchemaRegistry} from './template_parser_spec';
|
||||
import {
|
||||
NormalizedDirectiveMetadata,
|
||||
TypeMetadata,
|
||||
ChangeDetectionMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
import {
|
||||
Parser,
|
||||
@ -33,9 +36,12 @@ import {Pipes} from 'angular2/src/core/change_detection/pipes';
|
||||
import {createChangeDetectorDefinitions} from 'angular2/src/compiler/change_definition_factory';
|
||||
import {TestContext, TestDirective, TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
|
||||
export function main() {
|
||||
describe('ChangeDefinitionFactory', () => {
|
||||
var domParser: HtmlParser;
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
|
||||
var parser: TemplateParser;
|
||||
var dispatcher: TestDispatcher;
|
||||
var context: TestContext;
|
||||
@ -44,26 +50,23 @@ export function main() {
|
||||
var pipes: Pipes;
|
||||
var eventLocals: Locals;
|
||||
|
||||
beforeEach(() => {
|
||||
domParser = new HtmlParser();
|
||||
parser = new TemplateParser(
|
||||
new Parser(new Lexer()),
|
||||
new MockSchemaRegistry({'invalidProp': false}, {'mappedAttr': 'mappedProp'}));
|
||||
beforeEach(inject([TemplateParser], (_templateParser) => {
|
||||
parser = _templateParser;
|
||||
context = new TestContext();
|
||||
directive = new TestDirective();
|
||||
dispatcher = new TestDispatcher([directive], []);
|
||||
locals = new Locals(null, MapWrapper.createFromStringMap({'someVar': null}));
|
||||
eventLocals = new Locals(null, MapWrapper.createFromStringMap({'$event': null}));
|
||||
pipes = new TestPipes();
|
||||
});
|
||||
}));
|
||||
|
||||
function createChangeDetector(template: string, directives: DirectiveMetadata[],
|
||||
function createChangeDetector(template: string, directives: NormalizedDirectiveMetadata[],
|
||||
protoViewIndex: number = 0): ChangeDetector {
|
||||
var protoChangeDetectors =
|
||||
createChangeDetectorDefinitions(
|
||||
new TypeMetadata({typeName: 'SomeComp'}), ChangeDetectionStrategy.Default,
|
||||
new ChangeDetectorGenConfig(true, true, false, false),
|
||||
parser.parse(domParser.parse(template, 'TestComp'), directives))
|
||||
createChangeDetectorDefinitions(new TypeMetadata({name: 'SomeComp'}),
|
||||
ChangeDetectionStrategy.Default,
|
||||
new ChangeDetectorGenConfig(true, true, false, false),
|
||||
parser.parse(template, directives, 'TestComp'))
|
||||
.map(definition => new DynamicProtoChangeDetector(definition));
|
||||
var changeDetector = protoChangeDetectors[protoViewIndex].instantiate(dispatcher);
|
||||
changeDetector.hydrate(context, locals, dispatcher, pipes);
|
||||
@ -103,8 +106,8 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should write directive properties', () => {
|
||||
var dirMeta = new DirectiveMetadata({
|
||||
type: new TypeMetadata({typeName: 'SomeDir'}),
|
||||
var dirMeta = new NormalizedDirectiveMetadata({
|
||||
type: new TypeMetadata({name: 'SomeDir'}),
|
||||
selector: 'div',
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['dirProp']})
|
||||
});
|
||||
@ -117,8 +120,8 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should watch directive host properties', () => {
|
||||
var dirMeta = new DirectiveMetadata({
|
||||
type: new TypeMetadata({typeName: 'SomeDir'}),
|
||||
var dirMeta = new NormalizedDirectiveMetadata({
|
||||
type: new TypeMetadata({name: 'SomeDir'}),
|
||||
selector: 'div',
|
||||
changeDetection: new ChangeDetectionMetadata({hostProperties: {'elProp': 'dirProp'}})
|
||||
});
|
||||
@ -131,8 +134,8 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should handle directive events', () => {
|
||||
var dirMeta = new DirectiveMetadata({
|
||||
type: new TypeMetadata({typeName: 'SomeDir'}),
|
||||
var dirMeta = new NormalizedDirectiveMetadata({
|
||||
type: new TypeMetadata({name: 'SomeDir'}),
|
||||
selector: 'div',
|
||||
changeDetection:
|
||||
new ChangeDetectionMetadata({hostListeners: {'click': 'onEvent($event)'}})
|
||||
|
@ -9,9 +9,10 @@ import {
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
import {IS_DART} from '../platform';
|
||||
import {bind} from 'angular2/src/core/di';
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
@ -19,21 +20,16 @@ import {Promise} from 'angular2/src/core/facade/async';
|
||||
|
||||
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
|
||||
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
NormalizedDirectiveMetadata,
|
||||
TypeMetadata,
|
||||
ChangeDetectionMetadata,
|
||||
SourceModule
|
||||
} from 'angular2/src/compiler/api';
|
||||
|
||||
import {MockSchemaRegistry} from './template_parser_spec';
|
||||
ChangeDetectionMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {SourceModule, SourceExpression, moduleRef} from 'angular2/src/compiler/source_module';
|
||||
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
|
||||
import {
|
||||
Parser,
|
||||
Lexer,
|
||||
ChangeDetectorGenConfig,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDispatcher,
|
||||
@ -45,61 +41,76 @@ import {
|
||||
|
||||
import {evalModule} from './eval_module';
|
||||
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
import {TestContext, TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
||||
|
||||
// Attention: These module names have to correspond to real modules!
|
||||
const MODULE_NAME = 'angular2/test/compiler/change_detector_compiler_spec';
|
||||
const THIS_MODULE = 'angular2/test/compiler/change_detector_compiler_spec';
|
||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE);
|
||||
|
||||
export function main() {
|
||||
describe('ChangeDetectorCompiler', () => {
|
||||
var domParser: HtmlParser;
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
|
||||
var parser: TemplateParser;
|
||||
var compiler: ChangeDetectionCompiler;
|
||||
|
||||
function createCompiler(useJit: boolean): ChangeDetectionCompiler {
|
||||
return new ChangeDetectionCompiler(new ChangeDetectorGenConfig(true, true, false, useJit));
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
domParser = new HtmlParser();
|
||||
parser = new TemplateParser(
|
||||
new Parser(new Lexer()),
|
||||
new MockSchemaRegistry({'invalidProp': false}, {'mappedAttr': 'mappedProp'}));
|
||||
});
|
||||
beforeEach(inject([TemplateParser, ChangeDetectionCompiler], (_parser, _compiler) => {
|
||||
parser = _parser;
|
||||
compiler = _compiler;
|
||||
}));
|
||||
|
||||
describe('compileComponentRuntime', () => {
|
||||
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
||||
directives: DirectiveMetadata[] = CONST_EXPR([])): string[] {
|
||||
var type = new TypeMetadata({typeName: 'SomeComp'});
|
||||
var parsedTemplate = parser.parse(domParser.parse(template, 'TestComp'), directives);
|
||||
directives: NormalizedDirectiveMetadata[] = CONST_EXPR([])): string[] {
|
||||
var type = new TypeMetadata({name: 'SomeComp'});
|
||||
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
||||
var factories =
|
||||
compiler.compileComponentRuntime(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
||||
return testChangeDetector(factories[0]);
|
||||
}
|
||||
|
||||
it('should watch element properties (no jit)', () => {
|
||||
expect(detectChanges(createCompiler(false), '<div [el-prop]="someProp">'))
|
||||
.toEqual(['elementProperty(elProp)=someValue']);
|
||||
describe('no jit', () => {
|
||||
beforeEachBindings(() => [
|
||||
bind(ChangeDetectorGenConfig)
|
||||
.toValue(new ChangeDetectorGenConfig(true, true, false, false))
|
||||
]);
|
||||
it('should watch element properties', () => {
|
||||
expect(detectChanges(compiler, '<div [el-prop]="someProp">'))
|
||||
.toEqual(['elementProperty(elProp)=someValue']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should watch element properties (jit)', () => {
|
||||
expect(detectChanges(createCompiler(true), '<div [el-prop]="someProp">'))
|
||||
.toEqual(['elementProperty(elProp)=someValue']);
|
||||
describe('jit', () => {
|
||||
beforeEachBindings(() => [
|
||||
bind(ChangeDetectorGenConfig)
|
||||
.toValue(new ChangeDetectorGenConfig(true, true, false, true))
|
||||
]);
|
||||
it('should watch element properties', () => {
|
||||
expect(detectChanges(compiler, '<div [el-prop]="someProp">'))
|
||||
.toEqual(['elementProperty(elProp)=someValue']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('compileComponentCodeGen', () => {
|
||||
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
||||
directives: DirectiveMetadata[] = CONST_EXPR([])): Promise<string[]> {
|
||||
var type = new TypeMetadata({typeName: 'SomeComp'});
|
||||
var parsedTemplate = parser.parse(domParser.parse(template, 'TestComp'), directives);
|
||||
var sourceModule =
|
||||
directives: NormalizedDirectiveMetadata[] = CONST_EXPR([])):
|
||||
Promise<string[]> {
|
||||
var type = new TypeMetadata({name: 'SomeComp'});
|
||||
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
||||
var sourceExpression =
|
||||
compiler.compileComponentCodeGen(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
||||
var testableModule = createTestableModule(sourceModule, 0);
|
||||
var testableModule = createTestableModule(sourceExpression, 0).getSourceWithImports();
|
||||
return evalModule(testableModule.source, testableModule.imports, null);
|
||||
}
|
||||
|
||||
it('should watch element properties', inject([AsyncTestCompleter], (async) => {
|
||||
detectChanges(createCompiler(true), '<div [el-prop]="someProp">')
|
||||
detectChanges(compiler, '<div [el-prop]="someProp">')
|
||||
.then((value) => {
|
||||
expect(value).toEqual(['elementProperty(elProp)=someValue']);
|
||||
async.done();
|
||||
@ -111,19 +122,12 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createTestableModule(sourceModule: SourceModule, changeDetectorIndex: number):
|
||||
SourceModule {
|
||||
var testableSource;
|
||||
var testableImports = [[MODULE_NAME, 'mocks']].concat(sourceModule.imports);
|
||||
if (IS_DART) {
|
||||
testableSource = `${sourceModule.source}
|
||||
run(_) { return mocks.testChangeDetector(CHANGE_DETECTORS[${changeDetectorIndex}]); }`;
|
||||
} else {
|
||||
testableSource = `${sourceModule.source}
|
||||
exports.run = function(_) { return mocks.testChangeDetector(CHANGE_DETECTORS[${changeDetectorIndex}]); }`;
|
||||
}
|
||||
return new SourceModule(null, testableSource, testableImports);
|
||||
function createTestableModule(source: SourceExpression, changeDetectorIndex: number): SourceModule {
|
||||
var resultExpression =
|
||||
`${THIS_MODULE_REF}testChangeDetector((${source.expression})[${changeDetectorIndex}])`;
|
||||
var testableSource = `${source.declarations.join('\n')}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
||||
return new SourceModule(null, testableSource);
|
||||
}
|
||||
|
||||
export function testChangeDetector(changeDetectorFactory: Function): string[] {
|
||||
|
@ -9,16 +9,13 @@ import {
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {IS_DART} from '../platform';
|
||||
import {CONST_EXPR, stringify, isType, Type, isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
import {MockSchemaRegistry} from './template_parser_spec';
|
||||
import {Parser, Lexer} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {
|
||||
CommandVisitor,
|
||||
TextCmd,
|
||||
@ -32,14 +29,19 @@ import {
|
||||
} from 'angular2/src/core/compiler/template_commands';
|
||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
NormalizedDirectiveMetadata,
|
||||
TypeMetadata,
|
||||
TemplateMetadata,
|
||||
SourceModule
|
||||
} from 'angular2/src/compiler/api';
|
||||
NormalizedTemplateMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {SourceModule, SourceExpression, moduleRef} from 'angular2/src/compiler/source_module';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
import {evalModule} from './eval_module';
|
||||
import {escapeSingleQuoteString} from 'angular2/src/compiler/util';
|
||||
import {
|
||||
escapeSingleQuoteString,
|
||||
codeGenValueFn,
|
||||
codeGenExportVariable
|
||||
} from 'angular2/src/compiler/util';
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
|
||||
const BEGIN_ELEMENT = 'BEGIN_ELEMENT';
|
||||
const END_ELEMENT = 'END_ELEMENT';
|
||||
@ -50,8 +52,9 @@ const NG_CONTENT = 'NG_CONTENT';
|
||||
const EMBEDDED_TEMPLATE = 'EMBEDDED_TEMPLATE';
|
||||
|
||||
// Attention: These module names have to correspond to real modules!
|
||||
const MODULE_NAME = 'angular2/test/compiler/command_compiler_spec';
|
||||
const TEMPLATE_COMMANDS_MODULE_NAME = 'angular2/src/core/compiler/template_commands';
|
||||
const THIS_MODULE_NAME = 'angular2/test/compiler/command_compiler_spec';
|
||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE_NAME);
|
||||
var TEMPLATE_COMMANDS_MODULE_REF = moduleRef('angular2/src/core/compiler/template_commands');
|
||||
|
||||
// Attention: read by eval!
|
||||
export class RootComp {}
|
||||
@ -59,27 +62,26 @@ export class SomeDir {}
|
||||
export class AComp {}
|
||||
|
||||
var RootCompTypeMeta =
|
||||
new TypeMetadata({typeName: 'RootComp', id: 1, type: RootComp, typeUrl: MODULE_NAME});
|
||||
new TypeMetadata({id: 1, name: 'RootComp', runtime: RootComp, moduleId: THIS_MODULE_NAME});
|
||||
var SomeDirTypeMeta =
|
||||
new TypeMetadata({typeName: 'SomeDir', id: 2, type: SomeDir, typeUrl: MODULE_NAME});
|
||||
var ACompTypeMeta = new TypeMetadata({typeName: 'AComp', id: 3, type: AComp, typeUrl: MODULE_NAME});
|
||||
new TypeMetadata({id: 2, name: 'SomeDir', runtime: SomeDir, moduleId: THIS_MODULE_NAME});
|
||||
var ACompTypeMeta =
|
||||
new TypeMetadata({id: 3, name: 'AComp', runtime: AComp, moduleId: THIS_MODULE_NAME});
|
||||
|
||||
var NESTED_COMPONENT = new CompiledTemplate('someNestedComponentId', []);
|
||||
var NESTED_COMPONENT = new CompiledTemplate(45, () => []);
|
||||
|
||||
export function main() {
|
||||
describe('CommandCompiler', () => {
|
||||
var domParser: HtmlParser;
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
|
||||
var parser: TemplateParser;
|
||||
var commandCompiler: CommandCompiler;
|
||||
var componentTemplateFactory: Function;
|
||||
|
||||
beforeEach(() => {
|
||||
domParser = new HtmlParser();
|
||||
parser = new TemplateParser(
|
||||
new Parser(new Lexer()),
|
||||
new MockSchemaRegistry({'invalidProp': false}, {'mappedAttr': 'mappedProp'}));
|
||||
commandCompiler = new CommandCompiler();
|
||||
});
|
||||
beforeEach(inject([TemplateParser, CommandCompiler], (_templateParser, _commandCompiler) => {
|
||||
parser = _templateParser;
|
||||
commandCompiler = _commandCompiler;
|
||||
}));
|
||||
|
||||
function createComp({type, selector, template, encapsulation, ngContentSelectors}: {
|
||||
type?: TypeMetadata,
|
||||
@ -87,7 +89,7 @@ export function main() {
|
||||
template?: string,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
ngContentSelectors?: string[]
|
||||
}): DirectiveMetadata {
|
||||
}): NormalizedDirectiveMetadata {
|
||||
if (isBlank(encapsulation)) {
|
||||
encapsulation = ViewEncapsulation.None;
|
||||
}
|
||||
@ -100,11 +102,11 @@ export function main() {
|
||||
if (isBlank(template)) {
|
||||
template = '';
|
||||
}
|
||||
return new DirectiveMetadata({
|
||||
return new NormalizedDirectiveMetadata({
|
||||
selector: selector,
|
||||
isComponent: true,
|
||||
type: type,
|
||||
template: new TemplateMetadata({
|
||||
template: new NormalizedTemplateMetadata({
|
||||
template: template,
|
||||
ngContentSelectors: ngContentSelectors,
|
||||
encapsulation: encapsulation
|
||||
@ -112,8 +114,8 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
function createDirective(type: TypeMetadata, selector: string): DirectiveMetadata {
|
||||
return new DirectiveMetadata({selector: selector, isComponent: false, type: type});
|
||||
function createDirective(type: TypeMetadata, selector: string): NormalizedDirectiveMetadata {
|
||||
return new NormalizedDirectiveMetadata({selector: selector, isComponent: false, type: type});
|
||||
}
|
||||
|
||||
|
||||
@ -229,7 +231,7 @@ export function main() {
|
||||
['ACompType'],
|
||||
false,
|
||||
null,
|
||||
'AComp'
|
||||
3
|
||||
],
|
||||
[END_COMPONENT]
|
||||
]);
|
||||
@ -258,7 +260,7 @@ export function main() {
|
||||
['ACompType'],
|
||||
false,
|
||||
null,
|
||||
'AComp'
|
||||
3
|
||||
],
|
||||
[END_COMPONENT]
|
||||
]);
|
||||
@ -273,7 +275,7 @@ export function main() {
|
||||
run(rootComp, [comp])
|
||||
.then((data) => {
|
||||
expect(data).toEqual([
|
||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], true, null, 'AComp'],
|
||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], true, null, 3],
|
||||
[END_COMPONENT]
|
||||
]);
|
||||
async.done();
|
||||
@ -287,7 +289,7 @@ export function main() {
|
||||
run(rootComp, [comp])
|
||||
.then((data) => {
|
||||
expect(data).toEqual([
|
||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], false, null, 'AComp'],
|
||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], false, null, 3],
|
||||
[TEXT, 't', false, 0],
|
||||
[END_COMPONENT]
|
||||
]);
|
||||
@ -362,15 +364,15 @@ export function main() {
|
||||
|
||||
describe('compileComponentRuntime', () => {
|
||||
beforeEach(() => {
|
||||
componentTemplateFactory = (directiveType: TypeMetadata) => {
|
||||
return new CompiledTemplate(directiveType.typeName, []);
|
||||
componentTemplateFactory = (directive: NormalizedDirectiveMetadata) => {
|
||||
return new CompiledTemplate(directive.type.id, () => []);
|
||||
};
|
||||
});
|
||||
|
||||
function run(component: DirectiveMetadata, directives: DirectiveMetadata[]):
|
||||
Promise<any[][]> {
|
||||
var parsedTemplate = parser.parse(
|
||||
domParser.parse(component.template.template, component.type.typeName), directives);
|
||||
function run(component: NormalizedDirectiveMetadata,
|
||||
directives: NormalizedDirectiveMetadata[]): Promise<any[][]> {
|
||||
var parsedTemplate =
|
||||
parser.parse(component.template.template, directives, component.type.name);
|
||||
var commands = commandCompiler.compileComponentRuntime(component, parsedTemplate,
|
||||
componentTemplateFactory);
|
||||
return PromiseWrapper.resolve(humanize(commands));
|
||||
@ -382,19 +384,18 @@ export function main() {
|
||||
|
||||
describe('compileComponentCodeGen', () => {
|
||||
beforeEach(() => {
|
||||
componentTemplateFactory = (directiveType: TypeMetadata, imports: string[][]) => {
|
||||
imports.push([TEMPLATE_COMMANDS_MODULE_NAME, 'tcm']);
|
||||
return `new tcm.CompiledTemplate(${escapeSingleQuoteString(directiveType.typeName)}, [])`;
|
||||
componentTemplateFactory = (directive: NormalizedDirectiveMetadata) => {
|
||||
return `new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${directive.type.id}, ${codeGenValueFn([], '{}')})`;
|
||||
};
|
||||
});
|
||||
|
||||
function run(component: DirectiveMetadata, directives: DirectiveMetadata[]):
|
||||
Promise<any[][]> {
|
||||
var parsedTemplate = parser.parse(
|
||||
domParser.parse(component.template.template, component.type.typeName), directives);
|
||||
function run(component: NormalizedDirectiveMetadata,
|
||||
directives: NormalizedDirectiveMetadata[]): Promise<any[][]> {
|
||||
var parsedTemplate =
|
||||
parser.parse(component.template.template, directives, component.type.name);
|
||||
var sourceModule = commandCompiler.compileComponentCodeGen(component, parsedTemplate,
|
||||
componentTemplateFactory);
|
||||
var testableModule = createTestableModule(sourceModule);
|
||||
var testableModule = createTestableModule(sourceModule).getSourceWithImports();
|
||||
return evalModule(testableModule.source, testableModule.imports, null);
|
||||
}
|
||||
|
||||
@ -453,6 +454,7 @@ class CommandHumanizer implements CommandVisitor {
|
||||
cmd.directives.map(checkAndStringifyType),
|
||||
cmd.nativeShadow,
|
||||
cmd.ngContentIndex,
|
||||
// TODO humanizeTemplate(cmd.template)
|
||||
cmd.template.id
|
||||
]);
|
||||
return null;
|
||||
@ -475,15 +477,9 @@ class CommandHumanizer implements CommandVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
function createTestableModule(sourceModule: SourceModule): SourceModule {
|
||||
var testableSource;
|
||||
var testableImports = [[MODULE_NAME, 'mocks']].concat(sourceModule.imports);
|
||||
if (IS_DART) {
|
||||
testableSource = `${sourceModule.source}
|
||||
run(_) { return mocks.humanize(COMMANDS); }`;
|
||||
} else {
|
||||
testableSource = `${sourceModule.source}
|
||||
exports.run = function(_) { return mocks.humanize(COMMANDS); }`;
|
||||
}
|
||||
return new SourceModule(null, testableSource, testableImports);
|
||||
function createTestableModule(source: SourceExpression): SourceModule {
|
||||
var resultExpression = `${THIS_MODULE_REF}humanize(${source.expression})`;
|
||||
var testableSource = `${source.declarations.join('\n')}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
||||
return new SourceModule(null, testableSource);
|
||||
}
|
||||
|
@ -13,28 +13,29 @@ import {
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
NormalizedDirectiveMetadata,
|
||||
TypeMetadata,
|
||||
TemplateMetadata,
|
||||
NormalizedTemplateMetadata,
|
||||
ChangeDetectionMetadata
|
||||
} from 'angular2/src/compiler/api';
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe('Compiler api', () => {
|
||||
describe('DirectiveMetadata', () => {
|
||||
var fullTypeMeta: TypeMetadata;
|
||||
var fullTemplateMeta: TemplateMetadata;
|
||||
var fullTemplateMeta: NormalizedTemplateMetadata;
|
||||
var fullChangeDetectionMeta: ChangeDetectionMetadata;
|
||||
var fullDirectiveMeta: DirectiveMetadata;
|
||||
var fullDirectiveMeta: NormalizedDirectiveMetadata;
|
||||
|
||||
beforeEach(() => {
|
||||
fullTypeMeta = new TypeMetadata({id: 23, typeName: 'SomeType', typeUrl: 'someUrl'});
|
||||
fullTemplateMeta = new TemplateMetadata({
|
||||
fullTypeMeta = new TypeMetadata({id: 23, name: 'SomeType', moduleId: 'someUrl'});
|
||||
fullTemplateMeta = new NormalizedTemplateMetadata({
|
||||
encapsulation: ViewEncapsulation.Emulated,
|
||||
template: '<a></a>',
|
||||
styles: ['someStyle'],
|
||||
styleAbsUrls: ['someStyleUrl'],
|
||||
hostAttributes: {'attr1': 'attrValue2'},
|
||||
ngContentSelectors: ['*']
|
||||
});
|
||||
fullChangeDetectionMeta = new ChangeDetectionMetadata({
|
||||
@ -51,10 +52,10 @@ export function main() {
|
||||
callDoCheck: true,
|
||||
callOnInit: true
|
||||
});
|
||||
fullDirectiveMeta = new DirectiveMetadata({
|
||||
fullDirectiveMeta = new NormalizedDirectiveMetadata({
|
||||
selector: 'someSelector',
|
||||
isComponent: true,
|
||||
hostAttributes: {'attr1': 'attrValue2'},
|
||||
dynamicLoadable: true,
|
||||
type: fullTypeMeta, template: fullTemplateMeta,
|
||||
changeDetection: fullChangeDetectionMeta,
|
||||
});
|
||||
@ -63,12 +64,13 @@ export function main() {
|
||||
|
||||
describe('DirectiveMetadata', () => {
|
||||
it('should serialize with full data', () => {
|
||||
expect(DirectiveMetadata.fromJson(fullDirectiveMeta.toJson())).toEqual(fullDirectiveMeta);
|
||||
expect(NormalizedDirectiveMetadata.fromJson(fullDirectiveMeta.toJson()))
|
||||
.toEqual(fullDirectiveMeta);
|
||||
});
|
||||
|
||||
it('should serialize with no data', () => {
|
||||
var empty = new DirectiveMetadata();
|
||||
expect(DirectiveMetadata.fromJson(empty.toJson())).toEqual(empty);
|
||||
var empty = new NormalizedDirectiveMetadata();
|
||||
expect(NormalizedDirectiveMetadata.fromJson(empty.toJson())).toEqual(empty);
|
||||
});
|
||||
});
|
||||
|
||||
@ -84,12 +86,13 @@ export function main() {
|
||||
|
||||
describe('TemplateMetadata', () => {
|
||||
it('should serialize with full data', () => {
|
||||
expect(TemplateMetadata.fromJson(fullTemplateMeta.toJson())).toEqual(fullTemplateMeta);
|
||||
expect(NormalizedTemplateMetadata.fromJson(fullTemplateMeta.toJson()))
|
||||
.toEqual(fullTemplateMeta);
|
||||
});
|
||||
|
||||
it('should serialize with no data', () => {
|
||||
var empty = new TemplateMetadata();
|
||||
expect(TemplateMetadata.fromJson(empty.toJson())).toEqual(empty);
|
||||
var empty = new NormalizedTemplateMetadata();
|
||||
expect(NormalizedTemplateMetadata.fromJson(empty.toJson())).toEqual(empty);
|
||||
});
|
||||
});
|
||||
|
@ -7,31 +7,27 @@ Uri toDartDataUri(String source) {
|
||||
}
|
||||
|
||||
createIsolateSource(String moduleSource, List<List<String>> moduleImports) {
|
||||
var moduleSourceParts = [];
|
||||
var moduleSourceParts = ['import "dart:isolate";'];
|
||||
moduleImports.forEach((sourceImport) {
|
||||
String modName = sourceImport[0];
|
||||
String modAlias = sourceImport[1];
|
||||
moduleSourceParts.add("import 'package:${modName}.dart' as ${modAlias};");
|
||||
});
|
||||
moduleSourceParts.add(moduleSource);
|
||||
|
||||
return """
|
||||
import "dart:isolate";
|
||||
import "${toDartDataUri(moduleSourceParts.join('\n'))}" as mut;
|
||||
|
||||
moduleSourceParts.add(moduleSource);
|
||||
moduleSourceParts.add("""
|
||||
main(List args, SendPort replyPort) {
|
||||
replyPort.send(mut.run(args));
|
||||
replyPort.send(run(args));
|
||||
}
|
||||
""");
|
||||
return moduleSourceParts.join('\n');
|
||||
}
|
||||
""";
|
||||
|
||||
}
|
||||
|
||||
var timeStamp = new DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
dynamic callModule(dynamic data) { return data.map( (a) => a+1); }
|
||||
|
||||
evalModule(String moduleSource, List<List<String>> moduleImports, List args) {
|
||||
String source = createIsolateSource(moduleSource, moduleImports);
|
||||
evalModule(String moduleSource, List<List<String>> imports, List args) {
|
||||
String source = createIsolateSource(moduleSource, imports);
|
||||
Completer completer = new Completer();
|
||||
RawReceivePort receivePort;
|
||||
receivePort = new RawReceivePort( (message) {
|
||||
@ -43,12 +39,12 @@ evalModule(String moduleSource, List<List<String>> moduleImports, List args) {
|
||||
// With this, spawning multiple isolates gets faster as Darts does not
|
||||
// reload the files from the server.
|
||||
var packageRoot = Uri.parse('/packages_${timeStamp}');
|
||||
return Isolate.spawnUri(toDartDataUri(source), args, receivePort.sendPort, packageRoot: packageRoot).then( (isolate) {
|
||||
return Isolate.spawnUri(toDartDataUri(source), args, receivePort.sendPort, packageRoot: packageRoot).then( (isolate) {
|
||||
RawReceivePort errorPort;
|
||||
errorPort = new RawReceivePort( (message) {
|
||||
completer.completeError(message);
|
||||
});
|
||||
isolate.addErrorListener(errorPort.sendPort);
|
||||
return completer.future;
|
||||
return completer.future;
|
||||
});
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||
import {isPresent, global} from 'angular2/src/core/facade/lang';
|
||||
import {isPresent, global, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||
|
||||
var evalCounter = 0;
|
||||
|
||||
function nextModuleName() {
|
||||
function nextModuleId() {
|
||||
return `evalScript${evalCounter++}`;
|
||||
}
|
||||
|
||||
export function evalModule(moduleSource: string, moduleImports: string[][], args: any[]):
|
||||
Promise<any> {
|
||||
var moduleName = nextModuleName();
|
||||
export function evalModule(moduleSource: string, imports: string[][], args: any[]): Promise<any> {
|
||||
var moduleId = nextModuleId();
|
||||
var moduleSourceWithImports = [];
|
||||
var importModuleNames = [];
|
||||
moduleImports.forEach(sourceImport => {
|
||||
imports.forEach(sourceImport => {
|
||||
var modName = sourceImport[0];
|
||||
var modAlias = sourceImport[1];
|
||||
importModuleNames.push(modName);
|
||||
@ -28,8 +27,8 @@ export function evalModule(moduleSource: string, moduleImports: string[][], args
|
||||
var moduleBody = new Function('require', 'exports', 'module', moduleSourceWithImports.join('\n'));
|
||||
var System = global['System'];
|
||||
if (isPresent(System) && isPresent(System.registerDynamic)) {
|
||||
System.registerDynamic(moduleName, importModuleNames, false, moduleBody);
|
||||
return <Promise<any>>System.import(moduleName).then((module) => module.run(args));
|
||||
System.registerDynamic(moduleId, importModuleNames, false, moduleBody);
|
||||
return <Promise<any>>System.import(moduleId).then((module) => module.run(args));
|
||||
} else {
|
||||
var exports = {};
|
||||
moduleBody(require, exports, {});
|
||||
|
@ -19,14 +19,14 @@ import {evalModule} from './eval_module';
|
||||
// when evaling the test module!
|
||||
export var TEST_VALUE = 23;
|
||||
|
||||
const THIS_MODULE = 'angular2/test/compiler/eval_module_spec';
|
||||
|
||||
export function main() {
|
||||
describe('evalModule', () => {
|
||||
it('should call the "run" function and allow to use imports',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var moduleSource = IS_DART ? testDartModule : testJsModule;
|
||||
var imports = [['angular2/test/compiler/eval_module_spec', 'testMod']];
|
||||
|
||||
evalModule(moduleSource, imports, [1])
|
||||
evalModule(moduleSource, [[THIS_MODULE, 'tst']], [1])
|
||||
.then((value) => {
|
||||
expect(value).toEqual([1, 23]);
|
||||
async.done();
|
||||
@ -36,15 +36,15 @@ export function main() {
|
||||
}
|
||||
|
||||
var testDartModule = `
|
||||
run(data) {
|
||||
data.add(testMod.TEST_VALUE);
|
||||
run(data) {
|
||||
data.add(tst.TEST_VALUE);
|
||||
return data;
|
||||
}
|
||||
`;
|
||||
|
||||
var testJsModule = `
|
||||
exports.run = function(data) {
|
||||
data.push(testMod.TEST_VALUE);
|
||||
data.push(tst.TEST_VALUE);
|
||||
return data;
|
||||
}
|
||||
`;
|
131
modules/angular2/test/compiler/runtime_metadata_spec.ts
Normal file
131
modules/angular2/test/compiler/runtime_metadata_spec.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
xdescribe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {stringify} from 'angular2/src/core/facade/lang';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {
|
||||
Component,
|
||||
View,
|
||||
Directive,
|
||||
ViewEncapsulation,
|
||||
ChangeDetectionStrategy,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
DoCheck,
|
||||
OnDestroy,
|
||||
AfterContentInit,
|
||||
AfterContentChecked,
|
||||
AfterViewInit,
|
||||
AfterViewChecked
|
||||
} from 'angular2/core';
|
||||
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
import {IS_DART} from '../platform';
|
||||
|
||||
export function main() {
|
||||
describe('RuntimeMetadataResolver', () => {
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
|
||||
describe('getMetadata', () => {
|
||||
it('should read metadata',
|
||||
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => {
|
||||
var meta = resolver.getMetadata(ComponentWithEverything);
|
||||
expect(meta.selector).toEqual('someSelector');
|
||||
expect(meta.isComponent).toBe(true);
|
||||
expect(meta.dynamicLoadable).toBe(true);
|
||||
expect(meta.type.runtime).toBe(ComponentWithEverything);
|
||||
expect(meta.type.name).toEqual(stringify(ComponentWithEverything));
|
||||
expect(meta.type.moduleId).toEqual('someModuleId');
|
||||
expect(meta.changeDetection.callAfterContentChecked).toBe(true);
|
||||
expect(meta.changeDetection.callAfterContentInit).toBe(true);
|
||||
expect(meta.changeDetection.callAfterViewChecked).toBe(true);
|
||||
expect(meta.changeDetection.callAfterViewInit).toBe(true);
|
||||
expect(meta.changeDetection.callDoCheck).toBe(true);
|
||||
expect(meta.changeDetection.callOnChanges).toBe(true);
|
||||
expect(meta.changeDetection.callOnInit).toBe(true);
|
||||
expect(meta.changeDetection.changeDetection).toBe(ChangeDetectionStrategy.CheckAlways);
|
||||
expect(meta.changeDetection.properties).toEqual(['someProp']);
|
||||
expect(meta.changeDetection.events).toEqual(['someEvent']);
|
||||
expect(meta.changeDetection.hostListeners)
|
||||
.toEqual({'someHostListener': 'someHostListenerExpr'});
|
||||
expect(meta.changeDetection.hostProperties)
|
||||
.toEqual({'someHostProp': 'someHostPropExpr'});
|
||||
expect(meta.template.encapsulation).toBe(ViewEncapsulation.Emulated);
|
||||
expect(meta.template.hostAttributes).toEqual({'someHostAttr': 'someHostAttrValue'});
|
||||
expect(meta.template.styles).toEqual(['someStyle']);
|
||||
expect(meta.template.styleUrls).toEqual(['someStyleUrl']);
|
||||
expect(meta.template.template).toEqual('someTemplate');
|
||||
expect(meta.template.templateUrl).toEqual('someTemplateUrl');
|
||||
}));
|
||||
|
||||
it('should use the moduleId from the reflector if none is given',
|
||||
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => {
|
||||
var expectedValue = IS_DART ? 'angular2/test/compiler/runtime_metadata_spec' : null;
|
||||
expect(resolver.getMetadata(DirectiveWithoutModuleId).type.moduleId)
|
||||
.toEqual(expectedValue);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('getViewDirectivesMetadata', () => {
|
||||
|
||||
it('should return the directive metadatas',
|
||||
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => {
|
||||
expect(resolver.getViewDirectivesMetadata(ComponentWithEverything))
|
||||
.toEqual([resolver.getMetadata(DirectiveWithoutModuleId)]);
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Directive({selector: 'someSelector'})
|
||||
class DirectiveWithoutModuleId {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'someSelector',
|
||||
properties: ['someProp'],
|
||||
events: ['someEvent'],
|
||||
host: {
|
||||
'[someHostProp]': 'someHostPropExpr',
|
||||
'(someHostListener)': 'someHostListenerExpr',
|
||||
'someHostAttr': 'someHostAttrValue'
|
||||
},
|
||||
dynamicLoadable: true,
|
||||
moduleId: 'someModuleId',
|
||||
changeDetection: ChangeDetectionStrategy.CheckAlways
|
||||
})
|
||||
@View({
|
||||
template: 'someTemplate',
|
||||
templateUrl: 'someTemplateUrl',
|
||||
encapsulation: ViewEncapsulation.Emulated,
|
||||
styles: ['someStyle'],
|
||||
styleUrls: ['someStyleUrl'],
|
||||
directives: [DirectiveWithoutModuleId]
|
||||
})
|
||||
class ComponentWithEverything implements OnChanges,
|
||||
OnInit, DoCheck, OnDestroy, AfterContentInit, AfterContentChecked, AfterViewInit,
|
||||
AfterViewChecked {
|
||||
onChanges(changes: StringMap<string, any>): void {}
|
||||
onInit(): void {}
|
||||
doCheck(): void {}
|
||||
onDestroy(): void {}
|
||||
afterContentInit(): void {}
|
||||
afterContentChecked(): void {}
|
||||
afterViewInit(): void {}
|
||||
afterViewChecked(): void {}
|
||||
}
|
17
modules/angular2/test/compiler/schema_registry_mock.ts
Normal file
17
modules/angular2/test/compiler/schema_registry_mock.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||
import {StringMap} from 'angular2/src/core/facade/collection';
|
||||
import {isPresent} from 'angular2/src/core/facade/lang';
|
||||
|
||||
export class MockSchemaRegistry implements ElementSchemaRegistry {
|
||||
constructor(public existingProperties: StringMap<string, boolean>,
|
||||
public attrPropMapping: StringMap<string, string>) {}
|
||||
hasProperty(tagName: string, property: string): boolean {
|
||||
var result = this.existingProperties[property];
|
||||
return isPresent(result) ? result : true;
|
||||
}
|
||||
|
||||
getMappedPropName(attrName: string): string {
|
||||
var result = this.attrPropMapping[attrName];
|
||||
return isPresent(result) ? result : attrName;
|
||||
}
|
||||
}
|
43
modules/angular2/test/compiler/source_module_spec.ts
Normal file
43
modules/angular2/test/compiler/source_module_spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
TestComponentBuilder
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {SourceModule, moduleRef} from 'angular2/src/compiler/source_module';
|
||||
|
||||
export function main() {
|
||||
describe('SourceModule', () => {
|
||||
describe('getSourceWithImports', () => {
|
||||
it('should generate named imports for modules', () => {
|
||||
var sourceWithImports =
|
||||
new SourceModule('some/moda', `${moduleRef('some/modb')}A`).getSourceWithImports();
|
||||
expect(sourceWithImports.source).toEqual('import0.A');
|
||||
expect(sourceWithImports.imports).toEqual([['some/modb', 'import0']]);
|
||||
});
|
||||
|
||||
it('should dedupe imports', () => {
|
||||
var sourceWithImports =
|
||||
new SourceModule('some/moda', `${moduleRef('some/modb')}A + ${moduleRef('some/modb')}B`)
|
||||
.getSourceWithImports();
|
||||
expect(sourceWithImports.source).toEqual('import0.A + import0.B');
|
||||
expect(sourceWithImports.imports).toEqual([['some/modb', 'import0']]);
|
||||
});
|
||||
|
||||
it('should not use an import for the moduleId of the SourceModule', () => {
|
||||
var sourceWithImports =
|
||||
new SourceModule('some/moda', `${moduleRef('some/moda')}A`).getSourceWithImports();
|
||||
expect(sourceWithImports.source).toEqual('A');
|
||||
expect(sourceWithImports.imports).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -9,19 +9,27 @@ import {
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
import {IS_DART} from '../platform';
|
||||
import {bind} from 'angular2/src/core/di';
|
||||
import {SpyXHR} from '../core/spies';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
||||
|
||||
import {CONST_EXPR, isPresent, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
import {evalModule} from './eval_module';
|
||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
import {DirectiveMetadata, TemplateMetadata, TypeMetadata} from 'angular2/src/compiler/api';
|
||||
import {
|
||||
NormalizedDirectiveMetadata,
|
||||
NormalizedTemplateMetadata,
|
||||
TypeMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {SourceExpression, SourceModule} from 'angular2/src/compiler/source_module';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
||||
|
||||
// Attention: These module names have to correspond to real modules!
|
||||
const MODULE_NAME = 'angular2/test/compiler/style_compiler_spec';
|
||||
@ -33,19 +41,21 @@ const IMPORT_ABS_MODULE_NAME_WITH_IMPORT =
|
||||
|
||||
export function main() {
|
||||
describe('StyleCompiler', () => {
|
||||
var compiler: StyleCompiler;
|
||||
var xhr;
|
||||
|
||||
beforeEach(() => {
|
||||
var xhr: SpyXHR;
|
||||
beforeEachBindings(() => {
|
||||
xhr = <any>new SpyXHR();
|
||||
compiler = new StyleCompiler(xhr, new UrlResolver());
|
||||
return [TEST_BINDINGS, bind(XHR).toValue(xhr)];
|
||||
});
|
||||
|
||||
var compiler: StyleCompiler;
|
||||
|
||||
beforeEach(inject([StyleCompiler], (_compiler) => { compiler = _compiler; }));
|
||||
|
||||
function comp(styles: string[], styleAbsUrls: string[], encapsulation: ViewEncapsulation):
|
||||
DirectiveMetadata {
|
||||
return new DirectiveMetadata({
|
||||
type: new TypeMetadata({id: 23, typeUrl: 'someUrl'}),
|
||||
template: new TemplateMetadata(
|
||||
NormalizedDirectiveMetadata {
|
||||
return new NormalizedDirectiveMetadata({
|
||||
type: new TypeMetadata({id: 23, moduleId: 'someUrl'}),
|
||||
template: new NormalizedTemplateMetadata(
|
||||
{styles: styles, styleAbsUrls: styleAbsUrls, encapsulation: encapsulation})
|
||||
});
|
||||
}
|
||||
@ -117,9 +127,10 @@ export function main() {
|
||||
function runTest(styles: string[], styleAbsUrls: string[], encapsulation: ViewEncapsulation,
|
||||
expectedStyles: string[]) {
|
||||
return inject([AsyncTestCompleter], (async) => {
|
||||
var sourceModule =
|
||||
var sourceExpression =
|
||||
compiler.compileComponentCodeGen(comp(styles, styleAbsUrls, encapsulation));
|
||||
evalModule(testableModule(sourceModule.source), sourceModule.imports, null)
|
||||
var sourceWithImports = testableExpression(sourceExpression).getSourceWithImports();
|
||||
evalModule(sourceWithImports.source, sourceWithImports.imports, null)
|
||||
.then((value) => {
|
||||
compareStyles(value, expectedStyles);
|
||||
async.done();
|
||||
@ -163,9 +174,12 @@ export function main() {
|
||||
function runTest(style: string, expectedStyles: string[], expectedShimStyles: string[]) {
|
||||
return inject([AsyncTestCompleter], (async) => {
|
||||
var sourceModules = compiler.compileStylesheetCodeGen(MODULE_NAME, style);
|
||||
PromiseWrapper.all(sourceModules.map(sourceModule =>
|
||||
evalModule(testableModule(sourceModule.source),
|
||||
sourceModule.imports, null)))
|
||||
PromiseWrapper.all(sourceModules.map(sourceModule => {
|
||||
var sourceWithImports =
|
||||
testableModule(sourceModule).getSourceWithImports();
|
||||
return evalModule(sourceWithImports.source, sourceWithImports.imports,
|
||||
null);
|
||||
}))
|
||||
.then((values) => {
|
||||
compareStyles(values[0], expectedStyles);
|
||||
compareStyles(values[1], expectedShimStyles);
|
||||
@ -188,16 +202,17 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
function testableModule(sourceModule: string) {
|
||||
if (IS_DART) {
|
||||
return `${sourceModule}
|
||||
run(_) { return STYLES; }
|
||||
`;
|
||||
} else {
|
||||
return `${sourceModule}
|
||||
exports.run = function(_) { return STYLES; };
|
||||
`;
|
||||
}
|
||||
|
||||
function testableExpression(source: SourceExpression): SourceModule {
|
||||
var testableSource = `${source.declarations.join('\n')}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], source.expression)};`;
|
||||
return new SourceModule(null, testableSource);
|
||||
}
|
||||
|
||||
function testableModule(sourceModule: SourceModule): SourceModule {
|
||||
var testableSource = `${sourceModule.source}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
||||
}
|
||||
|
||||
// Needed for Android browsers which add an extra space at the end of some lines
|
||||
|
334
modules/angular2/test/compiler/template_compiler_spec.ts
Normal file
334
modules/angular2/test/compiler/template_compiler_spec.ts
Normal file
@ -0,0 +1,334 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
xdescribe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||
import {Type, isPresent, isBlank, stringify, isString} from 'angular2/src/core/facade/lang';
|
||||
import {MapWrapper, SetWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {
|
||||
TemplateCompiler,
|
||||
NormalizedComponentWithViewDirectives
|
||||
} from 'angular2/src/compiler/template_compiler';
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
NormalizedDirectiveMetadata,
|
||||
INormalizedDirectiveMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {evalModule} from './eval_module';
|
||||
import {SourceModule, moduleRef} from 'angular2/src/compiler/source_module';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {MockXHR} from 'angular2/src/core/render/xhr_mock';
|
||||
|
||||
import {Locals} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {
|
||||
CommandVisitor,
|
||||
TextCmd,
|
||||
NgContentCmd,
|
||||
BeginElementCmd,
|
||||
BeginComponentCmd,
|
||||
EmbeddedTemplateCmd,
|
||||
TemplateCmd,
|
||||
visitAllCommands,
|
||||
CompiledTemplate
|
||||
} from 'angular2/src/core/compiler/template_commands';
|
||||
|
||||
import {Component, View, Directive} from 'angular2/core';
|
||||
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
import {TestContext, TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
||||
|
||||
// Attention: This path has to point to this test file!
|
||||
const THIS_MODULE = 'angular2/test/compiler/template_compiler_spec';
|
||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE);
|
||||
|
||||
export function main() {
|
||||
describe('TemplateCompiler', () => {
|
||||
var compiler: TemplateCompiler;
|
||||
var runtimeMetadataResolver: RuntimeMetadataResolver;
|
||||
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver],
|
||||
(_compiler, _runtimeMetadataResolver) => {
|
||||
compiler = _compiler;
|
||||
runtimeMetadataResolver = _runtimeMetadataResolver;
|
||||
}));
|
||||
|
||||
describe('compile templates', () => {
|
||||
|
||||
function runTests(compile) {
|
||||
it('should compile host components', inject([AsyncTestCompleter], (async) => {
|
||||
compile([CompWithBindingsAndStyles])
|
||||
.then((humanizedTemplate) => {
|
||||
expect(humanizedTemplate['styles']).toEqual([]);
|
||||
expect(humanizedTemplate['commands'][0]).toEqual('<comp-a>');
|
||||
expect(humanizedTemplate['cd']).toEqual(['elementProperty(title)=someDirValue']);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should compile nested components', inject([AsyncTestCompleter], (async) => {
|
||||
compile([CompWithBindingsAndStyles])
|
||||
.then((humanizedTemplate) => {
|
||||
var nestedTemplate = humanizedTemplate['commands'][1];
|
||||
expect(nestedTemplate['styles']).toEqual(['div {color: red}']);
|
||||
expect(nestedTemplate['commands'][0]).toEqual('<a>');
|
||||
expect(nestedTemplate['cd']).toEqual(['elementProperty(href)=someCtxValue']);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should compile recursive components', inject([AsyncTestCompleter], (async) => {
|
||||
compile([TreeComp])
|
||||
.then((humanizedTemplate) => {
|
||||
expect(humanizedTemplate['commands'][0]).toEqual('<tree>');
|
||||
expect(humanizedTemplate['commands'][1]['commands'][0]).toEqual('<tree>');
|
||||
expect(humanizedTemplate['commands'][1]['commands'][1]['commands'][0])
|
||||
.toEqual('<tree>');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
describe('compileHostComponentRuntime', () => {
|
||||
function compile(components: Type[]): Promise<any[]> {
|
||||
return compiler.compileHostComponentRuntime(components[0]).then(humanizeTemplate);
|
||||
}
|
||||
|
||||
runTests(compile);
|
||||
|
||||
it('should cache components', inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||
// we expect only one request!
|
||||
xhr.expect('angular2/test/compiler/compUrl.html', '');
|
||||
PromiseWrapper.all([
|
||||
compiler.compileHostComponentRuntime(CompWithTemplateUrl),
|
||||
compiler.compileHostComponentRuntime(CompWithTemplateUrl)
|
||||
])
|
||||
.then((humanizedTemplates) => {
|
||||
expect(humanizedTemplates[0]).toEqual(humanizedTemplates[1]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should only allow dynamic loadable components', () => {
|
||||
expect(() => compiler.compileHostComponentRuntime(PlainDirective))
|
||||
.toThrowError(
|
||||
`Could not compile '${stringify(PlainDirective)}' because it is not dynamically loadable.`);
|
||||
expect(() => compiler.compileHostComponentRuntime(CompWithoutHost))
|
||||
.toThrowError(
|
||||
`Could not compile '${stringify(CompWithoutHost)}' because it is not dynamically loadable.`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('compileTemplatesCodeGen', () => {
|
||||
function normalizeComponent(component: Type):
|
||||
Promise<NormalizedComponentWithViewDirectives> {
|
||||
var compAndViewDirMetas = [runtimeMetadataResolver.getMetadata(component)].concat(
|
||||
runtimeMetadataResolver.getViewDirectivesMetadata(component));
|
||||
return PromiseWrapper.all(compAndViewDirMetas.map(meta =>
|
||||
compiler.normalizeDirective(meta)))
|
||||
.then((normalizedCompAndViewDirMetas: NormalizedDirectiveMetadata[]) =>
|
||||
new NormalizedComponentWithViewDirectives(
|
||||
normalizedCompAndViewDirMetas[0],
|
||||
normalizedCompAndViewDirMetas.slice(1)));
|
||||
}
|
||||
|
||||
function compile(components: Type[]): Promise<any[]> {
|
||||
return PromiseWrapper.all(components.map(normalizeComponent))
|
||||
.then((normalizedCompWithViewDirMetas: NormalizedComponentWithViewDirectives[]) => {
|
||||
var sourceModule =
|
||||
compiler.compileTemplatesCodeGen(THIS_MODULE, normalizedCompWithViewDirMetas);
|
||||
var sourceWithImports =
|
||||
testableTemplateModule(sourceModule,
|
||||
normalizedCompWithViewDirMetas[0].component)
|
||||
.getSourceWithImports();
|
||||
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
|
||||
});
|
||||
}
|
||||
|
||||
runTests(compile);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('serializeTemplateMetadata and deserializeTemplateMetadata', () => {
|
||||
it('should serialize and deserialize', inject([AsyncTestCompleter], (async) => {
|
||||
compiler.normalizeDirective(
|
||||
runtimeMetadataResolver.getMetadata(CompWithBindingsAndStyles))
|
||||
.then((meta: NormalizedDirectiveMetadata) => {
|
||||
var json = compiler.serializeTemplateMetadata(meta);
|
||||
expect(isString(json)).toBe(true);
|
||||
// Note: serializing will clear our the runtime type!
|
||||
var clonedMeta =
|
||||
<NormalizedDirectiveMetadata>compiler.deserializeTemplateMetadata(json);
|
||||
expect(meta.changeDetection).toEqual(clonedMeta.changeDetection);
|
||||
expect(meta.template).toEqual(clonedMeta.template);
|
||||
expect(meta.selector).toEqual(clonedMeta.selector);
|
||||
expect(meta.type.name).toEqual(clonedMeta.type.name);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('normalizeDirective', () => {
|
||||
it('should normalize the template',
|
||||
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||
xhr.expect('angular2/test/compiler/compUrl.html', 'loadedTemplate');
|
||||
compiler.normalizeDirective(runtimeMetadataResolver.getMetadata(CompWithTemplateUrl))
|
||||
.then((meta: NormalizedDirectiveMetadata) => {
|
||||
expect(meta.template.template).toEqual('loadedTemplate');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should copy all the other fields', inject([AsyncTestCompleter], (async) => {
|
||||
var meta = runtimeMetadataResolver.getMetadata(CompWithBindingsAndStyles);
|
||||
compiler.normalizeDirective(meta).then((normMeta: NormalizedDirectiveMetadata) => {
|
||||
expect(normMeta.selector).toEqual(meta.selector);
|
||||
expect(normMeta.dynamicLoadable).toEqual(meta.dynamicLoadable);
|
||||
expect(normMeta.isComponent).toEqual(meta.isComponent);
|
||||
expect(normMeta.type).toEqual(meta.type);
|
||||
expect(normMeta.changeDetection).toEqual(meta.changeDetection);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('compileStylesheetCodeGen', () => {
|
||||
it('should compile stylesheets into code', inject([AsyncTestCompleter], (async) => {
|
||||
var cssText = 'div {color: red}';
|
||||
var sourceModule = compiler.compileStylesheetCodeGen('someModuleId', cssText)[0];
|
||||
var sourceWithImports = testableStylesModule(sourceModule).getSourceWithImports();
|
||||
evalModule(sourceWithImports.source, sourceWithImports.imports, null)
|
||||
.then(loadedCssText => {
|
||||
expect(loadedCssText).toEqual([cssText]);
|
||||
async.done();
|
||||
});
|
||||
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp-a',
|
||||
dynamicLoadable: true,
|
||||
host: {'[title]': 'someProp'},
|
||||
moduleId: THIS_MODULE
|
||||
})
|
||||
@View({template: '<a [href]="someProp"></a>', styles: ['div {color: red}']})
|
||||
class CompWithBindingsAndStyles {
|
||||
}
|
||||
|
||||
@Component({selector: 'tree', dynamicLoadable: true, moduleId: THIS_MODULE})
|
||||
@View({template: '<tree></tree>', directives: [TreeComp]})
|
||||
class TreeComp {
|
||||
}
|
||||
|
||||
@Component({selector: 'comp-url', dynamicLoadable: true, moduleId: THIS_MODULE})
|
||||
@View({templateUrl: 'compUrl.html'})
|
||||
class CompWithTemplateUrl {
|
||||
}
|
||||
|
||||
@Directive({selector: 'plain', moduleId: THIS_MODULE})
|
||||
class PlainDirective {
|
||||
}
|
||||
|
||||
@Component({selector: 'comp', moduleId: THIS_MODULE})
|
||||
@View({template: ''})
|
||||
class CompWithoutHost {
|
||||
}
|
||||
|
||||
function testableTemplateModule(sourceModule: SourceModule, comp: INormalizedDirectiveMetadata):
|
||||
SourceModule {
|
||||
var normComp = <NormalizedDirectiveMetadata>comp;
|
||||
var resultExpression = `${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template)`;
|
||||
var testableSource = `${sourceModule.source}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
||||
}
|
||||
|
||||
function testableStylesModule(sourceModule: SourceModule): SourceModule {
|
||||
var testableSource = `${sourceModule.source}
|
||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
||||
}
|
||||
|
||||
// Attention: read by eval!
|
||||
export function humanizeTemplate(template: CompiledTemplate,
|
||||
humanizedTemplates: Map<number, StringMap<string, any>> = null):
|
||||
StringMap<string, any> {
|
||||
if (isBlank(humanizedTemplates)) {
|
||||
humanizedTemplates = new Map();
|
||||
}
|
||||
var result = humanizedTemplates.get(template.id);
|
||||
if (isPresent(result)) {
|
||||
return result;
|
||||
}
|
||||
var commands = [];
|
||||
result = {
|
||||
'styles': template.styles,
|
||||
'commands': commands,
|
||||
'cd': testChangeDetector(template.changeDetectorFactories[0])
|
||||
};
|
||||
humanizedTemplates.set(template.id, result);
|
||||
visitAllCommands(new CommandHumanizer(commands, humanizedTemplates), template.commands);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function testChangeDetector(changeDetectorFactory: Function): string[] {
|
||||
var ctx = new TestContext();
|
||||
ctx.someProp = 'someCtxValue';
|
||||
var dir1 = new TestContext();
|
||||
dir1.someProp = 'someDirValue';
|
||||
|
||||
var dispatcher = new TestDispatcher([dir1], []);
|
||||
var cd = changeDetectorFactory(dispatcher);
|
||||
var locals = new Locals(null, MapWrapper.createFromStringMap({'someVar': null}));
|
||||
cd.hydrate(ctx, locals, dispatcher, new TestPipes());
|
||||
cd.detectChanges();
|
||||
return dispatcher.log;
|
||||
}
|
||||
|
||||
|
||||
class CommandHumanizer implements CommandVisitor {
|
||||
constructor(private result: any[],
|
||||
private humanizedTemplates: Map<number, StringMap<string, any>>) {}
|
||||
visitText(cmd: TextCmd, context: any): any { return null; }
|
||||
visitNgContent(cmd: NgContentCmd, context: any): any { return null; }
|
||||
visitBeginElement(cmd: BeginElementCmd, context: any): any {
|
||||
this.result.push(`<${cmd.name}>`);
|
||||
return null;
|
||||
}
|
||||
visitEndElement(context: any): any {
|
||||
this.result.push('</>');
|
||||
return null;
|
||||
}
|
||||
visitBeginComponent(cmd: BeginComponentCmd, context: any): any {
|
||||
this.result.push(`<${cmd.name}>`);
|
||||
this.result.push(humanizeTemplate(cmd.template, this.humanizedTemplates));
|
||||
return null;
|
||||
}
|
||||
visitEndComponent(context: any): any { return this.visitEndElement(context); }
|
||||
visitEmbeddedTemplate(cmd: EmbeddedTemplateCmd, context: any): any { return null; }
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
TestComponentBuilder
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {TypeMetadata, TemplateMetadata} from 'angular2/src/compiler/api';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
|
||||
import {TemplateLoader} from 'angular2/src/compiler/template_loader';
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {MockXHR} from 'angular2/src/core/render/xhr_mock';
|
||||
|
||||
export function main() {
|
||||
describe('TemplateLoader', () => {
|
||||
var loader: TemplateLoader;
|
||||
var dirType: TypeMetadata;
|
||||
var xhr: MockXHR;
|
||||
var htmlParser: HtmlParser;
|
||||
|
||||
beforeEach(inject([XHR], (mockXhr) => {
|
||||
xhr = mockXhr;
|
||||
htmlParser = new HtmlParser();
|
||||
loader = new TemplateLoader(xhr, new UrlResolver(), htmlParser);
|
||||
dirType = new TypeMetadata({typeUrl: 'http://sometypeurl', typeName: 'SomeComp'});
|
||||
}));
|
||||
|
||||
describe('loadTemplate', () => {
|
||||
describe('inline template', () => {
|
||||
it('should store the template', inject([AsyncTestCompleter], (async) => {
|
||||
loader.loadTemplate(dirType, null, 'a', null, [], ['test.css'])
|
||||
.then((template: TemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve styles against the typeUrl', inject([AsyncTestCompleter], (async) => {
|
||||
loader.loadTemplate(dirType, null, 'a', null, [], ['test.css'])
|
||||
.then((template: TemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['http://sometypeurl/test.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('templateUrl', () => {
|
||||
|
||||
it('should load a template from a url that is resolved against typeUrl',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://sometypeurl/sometplurl', 'a');
|
||||
loader.loadTemplate(dirType, null, null, 'sometplurl', [], ['test.css'])
|
||||
.then((template: TemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles against the templateUrl',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://sometypeurl/tpl/sometplurl', 'a');
|
||||
loader.loadTemplate(dirType, null, null, 'tpl/sometplurl', [], ['test.css'])
|
||||
.then((template: TemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['http://sometypeurl/tpl/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('loadTemplateFromString', () => {
|
||||
it('should store the viewEncapsulationin the result', () => {
|
||||
var viewEncapsulation = ViewEncapsulation.Native;
|
||||
var template = loader.createTemplateFromString(dirType, viewEncapsulation, '',
|
||||
'http://someurl/', [], []);
|
||||
expect(template.encapsulation).toBe(viewEncapsulation);
|
||||
});
|
||||
|
||||
it('should keep the template as html', () => {
|
||||
var template =
|
||||
loader.createTemplateFromString(dirType, null, 'a', 'http://someurl/', [], []);
|
||||
expect(template.template).toEqual('a')
|
||||
});
|
||||
|
||||
it('should collect and keep ngContent', () => {
|
||||
var template = loader.createTemplateFromString(
|
||||
dirType, null, '<ng-content select="a"></ng-content>', 'http://someurl/', [], []);
|
||||
expect(template.ngContentSelectors).toEqual(['a']);
|
||||
expect(template.template).toEqual('<ng-content select="a"></ng-content>');
|
||||
});
|
||||
|
||||
it('should normalize ngContent wildcard selector', () => {
|
||||
var template = loader.createTemplateFromString(
|
||||
dirType, null,
|
||||
'<ng-content></ng-content><ng-content select></ng-content><ng-content select="*"></ng-content>',
|
||||
'http://someurl/', [], []);
|
||||
expect(template.ngContentSelectors).toEqual(['*', '*', '*']);
|
||||
});
|
||||
|
||||
it('should collect and remove top level styles in the template', () => {
|
||||
var template = loader.createTemplateFromString(dirType, null, '<style>a</style>',
|
||||
'http://someurl/', [], []);
|
||||
expect(template.styles).toEqual(['a']);
|
||||
expect(template.template).toEqual('');
|
||||
});
|
||||
|
||||
it('should collect and remove styles inside in elements', () => {
|
||||
var template = loader.createTemplateFromString(dirType, null, '<div><style>a</style></div>',
|
||||
'http://someurl/', [], []);
|
||||
expect(template.styles).toEqual(['a']);
|
||||
expect(template.template).toEqual('<div></div>');
|
||||
});
|
||||
|
||||
it('should collect and remove styleUrls in the template', () => {
|
||||
var template = loader.createTemplateFromString(
|
||||
dirType, null, '<link rel="stylesheet" href="aUrl">', 'http://someurl/', [], []);
|
||||
expect(template.styleAbsUrls).toEqual(['http://someurl/aUrl']);
|
||||
expect(template.template).toEqual('');
|
||||
});
|
||||
|
||||
it('should collect and remove styleUrls in elements', () => {
|
||||
var template = loader.createTemplateFromString(
|
||||
dirType, null, '<div><link rel="stylesheet" href="aUrl"></div>', 'http://someurl/', [],
|
||||
[]);
|
||||
expect(template.styleAbsUrls).toEqual(['http://someurl/aUrl']);
|
||||
expect(template.template).toEqual('<div></div>');
|
||||
});
|
||||
|
||||
it('should keep link elements with non stylesheet rel attribute', () => {
|
||||
var template = loader.createTemplateFromString(
|
||||
dirType, null, '<link href="b" rel="a"></link>', 'http://someurl/', [], []);
|
||||
expect(template.styleAbsUrls).toEqual([]);
|
||||
expect(template.template).toEqual('<link href="b" rel="a"></link>');
|
||||
});
|
||||
|
||||
it('should extract @import style urls into styleAbsUrl', () => {
|
||||
var template = loader.createTemplateFromString(dirType, null, '', 'http://someurl',
|
||||
['@import "test.css";'], []);
|
||||
expect(template.styles).toEqual(['']);
|
||||
expect(template.styleAbsUrls).toEqual(['http://someurl/test.css']);
|
||||
});
|
||||
|
||||
it('should resolve relative urls in inline styles', () => {
|
||||
var template =
|
||||
loader.createTemplateFromString(dirType, null, '', 'http://someurl',
|
||||
['.foo{background-image: url(\'double.jpg\');'], []);
|
||||
expect(template.styles)
|
||||
.toEqual(['.foo{background-image: url(\'http://someurl/double.jpg\');']);
|
||||
});
|
||||
|
||||
it('should resolve relative style urls in styleUrls', () => {
|
||||
var template =
|
||||
loader.createTemplateFromString(dirType, null, '', 'http://someurl', [], ['test.css']);
|
||||
expect(template.styles).toEqual([]);
|
||||
expect(template.styleAbsUrls).toEqual(['http://someurl/test.css']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
268
modules/angular2/test/compiler/template_normalizer_spec.ts
Normal file
268
modules/angular2/test/compiler/template_normalizer_spec.ts
Normal file
@ -0,0 +1,268 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
TestComponentBuilder,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
TypeMetadata,
|
||||
NormalizedTemplateMetadata,
|
||||
TemplateMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
|
||||
import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {MockXHR} from 'angular2/src/core/render/xhr_mock';
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
|
||||
export function main() {
|
||||
describe('TemplateNormalizer', () => {
|
||||
var dirType: TypeMetadata;
|
||||
|
||||
beforeEachBindings(() => TEST_BINDINGS);
|
||||
|
||||
beforeEach(
|
||||
() => { dirType = new TypeMetadata({moduleId: 'some/module/id', name: 'SomeComp'}); });
|
||||
|
||||
describe('loadTemplate', () => {
|
||||
describe('inline template', () => {
|
||||
it('should store the template',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer],
|
||||
(async, normalizer: TemplateNormalizer) => {
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: 'a',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleId',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer],
|
||||
(async, normalizer: TemplateNormalizer) => {
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the moduleId',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer],
|
||||
(async, normalizer: TemplateNormalizer) => {
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: '<style>@import test.css</style>',
|
||||
templateUrl: null,
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('templateUrl', () => {
|
||||
|
||||
it('should load a template from a url that is resolved against moduleId',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('some/module/sometplurl', 'a');
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'sometplurl',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.template).toEqual('a');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles on the annotation against the moduleId',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('some/module/tpl/sometplurl', '');
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl',
|
||||
styles: [],
|
||||
styleUrls: ['test.css']
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve styles in the template against the templateUrl',
|
||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||
xhr.expect('some/module/tpl/sometplurl', '<style>@import test.css</style>');
|
||||
normalizer.normalizeTemplate(dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
template: null,
|
||||
templateUrl: 'tpl/sometplurl',
|
||||
styles: [],
|
||||
styleUrls: []
|
||||
}))
|
||||
.then((template: NormalizedTemplateMetadata) => {
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/tpl/test.css']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('normalizeLoadedTemplate', () => {
|
||||
it('should store the viewEncapsulationin the result',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
|
||||
var viewEncapsulation = ViewEncapsulation.Native;
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType,
|
||||
new TemplateMetadata({encapsulation: viewEncapsulation, styles: [], styleUrls: []}),
|
||||
'', 'some/module/');
|
||||
expect(template.encapsulation).toBe(viewEncapsulation);
|
||||
}));
|
||||
|
||||
it('should keep the template as html',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), 'a',
|
||||
'some/module/');
|
||||
expect(template.template).toEqual('a')
|
||||
}));
|
||||
|
||||
it('should collect and keep ngContent',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<ng-content select="a"></ng-content>', 'some/module/');
|
||||
expect(template.ngContentSelectors).toEqual(['a']);
|
||||
expect(template.template).toEqual('<ng-content select="a"></ng-content>');
|
||||
}));
|
||||
|
||||
it('should normalize ngContent wildcard selector',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<ng-content></ng-content><ng-content select></ng-content><ng-content select="*"></ng-content>',
|
||||
'some/module/');
|
||||
expect(template.ngContentSelectors).toEqual(['*', '*', '*']);
|
||||
}));
|
||||
|
||||
it('should collect and remove top level styles in the template',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<style>a</style>', 'some/module/');
|
||||
expect(template.styles).toEqual(['a']);
|
||||
expect(template.template).toEqual('');
|
||||
}));
|
||||
|
||||
it('should collect and remove styles inside in elements',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<div><style>a</style></div>', 'some/module/');
|
||||
expect(template.styles).toEqual(['a']);
|
||||
expect(template.template).toEqual('<div></div>');
|
||||
}));
|
||||
|
||||
it('should collect and remove styleUrls in the template',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<link rel="stylesheet" href="aUrl">', 'some/module/');
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/aUrl']);
|
||||
expect(template.template).toEqual('');
|
||||
}));
|
||||
|
||||
it('should collect and remove styleUrls in elements',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<div><link rel="stylesheet" href="aUrl"></div>', 'some/module/');
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/aUrl']);
|
||||
expect(template.template).toEqual('<div></div>');
|
||||
}));
|
||||
|
||||
it('should keep link elements with non stylesheet rel attribute',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||
'<link href="b" rel="a"></link>', 'some/module/');
|
||||
expect(template.styleAbsUrls).toEqual([]);
|
||||
expect(template.template).toEqual('<link href="b" rel="a"></link>');
|
||||
}));
|
||||
|
||||
it('should extract @import style urls into styleAbsUrl',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata(
|
||||
{encapsulation: null, styles: ['@import "test.css";'], styleUrls: []}),
|
||||
'', 'some/module/id');
|
||||
expect(template.styles).toEqual(['']);
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/test.css']);
|
||||
}));
|
||||
|
||||
it('should resolve relative urls in inline styles',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType, new TemplateMetadata({
|
||||
encapsulation: null,
|
||||
styles: ['.foo{background-image: url(\'double.jpg\');'],
|
||||
styleUrls: []
|
||||
}),
|
||||
'', 'some/module/id');
|
||||
expect(template.styles)
|
||||
.toEqual(['.foo{background-image: url(\'some/module/double.jpg\');']);
|
||||
}));
|
||||
|
||||
it('should resolve relative style urls in styleUrls',
|
||||
inject([TemplateNormalizer], (normalizer: TemplateNormalizer) => {
|
||||
var template = normalizer.normalizeLoadedTemplate(
|
||||
dirType,
|
||||
new TemplateMetadata({encapsulation: null, styles: [], styleUrls: ['test.css']}), '',
|
||||
'some/module/id');
|
||||
expect(template.styles).toEqual([]);
|
||||
expect(template.styleAbsUrls).toEqual(['some/module/test.css']);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
@ -1,15 +1,26 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {isPresent} from 'angular2/src/core/facade/lang';
|
||||
import {Parser, Lexer} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {TemplateParser, splitClasses} from 'angular2/src/compiler/template_parser';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {
|
||||
DirectiveMetadata,
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
inject,
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
import {bind} from 'angular2/src/core/di';
|
||||
|
||||
import {TEST_BINDINGS} from './test_bindings';
|
||||
import {isPresent} from 'angular2/src/core/facade/lang';
|
||||
import {TemplateParser, splitClasses} from 'angular2/src/compiler/template_parser';
|
||||
import {
|
||||
NormalizedDirectiveMetadata,
|
||||
TypeMetadata,
|
||||
ChangeDetectionMetadata,
|
||||
TemplateMetadata
|
||||
} from 'angular2/src/compiler/api';
|
||||
NormalizedTemplateMetadata
|
||||
} from 'angular2/src/compiler/directive_metadata';
|
||||
import {
|
||||
templateVisitAll,
|
||||
TemplateAstVisitor,
|
||||
@ -29,6 +40,7 @@ import {
|
||||
} from 'angular2/src/compiler/template_ast';
|
||||
|
||||
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||
import {MockSchemaRegistry} from './schema_registry_mock';
|
||||
|
||||
import {Unparser} from '../core/change_detection/parser/unparser';
|
||||
|
||||
@ -36,24 +48,26 @@ var expressionUnparser = new Unparser();
|
||||
|
||||
export function main() {
|
||||
describe('TemplateParser', () => {
|
||||
var domParser: HtmlParser;
|
||||
beforeEachBindings(() => [
|
||||
TEST_BINDINGS,
|
||||
bind(ElementSchemaRegistry)
|
||||
.toValue(new MockSchemaRegistry({'invalidProp': false}, {'mappedAttr': 'mappedProp'}))
|
||||
]);
|
||||
|
||||
var parser: TemplateParser;
|
||||
var ngIf;
|
||||
|
||||
beforeEach(() => {
|
||||
domParser = new HtmlParser();
|
||||
parser = new TemplateParser(
|
||||
new Parser(new Lexer()),
|
||||
new MockSchemaRegistry({'invalidProp': false}, {'mappedAttr': 'mappedProp'}));
|
||||
ngIf = new DirectiveMetadata({
|
||||
beforeEach(inject([TemplateParser], (_parser) => {
|
||||
parser = _parser;
|
||||
ngIf = new NormalizedDirectiveMetadata({
|
||||
selector: '[ng-if]',
|
||||
type: new TypeMetadata({typeName: 'NgIf'}),
|
||||
type: new TypeMetadata({name: 'NgIf'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['ngIf']})
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
function parse(template: string, directives: DirectiveMetadata[]): TemplateAst[] {
|
||||
return parser.parse(domParser.parse(template, 'TestComp'), directives);
|
||||
function parse(template: string, directives: NormalizedDirectiveMetadata[]): TemplateAst[] {
|
||||
return parser.parse(template, directives, 'TestComp');
|
||||
}
|
||||
|
||||
describe('parse', () => {
|
||||
@ -341,16 +355,16 @@ export function main() {
|
||||
});
|
||||
|
||||
describe('directives', () => {
|
||||
it('should locate directives ordered by typeName and components first', () => {
|
||||
var dirA = new DirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({typeName: 'DirA'})});
|
||||
var dirB =
|
||||
new DirectiveMetadata({selector: '[a]', type: new TypeMetadata({typeName: 'DirB'})});
|
||||
var comp = new DirectiveMetadata({
|
||||
it('should locate directives ordered by name and components first', () => {
|
||||
var dirA = new NormalizedDirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({name: 'DirA'})});
|
||||
var dirB = new NormalizedDirectiveMetadata(
|
||||
{selector: '[a]', type: new TypeMetadata({name: 'DirB'})});
|
||||
var comp = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'ZComp'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: []})
|
||||
type: new TypeMetadata({name: 'ZComp'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div a="b">', [dirB, dirA, comp])))
|
||||
.toEqual([
|
||||
@ -363,10 +377,10 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should locate directives in property bindings', () => {
|
||||
var dirA = new DirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({typeName: 'DirA'})});
|
||||
var dirB =
|
||||
new DirectiveMetadata({selector: '[b]', type: new TypeMetadata({typeName: 'DirB'})});
|
||||
var dirA = new NormalizedDirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({name: 'DirA'})});
|
||||
var dirB = new NormalizedDirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({name: 'DirB'})});
|
||||
expect(humanizeTemplateAsts(parse('<div [a]="b">', [dirA, dirB])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div', 'TestComp > div:nth-child(0)'],
|
||||
@ -383,10 +397,10 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should locate directives in variable bindings', () => {
|
||||
var dirA = new DirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({typeName: 'DirA'})});
|
||||
var dirB =
|
||||
new DirectiveMetadata({selector: '[b]', type: new TypeMetadata({typeName: 'DirB'})});
|
||||
var dirA = new NormalizedDirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({name: 'DirA'})});
|
||||
var dirB = new NormalizedDirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({name: 'DirB'})});
|
||||
expect(humanizeTemplateAsts(parse('<div #a="b">', [dirA, dirB])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div', 'TestComp > div:nth-child(0)'],
|
||||
@ -396,9 +410,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should parse directive host properties', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({hostProperties: {'a': 'expr'}})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div></div>', [dirA])))
|
||||
@ -417,9 +431,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should parse directive host listeners', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({hostListeners: {'a': 'expr'}})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div></div>', [dirA])))
|
||||
@ -431,9 +445,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should parse directive properties', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['aProp']})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div [a-prop]="expr"></div>', [dirA])))
|
||||
@ -450,9 +464,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should parse renamed directive properties', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['b:a']})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div [a]="expr"></div>', [dirA])))
|
||||
@ -464,9 +478,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should parse literal directive properties', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['a']})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div a="literal"></div>', [dirA])))
|
||||
@ -484,9 +498,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should support optional directive properties', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['a']})
|
||||
});
|
||||
expect(humanizeTemplateAsts(parse('<div></div>', [dirA])))
|
||||
@ -549,13 +563,13 @@ export function main() {
|
||||
|
||||
describe('directives', () => {
|
||||
it('should locate directives in property bindings', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: '[a=b]',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['a']})
|
||||
});
|
||||
var dirB = new DirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({typeName: 'DirB'})});
|
||||
var dirB = new NormalizedDirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({name: 'DirB'})});
|
||||
expect(humanizeTemplateAsts(parse('<div template="a b" b>', [dirA, dirB])))
|
||||
.toEqual([
|
||||
[EmbeddedTemplateAst, 'TestComp > div:nth-child(0)'],
|
||||
@ -573,10 +587,10 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should locate directives in variable bindings', () => {
|
||||
var dirA = new DirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({typeName: 'DirA'})});
|
||||
var dirB = new DirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({typeName: 'DirB'})});
|
||||
var dirA = new NormalizedDirectiveMetadata(
|
||||
{selector: '[a=b]', type: new TypeMetadata({name: 'DirA'})});
|
||||
var dirB = new NormalizedDirectiveMetadata(
|
||||
{selector: '[b]', type: new TypeMetadata({name: 'DirB'})});
|
||||
expect(humanizeTemplateAsts(parse('<div template="#a=b" b>', [dirA, dirB])))
|
||||
.toEqual([
|
||||
[EmbeddedTemplateAst, 'TestComp > div:nth-child(0)'],
|
||||
@ -609,12 +623,13 @@ export function main() {
|
||||
});
|
||||
|
||||
describe('content projection', () => {
|
||||
function createComp(selector: string, ngContentSelectors: string[]): DirectiveMetadata {
|
||||
return new DirectiveMetadata({
|
||||
function createComp(selector: string, ngContentSelectors: string[]):
|
||||
NormalizedDirectiveMetadata {
|
||||
return new NormalizedDirectiveMetadata({
|
||||
selector: selector,
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'SomeComp'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: ngContentSelectors})
|
||||
type: new TypeMetadata({name: 'SomeComp'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: ngContentSelectors})
|
||||
})
|
||||
}
|
||||
|
||||
@ -710,26 +725,26 @@ Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp > div:nth-ch
|
||||
|
||||
it('should not throw on invalid property names if the property is used by a directive',
|
||||
() => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
changeDetection: new ChangeDetectionMetadata({properties: ['invalidProp']})
|
||||
});
|
||||
expect(() => parse('<div [invalid-prop]></div>', [dirA])).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not allow more than 1 component per element', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: []})
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirB = new DirectiveMetadata({
|
||||
var dirB = new NormalizedDirectiveMetadata({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'DirB'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: []})
|
||||
type: new TypeMetadata({name: 'DirB'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
expect(() => parse('<div>', [dirB, dirA])).toThrowError(`Template parse errors:
|
||||
More than one component: DirA,DirB in TestComp > div:nth-child(0)`);
|
||||
@ -737,11 +752,11 @@ More than one component: DirA,DirB in TestComp > div:nth-child(0)`);
|
||||
|
||||
it('should not allow components or element nor event bindings on explicit embedded templates',
|
||||
() => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: []})
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
expect(() => parse('<template [a]="b" (e)="f"></template>', [dirA]))
|
||||
.toThrowError(`Template parse errors:
|
||||
@ -751,11 +766,11 @@ Event binding e on an embedded template in TestComp > template:nth-child(0)[(e)=
|
||||
});
|
||||
|
||||
it('should not allow components or element bindings on inline embedded templates', () => {
|
||||
var dirA = new DirectiveMetadata({
|
||||
var dirA = new NormalizedDirectiveMetadata({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new TypeMetadata({typeName: 'DirA'}),
|
||||
template: new TemplateMetadata({ngContentSelectors: []})
|
||||
type: new TypeMetadata({name: 'DirA'}),
|
||||
template: new NormalizedTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
expect(() => parse('<div *a="b">', [dirA])).toThrowError(`Template parse errors:
|
||||
Components on an embedded template: DirA in TestComp > div:nth-child(0)
|
||||
@ -887,17 +902,3 @@ class TemplateContentProjectionHumanizer implements TemplateAstVisitor {
|
||||
visitDirective(ast: DirectiveAst, context: any): any { return null; }
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
export class MockSchemaRegistry implements ElementSchemaRegistry {
|
||||
constructor(public existingProperties: StringMap<string, boolean>,
|
||||
public attrPropMapping: StringMap<string, string>) {}
|
||||
hasProperty(tagName: string, property: string): boolean {
|
||||
var result = this.existingProperties[property];
|
||||
return isPresent(result) ? result : true;
|
||||
}
|
||||
|
||||
getMappedPropName(attrName: string): string {
|
||||
var result = this.attrPropMapping[attrName];
|
||||
return isPresent(result) ? result : attrName;
|
||||
}
|
||||
}
|
26
modules/angular2/test/compiler/test_bindings.ts
Normal file
26
modules/angular2/test/compiler/test_bindings.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {bind, Binding} from 'angular2/src/core/di';
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
|
||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {MockSchemaRegistry} from './schema_registry_mock';
|
||||
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||
|
||||
// TODO(tbosch): move this into test_injector once the new compiler pipeline is used fully
|
||||
export var TEST_BINDINGS = [
|
||||
HtmlParser,
|
||||
TemplateParser,
|
||||
TemplateNormalizer,
|
||||
RuntimeMetadataResolver,
|
||||
StyleCompiler,
|
||||
CommandCompiler,
|
||||
ChangeDetectionCompiler,
|
||||
bind(ChangeDetectorGenConfig).toValue(new ChangeDetectorGenConfig(true, true, false, false)),
|
||||
TemplateCompiler,
|
||||
bind(ElementSchemaRegistry).toValue(new MockSchemaRegistry({}, {}))
|
||||
];
|
@ -242,6 +242,20 @@ export function main() {
|
||||
expect(reflector.method("abc")("anything", ["fake"])).toEqual(['fake']);
|
||||
});
|
||||
});
|
||||
|
||||
if (IS_DART) {
|
||||
describe("moduleId", () => {
|
||||
it("should return the moduleId for a type", () => {
|
||||
expect(reflector.moduleId(TestObjWith00Args))
|
||||
.toEqual('angular2/test/core/reflection/reflector_spec');
|
||||
});
|
||||
|
||||
it("should return an empty array otherwise", () => {
|
||||
var p = reflector.interfaces(ClassWithDecorators);
|
||||
expect(p).toEqual([]);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user