refactor(compiler): remove unused code
BREAKING CHANGE: - Removes `ChangeDetection`, use a binding for `ChangeDetectorGenConfig` instead to configure change detection. - `RenderElementRef.renderBoundElementIndex` was renamed to `RenderElementRef.boundElementIndex`. - Removes `ViewLoader`, use `XHRImpl` instead.
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {SpyProtoChangeDetector} from '../spies';
|
||||
|
||||
import {
|
||||
PreGeneratedChangeDetection,
|
||||
ChangeDetectorDefinition,
|
||||
DynamicProtoChangeDetector
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe("PreGeneratedChangeDetection", () => {
|
||||
var proto;
|
||||
var def;
|
||||
|
||||
beforeEach(() => {
|
||||
proto = new SpyProtoChangeDetector();
|
||||
def = new ChangeDetectorDefinition('id', null, [], [], [], [], null);
|
||||
});
|
||||
|
||||
it("should return a proto change detector when one is available", () => {
|
||||
var map = {'id': (def) => proto};
|
||||
var cd = new PreGeneratedChangeDetection(null, map);
|
||||
|
||||
expect(cd.getProtoChangeDetector('id', def)).toBe(proto)
|
||||
});
|
||||
|
||||
it("should delegate to dynamic change detection otherwise", () => {
|
||||
var cd = new PreGeneratedChangeDetection(null, {});
|
||||
expect(cd.getProtoChangeDetector('id', def)).toBeAnInstanceOf(DynamicProtoChangeDetector);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
library angular2.test.core.compiler.component_url_mapper_spec;
|
||||
|
||||
import 'package:angular2/test_lib.dart';
|
||||
import 'package:angular2/src/core/compiler/component_url_mapper.dart';
|
||||
|
||||
main() {
|
||||
describe("ComponentUrlMapper", () {
|
||||
it("should return the URL of the component's library", () {
|
||||
var mapper = new ComponentUrlMapper();
|
||||
expect(mapper
|
||||
.getUrl(SomeComponent)
|
||||
.endsWith("core/compiler/component_url_mapper_spec.dart")).toBeTrue();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class SomeComponent {}
|
||||
@@ -1,25 +0,0 @@
|
||||
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
ComponentUrlMapper,
|
||||
RuntimeComponentUrlMapper
|
||||
} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
|
||||
export function main() {
|
||||
describe('RuntimeComponentUrlMapper', () => {
|
||||
it('should return the registered URL', () => {
|
||||
var url = 'http://path/to/component';
|
||||
var mapper = new RuntimeComponentUrlMapper();
|
||||
mapper.setComponentUrl(SomeComponent, url);
|
||||
expect(mapper.getUrl(SomeComponent)).toEqual(url);
|
||||
});
|
||||
|
||||
it('should fallback to ComponentUrlMapper', () => {
|
||||
var mapper = new ComponentUrlMapper();
|
||||
var runtimeMapper = new RuntimeComponentUrlMapper();
|
||||
expect(runtimeMapper.getUrl(SomeComponent)).toEqual(mapper.getUrl(SomeComponent));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class SomeComponent {}
|
||||
@@ -1,112 +1,102 @@
|
||||
library angular2.test.core.compiler.directive_lifecycle_spec;
|
||||
|
||||
import 'package:angular2/test_lib.dart';
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:angular2/src/core/compiler/element_injector.dart';
|
||||
import 'package:angular2/src/core/compiler/directive_lifecycle_reflector.dart';
|
||||
import 'package:angular2/src/core/compiler/interfaces.dart';
|
||||
|
||||
main() {
|
||||
describe('Create DirectiveMetadata', () {
|
||||
describe('lifecycle', () {
|
||||
metadata(type, annotation) =>
|
||||
DirectiveBinding.createFromType(type, annotation).metadata;
|
||||
|
||||
describe("onChanges", () {
|
||||
it("should be true when the directive implements OnChanges", () {
|
||||
expect(metadata(DirectiveImplementingOnChanges, new Directive())
|
||||
.callOnChanges).toBe(true);
|
||||
it("should be true when the directive has the onChanges method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveImplementingOnChanges))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive()).callOnChanges)
|
||||
.toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onDestroy", () {
|
||||
it("should be true when the directive implements OnDestroy", () {
|
||||
expect(metadata(DirectiveImplementingOnDestroy, new Directive())
|
||||
.callOnDestroy).toBe(true);
|
||||
it("should be true when the directive has the onDestroy method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveImplementingOnDestroy))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive()).callOnDestroy)
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("doCheck", () {
|
||||
it("should be true when the directive implements DoCheck", () {
|
||||
expect(metadata(DirectiveImplementingOnCheck, new Directive())
|
||||
.callDoCheck).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive()).callDoCheck)
|
||||
.toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInit", () {
|
||||
it("should be true when the directive implements OnInit", () {
|
||||
expect(metadata(DirectiveImplementingOnInit, new Directive())
|
||||
.callOnInit).toBe(true);
|
||||
it("should be true when the directive has the onInit method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveImplementingOnInit))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive()).callOnInit)
|
||||
.toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("doCheck", () {
|
||||
it("should be true when the directive has the doCheck method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveImplementingOnCheck))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentInit", () {
|
||||
it("should be true when the directive implements AfterContentInit", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterContentInit, new Directive())
|
||||
.callAfterContentInit).toBe(true);
|
||||
it("should be true when the directive has the afterContentInit method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveImplementingAfterContentInit))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterContentInit).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveNoHooks))
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentChecked", () {
|
||||
it("should be true when the directive implements AfterContentChecked", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterContentChecked, new Directive())
|
||||
.callAfterContentChecked).toBe(true);
|
||||
it("should be true when the directive has the afterContentChecked method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveImplementingAfterContentChecked))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterContentChecked).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveNoHooks))
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("afterViewInit", () {
|
||||
it("should be true when the directive implements AfterViewInit", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterViewInit, new Directive())
|
||||
.callAfterViewInit).toBe(true);
|
||||
it("should be true when the directive has the afterViewInit method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveImplementingAfterViewInit))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterViewInit).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterViewChecked", () {
|
||||
it("should be true when the directive implements AfterViewChecked", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterViewChecked, new Directive())
|
||||
.callAfterViewChecked).toBe(true);
|
||||
it("should be true when the directive has the afterViewChecked method", () {
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveImplementingAfterViewChecked))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterViewChecked).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveNoHooks))
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,83 +13,76 @@ import {
|
||||
proxy
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DirectiveMetadata} from 'angular2/src/core/metadata';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
|
||||
import {hasLifecycleHook} from 'angular2/src/core/compiler/directive_lifecycle_reflector';
|
||||
import {LifecycleHooks} from 'angular2/src/core/compiler/interfaces';
|
||||
|
||||
export function main() {
|
||||
describe('Create DirectiveMetadata', () => {
|
||||
describe('lifecycle', () => {
|
||||
function metadata(type, annotation): RenderDirectiveMetadata {
|
||||
return DirectiveBinding.createFromType(type, annotation).metadata;
|
||||
}
|
||||
|
||||
describe("onChanges", () => {
|
||||
it("should be true when the directive has the onChanges method", () => {
|
||||
expect(metadata(DirectiveWithOnChangesMethod, new DirectiveMetadata({})).callOnChanges)
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveWithOnChangesMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnChanges).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onDestroy", () => {
|
||||
it("should be true when the directive has the onDestroy method", () => {
|
||||
expect(metadata(DirectiveWithOnDestroyMethod, new DirectiveMetadata({})).callOnDestroy)
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveWithOnDestroyMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnDestroy).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInit", () => {
|
||||
it("should be true when the directive has the onInit method", () => {
|
||||
expect(metadata(DirectiveWithOnInitMethod, new DirectiveMetadata({})).callOnInit)
|
||||
.toBe(true);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveWithOnInitMethod)).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnInit).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("doCheck", () => {
|
||||
it("should be true when the directive has the doCheck method", () => {
|
||||
expect(metadata(DirectiveWithOnCheckMethod, new DirectiveMetadata({})).callDoCheck)
|
||||
.toBe(true);
|
||||
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveWithOnCheckMethod)).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callDoCheck).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentInit", () => {
|
||||
it("should be true when the directive has the afterContentInit method", () => {
|
||||
expect(metadata(DirectiveWithAfterContentInitMethod, new DirectiveMetadata({}))
|
||||
.callAfterContentInit)
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit,
|
||||
DirectiveWithAfterContentInitMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentInit)
|
||||
.toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentChecked", () => {
|
||||
it("should be true when the directive has the afterContentChecked method", () => {
|
||||
expect(metadata(DirectiveWithAfterContentCheckedMethod, new DirectiveMetadata({}))
|
||||
.callAfterContentChecked)
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked,
|
||||
DirectiveWithAfterContentCheckedMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentChecked)
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveNoHooks))
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -97,26 +90,24 @@ export function main() {
|
||||
|
||||
describe("afterViewInit", () => {
|
||||
it("should be true when the directive has the afterViewInit method", () => {
|
||||
expect(metadata(DirectiveWithAfterViewInitMethod, new DirectiveMetadata({}))
|
||||
.callAfterViewInit)
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveWithAfterViewInitMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewInit).toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterViewChecked", () => {
|
||||
it("should be true when the directive has the afterViewChecked method", () => {
|
||||
expect(metadata(DirectiveWithAfterViewCheckedMethod, new DirectiveMetadata({}))
|
||||
.callAfterViewChecked)
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked,
|
||||
DirectiveWithAfterViewCheckedMethod))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewChecked)
|
||||
.toBe(false);
|
||||
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveNoHooks)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -62,8 +62,6 @@ import {
|
||||
PipeTransform,
|
||||
ChangeDetectorRef,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetection,
|
||||
DynamicChangeDetection,
|
||||
ChangeDetectorGenConfig
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
ViewMetadata
|
||||
} from 'angular2/core';
|
||||
import {By} from 'angular2/src/core/debug';
|
||||
import {MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE} from 'angular2/src/core/render';
|
||||
|
||||
export function main() {
|
||||
describe('projection', () => {
|
||||
@@ -421,45 +420,29 @@ export function main() {
|
||||
}));
|
||||
}
|
||||
|
||||
describe('different proto view storages', () => {
|
||||
function runTests() {
|
||||
it('should support nested conditionals that contain ng-contents',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(MainComp, new ViewMetadata({
|
||||
template: `<conditional-text>a</conditional-text>`,
|
||||
directives: [ConditionalTextComponent]
|
||||
}))
|
||||
.createAsync(MainComp)
|
||||
.then((main) => {
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN()');
|
||||
it('should support nested conditionals that contain ng-contents',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(MainComp, new ViewMetadata({
|
||||
template: `<conditional-text>a</conditional-text>`,
|
||||
directives: [ConditionalTextComponent]
|
||||
}))
|
||||
.createAsync(MainComp)
|
||||
.then((main) => {
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN()');
|
||||
|
||||
var viewportElement =
|
||||
main.debugElement.componentViewChildren[0].componentViewChildren[0];
|
||||
viewportElement.inject(ManualViewportDirective).show();
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN(FIRST())');
|
||||
var viewportElement =
|
||||
main.debugElement.componentViewChildren[0].componentViewChildren[0];
|
||||
viewportElement.inject(ManualViewportDirective).show();
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN(FIRST())');
|
||||
|
||||
viewportElement =
|
||||
main.debugElement.componentViewChildren[0].componentViewChildren[1];
|
||||
viewportElement.inject(ManualViewportDirective).show();
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))');
|
||||
viewportElement =
|
||||
main.debugElement.componentViewChildren[0].componentViewChildren[1];
|
||||
viewportElement.inject(ManualViewportDirective).show();
|
||||
expect(main.debugElement.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
describe('serialize templates', () => {
|
||||
beforeEachBindings(() => [bind(MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE).toValue(0)]);
|
||||
runTests();
|
||||
});
|
||||
|
||||
describe("don't serialize templates", () => {
|
||||
beforeEachBindings(() => [bind(MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE).toValue(-1)]);
|
||||
runTests();
|
||||
});
|
||||
|
||||
});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,133 +11,9 @@ import {
|
||||
it
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {SpyChangeDetection} from '../spies';
|
||||
import {isBlank, stringify} from 'angular2/src/core/facade/lang';
|
||||
|
||||
import {
|
||||
ChangeDetection,
|
||||
ChangeDetectorDefinition,
|
||||
BindingRecord,
|
||||
DirectiveIndex,
|
||||
Parser
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {
|
||||
BindingRecordsCreator,
|
||||
getChangeDetectorDefinitions
|
||||
} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Component, Directive} from 'angular2/src/core/metadata';
|
||||
import {Key, Binding} from 'angular2/core';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {
|
||||
RenderElementBinder,
|
||||
EventBinding,
|
||||
RenderDirectiveMetadata,
|
||||
ViewType,
|
||||
ProtoViewDto,
|
||||
DirectiveBinder
|
||||
} from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('ProtoViewFactory', () => {
|
||||
var changeDetection;
|
||||
var directiveResolver;
|
||||
// TODO
|
||||
|
||||
beforeEach(() => {
|
||||
directiveResolver = new DirectiveResolver();
|
||||
changeDetection = new SpyChangeDetection();
|
||||
changeDetection.prop("generateDetectors", true);
|
||||
});
|
||||
|
||||
function bindDirective(type) {
|
||||
return DirectiveBinding.createFromType(type, directiveResolver.resolve(type));
|
||||
}
|
||||
|
||||
describe('getChangeDetectorDefinitions', () => {
|
||||
|
||||
it('should create a ChangeDetectorDefinition for the root render proto view', () => {
|
||||
var renderPv = createRenderProtoView();
|
||||
var defs =
|
||||
getChangeDetectorDefinitions(bindDirective(MainComponent).metadata, renderPv, [], null);
|
||||
expect(defs.length).toBe(1);
|
||||
expect(defs[0].id).toEqual(`${stringify(MainComponent)}_comp_0`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('BindingRecordsCreator', () => {
|
||||
var creator: BindingRecordsCreator;
|
||||
|
||||
beforeEach(() => { creator = new BindingRecordsCreator(); });
|
||||
|
||||
describe('getEventBindingRecords', () => {
|
||||
it("should return template event records", inject([Parser], (p: Parser) => {
|
||||
var ast1 = p.parseAction("1", null);
|
||||
var ast2 = p.parseAction("2", null);
|
||||
|
||||
var rec = creator.getEventBindingRecords(
|
||||
[
|
||||
new RenderElementBinder(
|
||||
{eventBindings: [new EventBinding("a", ast1)], directives: []}),
|
||||
new RenderElementBinder(
|
||||
{eventBindings: [new EventBinding("b", ast2)], directives: []})
|
||||
],
|
||||
[]);
|
||||
|
||||
expect(rec).toEqual([
|
||||
BindingRecord.createForEvent(ast1, "a", 0),
|
||||
BindingRecord.createForEvent(ast2, "b", 1)
|
||||
]);
|
||||
}));
|
||||
|
||||
it('should return host event records', inject([Parser], (p: Parser) => {
|
||||
var ast1 = p.parseAction("1", null);
|
||||
|
||||
var rec = creator.getEventBindingRecords(
|
||||
[
|
||||
new RenderElementBinder({
|
||||
eventBindings: [],
|
||||
directives: [
|
||||
new DirectiveBinder(
|
||||
{directiveIndex: 0, eventBindings: [new EventBinding("a", ast1)]})
|
||||
]
|
||||
})
|
||||
],
|
||||
[RenderDirectiveMetadata.create({id: 'some-id'})]);
|
||||
|
||||
expect(rec.length).toEqual(1);
|
||||
expect(rec[0].target.name).toEqual("a");
|
||||
expect(rec[0].implicitReceiver).toBeAnInstanceOf(DirectiveIndex);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function directiveBinding({metadata}: {metadata?: any} = {}) {
|
||||
return new DirectiveBinding(Key.get("dummy"), null, null, metadata, [], []);
|
||||
}
|
||||
|
||||
function createRenderProtoView(elementBinders = null, type: ViewType = null,
|
||||
variableBindings = null) {
|
||||
if (isBlank(type)) {
|
||||
type = ViewType.COMPONENT;
|
||||
}
|
||||
if (isBlank(elementBinders)) {
|
||||
elementBinders = [];
|
||||
}
|
||||
if (isBlank(variableBindings)) {
|
||||
variableBindings = new Map();
|
||||
}
|
||||
return new ProtoViewDto({
|
||||
elementBinders: elementBinders,
|
||||
type: type,
|
||||
variableBindings: variableBindings,
|
||||
textBindings: [],
|
||||
transitiveNgContentCount: 0
|
||||
});
|
||||
}
|
||||
|
||||
@Component({selector: 'main-comp'})
|
||||
class MainComponent {
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
RenderProtoViewRef,
|
||||
RenderFragmentRef,
|
||||
ViewType,
|
||||
RenderProtoViewMergeMapping,
|
||||
RenderViewWithFragments
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||
|
||||
@@ -37,11 +37,7 @@ import {
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {Component} from 'angular2/src/core/metadata';
|
||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||
import {
|
||||
RenderProtoViewMergeMapping,
|
||||
ViewType,
|
||||
RenderViewWithFragments
|
||||
} from 'angular2/src/core/render/render';
|
||||
import {ViewType, RenderViewWithFragments} from 'angular2/src/core/render/render';
|
||||
|
||||
export function main() {
|
||||
// TODO(tbosch): add more tests here!
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
|
||||
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {ddescribe, describe, expect, it} from 'angular2/test_lib';
|
||||
|
||||
export function main() {
|
||||
describe('Metadata', () => {
|
||||
describe('host', () => {
|
||||
it('should parse host configuration', () => {
|
||||
var md = RenderDirectiveMetadata.create({
|
||||
host: MapWrapper.createFromPairs(
|
||||
[['(event)', 'eventVal'], ['[prop]', 'propVal'], ['attr', 'attrVal']])
|
||||
});
|
||||
|
||||
expect(md.hostListeners).toEqual(MapWrapper.createFromPairs([['event', 'eventVal']]));
|
||||
expect(md.hostProperties).toEqual(MapWrapper.createFromPairs([['prop', 'propVal']]));
|
||||
expect(md.hostAttributes).toEqual(MapWrapper.createFromPairs([['attr', 'attrVal']]));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* Runs compiler tests using in-browser DOM adapter.
|
||||
*/
|
||||
|
||||
import {runCompilerCommonTests} from './compiler_common_tests';
|
||||
|
||||
export function main() {
|
||||
runCompilerCommonTests();
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {Type, isBlank, stringify, isPresent} from 'angular2/src/core/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
|
||||
import {DomCompiler} from 'angular2/src/core/render/dom/compiler/compiler';
|
||||
import {
|
||||
ProtoViewDto,
|
||||
ViewDefinition,
|
||||
RenderDirectiveMetadata,
|
||||
ViewType,
|
||||
ViewEncapsulation
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {CompileStep} from 'angular2/src/core/render/dom/compiler/compile_step';
|
||||
import {CompileStepFactory} from 'angular2/src/core/render/dom/compiler/compile_step_factory';
|
||||
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||
import {ViewLoader, TemplateAndStyles} from 'angular2/src/core/render/dom/compiler/view_loader';
|
||||
|
||||
import {resolveInternalDomProtoView} from 'angular2/src/core/render/dom/view/proto_view';
|
||||
import {SharedStylesHost} from 'angular2/src/core/render/dom/view/shared_styles_host';
|
||||
import {TemplateCloner} from 'angular2/src/core/render/dom/template_cloner';
|
||||
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function runCompilerCommonTests() {
|
||||
describe('DomCompiler', function() {
|
||||
var mockStepFactory: MockStepFactory;
|
||||
var sharedStylesHost: SharedStylesHost;
|
||||
|
||||
beforeEach(() => {sharedStylesHost = new SharedStylesHost()});
|
||||
|
||||
function createCompiler(processElementClosure = null, processStyleClosure = null,
|
||||
urlData = null) {
|
||||
if (isBlank(urlData)) {
|
||||
urlData = new Map();
|
||||
}
|
||||
var tplLoader = new FakeViewLoader(urlData);
|
||||
mockStepFactory =
|
||||
new MockStepFactory([new MockStep(processElementClosure, processStyleClosure)]);
|
||||
return new DomCompiler(new ElementSchemaRegistry(), new TemplateCloner(-1), mockStepFactory,
|
||||
tplLoader, sharedStylesHost);
|
||||
}
|
||||
|
||||
describe('compile', () => {
|
||||
|
||||
it('should run the steps and build the AppProtoView of the root element',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler((parent, current, control) => {
|
||||
current.inheritedProtoView.bindVariable('b', 'a');
|
||||
});
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someComponent', template: '<div></div>'}))
|
||||
.then((protoView) => {
|
||||
expect(protoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'a': 'b'}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler((parent, current, control) => {
|
||||
current.inheritedProtoView.bindVariable('b', 'a');
|
||||
});
|
||||
|
||||
var dirMetadata = RenderDirectiveMetadata.create(
|
||||
{id: 'id', selector: 'custom', type: RenderDirectiveMetadata.COMPONENT_TYPE});
|
||||
compiler.compileHost(dirMetadata)
|
||||
.then((protoView) => {
|
||||
expect(DOM.tagName(DOM.firstChild(DOM.content(templateRoot(protoView))))
|
||||
.toLowerCase())
|
||||
.toEqual('custom');
|
||||
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
|
||||
expect(protoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'a': 'b'}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should create element from component selector', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler((parent, current, control) => {
|
||||
current.inheritedProtoView.bindVariable('b', 'a');
|
||||
});
|
||||
|
||||
var dirMetadata = RenderDirectiveMetadata.create({
|
||||
id: 'id',
|
||||
selector: 'marquee.jazzy[size=huge]',
|
||||
type: RenderDirectiveMetadata.COMPONENT_TYPE
|
||||
});
|
||||
|
||||
compiler.compileHost(dirMetadata)
|
||||
.then((protoView) => {
|
||||
let element = DOM.firstChild(DOM.content(templateRoot(protoView)));
|
||||
expect(DOM.tagName(element).toLowerCase()).toEqual('marquee');
|
||||
expect(DOM.hasClass(element, 'jazzy')).toBe(true);
|
||||
expect(DOM.getAttribute(element, 'size')).toEqual('huge');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should use the inline template and compile in sync',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP);
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someId', template: 'inline component'}))
|
||||
.then((protoView) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoView))).toEqual('inline component');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should load url templates', inject([AsyncTestCompleter], (async) => {
|
||||
var urlData = MapWrapper.createFromStringMap({'someUrl': 'url component'});
|
||||
var compiler = createCompiler(EMPTY_STEP, null, urlData);
|
||||
compiler.compile(new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'}))
|
||||
.then((protoView) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoView))).toEqual('url component');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should remove script tags from templates', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP);
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someId', template: '<div></div><script></script>'}))
|
||||
.then((protoView) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoView))).toEqual('<div></div>');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should report loading errors', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP, null, new Map());
|
||||
PromiseWrapper.catchError(
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'})),
|
||||
(e) => {
|
||||
expect(e.message).toEqual(
|
||||
'Failed to load the template for "someId" : Failed to fetch url "someUrl"');
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
}));
|
||||
|
||||
it('should return ProtoViews of type COMPONENT_VIEW_TYPE',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP);
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someId', template: 'inline component'}))
|
||||
.then((protoView) => {
|
||||
expect(protoView.type).toEqual(ViewType.COMPONENT);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('compileHost', () => {
|
||||
|
||||
it('should return ProtoViews of type HOST_VIEW_TYPE',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP);
|
||||
compiler.compileHost(someComponent)
|
||||
.then((protoView) => {
|
||||
expect(protoView.type).toEqual(ViewType.HOST);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('compile styles', () => {
|
||||
it('should run the steps', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(null, (style) => { return style + 'b {};'; });
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then((protoViewDto) => {
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};b {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should store the styles in the SharedStylesHost for ViewEncapsulation.None',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoViewDto))).toEqual('');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should store the styles in the SharedStylesHost for ViewEncapsulation.Emulated',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.Emulated
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoViewDto))).toEqual('');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
if (DOM.supportsNativeShadowDOM()) {
|
||||
it('should store the styles in the template for ViewEncapsulation.Native',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.Native
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
expect(DOM.getInnerHTML(templateRoot(protoViewDto)))
|
||||
.toEqual('<style>a {};</style>');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual([]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
it('should default to ViewEncapsulation.None if no styles are specified',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someComponent', template: '', styles: []}))
|
||||
.then((protoView) => {
|
||||
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.None);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should default to ViewEncapsulation.Emulated if styles are specified',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then((protoView) => {
|
||||
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.Emulated);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('mergeProtoViews', () => {
|
||||
it('should store the styles of the merged ProtoView in the SharedStylesHost',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then(protoViewDto => compiler.mergeProtoViewsRecursively([protoViewDto.render]))
|
||||
.then(_ => {
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function templateRoot(protoViewDto: ProtoViewDto): Element {
|
||||
var pv = resolveInternalDomProtoView(protoViewDto.render);
|
||||
return (<Element>pv.cloneableTemplate);
|
||||
}
|
||||
|
||||
class MockStepFactory extends CompileStepFactory {
|
||||
steps: CompileStep[];
|
||||
subTaskPromises: Array<Promise<any>>;
|
||||
viewDef: ViewDefinition;
|
||||
|
||||
constructor(steps) {
|
||||
super();
|
||||
this.steps = steps;
|
||||
}
|
||||
createSteps(viewDef): CompileStep[] {
|
||||
this.viewDef = viewDef;
|
||||
return this.steps;
|
||||
}
|
||||
}
|
||||
|
||||
var EMPTY_STEP = (parent, current, control) => {
|
||||
if (isPresent(parent)) {
|
||||
current.inheritedProtoView = parent.inheritedProtoView;
|
||||
}
|
||||
};
|
||||
|
||||
class FakeViewLoader extends ViewLoader {
|
||||
_urlData: Map<string, string>;
|
||||
constructor(urlData) {
|
||||
super(null, null, null);
|
||||
this._urlData = urlData;
|
||||
}
|
||||
|
||||
load(viewDef): Promise<any> {
|
||||
var styles = isPresent(viewDef.styles) ? viewDef.styles : [];
|
||||
if (isPresent(viewDef.template)) {
|
||||
return PromiseWrapper.resolve(new TemplateAndStyles(viewDef.template, styles));
|
||||
}
|
||||
|
||||
if (isPresent(viewDef.templateAbsUrl)) {
|
||||
var content = this._urlData.get(viewDef.templateAbsUrl);
|
||||
return isPresent(content) ?
|
||||
PromiseWrapper.resolve(new TemplateAndStyles(content, styles)) :
|
||||
PromiseWrapper.reject(`Failed to fetch url "${viewDef.templateAbsUrl}"`, null);
|
||||
}
|
||||
|
||||
throw new BaseException('View should have either the templateUrl or template property set');
|
||||
}
|
||||
}
|
||||
|
||||
var someComponent = RenderDirectiveMetadata.create(
|
||||
{selector: 'some-comp', id: 'someComponent', type: RenderDirectiveMetadata.COMPONENT_TYPE});
|
||||
@@ -1,11 +0,0 @@
|
||||
library angular2.compiler.html5lib_dom_adapter.test;
|
||||
|
||||
import 'package:angular2/src/core/dom/html_adapter.dart';
|
||||
import 'package:angular2/src/test_lib/test_lib.dart' show testSetup;
|
||||
import 'compiler_common_tests.dart';
|
||||
|
||||
void main() {
|
||||
Html5LibDomAdapter.makeCurrent();
|
||||
testSetup();
|
||||
runCompilerCommonTests();
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib';
|
||||
import {isPresent, isBlank, assertionsEnabled} from 'angular2/src/core/facade/lang';
|
||||
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {DirectiveParser} from 'angular2/src/core/render/dom/compiler/directive_parser';
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
import {ViewDefinition, RenderDirectiveMetadata, ViewType} from 'angular2/src/core/render/api';
|
||||
import {Lexer, Parser} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {ElementBinderBuilder} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function main() {
|
||||
describe('DirectiveParser', () => {
|
||||
var parser, annotatedDirectives;
|
||||
|
||||
beforeEach(() => {
|
||||
annotatedDirectives = [
|
||||
someComponent,
|
||||
someComponent2,
|
||||
someDirective,
|
||||
someDirectiveIgnoringChildren,
|
||||
decoratorWithMultipleAttrs,
|
||||
someDirectiveWithProps,
|
||||
someDirectiveWithHostProperties,
|
||||
someDirectiveWithInvalidHostProperties,
|
||||
someDirectiveWithHostAttributes,
|
||||
someDirectiveWithEvents,
|
||||
someDirectiveWithGlobalEvents
|
||||
];
|
||||
parser = new Parser(new Lexer());
|
||||
});
|
||||
|
||||
function createPipeline(propertyBindings = null, directives = null) {
|
||||
if (isBlank(directives)) directives = annotatedDirectives;
|
||||
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(propertyBindings)) {
|
||||
StringMapWrapper.forEach(propertyBindings, (ast, name) => {
|
||||
current.bindElement().bindProperty(name, ast);
|
||||
});
|
||||
}
|
||||
}),
|
||||
new DirectiveParser(parser, directives)
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(el, propertyBindings = null, directives = null): ElementBinderBuilder[] {
|
||||
var pipeline = createPipeline(propertyBindings, directives);
|
||||
return ListWrapper.map(
|
||||
pipeline.processElements(el, ViewType.COMPONENT, createViewDefinition()),
|
||||
(ce) => ce.inheritedElementBinder);
|
||||
}
|
||||
|
||||
it('should not add directives if they are not used', () => {
|
||||
var results = process(el('<div></div>'));
|
||||
expect(results[0]).toBe(null);
|
||||
});
|
||||
|
||||
it('should detect directives in attributes', () => {
|
||||
var results = process(el('<div some-decor></div>'));
|
||||
expect(results[0].directives[0].directiveIndex)
|
||||
.toBe(annotatedDirectives.indexOf(someDirective));
|
||||
});
|
||||
|
||||
it('should detect directives with multiple attributes', () => {
|
||||
var results = process(el('<input type=text control=one></input>'));
|
||||
expect(results[0].directives[0].directiveIndex)
|
||||
.toBe(annotatedDirectives.indexOf(decoratorWithMultipleAttrs));
|
||||
});
|
||||
|
||||
it('should compile children by default', () => {
|
||||
var results = createPipeline().processElements(el('<div some-decor></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].compileChildren).toEqual(true);
|
||||
});
|
||||
|
||||
it('should stop compiling children when specified in the directive config', () => {
|
||||
var results = createPipeline().processElements(el('<div some-decor-ignoring-children></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].compileChildren).toEqual(false);
|
||||
});
|
||||
|
||||
it('should bind directive properties from bound properties', () => {
|
||||
var results = process(el('<div some-decor-props></div>'),
|
||||
{'elProp': parser.parseBinding('someExpr', '')});
|
||||
var directiveBinding = results[0].directives[0];
|
||||
expect(directiveBinding.propertyBindings.get('dirProp').source).toEqual('someExpr');
|
||||
});
|
||||
|
||||
it('should bind directive properties from attribute values', () => {
|
||||
var results = process(el('<div some-decor-props el-prop="someValue"></div>'));
|
||||
var directiveBinding = results[0].directives[0];
|
||||
var simpleProp = directiveBinding.propertyBindings.get('dirProp');
|
||||
expect(simpleProp.source).toEqual('someValue');
|
||||
});
|
||||
|
||||
it('should bind host directive properties', () => {
|
||||
var element = el('<input some-decor-with-host-props>');
|
||||
var results = process(element);
|
||||
|
||||
var directiveBinding = results[0].directives[0];
|
||||
|
||||
var ast = directiveBinding.hostPropertyBindings.get('hostProp');
|
||||
expect(ast.source).toEqual('dirProp');
|
||||
});
|
||||
|
||||
it('should throw when parsing invalid host properties', () => {
|
||||
expect(() => process(el('<input some-decor-with-invalid-host-props>')))
|
||||
.toThrowError(
|
||||
new RegExp('Simple binding expression can only contain field access and constants'));
|
||||
});
|
||||
|
||||
it('should set host element attributes', () => {
|
||||
var element = el('<input some-decor-with-host-attrs>');
|
||||
var results = process(element);
|
||||
|
||||
expect(DOM.getAttribute(results[0].element, 'attr_name')).toEqual('attr_val');
|
||||
});
|
||||
|
||||
it('should not set host element attribute if an attribute already exists', () => {
|
||||
var element = el('<input attr_name="initial" some-decor-with-host-attrs>');
|
||||
var results = process(element);
|
||||
|
||||
expect(DOM.getAttribute(results[0].element, 'attr_name')).toEqual('initial');
|
||||
|
||||
DOM.removeAttribute(element, 'attr_name');
|
||||
results = process(element);
|
||||
expect(DOM.getAttribute(results[0].element, 'attr_name')).toEqual('attr_val');
|
||||
});
|
||||
|
||||
it('should add CSS classes if "class" specified in host element attributes', () => {
|
||||
var element = el('<input class="foo baz" some-decor-with-host-attrs>');
|
||||
var results = process(element);
|
||||
|
||||
expect(DOM.hasClass(results[0].element, 'foo')).toBeTruthy();
|
||||
expect(DOM.hasClass(results[0].element, 'bar')).toBeTruthy();
|
||||
expect(DOM.hasClass(results[0].element, 'baz')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should read attribute values', () => {
|
||||
var element = el('<input some-decor-props some-attr="someValue">');
|
||||
var results = process(element);
|
||||
expect(results[0].readAttributes.get('some-attr')).toEqual('someValue');
|
||||
});
|
||||
|
||||
it('should bind directive events', () => {
|
||||
var results = process(el('<div some-decor-events></div>'));
|
||||
var directiveBinding = results[0].directives[0];
|
||||
expect(directiveBinding.eventBindings.length).toEqual(1);
|
||||
var eventBinding = directiveBinding.eventBindings[0];
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
expect(eventBinding.source.source).toEqual('doIt()');
|
||||
});
|
||||
|
||||
it('should bind directive global events', () => {
|
||||
var results = process(el('<div some-decor-globalevents></div>'));
|
||||
var directiveBinding = results[0].directives[0];
|
||||
expect(directiveBinding.eventBindings.length).toEqual(1);
|
||||
var eventBinding = directiveBinding.eventBindings[0];
|
||||
expect(eventBinding.fullName).toEqual('window:resize');
|
||||
expect(eventBinding.source.source).toEqual('doItGlobal()');
|
||||
});
|
||||
|
||||
// TODO: assertions should be enabled when running tests:
|
||||
// https://github.com/angular/angular/issues/1340
|
||||
describe('component directives', () => {
|
||||
it('should save the component id', () => {
|
||||
var results = process(el('<some-comp></some-comp>'));
|
||||
expect(results[0].componentId).toEqual('someComponent');
|
||||
});
|
||||
|
||||
it('should not allow multiple component directives on the same element', () => {
|
||||
expect(() => {
|
||||
process(el('<some-comp></some-comp>'), null, [someComponent, someComponentDup]);
|
||||
}).toThrowError(new RegExp('Only one component directive is allowed per element'));
|
||||
});
|
||||
|
||||
it('should sort the directives and store the component as the first directive', () => {
|
||||
var results = process(el('<some-comp some-decor></some-comp>'));
|
||||
expect(annotatedDirectives[results[0].directives[0].directiveIndex].id)
|
||||
.toEqual('someComponent');
|
||||
expect(annotatedDirectives[results[0].directives[1].directiveIndex].id)
|
||||
.toEqual('someDirective');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var someComponent = RenderDirectiveMetadata.create(
|
||||
{selector: 'some-comp', id: 'someComponent', type: RenderDirectiveMetadata.COMPONENT_TYPE});
|
||||
|
||||
var someComponentDup = RenderDirectiveMetadata.create(
|
||||
{selector: 'some-comp', id: 'someComponentDup', type: RenderDirectiveMetadata.COMPONENT_TYPE});
|
||||
|
||||
var someComponent2 = RenderDirectiveMetadata.create(
|
||||
{selector: 'some-comp2', id: 'someComponent2', type: RenderDirectiveMetadata.COMPONENT_TYPE});
|
||||
|
||||
var someDirective = RenderDirectiveMetadata.create(
|
||||
{selector: '[some-decor]', id: 'someDirective', type: RenderDirectiveMetadata.DIRECTIVE_TYPE});
|
||||
|
||||
var someDirectiveIgnoringChildren = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-ignoring-children]',
|
||||
compileChildren: false,
|
||||
type: RenderDirectiveMetadata.DIRECTIVE_TYPE
|
||||
|
||||
});
|
||||
|
||||
var decoratorWithMultipleAttrs = RenderDirectiveMetadata.create({
|
||||
selector: 'input[type=text][control]',
|
||||
id: 'decoratorWithMultipleAttrs',
|
||||
type: RenderDirectiveMetadata.DIRECTIVE_TYPE
|
||||
});
|
||||
|
||||
var someDirectiveWithProps = RenderDirectiveMetadata.create(
|
||||
{selector: '[some-decor-props]', inputs: ['dirProp: elProp'], readAttributes: ['some-attr']});
|
||||
|
||||
var someDirectiveWithHostProperties = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-with-host-props]',
|
||||
host: MapWrapper.createFromStringMap<string>({'[hostProp]': 'dirProp'})
|
||||
});
|
||||
|
||||
var someDirectiveWithInvalidHostProperties = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-with-invalid-host-props]',
|
||||
host: MapWrapper.createFromStringMap<string>({'[hostProp]': 'dirProp + dirProp2'})
|
||||
});
|
||||
|
||||
var someDirectiveWithHostAttributes = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-with-host-attrs]',
|
||||
host: MapWrapper.createFromStringMap<string>({'attr_name': 'attr_val', 'class': 'foo bar'})
|
||||
});
|
||||
|
||||
var someDirectiveWithEvents = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-events]',
|
||||
host: MapWrapper.createFromStringMap<string>({'(click)': 'doIt()'})
|
||||
});
|
||||
|
||||
var someDirectiveWithGlobalEvents = RenderDirectiveMetadata.create({
|
||||
selector: '[some-decor-globalevents]',
|
||||
host: MapWrapper.createFromStringMap<string>({'(window:resize)': 'doItGlobal()'})
|
||||
});
|
||||
|
||||
var componentWithNonElementSelector = RenderDirectiveMetadata.create({
|
||||
id: 'componentWithNonElementSelector',
|
||||
selector: '[attr]',
|
||||
type: RenderDirectiveMetadata.COMPONENT_TYPE
|
||||
});
|
||||
@@ -1,287 +0,0 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib';
|
||||
import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {isPresent, NumberWrapper, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
import {CompileElement} from 'angular2/src/core/render/dom/compiler/compile_element';
|
||||
import {CompileStep} from 'angular2/src/core/render/dom/compiler/compile_step';
|
||||
import {CompileControl} from 'angular2/src/core/render/dom/compiler/compile_control';
|
||||
|
||||
import {ProtoViewBuilder} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {
|
||||
ProtoViewDto,
|
||||
ViewType,
|
||||
ViewEncapsulation,
|
||||
ViewDefinition
|
||||
} from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('compile_pipeline', () => {
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
describe('children compilation', () => {
|
||||
it('should walk the tree in depth first order including template contents', () => {
|
||||
var element = el('<div id="1"><template id="2"><span id="3"></span></template></div>');
|
||||
|
||||
var step0Log = [];
|
||||
var results = new CompilePipeline([createLoggerStep(step0Log)])
|
||||
.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
|
||||
it('should stop walking the tree when compileChildren is false', () => {
|
||||
var element = el(
|
||||
'<div id="1"><template id="2" ignore-children><span id="3"></span></template></div>');
|
||||
|
||||
var step0Log = [];
|
||||
var pipeline = new CompilePipeline([new IgnoreChildrenStep(), createLoggerStep(step0Log)]);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should inherit protoViewBuilders to children', () => {
|
||||
var element = el('<div><div><span viewroot><span></span></span></div></div>');
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(DOM.getAttribute(current.element, 'viewroot'))) {
|
||||
current.inheritedProtoView =
|
||||
new ProtoViewBuilder(current.element, ViewType.EMBEDDED, ViewEncapsulation.None);
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedProtoView).toBe(results[1].inheritedProtoView);
|
||||
expect(results[2].inheritedProtoView).toBe(results[3].inheritedProtoView);
|
||||
});
|
||||
|
||||
it('should inherit elementBinderBuilders to children', () => {
|
||||
var element = el('<div bind><div><span bind><span></span></span></div></div>');
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(DOM.getAttribute(current.element, 'bind'))) {
|
||||
current.bindElement();
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedElementBinder).toBe(results[1].inheritedElementBinder);
|
||||
expect(results[2].inheritedElementBinder).toBe(results[3].inheritedElementBinder);
|
||||
});
|
||||
|
||||
it('should mark root elements as viewRoot', () => {
|
||||
var rootElement = el('<div></div>');
|
||||
var results = new CompilePipeline([])
|
||||
.processElements(rootElement, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should calculate distanceToParent / parent correctly', () => {
|
||||
var element = el('<div bind><div bind></div><div><div bind></div></div></div>');
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(DOM.getAttribute(current.element, 'bind'))) {
|
||||
current.bindElement();
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedElementBinder.distanceToParent).toBe(0);
|
||||
expect(results[1].inheritedElementBinder.distanceToParent).toBe(1);
|
||||
expect(results[3].inheritedElementBinder.distanceToParent).toBe(2);
|
||||
expect(results[1].inheritedElementBinder.parent).toBe(results[0].inheritedElementBinder);
|
||||
expect(results[3].inheritedElementBinder.parent).toBe(results[0].inheritedElementBinder);
|
||||
});
|
||||
|
||||
it('should not execute further steps when ignoreCurrentElement has been called', () => {
|
||||
var element = el('<div id="1"><span id="2" ignore-current></span><span id="3"></span></div>');
|
||||
var logs = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
new IgnoreCurrentElementStep(),
|
||||
createLoggerStep(logs),
|
||||
]);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(results.length).toBe(2);
|
||||
expect(logs).toEqual(['1', '1<3'])
|
||||
});
|
||||
|
||||
describe('control.addParent', () => {
|
||||
it('should report the new parent to the following processor and the result', () => {
|
||||
var element = el('<div id="1"><span wrap0="1" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var pipeline =
|
||||
new CompilePipeline([createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', '2', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add a parent by multiple processors to the same element', () => {
|
||||
var element =
|
||||
el('<div id="1"><span wrap0="1" wrap1="1" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var step2Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap1#0', 'wrap1#0<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', 'wrap1#0', '2', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add a parent by multiple processors to different elements', () => {
|
||||
var element =
|
||||
el('<div id="1"><span wrap0="1" id="2"><b id="3" wrap1="1"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var step2Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<wrap1#0', 'wrap1#0<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', '2', 'wrap1#0', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add multiple parents by the same processor', () => {
|
||||
var element = el('<div id="1"><span wrap0="2" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var pipeline =
|
||||
new CompilePipeline([createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap0#1', 'wrap0#1<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', 'wrap0#1', '2', '3']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('control.addChild', () => {
|
||||
it('should report the new child to all processors and the result', () => {
|
||||
var element = el('<div id="1"><div id="2"></div></div>');
|
||||
var resultLog = [];
|
||||
var newChild = new CompileElement(el('<div id="3"></div>'));
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (StringWrapper.equals(DOM.getAttribute(current.element, 'id'), '1')) {
|
||||
control.addChild(newChild);
|
||||
}
|
||||
}),
|
||||
createLoggerStep(resultLog)
|
||||
]);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(result[2]).toBe(newChild);
|
||||
expect(resultLog).toEqual(['1', '1<2', '1<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('processStyles', () => {
|
||||
it('should call the steps for every style', () => {
|
||||
var stepCalls = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep(null,
|
||||
(style) => {
|
||||
stepCalls.push(style);
|
||||
return style;
|
||||
})
|
||||
]);
|
||||
var result = pipeline.processStyles(['a', 'b']);
|
||||
expect(result[0]).toEqual('a');
|
||||
expect(result[1]).toEqual('b');
|
||||
expect(result).toEqual(stepCalls);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
export class MockStep implements CompileStep {
|
||||
constructor(private _processElementClosure: Function,
|
||||
private _processStyleClosure: Function = null) {}
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
if (isPresent(this._processElementClosure)) {
|
||||
this._processElementClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string {
|
||||
if (isPresent(this._processStyleClosure)) {
|
||||
return this._processStyleClosure(style);
|
||||
} else {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class IgnoreChildrenStep implements CompileStep {
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attributeMap = DOM.attributeMap(current.element);
|
||||
if (attributeMap.has('ignore-children')) {
|
||||
current.compileChildren = false;
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string { return style; }
|
||||
}
|
||||
|
||||
class IgnoreCurrentElementStep implements CompileStep {
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attributeMap = DOM.attributeMap(current.element);
|
||||
if (attributeMap.has('ignore-current')) {
|
||||
control.ignoreCurrentElement();
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string { return style; }
|
||||
}
|
||||
|
||||
function logEntry(log: string[], parent, current) {
|
||||
var parentId = '';
|
||||
if (isPresent(parent)) {
|
||||
parentId = DOM.getAttribute(parent.element, 'id') + '<';
|
||||
}
|
||||
log.push(parentId + DOM.getAttribute(current.element, 'id'));
|
||||
}
|
||||
|
||||
function createLoggerStep(log: string[]) {
|
||||
return new MockStep((parent, current, control) => { logEntry(log, parent, current); });
|
||||
}
|
||||
|
||||
function createWrapperStep(wrapperId, log) {
|
||||
var nextElementId = 0;
|
||||
return new MockStep((parent, current, control) => {
|
||||
var parentCountStr = DOM.getAttribute(current.element, wrapperId);
|
||||
if (isPresent(parentCountStr)) {
|
||||
var parentCount = NumberWrapper.parseInt(parentCountStr, 10);
|
||||
while (parentCount > 0) {
|
||||
control.addParent(new CompileElement(el(`<a id="${wrapperId}#${nextElementId++}"></a>`)));
|
||||
parentCount--;
|
||||
}
|
||||
}
|
||||
logEntry(log, parent, current);
|
||||
});
|
||||
}
|
||||
|
||||
function resultIdLog(result) {
|
||||
var idLog = [];
|
||||
ListWrapper.forEach(result, (current) => { logEntry(idLog, null, current); });
|
||||
return idLog;
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib';
|
||||
import {PropertyBindingParser} from 'angular2/src/core/render/dom/compiler/property_binding_parser';
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {Lexer, Parser} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {ElementBinderBuilder} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {ViewDefinition, ViewType} from 'angular2/src/core/render/api';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
var EMPTY_MAP = new Map();
|
||||
|
||||
export function main() {
|
||||
describe('PropertyBindingParser', () => {
|
||||
function createPipeline(hasNestedProtoView = false) {
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (hasNestedProtoView) {
|
||||
current.bindElement().bindNestedProtoView(el('<template></template>'));
|
||||
}
|
||||
}),
|
||||
new PropertyBindingParser(new Parser(new Lexer()))
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(element, hasNestedProtoView = false): ElementBinderBuilder[] {
|
||||
return ListWrapper.map(
|
||||
createPipeline(hasNestedProtoView)
|
||||
.processElements(element, ViewType.COMPONENT, createViewDefinition()),
|
||||
(compileElement) => compileElement.inheritedElementBinder);
|
||||
}
|
||||
|
||||
it('should detect [] syntax', () => {
|
||||
var results = process(el('<div [a]="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect [] syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-[a]="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect [] syntax only if an attribute name starts and ends with []', () => {
|
||||
expect(process(el('<div z[a]="b"></div>'))[0]).toBe(null);
|
||||
expect(process(el('<div [a]v="b"></div>'))[0]).toBe(null);
|
||||
});
|
||||
|
||||
it('should throw when [] binding contains interpolation', () => {
|
||||
expect(() => process(el('<div [a]="a + {{b()}}"></div>'))[0])
|
||||
.toThrowErrorWith(
|
||||
'Got interpolation ({{}}) where expression was expected at column 4 in [a + {{b()}}] in someComponent');
|
||||
});
|
||||
|
||||
it('should detect bind- syntax', () => {
|
||||
var results = process(el('<div bind-a="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect bind- syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-bind-a="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect bind- syntax only if an attribute name starts with bind',
|
||||
() => { expect(process(el('<div _bind-a="b"></div>'))[0]).toEqual(null); });
|
||||
|
||||
it('should detect interpolation syntax', () => {
|
||||
var results = process(el('<div a="{{b}}"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('{{b}}');
|
||||
});
|
||||
|
||||
it('should detect interpolation syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-a="{{b}}"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('{{b}}');
|
||||
});
|
||||
|
||||
it('should store property setters as camel case', () => {
|
||||
var element = el('<div bind-some-prop="1">');
|
||||
var results = process(element);
|
||||
expect(results[0].propertyBindings.get('someProp')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should detect var- syntax', () => {
|
||||
var results = process(el('<template var-a="b"></template>'));
|
||||
expect(results[0].variableBindings.get('b')).toEqual('a');
|
||||
});
|
||||
|
||||
it('should detect var- syntax with data- prefix', () => {
|
||||
var results = process(el('<template data-var-a="b"></template>'));
|
||||
expect(results[0].variableBindings.get('b')).toEqual('a');
|
||||
});
|
||||
|
||||
it('should store variable binding for a template element on the nestedProtoView', () => {
|
||||
var results = process(el('<template var-george="washington"></p>'), true);
|
||||
expect(results[0].variableBindings).toEqual(EMPTY_MAP);
|
||||
expect(results[0].nestedProtoView.variableBindings.get('washington')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should store variable binding for a non-template element using shorthand syntax on the nestedProtoView',
|
||||
() => {
|
||||
var results = process(el('<template #george="washington"></template>'), true);
|
||||
expect(results[0].variableBindings).toEqual(EMPTY_MAP);
|
||||
expect(results[0].nestedProtoView.variableBindings.get('washington')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should store variable binding for a non-template element', () => {
|
||||
var results = process(el('<p var-george="washington"></p>'));
|
||||
expect(results[0].variableBindings.get('washington')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should store variable binding for a non-template element using shorthand syntax', () => {
|
||||
var results = process(el('<p #george="washington"></p>'));
|
||||
expect(results[0].variableBindings.get('washington')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should store a variable binding with an implicit value', () => {
|
||||
var results = process(el('<p var-george></p>'));
|
||||
expect(results[0].variableBindings.get('\$implicit')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should store a variable binding with an implicit value using shorthand syntax', () => {
|
||||
var results = process(el('<p #george></p>'));
|
||||
expect(results[0].variableBindings.get('\$implicit')).toEqual('george');
|
||||
});
|
||||
|
||||
it('should detect variable bindings only if an attribute name starts with #', () => {
|
||||
var results = process(el('<p b#george></p>'));
|
||||
expect(results[0]).toEqual(null);
|
||||
});
|
||||
|
||||
it('should detect () syntax', () => {
|
||||
var results = process(el('<div (click)="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
// "(click[])" is not an expected syntax and is only used to validate the regexp
|
||||
results = process(el('<div (click[])="b()"></div>'));
|
||||
eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click[]');
|
||||
});
|
||||
|
||||
it('should detect () syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-(click)="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should detect () syntax only if an attribute name starts and ends with ()', () => {
|
||||
expect(process(el('<div z(a)="b()"></div>'))[0]).toEqual(null);
|
||||
expect(process(el('<div (a)v="b()"></div>'))[0]).toEqual(null);
|
||||
});
|
||||
|
||||
it('should parse event handlers using () syntax as actions', () => {
|
||||
var results = process(el('<div (click)="foo=bar"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('foo=bar');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should throw when () action contains interpolation', () => {
|
||||
expect(() => process(el('<div (a)="{{b()}}"></div>'))[0])
|
||||
.toThrowErrorWith(
|
||||
'Got interpolation ({{}}) where expression was expected at column 0 in [{{b()}}] in someComponent');
|
||||
});
|
||||
|
||||
it('should detect on- syntax', () => {
|
||||
var results = process(el('<div on-click="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should detect on- syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-on-click="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should parse event handlers using on- syntax as actions', () => {
|
||||
var results = process(el('<div on-click="foo=bar"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('foo=bar');
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should store bound properties as temporal attributes', () => {
|
||||
var results = createPipeline().processElements(el('<div bind-a="b" [c]="d"></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].attrs().get('a')).toEqual('b');
|
||||
expect(results[0].attrs().get('c')).toEqual('d');
|
||||
});
|
||||
|
||||
it('should store variables as temporal attributes', () => {
|
||||
var results = createPipeline().processElements(el('<div var-a="b" #c="d"></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].attrs().get('a')).toEqual('b');
|
||||
expect(results[0].attrs().get('c')).toEqual('d');
|
||||
});
|
||||
|
||||
it('should detect [()] syntax', () => {
|
||||
var results = process(el('<div [(a)]="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
expect(results[0].eventBindings[0].source.source).toEqual('b=$event');
|
||||
});
|
||||
|
||||
it('should detect [()] syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-[(a)]="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
expect(results[0].eventBindings[0].source.source).toEqual('b=$event');
|
||||
});
|
||||
|
||||
it('should detect bindon- syntax', () => {
|
||||
var results = process(el('<div bindon-a="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
expect(results[0].eventBindings[0].source.source).toEqual('b=$event');
|
||||
});
|
||||
|
||||
it('should detect bindon- syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-bindon-a="b"></div>'));
|
||||
expect(results[0].propertyBindings.get('a').source).toEqual('b');
|
||||
expect(results[0].eventBindings[0].source.source).toEqual('b=$event');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {
|
||||
ProtoViewBuilder,
|
||||
ElementBinderBuilder
|
||||
} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {ViewDefinition, ViewType, ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
|
||||
import {StyleEncapsulator} from 'angular2/src/core/render/dom/compiler/style_encapsulator';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function main() {
|
||||
describe('StyleEncapsulator', () => {
|
||||
var componentIdCache;
|
||||
|
||||
beforeEach(() => { componentIdCache = new Map(); });
|
||||
|
||||
function createPipeline(viewDef: ViewDefinition) {
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
var tagName = DOM.tagName(current.element).toLowerCase();
|
||||
if (tagName.startsWith('comp-')) {
|
||||
current.bindElement().setComponentId(tagName);
|
||||
}
|
||||
}),
|
||||
new StyleEncapsulator('someapp', viewDef, componentIdCache)
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(encapsulation: ViewEncapsulation, componentId: string):
|
||||
ViewDefinition {
|
||||
return new ViewDefinition({encapsulation: encapsulation, componentId: componentId});
|
||||
}
|
||||
|
||||
function processStyles(encapsulation: ViewEncapsulation, componentId: string, styles: string[]):
|
||||
string[] {
|
||||
var viewDef = createViewDefinition(encapsulation, componentId);
|
||||
return createPipeline(viewDef).processStyles(styles);
|
||||
}
|
||||
|
||||
function processElements(encapsulation: ViewEncapsulation, componentId: string,
|
||||
template: Element, viewType: ViewType = ViewType.COMPONENT):
|
||||
ProtoViewBuilder {
|
||||
var viewDef = createViewDefinition(encapsulation, componentId);
|
||||
var compileElements = createPipeline(viewDef).processElements(template, viewType, viewDef);
|
||||
return compileElements[0].inheritedProtoView;
|
||||
}
|
||||
|
||||
describe('ViewEncapsulation.None', () => {
|
||||
it('should not change the styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.None, 'someComponent', ['.one {}']);
|
||||
expect(cs[0]).toEqual('.one {}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ViewEncapsulation.Native', () => {
|
||||
it('should not change the styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.Native, 'someComponent', ['.one {}']);
|
||||
expect(cs[0]).toEqual('.one {}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ViewEncapsulation.Emulated', () => {
|
||||
it('should scope styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.Emulated, 'someComponent', ['.foo {} :host {}']);
|
||||
expect(cs[0]).toEqual(".foo[_ngcontent-someapp-0] {\n\n}\n\n[_nghost-someapp-0] {\n\n}");
|
||||
});
|
||||
|
||||
it('should return the same style given the same component', () => {
|
||||
var style = '.foo {} :host {}';
|
||||
var cs1 = processStyles(ViewEncapsulation.Emulated, 'someComponent', [style]);
|
||||
var cs2 = processStyles(ViewEncapsulation.Emulated, 'someComponent', [style]);
|
||||
|
||||
expect(cs1[0]).toEqual(cs2[0]);
|
||||
});
|
||||
|
||||
it('should return different styles given different components', () => {
|
||||
var style = '.foo {} :host {}';
|
||||
var cs1 = processStyles(ViewEncapsulation.Emulated, 'someComponent1', [style]);
|
||||
var cs2 = processStyles(ViewEncapsulation.Emulated, 'someComponent2', [style]);
|
||||
|
||||
expect(cs1[0]).not.toEqual(cs2[0]);
|
||||
});
|
||||
|
||||
it('should add a host attribute to component proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder =
|
||||
processElements(ViewEncapsulation.Emulated, 'someComponent', template);
|
||||
expect(protoViewBuilder.hostAttributes.get('_nghost-someapp-0')).toEqual('');
|
||||
});
|
||||
|
||||
it('should not add a host attribute to embedded proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder = processElements(ViewEncapsulation.Emulated, 'someComponent',
|
||||
template, ViewType.EMBEDDED);
|
||||
expect(protoViewBuilder.hostAttributes.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should not add a host attribute to host proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder =
|
||||
processElements(ViewEncapsulation.Emulated, 'someComponent', template, ViewType.HOST);
|
||||
expect(protoViewBuilder.hostAttributes.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should add an attribute to the content elements', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
processElements(ViewEncapsulation.Emulated, 'someComponent', template);
|
||||
expect(DOM.getInnerHTML(template)).toEqual('<div _ngcontent-someapp-0=""></div>');
|
||||
});
|
||||
|
||||
it('should not add an attribute to the content elements for host views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
processElements(ViewEncapsulation.Emulated, 'someComponent', template, ViewType.HOST);
|
||||
expect(DOM.getInnerHTML(template)).toEqual('<div></div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
beforeEachBindings,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {StyleInliner} from 'angular2/src/core/render/dom/compiler/style_inliner';
|
||||
|
||||
import {isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||
import {Map, MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
|
||||
import {bind} from 'angular2/core';
|
||||
|
||||
export function main() {
|
||||
describe('StyleInliner', () => {
|
||||
beforeEachBindings(() => [
|
||||
bind(XHR)
|
||||
.toClass(FakeXHR),
|
||||
]);
|
||||
|
||||
describe('loading', () => {
|
||||
|
||||
it('should return a string when there is no import statement',
|
||||
inject([StyleInliner], (inliner) => {
|
||||
var css = '.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toEqual(css);
|
||||
}));
|
||||
|
||||
it('should inline @import rules',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
var css = '@import url("one.css");.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('.one {}\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should support url([unquoted url]) in @import rules',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
var css = '@import url(one.css);.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('.one {}\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should handle @import error gracefuly',
|
||||
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should inline multiple @import rules',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
xhr.reply('http://base/two.css', '.two {}');
|
||||
var css = '@import "one.css";@import "two.css";.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('.one {}\n.two {}\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should inline nested @import rules',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('http://base/two.css', '.two {}');
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('.two {}\n.one {}\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should handle circular dependencies gracefuly',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('.two {}\n.one {}\n.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
|
||||
it('should handle invalid @import fracefuly',
|
||||
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
|
||||
// Invalid rule: the url is not quoted
|
||||
var css = '@import one.css;.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
});
|
||||
|
||||
describe('media query', () => {
|
||||
it('should wrap inlined content in media query',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual(
|
||||
'@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
});
|
||||
|
||||
describe('url rewritting', () => {
|
||||
it('should rewrite url in inlined content',
|
||||
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
|
||||
// it should rewrite both '@import' and 'url()'
|
||||
xhr.reply('http://base/one.css',
|
||||
'@import "./nested/two.css";.one {background-image: url("one.jpg");}');
|
||||
xhr.reply('http://base/nested/two.css',
|
||||
'.two {background-image: url("../img/two.jpg");}');
|
||||
var css = '@import "one.css";';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
function(css) {
|
||||
expect(css).toEqual(".two {background-image: url('http://base/img/two.jpg');}\n" +
|
||||
".one {background-image: url('http://base/one.jpg');}\n");
|
||||
async.done();
|
||||
},
|
||||
function(e) { throw 'fail;' });
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeXHR extends XHR {
|
||||
_responses = new Map<string, string>();
|
||||
|
||||
constructor() { super(); }
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
var response = this._responses.get(url);
|
||||
if (isBlank(response)) {
|
||||
return PromiseWrapper.reject('xhr error', null);
|
||||
}
|
||||
|
||||
return PromiseWrapper.resolve(response);
|
||||
}
|
||||
|
||||
reply(url: string, response: string) { this._responses.set(url, response); }
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
|
||||
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
|
||||
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
|
||||
export function main() {
|
||||
describe('StyleUrlResolver', () => {
|
||||
let styleUrlResolver;
|
||||
|
||||
beforeEach(() => { styleUrlResolver = new StyleUrlResolver(new UrlResolver()); });
|
||||
|
||||
it('should resolve "url()" urls', () => {
|
||||
var css = `
|
||||
.foo {
|
||||
background-image: url("double.jpg");
|
||||
background-image: url('simple.jpg');
|
||||
background-image: url(noquote.jpg);
|
||||
}`;
|
||||
var expectedCss = `
|
||||
.foo {
|
||||
background-image: url('http://ng.io/double.jpg');
|
||||
background-image: url('http://ng.io/simple.jpg');
|
||||
background-image: url('http://ng.io/noquote.jpg');
|
||||
}`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'http://ng.io');
|
||||
expect(resolvedCss).toEqual(expectedCss);
|
||||
});
|
||||
|
||||
it('should resolve "@import" urls', () => {
|
||||
var css = `
|
||||
@import '1.css';
|
||||
@import "2.css";
|
||||
`;
|
||||
var expectedCss = `
|
||||
@import 'http://ng.io/1.css';
|
||||
@import 'http://ng.io/2.css';
|
||||
`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'http://ng.io');
|
||||
expect(resolvedCss).toEqual(expectedCss);
|
||||
});
|
||||
|
||||
it('should resolve "@import url()" urls', () => {
|
||||
var css = `
|
||||
@import url('3.css');
|
||||
@import url("4.css");
|
||||
@import url(5.css);
|
||||
`;
|
||||
var expectedCss = `
|
||||
@import url('http://ng.io/3.css');
|
||||
@import url('http://ng.io/4.css');
|
||||
@import url('http://ng.io/5.css');
|
||||
`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'http://ng.io');
|
||||
expect(resolvedCss).toEqual(expectedCss);
|
||||
});
|
||||
|
||||
it('should support media query in "@import"', () => {
|
||||
var css = `
|
||||
@import 'print.css' print;
|
||||
@import url(print.css) print;
|
||||
`;
|
||||
var expectedCss = `
|
||||
@import 'http://ng.io/print.css' print;
|
||||
@import url('http://ng.io/print.css') print;
|
||||
`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'http://ng.io');
|
||||
expect(resolvedCss).toEqual(expectedCss);
|
||||
});
|
||||
|
||||
it('should not strip quotes from inlined SVG styles', () => {
|
||||
var css = `
|
||||
.selector {
|
||||
background:rgb(55,71,79) url('data:image/svg+xml;utf8,<?xml version="1.0"?>');
|
||||
background:rgb(55,71,79) url("data:image/svg+xml;utf8,<?xml version='1.0'?>");
|
||||
background:rgb(55,71,79) url("/some/data:image");
|
||||
}
|
||||
`;
|
||||
|
||||
var expectedCss = `
|
||||
.selector {
|
||||
background:rgb(55,71,79) url('data:image/svg+xml;utf8,<?xml version="1.0"?>');
|
||||
background:rgb(55,71,79) url("data:image/svg+xml;utf8,<?xml version='1.0'?>");
|
||||
background:rgb(55,71,79) url('http://ng.io/some/data:image');
|
||||
}
|
||||
`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'http://ng.io');
|
||||
expect(resolvedCss).toEqual(expectedCss);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import {describe, beforeEach, expect, it, iit, ddescribe, el} from 'angular2/test_lib';
|
||||
import {
|
||||
TextInterpolationParser
|
||||
} from 'angular2/src/core/render/dom/compiler/text_interpolation_parser';
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {Lexer, Parser, ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {IgnoreChildrenStep} from './pipeline_spec';
|
||||
import {
|
||||
ProtoViewBuilder,
|
||||
ElementBinderBuilder
|
||||
} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {ViewDefinition, ViewType} from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('TextInterpolationParser', () => {
|
||||
function createPipeline() {
|
||||
return new CompilePipeline(
|
||||
[new IgnoreChildrenStep(), new TextInterpolationParser(new Parser(new Lexer()))]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(templateString: string): ProtoViewBuilder {
|
||||
var compileElements = createPipeline().processElements(
|
||||
DOM.createTemplate(templateString), ViewType.COMPONENT, createViewDefinition());
|
||||
return compileElements[0].inheritedProtoView;
|
||||
}
|
||||
|
||||
function assertRootTextBinding(protoViewBuilder: ProtoViewBuilder, nodeIndex: number,
|
||||
expression: string) {
|
||||
var node = DOM.childNodes(DOM.templateAwareRoot(protoViewBuilder.rootElement))[nodeIndex];
|
||||
expect(protoViewBuilder.rootTextBindings.get(node).source).toEqual(expression);
|
||||
}
|
||||
|
||||
function assertElementTextBinding(elementBinderBuilder: ElementBinderBuilder, nodeIndex: number,
|
||||
expression: string) {
|
||||
var node = DOM.childNodes(DOM.templateAwareRoot(elementBinderBuilder.element))[nodeIndex];
|
||||
expect(elementBinderBuilder.textBindings.get(node).source).toEqual(expression);
|
||||
}
|
||||
|
||||
it('should find root text interpolations', () => {
|
||||
var result = process('{{expr1}}{{expr2}}<div></div>{{expr3}}');
|
||||
assertRootTextBinding(result, 0, "{{expr1}}{{expr2}}");
|
||||
assertRootTextBinding(result, 2, "{{expr3}}");
|
||||
});
|
||||
|
||||
it('should find text interpolation in normal elements', () => {
|
||||
var result = process('<div>{{expr1}}<span></span>{{expr2}}</div>');
|
||||
assertElementTextBinding(result.elements[0], 0, "{{expr1}}");
|
||||
assertElementTextBinding(result.elements[0], 2, "{{expr2}}");
|
||||
});
|
||||
|
||||
it('should allow multiple expressions', () => {
|
||||
var result = process('<div>{{expr1}}{{expr2}}</div>');
|
||||
assertElementTextBinding(result.elements[0], 0, "{{expr1}}{{expr2}}");
|
||||
});
|
||||
|
||||
it('should not interpolate when compileChildren is false', () => {
|
||||
var results = process('<div>{{included}}<span ignore-children>{{excluded}}</span></div>');
|
||||
assertElementTextBinding(results.elements[0], 0, "{{included}}");
|
||||
expect(results.elements.length).toBe(1);
|
||||
expect(results.elements[0].textBindings.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should allow fixed text before, in between and after expressions', () => {
|
||||
var result = process('<div>a{{expr1}}b{{expr2}}c</div>');
|
||||
assertElementTextBinding(result.elements[0], 0, "a{{expr1}}b{{expr2}}c");
|
||||
});
|
||||
|
||||
it('should escape quotes in fixed parts', () => {
|
||||
var result = process("<div>'\"a{{expr1}}</div>");
|
||||
assertElementTextBinding(result.elements[0], 0, "'\"a{{expr1}}");
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {ViewLoader, TemplateAndStyles} from 'angular2/src/core/render/dom/compiler/view_loader';
|
||||
import {StyleInliner} from 'angular2/src/core/render/dom/compiler/style_inliner';
|
||||
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {MockXHR} from 'angular2/src/core/render/xhr_mock';
|
||||
import {ViewDefinition} from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('ViewLoader', () => {
|
||||
var loader: ViewLoader;
|
||||
var xhr, styleUrlResolver, urlResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
xhr = new MockXHR();
|
||||
urlResolver = new UrlResolver();
|
||||
styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
|
||||
});
|
||||
|
||||
describe('html', () => {
|
||||
it('should load inline templates', inject([AsyncTestCompleter], (async) => {
|
||||
loader.load(new ViewDefinition({template: 'template template'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('template template');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', 'xhr template');
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('xhr template');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve urls in styles', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html',
|
||||
'<style>.foo { background-image: url("double.jpg"); }</style>');
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('');
|
||||
expect(el.styles)
|
||||
.toEqual([".foo { background-image: url('http://ng.io/double.jpg'); }"]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
let xhr = new FakeXHR();
|
||||
xhr.reply('http://ng.io/foo.html', '<style>@import "foo.css";</style>');
|
||||
xhr.reply('http://ng.io/foo.css', '/* foo.css */');
|
||||
|
||||
let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
let loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
|
||||
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('');
|
||||
expect(el.styles).toEqual(["/* foo.css */\n"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should throw when no template is defined', () => {
|
||||
expect(() => loader.load(new ViewDefinition(
|
||||
{componentId: 'TestComponent', template: null, templateAbsUrl: null})))
|
||||
.toThrowError(
|
||||
'View should have either the templateUrl or template property set but none was found for the \'TestComponent\' component');
|
||||
});
|
||||
|
||||
it('should return a rejected Promise when XHR loading fails',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', null);
|
||||
PromiseWrapper.then(
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'})),
|
||||
function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message).toEqual('Failed to fetch url "http://ng.io/foo.html"');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should replace $baseUrl in attributes with the template base url',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/path/foo.html', '<img src="$baseUrl/logo.png">');
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/path/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('<img src="http://ng.io/path/logo.png">');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('css', () => {
|
||||
it('should load inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
loader.load(new ViewDefinition({template: 'html', styles: ['style 1', 'style 2']}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('html');
|
||||
expect(el.styles).toEqual(['style 1', 'style 2']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve urls in inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', 'html');
|
||||
loader.load(new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['.foo { background-image: url("double.jpg"); }']
|
||||
}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('html');
|
||||
expect(el.styles)
|
||||
.toEqual([".foo { background-image: url('http://ng.io/double.jpg'); }"]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', 'xhr template');
|
||||
xhr.expect('http://ng.io/foo-1.css', '1');
|
||||
xhr.expect('http://ng.io/foo-2.css', '2');
|
||||
loader.load(new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['i1'],
|
||||
styleAbsUrls: ['http://ng.io/foo-1.css', 'http://ng.io/foo-2.css']
|
||||
}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('xhr template');
|
||||
expect(el.styles).toEqual(['i1', '1', '2']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
let xhr = new FakeXHR();
|
||||
xhr.reply('http://ng.io/foo.html', '<p>template</p>');
|
||||
xhr.reply('http://ng.io/foo.css', '/* foo.css */');
|
||||
|
||||
let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
let loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
|
||||
|
||||
loader.load(
|
||||
new ViewDefinition(
|
||||
{templateAbsUrl: 'http://ng.io/foo.html', styles: ['@import "foo.css";']}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual("<p>template</p>");
|
||||
expect(el.styles).toEqual(["/* foo.css */\n"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should return a rejected Promise when XHR loading fails',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.css', null);
|
||||
PromiseWrapper.then(
|
||||
loader.load(
|
||||
new ViewDefinition({template: '', styleAbsUrls: ['http://ng.io/foo.css']})),
|
||||
function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message).toEqual('Failed to fetch url "http://ng.io/foo.css"');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class SomeComponent {}
|
||||
|
||||
class FakeXHR extends XHR {
|
||||
_responses = new Map<string, string>();
|
||||
|
||||
constructor() { super(); }
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
return this._responses.has(url) ? PromiseWrapper.resolve(this._responses.get(url)) :
|
||||
PromiseWrapper.reject('xhr error', null);
|
||||
}
|
||||
|
||||
reply(url: string, response: string): void { this._responses.set(url, response); }
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
import {
|
||||
describe,
|
||||
beforeEach,
|
||||
it,
|
||||
expect,
|
||||
iit,
|
||||
ddescribe,
|
||||
el,
|
||||
stringifyElement
|
||||
} from 'angular2/test_lib';
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
import {ViewSplitter} from 'angular2/src/core/render/dom/compiler/view_splitter';
|
||||
import {CompilePipeline} from 'angular2/src/core/render/dom/compiler/compile_pipeline';
|
||||
import {CompileElement} from 'angular2/src/core/render/dom/compiler/compile_element';
|
||||
import {ProtoViewDto, ViewType, ViewDefinition} from 'angular2/src/core/render/api';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
|
||||
import {Lexer, Parser} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe('ViewSplitter', () => {
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function createPipeline() {
|
||||
return new CompilePipeline([new ViewSplitter(new Parser(new Lexer()))]);
|
||||
}
|
||||
|
||||
function proceess(el): CompileElement[] {
|
||||
return createPipeline().processElements(el, ViewType.COMPONENT, createViewDefinition());
|
||||
}
|
||||
|
||||
describe('<template> elements', () => {
|
||||
|
||||
it('should move the content into a new <template> element and mark that as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(stringifyElement(results[1].element))
|
||||
.toEqual('<template class="ng-binding" if="true"></template>');
|
||||
expect(results[1].isViewRoot).toBe(false);
|
||||
expect(stringifyElement(results[2].element)).toEqual('<template>a</template>');
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should mark the new <template> element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should not wrap the root element', () => {
|
||||
var rootElement = DOM.createTemplate('');
|
||||
var results = proceess(rootElement);
|
||||
expect(results.length).toBe(1);
|
||||
expect(stringifyElement(rootElement)).toEqual('<template></template>');
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
expect(results[2].inheritedProtoView.type).toBe(ViewType.EMBEDDED);
|
||||
expect(stringifyElement(results[2].inheritedProtoView.rootElement))
|
||||
.toEqual('<template>a</template>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('elements with template attribute', () => {
|
||||
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var originalChild = DOM.firstChild(DOM.content(rootElement));
|
||||
var results = proceess(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding"></template></template>');
|
||||
expect(stringifyElement(results[2].element))
|
||||
.toEqual('<template><span template=""></span></template>');
|
||||
expect(DOM.firstChild(DOM.content(results[2].element))).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div template>x</div>');
|
||||
var originalChild = DOM.content(rootElement).childNodes[0];
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding"></template></template>');
|
||||
expect(DOM.firstChild(DOM.content(results[2].element))).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<div template></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="some-prop:expr"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].inheritedElementBinder.propertyBindings.get('someProp').source)
|
||||
.toEqual('expr');
|
||||
expect(results[1].attrs().get('some-prop')).toEqual('expr');
|
||||
});
|
||||
|
||||
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="var var-name=mapName"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attributes to the element', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="varname"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].attrs().get('varname')).toEqual('');
|
||||
expect(results[1].inheritedElementBinder.propertyBindings).toEqual(new Map());
|
||||
expect(results[1].inheritedElementBinder.variableBindings).toEqual(new Map());
|
||||
});
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = DOM.createTemplate('<div template></div><after></after>');
|
||||
var results = proceess(rootElement);
|
||||
// 1 root + 2 initial + 2 generated template elements
|
||||
expect(results.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
expect(stringifyElement(results[2].inheritedProtoView.rootElement))
|
||||
.toEqual('<template><span template=""></span></template>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('elements with *directive_name attribute', () => {
|
||||
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = DOM.createTemplate('<span *ng-if></span>');
|
||||
var originalChild = DOM.firstChild(DOM.content(rootElement));
|
||||
var results = proceess(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding" ng-if=""></template></template>');
|
||||
expect(stringifyElement(results[2].element))
|
||||
.toEqual('<template><span *ng-if=""></span></template>');
|
||||
expect(DOM.firstChild(DOM.content(results[2].element))).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo="bar"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo>x</div>');
|
||||
var originalChild = DOM.content(rootElement).childNodes[0];
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding" foo=""></template></template>');
|
||||
expect(DOM.firstChild(DOM.content(results[2].element))).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = DOM.createTemplate('<div *prop="expr"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].inheritedElementBinder.propertyBindings.get('prop').source)
|
||||
.toEqual('expr');
|
||||
expect(results[1].attrs().get('prop')).toEqual('expr');
|
||||
});
|
||||
|
||||
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foreach="var varName=mapName"></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attribute to the element', () => {
|
||||
var rootElement = DOM.createTemplate('<div *varname></div>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].attrs().get('varname')).toEqual('');
|
||||
expect(results[1].inheritedElementBinder.propertyBindings).toEqual(new Map());
|
||||
expect(results[1].inheritedElementBinder.variableBindings).toEqual(new Map());
|
||||
});
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo></div><after></after>');
|
||||
var results = proceess(rootElement);
|
||||
// 1 root + 2 initial + 2 generated template elements
|
||||
expect(results.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
expect(stringifyElement(results[2].inheritedProtoView.rootElement))
|
||||
.toEqual('<template><span *foo=""></span></template>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
import {Inject, Injectable} from 'angular2/core';
|
||||
import {isPresent} from 'angular2/src/core/facade/lang';
|
||||
import {MapWrapper, ListWrapper, Map} from 'angular2/src/core/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
|
||||
import {DomRenderer} from 'angular2/src/core/render/dom/dom_renderer';
|
||||
import {DOCUMENT} from 'angular2/src/core/render/dom/dom_tokens';
|
||||
import {DefaultDomCompiler} from 'angular2/src/core/render/dom/compiler/compiler';
|
||||
import {
|
||||
RenderViewWithFragments,
|
||||
RenderFragmentRef,
|
||||
RenderViewRef,
|
||||
ProtoViewDto,
|
||||
ViewDefinition,
|
||||
RenderEventDispatcher,
|
||||
RenderDirectiveMetadata,
|
||||
RenderElementRef,
|
||||
RenderProtoViewMergeMapping,
|
||||
RenderProtoViewRef
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {resolveInternalDomView} from 'angular2/src/core/render/dom/view/view';
|
||||
import {resolveInternalDomFragment} from 'angular2/src/core/render/dom/view/fragment';
|
||||
import {el, dispatchEvent} from 'angular2/test_lib';
|
||||
|
||||
export class TestRootView {
|
||||
viewRef: RenderViewRef;
|
||||
fragments: RenderFragmentRef[];
|
||||
hostElement: Element;
|
||||
events: any[][];
|
||||
|
||||
constructor(viewWithFragments: RenderViewWithFragments) {
|
||||
this.viewRef = viewWithFragments.viewRef;
|
||||
this.fragments = viewWithFragments.fragmentRefs;
|
||||
this.hostElement = <Element>resolveInternalDomFragment(this.fragments[0])[0];
|
||||
this.events = [];
|
||||
}
|
||||
}
|
||||
|
||||
export class TestRenderElementRef implements RenderElementRef {
|
||||
constructor(public renderView: RenderViewRef, public renderBoundElementIndex: number) {}
|
||||
}
|
||||
|
||||
export function elRef(renderView: RenderViewRef, boundElementIndex: number) {
|
||||
return new TestRenderElementRef(renderView, boundElementIndex);
|
||||
}
|
||||
|
||||
export function rootNodes(view: RenderViewRef) {}
|
||||
|
||||
class LoggingEventDispatcher implements RenderEventDispatcher {
|
||||
log: any[][];
|
||||
|
||||
constructor(log: any[][]) { this.log = log; }
|
||||
|
||||
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>): boolean {
|
||||
this.log.push([elementIndex, eventName, locals]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class DomTestbed {
|
||||
renderer: DomRenderer;
|
||||
compiler: DefaultDomCompiler;
|
||||
rootEl;
|
||||
|
||||
constructor(renderer: DomRenderer, compiler: DefaultDomCompiler, @Inject(DOCUMENT) document) {
|
||||
this.renderer = renderer;
|
||||
this.compiler = compiler;
|
||||
this.rootEl = el('<div id="root" class="rootElem"></div>');
|
||||
var oldRoots = DOM.querySelectorAll(document, '#root');
|
||||
for (var i = 0; i < oldRoots.length; i++) {
|
||||
DOM.remove(oldRoots[i]);
|
||||
}
|
||||
DOM.appendChild(DOM.querySelector(document, 'body'), this.rootEl);
|
||||
}
|
||||
|
||||
compile(host: RenderDirectiveMetadata,
|
||||
componentViews: ViewDefinition[]): Promise<ProtoViewDto[]> {
|
||||
var promises = [this.compiler.compileHost(host)];
|
||||
componentViews.forEach(view => promises.push(this.compiler.compile(view)));
|
||||
return PromiseWrapper.all(promises);
|
||||
}
|
||||
|
||||
merge(protoViews:
|
||||
Array<ProtoViewDto | RenderProtoViewRef>): Promise<RenderProtoViewMergeMapping> {
|
||||
return this.compiler.mergeProtoViewsRecursively(collectMergeRenderProtoViewsRecurse(
|
||||
<ProtoViewDto>protoViews[0], ListWrapper.slice(protoViews, 1)));
|
||||
}
|
||||
|
||||
compileAndMerge(host: RenderDirectiveMetadata,
|
||||
componentViews: ViewDefinition[]): Promise<RenderProtoViewMergeMapping> {
|
||||
return this.compile(host, componentViews).then(protoViewDtos => this.merge(protoViewDtos));
|
||||
}
|
||||
|
||||
_createTestView(viewWithFragments: RenderViewWithFragments) {
|
||||
var testView = new TestRootView(viewWithFragments);
|
||||
this.renderer.setEventDispatcher(viewWithFragments.viewRef,
|
||||
new LoggingEventDispatcher(testView.events));
|
||||
return testView;
|
||||
}
|
||||
|
||||
createView(protoView: RenderProtoViewMergeMapping): TestRootView {
|
||||
var viewWithFragments = this.renderer.createView(protoView.mergedProtoViewRef, 0);
|
||||
this.renderer.hydrateView(viewWithFragments.viewRef);
|
||||
return this._createTestView(viewWithFragments);
|
||||
}
|
||||
|
||||
triggerEvent(elementRef: RenderElementRef, eventName: string) {
|
||||
var element = resolveInternalDomView(elementRef.renderView)
|
||||
.boundElements[elementRef.renderBoundElementIndex];
|
||||
dispatchEvent(element, eventName);
|
||||
}
|
||||
}
|
||||
|
||||
function collectMergeRenderProtoViewsRecurse(current: ProtoViewDto,
|
||||
components: Array<ProtoViewDto | RenderProtoViewRef>):
|
||||
Array<RenderProtoViewRef | any[]> {
|
||||
var result = [current.render];
|
||||
current.elementBinders.forEach((elementBinder) => {
|
||||
if (isPresent(elementBinder.nestedProtoView)) {
|
||||
result.push(collectMergeRenderProtoViewsRecurse(elementBinder.nestedProtoView, components));
|
||||
} else if (elementBinder.directives.length > 0) {
|
||||
if (components.length > 0) {
|
||||
var comp = components.shift();
|
||||
if (comp instanceof ProtoViewDto) {
|
||||
result.push(collectMergeRenderProtoViewsRecurse(comp, components));
|
||||
} else {
|
||||
result.push(comp);
|
||||
}
|
||||
} else {
|
||||
result.push(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
beforeEachBindings,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {TemplateCloner} from 'angular2/src/core/render/dom/template_cloner';
|
||||
|
||||
export function main() {
|
||||
describe('TemplateCloner', () => {
|
||||
var cloner: TemplateCloner;
|
||||
var bigTemplate: Element;
|
||||
var smallTemplate: Element;
|
||||
|
||||
beforeEach(() => {
|
||||
cloner = new TemplateCloner(1);
|
||||
bigTemplate = DOM.createTemplate('a<div></div>');
|
||||
smallTemplate = DOM.createTemplate('a');
|
||||
});
|
||||
|
||||
describe('prepareForClone', () => {
|
||||
it('should use a reference for small templates',
|
||||
() => { expect(cloner.prepareForClone(smallTemplate)).toBe(smallTemplate); });
|
||||
|
||||
it('should use a reference if the max element count is -1', () => {
|
||||
cloner = new TemplateCloner(-1);
|
||||
expect(cloner.prepareForClone(bigTemplate)).toBe(bigTemplate);
|
||||
});
|
||||
|
||||
it('should use a string for big templates', () => {
|
||||
expect(cloner.prepareForClone(bigTemplate)).toEqual(DOM.getInnerHTML(bigTemplate));
|
||||
});
|
||||
});
|
||||
|
||||
describe('cloneTemplate', () => {
|
||||
|
||||
function shouldReturnTemplateContentNodes(template: Element, importIntoDoc: boolean) {
|
||||
var clone = cloner.cloneContent(cloner.prepareForClone(template), importIntoDoc);
|
||||
expect(clone).not.toBe(DOM.content(template));
|
||||
expect(DOM.getText(DOM.firstChild(clone))).toEqual('a');
|
||||
}
|
||||
|
||||
it('should return template.content nodes (small template, no import)',
|
||||
() => { shouldReturnTemplateContentNodes(smallTemplate, false); });
|
||||
|
||||
it('should return template.content nodes (small template, import)',
|
||||
() => { shouldReturnTemplateContentNodes(smallTemplate, true); });
|
||||
|
||||
it('should return template.content nodes (big template, no import)',
|
||||
() => { shouldReturnTemplateContentNodes(bigTemplate, false); });
|
||||
|
||||
it('should return template.content nodes (big template, import)',
|
||||
() => { shouldReturnTemplateContentNodes(bigTemplate, true); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
import {
|
||||
describe,
|
||||
ddescribe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
xdescribe,
|
||||
expect,
|
||||
beforeEach,
|
||||
el
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
DomElementSchemaRegistry
|
||||
} from 'angular2/src/core/render/dom/schema/dom_element_schema_registry';
|
||||
import {TemplateCloner} from 'angular2/src/core/render/dom/template_cloner';
|
||||
import {ProtoViewBuilder} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {ASTWithSource, AST} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {PropertyBindingType, ViewType, ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {IS_DART} from '../../../../platform';
|
||||
|
||||
export function main() {
|
||||
function emptyExpr() { return new ASTWithSource(new AST(), 'empty', 'empty'); }
|
||||
|
||||
describe('ProtoViewBuilder', () => {
|
||||
var builder;
|
||||
var templateCloner;
|
||||
beforeEach(() => {
|
||||
templateCloner = new TemplateCloner(-1);
|
||||
builder =
|
||||
new ProtoViewBuilder(DOM.createTemplate(''), ViewType.EMBEDDED, ViewEncapsulation.None);
|
||||
});
|
||||
|
||||
if (!IS_DART) {
|
||||
describe('verification of properties', () => {
|
||||
|
||||
it('should throw for unknown properties', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('unknownProperty', emptyExpr());
|
||||
expect(() => builder.build(new DomElementSchemaRegistry(), templateCloner))
|
||||
.toThrowError(
|
||||
`Can't bind to 'unknownProperty' since it isn't a known property of the '<div>' element and there are no matching directives with a corresponding property`);
|
||||
});
|
||||
|
||||
it('should allow unknown properties if a directive uses it', () => {
|
||||
var binder = builder.bindElement(el('<div/>'));
|
||||
binder.bindDirective(0).bindProperty('someDirProperty', emptyExpr(), 'directiveProperty');
|
||||
binder.bindProperty('directiveProperty', emptyExpr());
|
||||
expect(() => builder.build(new DomElementSchemaRegistry(), templateCloner)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw for unknown host properties even if another directive uses it', () => {
|
||||
var binder = builder.bindElement(el('<div/>'));
|
||||
binder.bindDirective(0).bindProperty('someDirProperty', emptyExpr(), 'someDirProperty');
|
||||
binder.bindDirective(1).bindHostProperty('someDirProperty', emptyExpr());
|
||||
expect(() => builder.build(new DomElementSchemaRegistry()))
|
||||
.toThrowError(
|
||||
`Can't bind to 'someDirProperty' since it isn't a known property of the '<div>' element`);
|
||||
});
|
||||
|
||||
it('should allow unknown properties on custom elements', () => {
|
||||
var binder = builder.bindElement(el('<some-custom/>'));
|
||||
binder.bindProperty('unknownProperty', emptyExpr());
|
||||
expect(() => builder.build(new DomElementSchemaRegistry(), templateCloner)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw for unknown properties on custom elements if there is an ng component', () => {
|
||||
var binder = builder.bindElement(el('<some-custom/>'));
|
||||
binder.bindProperty('unknownProperty', emptyExpr());
|
||||
binder.setComponentId('someComponent');
|
||||
expect(() => builder.build(new DomElementSchemaRegistry(), templateCloner))
|
||||
.toThrowError(
|
||||
`Can't bind to 'unknownProperty' since it isn't a known property of the '<some-custom>' element and there are no matching directives with a corresponding property`);
|
||||
});
|
||||
|
||||
});
|
||||
} else {
|
||||
describe('verification of properties', () => {
|
||||
|
||||
// TODO(tbosch): This is just a temporary test that makes sure that the dart server and
|
||||
// dart browser is in sync. Change this to "not contains notifyBinding"
|
||||
// when https://github.com/angular/angular/issues/3019 is solved.
|
||||
it('should not throw for unknown properties', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('unknownProperty', emptyExpr());
|
||||
expect(() => builder.build(new DomElementSchemaRegistry(), templateCloner)).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
describe('property normalization', () => {
|
||||
it('should normalize "innerHtml" to "innerHTML"', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('innerHtml', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].property).toEqual('innerHTML');
|
||||
});
|
||||
|
||||
it('should normalize "tabindex" to "tabIndex"', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('tabindex', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].property).toEqual('tabIndex');
|
||||
});
|
||||
|
||||
it('should normalize "readonly" to "readOnly"', () => {
|
||||
builder.bindElement(el('<input/>')).bindProperty('readonly', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].property).toEqual('readOnly');
|
||||
});
|
||||
|
||||
it('should normalize "class" to "className"', () => {
|
||||
builder.bindElement(el('<div></div>')).bindProperty('class', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].property).toEqual('className');
|
||||
});
|
||||
});
|
||||
|
||||
describe('property binding', () => {
|
||||
describe('types', () => {
|
||||
it('should detect property names', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('tabindex', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].type)
|
||||
.toEqual(PropertyBindingType.PROPERTY);
|
||||
});
|
||||
|
||||
it('should detect attribute names', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('attr.someName', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].type)
|
||||
.toEqual(PropertyBindingType.ATTRIBUTE);
|
||||
});
|
||||
|
||||
it('should detect class names', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('class.someName', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].type).toEqual(PropertyBindingType.CLASS);
|
||||
});
|
||||
|
||||
it('should detect style names', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('style.someName', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].type).toEqual(PropertyBindingType.STYLE);
|
||||
});
|
||||
|
||||
it('should detect style units', () => {
|
||||
builder.bindElement(el('<div/>')).bindProperty('style.someName.someUnit', emptyExpr());
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings[0].unit).toEqual('someUnit');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create a property binding when there is already same directive property binding',
|
||||
() => {
|
||||
var binder = builder.bindElement(el('<div/>'));
|
||||
|
||||
binder.bindProperty('tabindex', emptyExpr());
|
||||
binder.bindDirective(0).bindProperty('tabindex', emptyExpr(), 'tabindex');
|
||||
|
||||
var pv = builder.build(new DomElementSchemaRegistry(), templateCloner);
|
||||
expect(pv.elementBinders[0].propertyBindings.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
xdescribe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
beforeEachBindings,
|
||||
SpyObject,
|
||||
stringifyElement
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {isPresent} from 'angular2/src/core/facade/lang';
|
||||
|
||||
import {DomTestbed} from '../../../../core/render/dom/dom_testbed';
|
||||
|
||||
import {
|
||||
ViewDefinition,
|
||||
RenderDirectiveMetadata,
|
||||
RenderProtoViewMergeMapping,
|
||||
ViewEncapsulation,
|
||||
ViewType
|
||||
} from 'angular2/src/core/render/api';
|
||||
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {cloneAndQueryProtoView} from 'angular2/src/core/render/dom/util';
|
||||
import {TemplateCloner} from 'angular2/src/core/render/dom/template_cloner';
|
||||
import {
|
||||
resolveInternalDomProtoView,
|
||||
DomProtoView
|
||||
} from 'angular2/src/core/render/dom/view/proto_view';
|
||||
import {ProtoViewBuilder} from 'angular2/src/core/render/dom/view/proto_view_builder';
|
||||
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||
|
||||
export function main() {
|
||||
describe('ProtoViewMerger integration test', () => {
|
||||
beforeEachBindings(() => [DomTestbed]);
|
||||
|
||||
describe('component views', () => {
|
||||
it('should merge a component view',
|
||||
runAndAssert('root', ['a'], ['<root class="ng-binding" idx="0">a</root>']));
|
||||
|
||||
it('should merge component views with interpolation at root level',
|
||||
runAndAssert('root', ['{{a}}'], ['<root class="ng-binding" idx="0">{0}</root>']));
|
||||
|
||||
it('should merge component views with interpolation not at root level',
|
||||
runAndAssert('root', ['<div>{{a}}</div>'], [
|
||||
'<root class="ng-binding" idx="0"><div class="ng-binding" idx="1">{0}</div></root>'
|
||||
]));
|
||||
|
||||
it('should merge component views with bound elements',
|
||||
runAndAssert('root', ['<div #a></div>'], [
|
||||
'<root class="ng-binding" idx="0"><div #a="" class="ng-binding" idx="1"></div></root>'
|
||||
]));
|
||||
});
|
||||
|
||||
describe('embedded views', () => {
|
||||
|
||||
it('should merge embedded views as fragments',
|
||||
runAndAssert('root', ['<template>a</template>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1"></template></root>',
|
||||
'a'
|
||||
]));
|
||||
|
||||
it('should merge embedded views with interpolation at root level',
|
||||
runAndAssert('root', ['<template>{{a}}</template>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1"></template></root>',
|
||||
'{0}'
|
||||
]));
|
||||
|
||||
it('should merge embedded views with interpolation not at root level',
|
||||
runAndAssert('root', ['<div *ng-if>{{a}}</div>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1" ng-if=""></template></root>',
|
||||
'<div *ng-if="" class="ng-binding" idx="2">{0}</div>'
|
||||
]));
|
||||
|
||||
it('should merge embedded views with bound elements',
|
||||
runAndAssert('root', ['<div *ng-if #a></div>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1" ng-if=""></template></root>',
|
||||
'<div #a="" *ng-if="" class="ng-binding" idx="2"></div>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('projection', () => {
|
||||
|
||||
it('should remove text nodes if there is no ng-content',
|
||||
runAndAssert(
|
||||
'root', ['<a>b</a>', ''],
|
||||
['<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"></a></root>']));
|
||||
|
||||
it('should project static text',
|
||||
runAndAssert('root', ['<a>b</a>', 'A(<ng-content></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<!--[-->b<!--]-->)</a></root>'
|
||||
]));
|
||||
|
||||
it('should project text interpolation',
|
||||
runAndAssert('root', ['<a>{{b}}</a>', 'A(<ng-content></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<!--[-->{0}<!--]-->)</a></root>'
|
||||
]));
|
||||
|
||||
it('should project text interpolation to elements without bindings',
|
||||
runAndAssert('root', ['<a>{{b}}</a>', '<div><ng-content></ng-content></div>'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"><div class="ng-binding"><!--[-->{0}<!--]--></div></a></root>'
|
||||
]));
|
||||
|
||||
it('should project elements',
|
||||
runAndAssert('root', ['<a><div></div></a>', 'A(<ng-content></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<!--[--><div></div><!--]-->)</a></root>'
|
||||
]));
|
||||
|
||||
it('should project elements using the selector',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a><div class="x">a</div><span></span><div class="x">b</div></a>',
|
||||
'A(<ng-content select=".x"></ng-content>)'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<!--[--><div class="x">a</div><div class="x">b</div><!--]-->)</a></root>'
|
||||
]));
|
||||
|
||||
it('should reproject',
|
||||
runAndAssert(
|
||||
'root',
|
||||
['<a>x</a>', 'A(<b><ng-content></ng-content></b>)', 'B(<ng-content></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<b class="ng-binding" idx="2">B(<!--[--><!--[-->x<!--]--><!--]-->)</b>)</a></root>'
|
||||
]));
|
||||
|
||||
it('should reproject text interpolation to sibling text nodes',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a>{{x}}</a>',
|
||||
'<b>A(<ng-content></ng-content>)</b>)',
|
||||
'B(<ng-content></ng-content>)'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"><b class="ng-binding" idx="2">B(<!--[-->A(<!--[-->{0}<!--]-->)<!--]-->)</b>)</a></root>'
|
||||
]));
|
||||
|
||||
it('should reproject by combining selectors',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a><div class="x"></div><div class="x y"></div><div class="y"></div></a>',
|
||||
'A(<b><ng-content select=".x"></ng-content></b>)',
|
||||
'B(<ng-content select=".y"></ng-content>)'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<b class="ng-binding" idx="2">B(<!--[--><div class="x y"></div><!--]-->)</b>)</a></root>'
|
||||
]));
|
||||
|
||||
it('should keep non projected embedded views as fragments (so that they can be moved manually)',
|
||||
runAndAssert(
|
||||
'root', ['<a><template class="x">b</template></a>', ''],
|
||||
['<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"></a></root>', 'b']));
|
||||
|
||||
it('should project embedded views and match the template element',
|
||||
runAndAssert(
|
||||
'root', ['<a><template class="x">b</template></a>', 'A(<ng-content></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<!--[--><template class="x ng-binding" idx="2"></template><!--]-->)</a></root>',
|
||||
'b'
|
||||
]));
|
||||
|
||||
it('should project nodes using the ng-content in embedded views',
|
||||
runAndAssert('root', ['<a>b</a>', 'A(<ng-content *ng-if></ng-content>)'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<template class="ng-binding" idx="2" ng-if=""></template>)</a></root>',
|
||||
'<!--[-->b<!--]-->'
|
||||
]));
|
||||
|
||||
it('should allow to use wildcard selector after embedded view with non wildcard selector',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a><div class="x">a</div>b</a>',
|
||||
'A(<ng-content select=".x" *ng-if></ng-content>, <ng-content></ng-content>)'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">A(<template class="ng-binding" idx="2" ng-if=""></template>, <!--[-->b<!--]-->)</a></root>',
|
||||
'<!--[--><div class="x">a</div><!--]-->'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('composition', () => {
|
||||
it('should merge multiple component views',
|
||||
runAndAssert('root', ['<a></a><b></b>', 'c', 'd'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">c</a><b class="ng-binding" idx="2">d</b></root>'
|
||||
]));
|
||||
|
||||
it('should merge multiple embedded views as fragments',
|
||||
runAndAssert('root', ['<div *ng-if></div><span *ng-for></span>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1" ng-if=""></template><template class="ng-binding" idx="2" ng-for=""></template></root>',
|
||||
'<div *ng-if=""></div>',
|
||||
'<span *ng-for=""></span>'
|
||||
]));
|
||||
|
||||
it('should merge nested embedded views as fragments',
|
||||
runAndAssert('root', ['<div *ng-if><span *ng-for></span></div>'], [
|
||||
'<root class="ng-binding" idx="0"><template class="ng-binding" idx="1" ng-if=""></template></root>',
|
||||
'<div *ng-if=""><template class="ng-binding" idx="2" ng-for=""></template></div>',
|
||||
'<span *ng-for=""></span>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('element index mapping should be grouped by view and view depth first', () => {
|
||||
|
||||
it('should map component views correctly',
|
||||
runAndAssert('root', ['<a></a><b></b>', '<c></c>'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"><c class="ng-binding" idx="3"></c></a><b class="ng-binding" idx="2"></b></root>'
|
||||
]));
|
||||
|
||||
it('should map moved projected elements correctly',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a><b></b><c></c></a>',
|
||||
'<ng-content select="c"></ng-content><ng-content select="b"></ng-content>'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"><!--[--><c class="ng-binding" idx="3"></c><!--]--><!--[--><b class="ng-binding" idx="2"></b><!--]--></a></root>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('text index mapping should be grouped by view and view depth first', () => {
|
||||
|
||||
it('should map component views correctly', runAndAssert('root', ['<a></a>{{b}}', '{{c}}'], [
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1">{1}</a>{0}</root>'
|
||||
]));
|
||||
|
||||
it('should map moved projected elements correctly',
|
||||
runAndAssert(
|
||||
'root',
|
||||
[
|
||||
'<a><div x>{{x}}</div><div y>{{y}}</div></a>',
|
||||
'<ng-content select="[y]"></ng-content><ng-content select="[x]"></ng-content>'
|
||||
],
|
||||
[
|
||||
'<root class="ng-binding" idx="0"><a class="ng-binding" idx="1"><!--[--><div class="ng-binding" idx="3" y="">{1}</div><!--]--><!--[--><div class="ng-binding" idx="2" x="">{0}</div><!--]--></a></root>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('native shadow dom support', () => {
|
||||
it('should keep the non projected light dom and wrap the component view into a shadow-root element',
|
||||
runAndAssert('native-root', ['<a>b</a>', 'c'], [
|
||||
'<native-root class="ng-binding" idx="0"><shadow-root><a class="ng-binding" idx="1"><shadow-root>c</shadow-root>b</a></shadow-root></native-root>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('host attributes', () => {
|
||||
it('should set host attributes while merging',
|
||||
inject([AsyncTestCompleter, DomTestbed, TemplateCloner], (async, tb: DomTestbed,
|
||||
cloner: TemplateCloner) => {
|
||||
tb.compiler.compileHost(rootDirective('root'))
|
||||
.then((rootProtoViewDto) => {
|
||||
var builder = new ProtoViewBuilder(DOM.createTemplate(''), ViewType.COMPONENT,
|
||||
ViewEncapsulation.None);
|
||||
builder.setHostAttribute('a', 'b');
|
||||
var componentProtoViewDto = builder.build(new ElementSchemaRegistry(), cloner);
|
||||
tb.merge([rootProtoViewDto, componentProtoViewDto])
|
||||
.then(mergeMappings => {
|
||||
var domPv = resolveInternalDomProtoView(mergeMappings.mergedProtoViewRef);
|
||||
expect(stringifyElement(templateRoot(domPv)))
|
||||
.toEqual('<template><root a="b" class="ng-binding"></root></template>');
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function templateRoot(pv: DomProtoView) {
|
||||
return <Element>pv.cloneableTemplate;
|
||||
}
|
||||
|
||||
function runAndAssert(hostElementName: string, componentTemplates: string[],
|
||||
expectedFragments: string[]) {
|
||||
var useNativeEncapsulation = hostElementName.startsWith('native-');
|
||||
var rootComp = rootDirective(hostElementName);
|
||||
return inject([AsyncTestCompleter, DomTestbed, TemplateCloner], (async, tb: DomTestbed,
|
||||
cloner: TemplateCloner) => {
|
||||
tb.compileAndMerge(rootComp, componentTemplates.map(template => componentView(
|
||||
template, useNativeEncapsulation ?
|
||||
ViewEncapsulation.Native :
|
||||
ViewEncapsulation.None)))
|
||||
.then((mergeMappings) => {
|
||||
expect(stringify(cloner, mergeMappings)).toEqual(expectedFragments);
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function rootDirective(hostElementName: string) {
|
||||
return RenderDirectiveMetadata.create(
|
||||
{id: 'rootComp', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: hostElementName});
|
||||
}
|
||||
|
||||
function componentView(template: string,
|
||||
encapsulation: ViewEncapsulation = ViewEncapsulation.None) {
|
||||
return new ViewDefinition({
|
||||
componentId: 'someComp',
|
||||
template: template,
|
||||
directives: [aComp, bComp, cComp],
|
||||
encapsulation: encapsulation
|
||||
});
|
||||
}
|
||||
|
||||
function stringify(cloner: TemplateCloner, protoViewMergeMapping: RenderProtoViewMergeMapping):
|
||||
string[] {
|
||||
var testView = cloneAndQueryProtoView(
|
||||
cloner, resolveInternalDomProtoView(protoViewMergeMapping.mergedProtoViewRef), false);
|
||||
for (var i = 0; i < protoViewMergeMapping.mappedElementIndices.length; i++) {
|
||||
var renderElIdx = protoViewMergeMapping.mappedElementIndices[i];
|
||||
if (isPresent(renderElIdx)) {
|
||||
DOM.setAttribute(testView.boundElements[renderElIdx], 'idx', `${i}`);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < protoViewMergeMapping.mappedTextIndices.length; i++) {
|
||||
var renderTextIdx = protoViewMergeMapping.mappedTextIndices[i];
|
||||
if (isPresent(renderTextIdx)) {
|
||||
DOM.setText(testView.boundTextNodes[renderTextIdx], `{${i}}`);
|
||||
}
|
||||
}
|
||||
expect(protoViewMergeMapping.fragmentCount).toEqual(testView.fragments.length);
|
||||
return testView.fragments.map(nodes => nodes.map(node => stringifyElement(node)).join(''));
|
||||
}
|
||||
|
||||
var aComp = RenderDirectiveMetadata.create(
|
||||
{id: 'aComp', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: 'a'});
|
||||
var bComp = RenderDirectiveMetadata.create(
|
||||
{id: 'bComp', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: 'b'});
|
||||
var cComp = RenderDirectiveMetadata.create(
|
||||
{id: 'cComp', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: 'c'});
|
||||
@@ -1,143 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
xdescribe,
|
||||
describe,
|
||||
el,
|
||||
dispatchEvent,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
beforeEachBindings,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
proxy
|
||||
} from 'angular2/test_lib';
|
||||
import {isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
import {DomProtoView} from 'angular2/src/core/render/dom/view/proto_view';
|
||||
import {DomElementBinder} from 'angular2/src/core/render/dom/view/element_binder';
|
||||
import {DomView} from 'angular2/src/core/render/dom/view/view';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {TemplateCloner} from 'angular2/src/core/render/dom/template_cloner';
|
||||
|
||||
export function main() {
|
||||
describe('DomView', () => {
|
||||
function createProtoView(binders = null) {
|
||||
if (isBlank(binders)) {
|
||||
binders = [];
|
||||
}
|
||||
var rootEl = DOM.createTemplate('<div></div>');
|
||||
return DomProtoView.create(new TemplateCloner(-1), null, <Element>rootEl, null, [1], [],
|
||||
binders, null);
|
||||
}
|
||||
|
||||
function createElementBinder() { return new DomElementBinder({textNodeIndices: []}); }
|
||||
|
||||
function createView(pv = null, boundElementCount = 0) {
|
||||
if (isBlank(pv)) {
|
||||
var elementBinders = ListWrapper.createFixedSize(boundElementCount);
|
||||
for (var i = 0; i < boundElementCount; i++) {
|
||||
elementBinders[i] = createElementBinder();
|
||||
}
|
||||
pv = createProtoView(elementBinders);
|
||||
}
|
||||
var root = el('<div><div></div></div>');
|
||||
var boundElements = [];
|
||||
for (var i = 0; i < boundElementCount; i++) {
|
||||
boundElements.push(el('<span></span'));
|
||||
}
|
||||
return new DomView(pv, [DOM.childNodes(root)[0]], boundElements);
|
||||
}
|
||||
|
||||
describe('setElementProperty', () => {
|
||||
var el, view;
|
||||
beforeEach(() => {
|
||||
view = createView(null, 1);
|
||||
el = view.boundElements[0];
|
||||
});
|
||||
|
||||
it('should update the property value', () => {
|
||||
view.setElementProperty(0, 'title', 'Hello');
|
||||
expect(el.title).toEqual('Hello');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('setElementAttribute', () => {
|
||||
var el, view;
|
||||
beforeEach(() => {
|
||||
view = createView(null, 1);
|
||||
el = view.boundElements[0];
|
||||
});
|
||||
|
||||
it('should update and remove an attribute', () => {
|
||||
view.setElementAttribute(0, 'role', 'button');
|
||||
expect(DOM.getAttribute(el, 'role')).toEqual('button');
|
||||
view.setElementAttribute(0, 'role', null);
|
||||
expect(DOM.getAttribute(el, 'role')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should de-normalize attribute names', () => {
|
||||
view.setElementAttribute(0, 'ariaLabel', 'fancy button');
|
||||
expect(DOM.getAttribute(el, 'aria-label')).toEqual('fancy button');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setElementClass', () => {
|
||||
var el, view;
|
||||
beforeEach(() => {
|
||||
view = createView(null, 1);
|
||||
el = view.boundElements[0];
|
||||
});
|
||||
|
||||
it('should set and remove a class', () => {
|
||||
view.setElementClass(0, 'active', true);
|
||||
expect(DOM.hasClass(el, 'active')).toEqual(true);
|
||||
|
||||
view.setElementClass(0, 'active', false);
|
||||
expect(DOM.hasClass(el, 'active')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should not de-normalize class names', () => {
|
||||
view.setElementClass(0, 'veryActive', true);
|
||||
view.setElementClass(0, 'very-active', true);
|
||||
expect(DOM.hasClass(el, 'veryActive')).toEqual(true);
|
||||
expect(DOM.hasClass(el, 'very-active')).toEqual(true);
|
||||
|
||||
view.setElementClass(0, 'veryActive', false);
|
||||
view.setElementClass(0, 'very-active', false);
|
||||
expect(DOM.hasClass(el, 'veryActive')).toEqual(false);
|
||||
expect(DOM.hasClass(el, 'very-active')).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setElementStyle', () => {
|
||||
var el, view;
|
||||
beforeEach(() => {
|
||||
view = createView(null, 1);
|
||||
el = view.boundElements[0];
|
||||
});
|
||||
|
||||
it('should set and remove styles', () => {
|
||||
view.setElementStyle(0, 'width', '40px');
|
||||
expect(DOM.getStyle(el, 'width')).toEqual('40px');
|
||||
|
||||
view.setElementStyle(0, 'width', null);
|
||||
expect(DOM.getStyle(el, 'width')).toEqual('');
|
||||
});
|
||||
|
||||
it('should de-normalize style names', () => {
|
||||
view.setElementStyle(0, 'maxWidth', '40px');
|
||||
expect(DOM.getStyle(el, 'max-width')).toEqual('40px');
|
||||
view.setElementStyle(0, 'maxWidth', null);
|
||||
expect(DOM.getStyle(el, 'max-width')).toEqual('');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -21,21 +21,11 @@ class SpyDependencyProvider extends SpyObject implements DependencyProvider {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyChangeDetection extends SpyObject implements ChangeDetection {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyChangeDetector extends SpyObject implements ChangeDetector {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyProtoChangeDetector extends SpyObject implements ProtoChangeDetector {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyChangeDispatcher extends SpyObject implements ChangeDispatcher {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
@@ -52,11 +42,6 @@ class SpyInjector extends SpyObject implements Injector {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyRenderCompiler extends SpyObject implements RenderCompiler {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyDirectiveResolver extends SpyObject implements DirectiveResolver {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {
|
||||
ChangeDetection,
|
||||
ChangeDetector,
|
||||
ChangeDetectorRef,
|
||||
ProtoChangeDetector,
|
||||
DynamicChangeDetector
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {RenderCompiler, Renderer, RenderEventDispatcher} from 'angular2/src/core/render/api';
|
||||
import {Renderer, RenderEventDispatcher} from 'angular2/src/core/render/api';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
|
||||
import {AppView} from 'angular2/src/core/compiler/view';
|
||||
@@ -29,26 +28,14 @@ import {SpyObject, proxy} from 'angular2/test_lib';
|
||||
|
||||
export class SpyDependencyProvider extends SpyObject {}
|
||||
|
||||
export class SpyChangeDetection extends SpyObject {
|
||||
constructor() { super(ChangeDetection); }
|
||||
}
|
||||
|
||||
export class SpyChangeDetector extends SpyObject {
|
||||
constructor() { super(DynamicChangeDetector); }
|
||||
}
|
||||
|
||||
export class SpyProtoChangeDetector extends SpyObject {
|
||||
constructor() { super(DynamicChangeDetector); }
|
||||
}
|
||||
|
||||
export class SpyChangeDispatcher extends SpyObject {}
|
||||
|
||||
export class SpyIterableDifferFactory extends SpyObject {}
|
||||
|
||||
export class SpyRenderCompiler extends SpyObject {
|
||||
constructor() { super(RenderCompiler); }
|
||||
}
|
||||
|
||||
export class SpyDirectiveResolver extends SpyObject {
|
||||
constructor() { super(DirectiveResolver); }
|
||||
}
|
||||
|
||||
@@ -188,8 +188,6 @@ var NG_API = [
|
||||
'ComponentRef.instance=',
|
||||
'ComponentRef.location',
|
||||
'ComponentRef.location=',
|
||||
'ComponentUrlMapper',
|
||||
'ComponentUrlMapper.getUrl()',
|
||||
'ContentChild',
|
||||
'ContentChild.descendants',
|
||||
'ContentChild.first',
|
||||
@@ -400,8 +398,6 @@ var NG_API = [
|
||||
'ElementRef.nativeElement',
|
||||
'ElementRef.parentView',
|
||||
'ElementRef.parentView=',
|
||||
'ElementRef.renderBoundElementIndex',
|
||||
'ElementRef.renderBoundElementIndex=',
|
||||
'ElementRef.renderView',
|
||||
'ElementRef.renderView=',
|
||||
'Output',
|
||||
@@ -534,7 +530,6 @@ var NG_API = [
|
||||
'LifeCycle.tick()',
|
||||
'LowerCasePipe',
|
||||
'LowerCasePipe.transform()',
|
||||
'MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE',
|
||||
'NG_VALIDATORS',
|
||||
'NgClass',
|
||||
'NgClass.doCheck()',
|
||||
@@ -838,52 +833,6 @@ var NG_API = [
|
||||
'QueryMetadata.selector',
|
||||
'QueryMetadata.token',
|
||||
'QueryMetadata.varBindings',
|
||||
'RenderDirectiveMetadata#COMPONENT_TYPE',
|
||||
'RenderDirectiveMetadata#DIRECTIVE_TYPE',
|
||||
'RenderDirectiveMetadata#create()',
|
||||
'RenderDirectiveMetadata',
|
||||
'RenderDirectiveMetadata.callAfterContentChecked',
|
||||
'RenderDirectiveMetadata.callAfterContentChecked=',
|
||||
'RenderDirectiveMetadata.callAfterContentInit',
|
||||
'RenderDirectiveMetadata.callAfterContentInit=',
|
||||
'RenderDirectiveMetadata.callAfterViewChecked',
|
||||
'RenderDirectiveMetadata.callAfterViewChecked=',
|
||||
'RenderDirectiveMetadata.callAfterViewInit',
|
||||
'RenderDirectiveMetadata.callAfterViewInit=',
|
||||
'RenderDirectiveMetadata.callDoCheck',
|
||||
'RenderDirectiveMetadata.callDoCheck=',
|
||||
'RenderDirectiveMetadata.callOnChanges',
|
||||
'RenderDirectiveMetadata.callOnChanges=',
|
||||
'RenderDirectiveMetadata.callOnDestroy',
|
||||
'RenderDirectiveMetadata.callOnDestroy=',
|
||||
'RenderDirectiveMetadata.callOnInit',
|
||||
'RenderDirectiveMetadata.callOnInit=',
|
||||
'RenderDirectiveMetadata.changeDetection',
|
||||
'RenderDirectiveMetadata.changeDetection=',
|
||||
'RenderDirectiveMetadata.compileChildren',
|
||||
'RenderDirectiveMetadata.compileChildren=',
|
||||
'RenderDirectiveMetadata.outputs',
|
||||
'RenderDirectiveMetadata.outputs=',
|
||||
'RenderDirectiveMetadata.exportAs',
|
||||
'RenderDirectiveMetadata.exportAs=',
|
||||
'RenderDirectiveMetadata.hostAttributes',
|
||||
'RenderDirectiveMetadata.hostAttributes=',
|
||||
'RenderDirectiveMetadata.hostListeners',
|
||||
'RenderDirectiveMetadata.hostListeners=',
|
||||
'RenderDirectiveMetadata.hostProperties',
|
||||
'RenderDirectiveMetadata.hostProperties=',
|
||||
'RenderDirectiveMetadata.id',
|
||||
'RenderDirectiveMetadata.id=',
|
||||
'RenderDirectiveMetadata.inputs',
|
||||
'RenderDirectiveMetadata.inputs=',
|
||||
'RenderDirectiveMetadata.queries',
|
||||
'RenderDirectiveMetadata.queries=',
|
||||
'RenderDirectiveMetadata.readAttributes',
|
||||
'RenderDirectiveMetadata.readAttributes=',
|
||||
'RenderDirectiveMetadata.selector',
|
||||
'RenderDirectiveMetadata.selector=',
|
||||
'RenderDirectiveMetadata.type',
|
||||
'RenderDirectiveMetadata.type=',
|
||||
'RenderFragmentRef',
|
||||
'RenderProtoViewRef',
|
||||
'RenderViewRef',
|
||||
@@ -1026,21 +975,6 @@ var NG_API = [
|
||||
'ViewContainerRef.remove()',
|
||||
'ViewContainerRef.viewManager',
|
||||
'ViewContainerRef.viewManager=',
|
||||
'ViewDefinition',
|
||||
'ViewDefinition.componentId',
|
||||
'ViewDefinition.componentId=',
|
||||
'ViewDefinition.directives',
|
||||
'ViewDefinition.directives=',
|
||||
'ViewDefinition.encapsulation',
|
||||
'ViewDefinition.encapsulation=',
|
||||
'ViewDefinition.styleAbsUrls',
|
||||
'ViewDefinition.styleAbsUrls=',
|
||||
'ViewDefinition.styles',
|
||||
'ViewDefinition.styles=',
|
||||
'ViewDefinition.template',
|
||||
'ViewDefinition.template=',
|
||||
'ViewDefinition.templateAbsUrl',
|
||||
'ViewDefinition.templateAbsUrl=',
|
||||
'ViewEncapsulation#Emulated',
|
||||
'ViewEncapsulation#Native',
|
||||
'ViewEncapsulation#None',
|
||||
@@ -1157,8 +1091,8 @@ var NG_API = [
|
||||
'{RenderTextCmd}.value',
|
||||
'{RenderTextCmd}.value=',
|
||||
'{RenderElementRef}',
|
||||
'{RenderElementRef}.renderBoundElementIndex',
|
||||
'{RenderElementRef}.renderBoundElementIndex=',
|
||||
'{RenderElementRef}.boundElementIndex',
|
||||
'{RenderElementRef}.boundElementIndex=',
|
||||
'{RenderElementRef}.renderView',
|
||||
'{RenderElementRef}.renderView=',
|
||||
'{RenderEventDispatcher}',
|
||||
|
||||
+1
@@ -8,6 +8,7 @@ import "package:angular2/test_lib.dart"
|
||||
inject,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
expect,
|
||||
beforeEach,
|
||||
createTestInjector,
|
||||
|
||||
Reference in New Issue
Block a user