refactor(core): move core/compiler to core/linker

This commit is contained in:
Tobias Bosch
2015-10-02 07:28:42 -07:00
parent 43cca2de76
commit 9f4fa1ab0a
41 changed files with 0 additions and 0 deletions

View File

@ -1,63 +0,0 @@
import {
ddescribe,
describe,
xdescribe,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
AsyncTestCompleter,
inject,
beforeEachBindings
} from 'angular2/test_lib';
import {Component, View, bind} from 'angular2/core';
import {SpyProtoViewFactory} from '../spies';
import {
CompiledHostTemplate,
CompiledTemplate,
BeginComponentCmd
} from 'angular2/src/core/compiler/template_commands';
import {Compiler} from 'angular2/src/core/compiler/compiler';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {reflector, ReflectionInfo} from 'angular2/src/core/reflection/reflection';
import {AppProtoView} from 'angular2/src/core/compiler/view';
export function main() {
describe('Compiler', () => {
var compiler: Compiler;
var protoViewFactorySpy;
var someProtoView;
var cht: CompiledHostTemplate;
beforeEachBindings(() => {
protoViewFactorySpy = new SpyProtoViewFactory();
someProtoView = new AppProtoView(null, null, null, null, null, null);
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
return [bind(ProtoViewFactory).toValue(protoViewFactorySpy), Compiler];
});
beforeEach(inject([Compiler], (_compiler) => {
compiler = _compiler;
cht = new CompiledHostTemplate(() => new CompiledTemplate(23, null));
reflector.registerType(SomeComponent, new ReflectionInfo([cht]));
}));
it('should read the template from an annotation', inject([AsyncTestCompleter], (async) => {
compiler.compileInHost(SomeComponent)
.then((_) => {
expect(protoViewFactorySpy.spy('createHost')).toHaveBeenCalledWith(cht);
async.done();
});
}));
it('should clear the cache', () => {
compiler.clearCache();
expect(protoViewFactorySpy.spy('clearCache')).toHaveBeenCalled();
});
});
}
class SomeComponent {}

View File

@ -1,138 +0,0 @@
library angular2.test.core.compiler.directive_lifecycle_spec;
import 'package:angular2/test_lib.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', () {
describe("onChanges", () {
it("should be true when the directive has the onChanges method", () {
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveImplementingOnChanges))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveNoHooks)).toBe(false);
});
});
describe("onDestroy", () {
it("should be true when the directive has the onDestroy method", () {
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveImplementingOnDestroy))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveNoHooks)).toBe(false);
});
});
describe("onInit", () {
it("should be true when the directive has the onInit method", () {
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveImplementingOnInit))
.toBe(true);
});
it("should be false otherwise", () {
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 has the afterContentInit method", () {
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveImplementingAfterContentInit))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveNoHooks))
.toBe(false);
});
});
describe("afterContentChecked", () {
it("should be true when the directive has the afterContentChecked method", () {
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveImplementingAfterContentChecked))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveNoHooks))
.toBe(false);
});
});
describe("afterViewInit", () {
it("should be true when the directive has the afterViewInit method", () {
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveImplementingAfterViewInit))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveNoHooks)).toBe(false);
});
});
describe("afterViewChecked", () {
it("should be true when the directive has the afterViewChecked method", () {
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveImplementingAfterViewChecked))
.toBe(true);
});
it("should be false otherwise", () {
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveNoHooks))
.toBe(false);
});
});
});
});
}
class DirectiveNoHooks {}
class DirectiveImplementingOnChanges implements OnChanges {
onChanges(_) {}
}
class DirectiveImplementingOnCheck implements DoCheck {
doCheck() {}
}
class DirectiveImplementingOnInit implements OnInit {
onInit() {}
}
class DirectiveImplementingOnDestroy implements OnDestroy {
onDestroy() {}
}
class DirectiveImplementingAfterContentInit implements AfterContentInit {
afterContentInit() {}
}
class DirectiveImplementingAfterContentChecked implements AfterContentChecked {
afterContentChecked() {}
}
class DirectiveImplementingAfterViewInit implements AfterViewInit {
afterViewInit() {}
}
class DirectiveImplementingAfterViewChecked implements AfterViewChecked {
afterViewChecked() {}
}

View File

@ -1,149 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
xdescribe,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
SpyObject,
proxy
} from 'angular2/test_lib';
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', () => {
describe("onChanges", () => {
it("should be true when the directive has the onChanges method", () => {
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveWithOnChangesMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.OnChanges, DirectiveNoHooks)).toBe(false);
});
});
describe("onDestroy", () => {
it("should be true when the directive has the onDestroy method", () => {
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveWithOnDestroyMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.OnDestroy, DirectiveNoHooks)).toBe(false);
});
});
describe("onInit", () => {
it("should be true when the directive has the onInit method", () => {
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveWithOnInitMethod)).toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.OnInit, DirectiveNoHooks)).toBe(false);
});
});
describe("doCheck", () => {
it("should be true when the directive has the doCheck method", () => {
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveWithOnCheckMethod)).toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.DoCheck, DirectiveNoHooks)).toBe(false);
});
});
describe("afterContentInit", () => {
it("should be true when the directive has the afterContentInit method", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit,
DirectiveWithAfterContentInitMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterContentInit, DirectiveNoHooks)).toBe(false);
});
});
describe("afterContentChecked", () => {
it("should be true when the directive has the afterContentChecked method", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked,
DirectiveWithAfterContentCheckedMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterContentChecked, DirectiveNoHooks))
.toBe(false);
});
});
describe("afterViewInit", () => {
it("should be true when the directive has the afterViewInit method", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveWithAfterViewInitMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterViewInit, DirectiveNoHooks)).toBe(false);
});
});
describe("afterViewChecked", () => {
it("should be true when the directive has the afterViewChecked method", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked,
DirectiveWithAfterViewCheckedMethod))
.toBe(true);
});
it("should be false otherwise", () => {
expect(hasLifecycleHook(LifecycleHooks.AfterViewChecked, DirectiveNoHooks)).toBe(false);
});
});
});
});
}
class DirectiveNoHooks {}
class DirectiveWithOnChangesMethod {
onChanges(_) {}
}
class DirectiveWithOnInitMethod {
onInit() {}
}
class DirectiveWithOnCheckMethod {
doCheck() {}
}
class DirectiveWithOnDestroyMethod {
onDestroy() {}
}
class DirectiveWithAfterContentInitMethod {
afterContentInit() {}
}
class DirectiveWithAfterContentCheckedMethod {
afterContentChecked() {}
}
class DirectiveWithAfterViewInitMethod {
afterViewInit() {}
}
class DirectiveWithAfterViewCheckedMethod {
afterViewChecked() {}
}

View File

@ -1,189 +0,0 @@
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {
DirectiveMetadata,
Directive,
Input,
Output,
HostBinding,
HostListener,
ContentChildren,
ContentChildrenMetadata,
ViewChildren,
ViewChildrenMetadata,
ContentChild,
ContentChildMetadata,
ViewChild,
ViewChildMetadata
} from 'angular2/src/core/metadata';
@Directive({selector: 'someDirective'})
class SomeDirective {
}
@Directive({selector: 'someChildDirective'})
class SomeChildDirective extends SomeDirective {
}
@Directive({selector: 'someDirective', inputs: ['c']})
class SomeDirectiveWithProperties {
@Input() a;
@Input("renamed") b;
c;
}
@Directive({selector: 'someDirective', outputs: ['c']})
class SomeDirectiveWithOutputs {
@Output() a;
@Output("renamed") b;
c;
}
@Directive({selector: 'someDirective'})
class SomeDirectiveWithSetterProps {
@Input("renamed")
set a(value) {
}
}
@Directive({selector: 'someDirective'})
class SomeDirectiveWithGetterOutputs {
@Output("renamed")
get a() {
return null;
}
}
@Directive({selector: 'someDirective', host: {'[c]': 'c'}})
class SomeDirectiveWithHostBindings {
@HostBinding() a;
@HostBinding("renamed") b;
c;
}
@Directive({selector: 'someDirective', host: {'(c)': 'onC()'}})
class SomeDirectiveWithHostListeners {
@HostListener('a')
onA() {
}
@HostListener('b', ['$event.value'])
onB(value) {
}
}
@Directive({selector: 'someDirective', queries: {"cs": new ContentChildren("c")}})
class SomeDirectiveWithContentChildren {
@ContentChildren("a") as: any;
c;
}
@Directive({selector: 'someDirective', queries: {"cs": new ViewChildren("c")}})
class SomeDirectiveWithViewChildren {
@ViewChildren("a") as: any;
c;
}
@Directive({selector: 'someDirective', queries: {"c": new ContentChild("c")}})
class SomeDirectiveWithContentChild {
@ContentChild("a") a: any;
c;
}
@Directive({selector: 'someDirective', queries: {"c": new ViewChild("c")}})
class SomeDirectiveWithViewChild {
@ViewChild("a") a: any;
c;
}
class SomeDirectiveWithoutMetadata {}
export function main() {
describe("DirectiveResolver", () => {
var resolver;
beforeEach(() => { resolver = new DirectiveResolver(); });
it('should read out the Directive metadata', () => {
var directiveMetadata = resolver.resolve(SomeDirective);
expect(directiveMetadata)
.toEqual(new DirectiveMetadata(
{selector: 'someDirective', inputs: [], outputs: [], host: {}, queries: {}}));
});
it('should throw if not matching metadata is found', () => {
expect(() => { resolver.resolve(SomeDirectiveWithoutMetadata); })
.toThrowError('No Directive annotation found on SomeDirectiveWithoutMetadata');
});
it('should not read parent class Directive metadata', function() {
var directiveMetadata = resolver.resolve(SomeChildDirective);
expect(directiveMetadata)
.toEqual(new DirectiveMetadata(
{selector: 'someChildDirective', inputs: [], outputs: [], host: {}, queries: {}}));
});
describe('inputs', () => {
it('should append directive inputs', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithProperties);
expect(directiveMetadata.inputs).toEqual(['c', 'a', 'b: renamed']);
});
it('should work with getters and setters', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithSetterProps);
expect(directiveMetadata.inputs).toEqual(['a: renamed']);
});
});
describe('outputs', () => {
it('should append directive outputs', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithOutputs);
expect(directiveMetadata.outputs).toEqual(['c', 'a', 'b: renamed']);
});
it('should work with getters and setters', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithGetterOutputs);
expect(directiveMetadata.outputs).toEqual(['a: renamed']);
});
});
describe('host', () => {
it('should append host bindings', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithHostBindings);
expect(directiveMetadata.host).toEqual({'[c]': 'c', '[a]': 'a', '[renamed]': 'b'});
});
it('should append host listeners', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithHostListeners);
expect(directiveMetadata.host)
.toEqual({'(c)': 'onC()', '(a)': 'onA()', '(b)': 'onB($event.value)'});
});
});
describe('queries', () => {
it('should append ContentChildren', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithContentChildren);
expect(directiveMetadata.queries)
.toEqual({"cs": new ContentChildren("c"), "as": new ContentChildren("a")});
});
it('should append ViewChildren', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithViewChildren);
expect(directiveMetadata.queries)
.toEqual({"cs": new ViewChildren("c"), "as": new ViewChildren("a")});
});
it('should append ContentChild', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithContentChild);
expect(directiveMetadata.queries)
.toEqual({"c": new ContentChild("c"), "a": new ContentChild("a")});
});
it('should append ViewChild', () => {
var directiveMetadata = resolver.resolve(SomeDirectiveWithViewChild);
expect(directiveMetadata.queries)
.toEqual({"c": new ViewChild("c"), "a": new ViewChild("a")});
});
});
});
}

View File

@ -1,319 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit,
TestComponentBuilder,
RootTestComponent
} from 'angular2/test_lib';
import {OnDestroy} from 'angular2/lifecycle_hooks';
import {Injector, NgIf} from 'angular2/core';
import {inspectElement, By} from 'angular2/src/core/debug';
import {Component, View, ViewMetadata} from 'angular2/src/core/metadata';
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {DOCUMENT} from 'angular2/src/core/render/render';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
export function main() {
describe('DynamicComponentLoader', function() {
describe("loading into a location", () => {
it('should work',
inject(
[DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp, new ViewMetadata(
{template: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
loader.loadIntoLocation(DynamicallyLoaded, tc.debugElement.elementRef, 'loc')
.then(ref => {
expect(tc.debugElement.nativeElement)
.toHaveText("Location;DynamicallyLoaded;");
async.done();
});
});
}));
it('should return a disposable component ref',
inject(
[DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp, new ViewMetadata(
{template: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
loader.loadIntoLocation(DynamicallyLoaded, tc.debugElement.elementRef, 'loc')
.then(ref => {
ref.dispose();
expect(tc.debugElement.nativeElement).toHaveText("Location;");
async.done();
});
});
}));
it('should allow to dispose even if the location has been removed',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<child-cmp *ng-if="ctxBoolProp"></child-cmp>',
directives: [NgIf, ChildComp]
}))
.overrideView(
ChildComp,
new ViewMetadata(
{template: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
tc.debugElement.componentInstance.ctxBoolProp = true;
tc.detectChanges();
var childCompEl = tc.debugElement.query(By.css('child-cmp'));
loader.loadIntoLocation(DynamicallyLoaded, childCompEl.elementRef, 'loc')
.then(ref => {
expect(tc.debugElement.nativeElement)
.toHaveText("Location;DynamicallyLoaded;");
tc.debugElement.componentInstance.ctxBoolProp = false;
tc.detectChanges();
expect(tc.debugElement.nativeElement).toHaveText("");
ref.dispose();
expect(tc.debugElement.nativeElement).toHaveText("");
async.done();
});
});
}));
it('should update host properties',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp,
new ViewMetadata(
{template: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
loader.loadIntoLocation(DynamicallyLoadedWithHostProps,
tc.debugElement.elementRef, 'loc')
.then(ref => {
ref.instance.id = "new value";
tc.detectChanges();
var newlyInsertedElement =
DOM.childNodes(tc.debugElement.nativeElement)[1];
expect((<HTMLElement>newlyInsertedElement).id).toEqual("new value");
async.done();
});
});
}));
it('should throw if the variable does not exist',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp,
new ViewMetadata(
{template: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
expect(() => loader.loadIntoLocation(DynamicallyLoadedWithHostProps,
tc.debugElement.elementRef,
'someUnknownVariable'))
.toThrowError('Could not find variable someUnknownVariable');
async.done();
});
}));
});
describe("loading next to a location", () => {
it('should work',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<div><location #loc></location></div>',
directives: [Location]
}))
.createAsync(MyComp)
.then((tc) => {
loader.loadNextToLocation(DynamicallyLoaded, tc.debugElement.elementRef)
.then(ref => {
expect(tc.debugElement.nativeElement).toHaveText("Location;");
expect(DOM.nextSibling(tc.debugElement.nativeElement))
.toHaveText('DynamicallyLoaded;');
async.done();
});
});
}));
it('should return a disposable component ref',
inject(
[DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<div><location #loc></location></div>',
directives: [Location]
}))
.
createAsync(MyComp)
.then((tc) => {
loader.loadNextToLocation(DynamicallyLoaded, tc.debugElement.elementRef)
.then(ref => {
loader.loadNextToLocation(DynamicallyLoaded2, tc.debugElement.elementRef)
.then(ref2 => {
var firstSibling = DOM.nextSibling(tc.debugElement.nativeElement);
var secondSibling = DOM.nextSibling(firstSibling);
expect(tc.debugElement.nativeElement).toHaveText("Location;");
expect(firstSibling).toHaveText("DynamicallyLoaded;");
expect(secondSibling).toHaveText("DynamicallyLoaded2;");
ref2.dispose();
firstSibling = DOM.nextSibling(tc.debugElement.nativeElement);
secondSibling = DOM.nextSibling(firstSibling);
expect(secondSibling).toBeNull();
async.done();
});
});
});
}));
it('should update host properties',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<div><location #loc></location></div>',
directives: [Location]
}))
.createAsync(MyComp)
.then((tc) => {
loader.loadNextToLocation(DynamicallyLoadedWithHostProps,
tc.debugElement.elementRef)
.then(ref => {
ref.instance.id = "new value";
tc.detectChanges();
var newlyInsertedElement =
DOM.nextSibling(tc.debugElement.nativeElement);
expect((<HTMLElement>newlyInsertedElement).id).toEqual("new value");
async.done();
});
});
}));
});
describe('loadAsRoot', () => {
it('should allow to create, update and destroy components',
inject([AsyncTestCompleter, DynamicComponentLoader, DOCUMENT, Injector],
(async, loader, doc, injector) => {
var rootEl = el('<child-cmp></child-cmp>');
DOM.appendChild(doc.body, rootEl);
loader.loadAsRoot(ChildComp, null, injector)
.then((componentRef) => {
var el = new RootTestComponent(componentRef);
expect(rootEl.parentNode).toBe(doc.body);
el.detectChanges();
expect(rootEl).toHaveText('hello');
componentRef.instance.ctxProp = 'new';
el.detectChanges();
expect(rootEl).toHaveText('new');
componentRef.dispose();
expect(rootEl.parentNode).toBeFalsy();
async.done();
});
}));
});
});
}
@Component({
selector: 'child-cmp',
})
@View({template: '{{ctxProp}}'})
class ChildComp {
ctxProp: string;
constructor() { this.ctxProp = 'hello'; }
}
class DynamicallyCreatedComponentService {}
@Component({selector: 'hello-cmp', viewBindings: [DynamicallyCreatedComponentService]})
@View({template: "{{greeting}}"})
class DynamicallyCreatedCmp implements OnDestroy {
greeting: string;
dynamicallyCreatedComponentService: DynamicallyCreatedComponentService;
destroyed: boolean = false;
constructor(a: DynamicallyCreatedComponentService) {
this.greeting = "hello";
this.dynamicallyCreatedComponentService = a;
}
onDestroy() { this.destroyed = true; }
}
@Component({selector: 'dummy'})
@View({template: "DynamicallyLoaded;"})
class DynamicallyLoaded {
}
@Component({selector: 'dummy'})
@View({template: "DynamicallyLoaded2;"})
class DynamicallyLoaded2 {
}
@Component({selector: 'dummy', host: {'[id]': 'id'}})
@View({template: "DynamicallyLoadedWithHostProps;"})
class DynamicallyLoadedWithHostProps {
id: string;
constructor() { this.id = "default"; }
}
@Component({selector: 'location'})
@View({template: "Location;"})
class Location {
elementRef: ElementRef;
constructor(elementRef: ElementRef) { this.elementRef = elementRef; }
}
@Component({selector: 'my-comp'})
@View({directives: []})
class MyComp {
ctxBoolProp: boolean;
constructor() { this.ctxBoolProp = false; }
}

File diff suppressed because it is too large Load Diff

View File

@ -1,308 +0,0 @@
/// This file contains tests that make sense only in Dart
library angular2.test.di.integration_dart_spec;
import 'package:angular2/angular2.dart';
import 'package:angular2/core.dart';
import 'package:angular2/src/core/debug.dart';
import 'package:angular2/test_lib.dart';
import 'package:observe/observe.dart';
import 'package:angular2/src/core/change_detection/differs/default_iterable_differ.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
class MockException implements Error {
var message;
var stackTrace;
}
class NonError {
var message;
}
void functionThatThrows() {
try {
throw new MockException();
} catch (e, stack) {
// If we lose the stack trace the message will no longer match
// the first line in the stack
e.message = stack.toString().split('\n')[0];
e.stackTrace = stack;
rethrow;
}
}
void functionThatThrowsNonError() {
try {
throw new NonError();
} catch (e, stack) {
// If we lose the stack trace the message will no longer match
// the first line in the stack
e.message = stack.toString().split('\n')[0];
rethrow;
}
}
main() {
describe('TypeLiteral', () {
it(
'should publish via viewBindings',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template:
'<type-literal-component></type-literal-component>',
directives: [TypeLiteralComponent]))
.createAsync(Dummy)
.then((tc) {
tc.detectChanges();
expect(asNativeElements(tc.debugElement.componentViewChildren))
.toHaveText('[Hello, World]');
async.done();
});
}));
});
describe('Error handling', () {
it(
'should preserve Error stack traces thrown from components',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template: '<throwing-component></throwing-component>',
directives: [ThrowingComponent]))
.createAsync(Dummy)
.catchError((e, stack) {
expect(e).toContainError("MockException");
expect(e).toContainError("functionThatThrows");
async.done();
});
}));
it(
'should preserve non-Error stack traces thrown from components',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template: '<throwing-component2></throwing-component2>',
directives: [ThrowingComponent2]))
.createAsync(Dummy)
.catchError((e, stack) {
expect(e).toContainError("NonError");
expect(e).toContainError("functionThatThrows");
async.done();
});
}));
});
describe('Property access', () {
it(
'should distinguish between map and property access',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template: '<property-access></property-access>',
directives: [PropertyAccess]))
.createAsync(Dummy)
.then((tc) {
tc.detectChanges();
expect(asNativeElements(tc.debugElement.componentViewChildren))
.toHaveText('prop:foo-prop;map:foo-map');
async.done();
});
}));
it(
'should not fallback on map access if property missing',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template: '<no-property-access></no-property-access>',
directives: [NoPropertyAccess]))
.createAsync(Dummy)
.then((tc) {
expect(() => tc.detectChanges())
.toThrowError(new RegExp('property not found'));
async.done();
});
}));
});
describe('OnChange', () {
it(
'should be notified of changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tb, async) {
tb
.overrideView(
Dummy,
new ViewMetadata(
template: '''<on-change [prop]="'hello'"></on-change>''',
directives: [OnChangeComponent]))
.createAsync(Dummy)
.then((tc) {
tc.detectChanges();
var cmp = tc.debugElement.componentViewChildren[0].inject(OnChangeComponent);
expect(cmp.prop).toEqual('hello');
expect(cmp.changes.containsKey('prop')).toEqual(true);
async.done();
});
}));
});
describe("ObservableListDiff", () {
it(
'should be notified of changes',
inject([TestComponentBuilder, Log],
fakeAsync((TestComponentBuilder tcb, Log log) {
tcb
.overrideView(
Dummy,
new ViewMetadata(
template:
'''<component-with-observable-list [list]="value"></component-with-observable-list>''',
directives: [ComponentWithObservableList]))
.createAsync(Dummy)
.then((tc) {
tc.debugElement.componentInstance.value = new ObservableList.from([1, 2]);
tc.detectChanges();
expect(log.result()).toEqual("check");
expect(asNativeElements(tc.debugElement.componentViewChildren)).toHaveText('12');
tc.detectChanges();
// we did not change the list => no checks
expect(log.result()).toEqual("check");
tc.debugElement.componentInstance.value.add(3);
flushMicrotasks();
tc.detectChanges();
// we changed the list => a check
expect(log.result()).toEqual("check; check");
expect(asNativeElements(tc.debugElement.componentViewChildren))
.toHaveText('123');
// we replaced the list => a check
tc.debugElement.componentInstance.value = new ObservableList.from([5, 6, 7]);
tc.detectChanges();
expect(log.result()).toEqual("check; check; check");
expect(asNativeElements(tc.debugElement.componentViewChildren))
.toHaveText('567');
});
})));
});
}
@Component(selector: 'dummy')
class Dummy {
dynamic value;
}
@Component(
selector: 'type-literal-component',
viewBindings: const [
const Binding(const TypeLiteral<List<String>>(),
toValue: const <String>['Hello', 'World'])
])
@View(template: '{{list}}')
class TypeLiteralComponent {
final List<String> list;
TypeLiteralComponent(this.list);
}
@Component(selector: 'throwing-component')
@View(template: '')
class ThrowingComponent {
ThrowingComponent() {
functionThatThrows();
}
}
@Component(selector: 'throwing-component2')
@View(template: '')
class ThrowingComponent2 {
ThrowingComponent2() {
functionThatThrowsNonError();
}
}
@proxy()
class PropModel implements Map {
final String foo = 'foo-prop';
operator [](_) => 'foo-map';
noSuchMethod(_) {
throw 'property not found';
}
}
@Component(selector: 'property-access')
@View(template: '''prop:{{model.foo}};map:{{model['foo']}}''')
class PropertyAccess {
final model = new PropModel();
}
@Component(selector: 'no-property-access')
@View(template: '''{{model.doesNotExist}}''')
class NoPropertyAccess {
final model = new PropModel();
}
@Component(
selector: 'on-change',
inputs: const ['prop'])
@View(template: '')
class OnChangeComponent implements OnChanges {
Map changes;
String prop;
@override
void onChanges(Map changes) {
this.changes = changes;
}
}
@Component(
selector: 'component-with-observable-list',
changeDetection: ChangeDetectionStrategy.OnPush,
inputs: const ['list'],
bindings: const [
const Binding(IterableDiffers,
toValue: const IterableDiffers(const [
const ObservableListDiffFactory(),
const DefaultIterableDifferFactory()
]))
])
@View(
template:
'<span *ng-for="#item of list">{{item}}</span><directive-logging-checks></directive-logging-checks>',
directives: const [NgFor, DirectiveLoggingChecks])
class ComponentWithObservableList {
Iterable list;
}
@Directive(
selector: 'directive-logging-checks')
class DirectiveLoggingChecks implements DoCheck {
Log log;
DirectiveLoggingChecks(this.log);
doCheck() => log.add("check");
}

File diff suppressed because it is too large Load Diff

View File

@ -1,565 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit,
containsRegexp,
stringifyElement,
TestComponentBuilder,
RootTestComponent,
fakeAsync,
tick
} from 'angular2/test_lib';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {
bind,
forwardRef,
Component,
Directive,
ElementRef,
TemplateRef,
View,
ViewContainerRef,
ViewEncapsulation,
ViewMetadata
} from 'angular2/core';
import {By} from 'angular2/src/core/debug';
export function main() {
describe('projection', () => {
it('should support simple components',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<simple>' +
'<div>A</div>' +
'</simple>',
directives: [Simple]
}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should support simple components with text interpolation as direct children',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '{{\'START(\'}}<simple>' +
'{{text}}' +
'</simple>{{\')END\'}}',
directives: [Simple]
}))
.createAsync(MainComp)
.then((main) => {
main.debugElement.componentInstance.text = 'A';
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('START(SIMPLE(A))END');
async.done();
});
}));
it('should support projecting text interpolation to a non bound element',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(
Simple,
new ViewMetadata(
{template: 'SIMPLE(<div><ng-content></ng-content></div>)', directives: []}))
.overrideView(
MainComp,
new ViewMetadata({template: '<simple>{{text}}</simple>', directives: [Simple]}))
.createAsync(MainComp)
.then((main) => {
main.debugElement.componentInstance.text = 'A';
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should support projecting text interpolation to a non bound element with other bound elements after it',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(
Simple, new ViewMetadata({
template:
'SIMPLE(<div><ng-content></ng-content></div><div [tab-index]="0">EL</div>)',
directives: []
}))
.overrideView(
MainComp,
new ViewMetadata({template: '<simple>{{text}}</simple>', directives: [Simple]}))
.createAsync(MainComp)
.then((main) => {
main.debugElement.componentInstance.text = 'A';
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('SIMPLE(AEL)');
async.done();
});
}));
it('should not show the light dom even if there is no content tag',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp,
new ViewMetadata({template: '<empty>A</empty>', directives: [Empty]}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('');
async.done();
});
}));
it('should support multiple content tags',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<multiple-content-tags>' +
'<div>B</div>' +
'<div>C</div>' +
'<div class="left">A</div>' +
'</multiple-content-tags>',
directives: [MultipleContentTagsComponent]
}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('(A, BC)');
async.done();
});
}));
it('should redistribute only direct children',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<multiple-content-tags>' +
'<div>B<div class="left">A</div></div>' +
'<div>C</div>' +
'</multiple-content-tags>',
directives: [MultipleContentTagsComponent]
}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('(, BAC)');
async.done();
});
}));
it("should redistribute direct child viewcontainers when the light dom changes",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<multiple-content-tags>' +
'<template manual class="left"><div>A1</div></template>' +
'<div>B</div>' +
'</multiple-content-tags>',
directives: [MultipleContentTagsComponent, ManualViewportDirective]
}))
.createAsync(MainComp)
.then((main) => {
var viewportDirectives =
main.debugElement.queryAll(By.directive(ManualViewportDirective))
.map(de => de.inject(ManualViewportDirective));
expect(main.debugElement.nativeElement).toHaveText('(, B)');
viewportDirectives.forEach(d => d.show());
expect(main.debugElement.nativeElement).toHaveText('(A1, B)');
viewportDirectives.forEach(d => d.hide());
expect(main.debugElement.nativeElement).toHaveText('(, B)');
async.done();
});
}));
it("should support nested components",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<outer-with-indirect-nested>' +
'<div>A</div>' +
'<div>B</div>' +
'</outer-with-indirect-nested>',
directives: [OuterWithIndirectNestedComponent]
}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('OUTER(SIMPLE(AB))');
async.done();
});
}));
it("should support nesting with content being direct child of a nested component",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<outer>' +
'<template manual class="left"><div>A</div></template>' +
'<div>B</div>' +
'<div>C</div>' +
'</outer>',
directives: [OuterComponent, ManualViewportDirective],
}))
.createAsync(MainComp)
.then((main) => {
var viewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
expect(main.debugElement.nativeElement).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
viewportDirective.show();
expect(main.debugElement.nativeElement).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
async.done();
});
}));
it('should redistribute when the shadow dom changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<conditional-content>' +
'<div class="left">A</div>' +
'<div>B</div>' +
'<div>C</div>' +
'</conditional-content>',
directives: [ConditionalContentComponent]
}))
.createAsync(MainComp)
.then((main) => {
var viewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
expect(main.debugElement.nativeElement).toHaveText('(, BC)');
viewportDirective.show();
expect(main.debugElement.nativeElement).toHaveText('(A, BC)');
viewportDirective.hide();
expect(main.debugElement.nativeElement).toHaveText('(, BC)');
async.done();
});
}));
// GH-2095 - https://github.com/angular/angular/issues/2095
// important as we are removing the ng-content element during compilation,
// which could skrew up text node indices.
it('should support text nodes after content tags',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
tcb.overrideView(
MainComp,
new ViewMetadata(
{template: '<simple string-prop="text"></simple>', directives: [Simple]}))
.overrideTemplate(Simple, '<ng-content></ng-content><p>P,</p>{{stringProp}}')
.createAsync(MainComp)
.then((main: RootTestComponent) => {
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('P,text');
async.done();
});
}));
// important as we are moving style tags around during compilation,
// which could skrew up text node indices.
it('should support text nodes after style tags',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
tcb.overrideView(
MainComp,
new ViewMetadata(
{template: '<simple string-prop="text"></simple>', directives: [Simple]}))
.overrideTemplate(Simple, '<style></style><p>P,</p>{{stringProp}}')
.createAsync(MainComp)
.then((main: RootTestComponent) => {
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('P,text');
async.done();
});
}));
it('should support moving non projected light dom around',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<empty>' +
' <template manual><div>A</div></template>' +
'</empty>' +
'START(<div project></div>)END',
directives: [Empty, ProjectDirective, ManualViewportDirective],
}))
.createAsync(MainComp)
.then((main) => {
var sourceDirective: ManualViewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
var projectDirective: ProjectDirective =
main.debugElement.query(By.directive(ProjectDirective)).inject(ProjectDirective);
expect(main.debugElement.nativeElement).toHaveText('START()END');
projectDirective.show(sourceDirective.templateRef);
expect(main.debugElement.nativeElement).toHaveText('START(A)END');
async.done();
});
}));
it('should support moving projected light dom around',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<simple><template manual><div>A</div></template></simple>' +
'START(<div project></div>)END',
directives: [Simple, ProjectDirective, ManualViewportDirective],
}))
.createAsync(MainComp)
.then((main) => {
var sourceDirective: ManualViewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
var projectDirective: ProjectDirective =
main.debugElement.query(By.directive(ProjectDirective)).inject(ProjectDirective);
expect(main.debugElement.nativeElement).toHaveText('SIMPLE()START()END');
projectDirective.show(sourceDirective.templateRef);
expect(main.debugElement.nativeElement).toHaveText('SIMPLE()START(A)END');
async.done();
});
}));
it('should support moving ng-content around',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MainComp, new ViewMetadata({
template: '<conditional-content>' +
'<div class="left">A</div>' +
'<div>B</div>' +
'</conditional-content>' +
'START(<div project></div>)END',
directives:
[ConditionalContentComponent, ProjectDirective, ManualViewportDirective]
}))
.createAsync(MainComp)
.then((main) => {
var sourceDirective: ManualViewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
var projectDirective: ProjectDirective =
main.debugElement.query(By.directive(ProjectDirective)).inject(ProjectDirective);
expect(main.debugElement.nativeElement).toHaveText('(, B)START()END');
projectDirective.show(sourceDirective.templateRef);
expect(main.debugElement.nativeElement).toHaveText('(, B)START(A)END');
// Stamping ng-content multiple times should not produce the content multiple
// times...
projectDirective.show(sourceDirective.templateRef);
expect(main.debugElement.nativeElement).toHaveText('(, B)START(A)END');
async.done();
});
}));
// Note: This does not use a ng-content element, but
// is still important as we are merging proto views independent of
// the presence of ng-content elements!
it('should still allow to implement a recursive trees',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp,
new ViewMetadata({template: '<tree></tree>', directives: [Tree]}))
.createAsync(MainComp)
.then((main) => {
main.detectChanges();
var manualDirective: ManualViewportDirective =
main.debugElement.query(By.directive(ManualViewportDirective))
.inject(ManualViewportDirective);
expect(main.debugElement.nativeElement).toHaveText('TREE(0:)');
manualDirective.show();
main.detectChanges();
expect(main.debugElement.nativeElement).toHaveText('TREE(0:TREE(1:))');
async.done();
});
}));
if (DOM.supportsNativeShadowDOM()) {
it('should support native content projection',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, new ViewMetadata({
template: '<simple-native>' +
'<div>A</div>' +
'</simple-native>',
directives: [SimpleNative]
}))
.createAsync(MainComp)
.then((main) => {
expect(main.debugElement.nativeElement).toHaveText('SIMPLE(A)');
async.done();
});
}));
}
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())');
viewportElement =
main.debugElement.componentViewChildren[0].componentViewChildren[1];
viewportElement.inject(ManualViewportDirective).show();
expect(main.debugElement.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))');
async.done();
});
}));
});
}
@Component({selector: 'main'})
@View({template: '', directives: []})
class MainComp {
text: string = '';
}
@Component({selector: 'simple', inputs: ['stringProp']})
@View({template: 'SIMPLE(<ng-content></ng-content>)', directives: []})
class Simple {
stringProp: string = '';
}
@Component({selector: 'simple-native'})
@View({
template: 'SIMPLE(<content></content>)',
directives: [],
encapsulation: ViewEncapsulation.Native
})
class SimpleNative {
}
@Component({selector: 'empty'})
@View({template: '', directives: []})
class Empty {
}
@Component({selector: 'multiple-content-tags'})
@View({
template: '(<ng-content select=".left"></ng-content>, <ng-content></ng-content>)',
directives: []
})
class MultipleContentTagsComponent {
}
@Directive({selector: '[manual]'})
class ManualViewportDirective {
constructor(public vc: ViewContainerRef, public templateRef: TemplateRef) {}
show() { this.vc.createEmbeddedView(this.templateRef, 0); }
hide() { this.vc.clear(); }
}
@Directive({selector: '[project]'})
class ProjectDirective {
constructor(public vc: ViewContainerRef) {}
show(templateRef: TemplateRef) { this.vc.createEmbeddedView(templateRef, 0); }
hide() { this.vc.clear(); }
}
@Component({selector: 'outer-with-indirect-nested'})
@View({
template: 'OUTER(<simple><div><ng-content></ng-content></div></simple>)',
directives: [Simple]
})
class OuterWithIndirectNestedComponent {
}
@Component({selector: 'outer'})
@View({
template:
'OUTER(<inner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></inner>)',
directives: [forwardRef(() => InnerComponent)]
})
class OuterComponent {
}
@Component({selector: 'inner'})
@View({
template:
'INNER(<innerinner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></innerinner>)',
directives: [forwardRef(() => InnerInnerComponent)]
})
class InnerComponent {
}
@Component({selector: 'innerinner'})
@View({
template: 'INNERINNER(<ng-content select=".left"></ng-content>,<ng-content></ng-content>)',
directives: []
})
class InnerInnerComponent {
}
@Component({selector: 'conditional-content'})
@View({
template:
'<div>(<div *manual><ng-content select=".left"></ng-content></div>, <ng-content></ng-content>)</div>',
directives: [ManualViewportDirective]
})
class ConditionalContentComponent {
}
@Component({selector: 'conditional-text'})
@View({
template:
'MAIN(<template manual>FIRST(<template manual>SECOND(<ng-content></ng-content>)</template>)</template>)',
directives: [ManualViewportDirective]
})
class ConditionalTextComponent {
}
@Component({selector: 'tab'})
@View({
template: '<div><div *manual>TAB(<ng-content></ng-content>)</div></div>',
directives: [ManualViewportDirective]
})
class Tab {
}
@Component({selector: 'tree', inputs: ['depth']})
@View({
template: 'TREE({{depth}}:<tree *manual [depth]="depth+1"></tree>)',
directives: [ManualViewportDirective, Tree]
})
class Tree {
depth = 0;
}

View File

@ -1,19 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
xdescribe,
ddescribe,
describe,
el,
expect,
iit,
inject,
it
} from 'angular2/test_lib';
export function main() {
describe('ProtoViewFactory', () => {
// TODO
});
}

View File

@ -1,943 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
TestComponentBuilder,
} from 'angular2/test_lib';
import {isPresent} from 'angular2/src/core/facade/lang';
import {ObservableWrapper} from 'angular2/src/core/facade/async';
import {
Component,
Directive,
Injectable,
NgIf,
NgFor,
Optional,
TemplateRef,
Query,
QueryList,
View,
ViewQuery,
ContentChildren,
ViewChildren,
ContentChild,
ViewChild,
AfterContentInit,
AfterViewInit,
AfterContentChecked,
AfterViewChecked
} from 'angular2/core';
import {asNativeElements} from 'angular2/src/core/debug';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
export function main() {
BrowserDomAdapter.makeCurrent();
describe('Query API', () => {
describe("querying by directive type", () => {
it('should contain all direct child directives in the light dom (constructor)',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div text="1"></div>' +
'<needs-query text="2"><div text="3">' +
'<div text="too-deep"></div>' +
'</div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|3|');
async.done();
});
}));
it('should contain all direct child directives in the content dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-content-children #q><div text="foo"></div></needs-content-children>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var q = view.debugElement.componentViewChildren[0].getLocal('q');
view.detectChanges();
expect(q.textDirChildren.length).toEqual(1);
expect(q.numberOfChildrenAfterContentInit).toEqual(1);
async.done();
});
}));
it('should contain the first content child',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-content-child #q><div *ng-if="shouldShow" text="foo"></div></needs-content-child>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.debugElement.componentInstance.shouldShow = true;
view.detectChanges();
var q = view.debugElement.componentViewChildren[0].getLocal('q');
expect(q.log).toEqual([["setter", "foo"], ["init", "foo"], ["check", "foo"]]);
view.debugElement.componentInstance.shouldShow = false;
view.detectChanges();
expect(q.log).toEqual([
["setter", "foo"],
["init", "foo"],
["check", "foo"],
["setter", null],
["check", null]
]);
async.done();
});
}));
it('should contain the first view child',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-child #q></needs-view-child>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var q = view.debugElement.componentViewChildren[0].getLocal('q');
expect(q.log).toEqual([["setter", "foo"], ["init", "foo"], ["check", "foo"]]);
q.shouldShow = false;
view.detectChanges();
expect(q.log).toEqual([
["setter", "foo"],
["init", "foo"],
["check", "foo"],
["setter", null],
["check", null]
]);
async.done();
});
}));
it('should contain all directives in the light dom when descendants flag is used',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div text="1"></div>' +
'<needs-query-desc text="2"><div text="3">' +
'<div text="4"></div>' +
'</div></needs-query-desc>' +
'<div text="5"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|3|4|');
async.done();
});
}));
it('should contain all directives in the light dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div text="1"></div>' +
'<needs-query text="2"><div text="3"></div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|3|');
async.done();
});
}));
it('should reflect dynamically inserted directives',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div text="1"></div>' +
'<needs-query text="2"><div *ng-if="shouldShow" [text]="\'3\'"></div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren)).toHaveText('2|');
view.debugElement.componentInstance.shouldShow = true;
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|3|');
async.done();
});
}));
it('should be cleanly destroyed when a query crosses view boundaries',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div text="1"></div>' +
'<needs-query text="2"><div *ng-if="shouldShow" [text]="\'3\'"></div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((rtc) => {
rtc.debugElement.componentInstance.shouldShow = true;
rtc.detectChanges();
rtc.destroy();
async.done();
});
}));
it('should reflect moved directives',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div text="1"></div>' +
'<needs-query text="2"><div *ng-for="var i of list" [text]="i"></div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|1d|2d|3d|');
view.debugElement.componentInstance.list = ['3d', '2d'];
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('2|3d|2d|');
async.done();
});
}));
});
describe('query for TemplateRef', () => {
it('should find TemplateRefs in the light and shadow dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-tpl><template var-x="light"></template></needs-tpl>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var needsTpl: NeedsTpl =
view.debugElement.componentViewChildren[0].inject(NeedsTpl);
expect(needsTpl.query.first.hasLocal('light')).toBe(true);
expect(needsTpl.viewQuery.first.hasLocal('shadow')).toBe(true);
async.done();
});
}));
});
describe("changes", () => {
it('should notify query on change',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query #q>' +
'<div text="1"></div>' +
'<div *ng-if="shouldShow" text="2"></div>' +
'</needs-query>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q = view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
ObservableWrapper.subscribe(q.query.changes, (_) => {
expect(q.query.first.text).toEqual("1");
expect(q.query.last.text).toEqual("2");
async.done();
});
view.debugElement.componentInstance.shouldShow = true;
view.detectChanges();
});
}));
it("should notify child's query before notifying parent's query",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-desc #q1>' +
'<needs-query-desc #q2>' +
'<div text="1"></div>' +
'</needs-query-desc>' +
'</needs-query-desc>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q1 = view.debugElement.componentViewChildren[0].getLocal("q1");
var q2 = view.debugElement.componentViewChildren[0].getLocal("q2");
var firedQ2 = false;
ObservableWrapper.subscribe(q2.query.changes, (_) => { firedQ2 = true; });
ObservableWrapper.subscribe(q1.query.changes, (_) => {
expect(firedQ2).toBe(true);
async.done();
});
view.detectChanges();
});
}));
it('should correctly clean-up when destroyed together with the directives it is querying',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-query #q *ng-if="shouldShow"><div text="foo"></div></needs-query>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.debugElement.componentInstance.shouldShow = true;
view.detectChanges();
var q: NeedsQuery = view.debugElement.componentViewChildren[1].getLocal('q');
expect(q.query.length).toEqual(1);
view.debugElement.componentInstance.shouldShow = false;
view.detectChanges();
view.debugElement.componentInstance.shouldShow = true;
view.detectChanges();
var q2: NeedsQuery = view.debugElement.componentViewChildren[1].getLocal('q');
expect(q2.query.length).toEqual(1);
async.done();
});
}));
});
describe("querying by var binding", () => {
it('should contain all the child directives in the light dom with the given var binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-query-by-var-binding #q>' +
'<div *ng-for="#item of list" [text]="item" #text-label="textDir"></div>' +
'</needs-query-by-var-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q = view.debugElement.componentViewChildren[0].getLocal("q");
view.debugElement.componentInstance.list = ['1d', '2d'];
view.detectChanges();
expect(q.query.first.text).toEqual("1d");
expect(q.query.last.text).toEqual("2d");
async.done();
});
}));
it('should support querying by multiple var bindings',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-bindings #q>' +
'<div text="one" #text-label1="textDir"></div>' +
'<div text="two" #text-label2="textDir"></div>' +
'</needs-query-by-var-bindings>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q = view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.first.text).toEqual("one");
expect(q.query.last.text).toEqual("two");
async.done();
});
}));
it('should reflect dynamically inserted directives',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-query-by-var-binding #q>' +
'<div *ng-for="#item of list" [text]="item" #text-label="textDir"></div>' +
'</needs-query-by-var-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q = view.debugElement.componentViewChildren[0].getLocal("q");
view.debugElement.componentInstance.list = ['1d', '2d'];
view.detectChanges();
view.debugElement.componentInstance.list = ['2d', '1d'];
view.detectChanges();
expect(q.query.last.text).toEqual("1d");
async.done();
});
}));
it('should contain all the elements in the light dom with the given var binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-binding #q>' +
'<div template="ng-for: #item of list">' +
'<div #text-label>{{item}}</div>' +
'</div>' +
'</needs-query-by-var-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q = view.debugElement.componentViewChildren[0].getLocal("q");
view.debugElement.componentInstance.list = ['1d', '2d'];
view.detectChanges();
expect(q.query.first.nativeElement).toHaveText("1d");
expect(q.query.last.nativeElement).toHaveText("2d");
async.done();
});
}));
it('should contain all the elements in the light dom even if they get projected',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-and-project #q>' +
'<div text="hello"></div><div text="world"></div>' +
'</needs-query-and-project>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
expect(asNativeElements(view.debugElement.componentViewChildren))
.toHaveText('hello|world|');
async.done();
});
}));
it('should support querying the view by using a view query',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-by-var-binding #q></needs-view-query-by-var-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryByLabel =
view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.first.nativeElement).toHaveText("text");
async.done();
});
}));
it('should contain all child directives in the view dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-children #q></needs-view-children>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var q = view.debugElement.componentViewChildren[0].getLocal('q');
view.detectChanges();
expect(q.textDirChildren.length).toEqual(1);
expect(q.numberOfChildrenAfterViewInit).toEqual(1);
async.done();
});
}));
});
describe("querying in the view", () => {
it('should contain all the elements in the view with that have the given directive',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query #q><div text="ignoreme"></div></needs-view-query>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQuery = view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "2", "3", "4"]);
async.done();
});
}));
it('should not include directive present on the host element',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query #q text="self"></needs-view-query>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQuery = view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "2", "3", "4"]);
async.done();
});
}));
it('should reflect changes in the component',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-if #q></needs-view-query-if>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryIf = view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.length).toBe(0);
q.show = true;
view.detectChanges();
expect(q.query.length).toBe(1);
expect(q.query.first.text).toEqual("1");
async.done();
});
}));
it('should not be affected by other changes in the component',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-nested-if #q></needs-view-query-nested-if>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryNestedIf =
view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.length).toEqual(1);
expect(q.query.first.text).toEqual("1");
q.show = false;
view.detectChanges();
expect(q.query.length).toEqual(1);
expect(q.query.first.text).toEqual("1");
async.done();
});
}));
it('should maintain directives in pre-order depth-first DOM order after dynamic insertion',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-order #q></needs-view-query-order>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryOrder =
view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "2", "3", "4"]);
q.list = ["-3", "2"];
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "-3", "2", "4"]);
async.done();
});
}));
it('should maintain directives in pre-order depth-first DOM order after dynamic insertion',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-order-with-p #q></needs-view-query-order-with-p>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryOrderWithParent =
view.debugElement.componentViewChildren[0].getLocal("q");
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "2", "3", "4"]);
q.list = ["-3", "2"];
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(["1", "-3", "2", "4"]);
async.done();
});
}));
it('should handle long ng-for cycles',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-order #q></needs-view-query-order>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
var q: NeedsViewQueryOrder =
view.debugElement.componentViewChildren[0].getLocal('q');
// no significance to 50, just a reasonably large cycle.
for (var i = 0; i < 50; i++) {
var newString = i.toString();
q.list = [newString];
view.detectChanges();
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', newString, '4']);
}
async.done();
});
}));
it('should support more than three queries',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-four-queries #q><div text="1"></div></needs-four-queries>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var q = view.debugElement.componentViewChildren[0].getLocal('q');
expect(q.query1).toBeDefined();
expect(q.query2).toBeDefined();
expect(q.query3).toBeDefined();
expect(q.query4).toBeDefined();
async.done();
});
}));
});
});
}
@Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'})
@Injectable()
class TextDirective {
text: string;
constructor() {}
}
@Component({selector: 'needs-content-children'})
@View({template: ''})
class NeedsContentChildren implements AfterContentInit {
@ContentChildren(TextDirective) textDirChildren: QueryList<TextDirective>;
numberOfChildrenAfterContentInit: number;
afterContentInit() { this.numberOfChildrenAfterContentInit = this.textDirChildren.length; }
}
@Component({selector: 'needs-view-children'})
@View({template: '<div text></div>', directives: [TextDirective]})
class NeedsViewChildren implements AfterViewInit {
@ViewChildren(TextDirective) textDirChildren: QueryList<TextDirective>;
numberOfChildrenAfterViewInit: number;
afterViewInit() { this.numberOfChildrenAfterViewInit = this.textDirChildren.length; }
}
@Component({selector: 'needs-content-child'})
@View({template: ''})
class NeedsContentChild implements AfterContentInit, AfterContentChecked {
_child: TextDirective;
@ContentChild(TextDirective)
set child(value) {
this._child = value;
this.log.push(['setter', isPresent(value) ? value.text : null]);
}
get child() { return this._child; }
log = [];
afterContentInit() { this.log.push(["init", isPresent(this.child) ? this.child.text : null]); }
afterContentChecked() {
this.log.push(["check", isPresent(this.child) ? this.child.text : null]);
}
}
@Component({selector: 'needs-view-child'})
@View({
template: `
<div *ng-if="shouldShow" text="foo"></div>
`,
directives: [NgIf, TextDirective]
})
class NeedsViewChild implements AfterViewInit,
AfterViewChecked {
shouldShow: boolean = true;
_child: TextDirective;
@ViewChild(TextDirective)
set child(value) {
this._child = value;
this.log.push(['setter', isPresent(value) ? value.text : null]);
}
get child() { return this._child; }
log = [];
afterViewInit() { this.log.push(["init", isPresent(this.child) ? this.child.text : null]); }
afterViewChecked() { this.log.push(["check", isPresent(this.child) ? this.child.text : null]); }
}
@Directive({selector: '[dir]'})
@Injectable()
class InertDirective {
constructor() {}
}
@Component({selector: 'needs-query'})
@View({
directives: [NgFor, TextDirective],
template: '<div text="ignoreme"></div><b *ng-for="var dir of query">{{dir.text}}|</b>'
})
@Injectable()
class NeedsQuery {
query: QueryList<TextDirective>;
constructor(@Query(TextDirective) query: QueryList<TextDirective>) { this.query = query; }
}
@Component({selector: 'needs-four-queries'})
@View({template: ''})
class NeedsFourQueries {
@ContentChild(TextDirective) query1: TextDirective;
@ContentChild(TextDirective) query2: TextDirective;
@ContentChild(TextDirective) query3: TextDirective;
@ContentChild(TextDirective) query4: TextDirective;
}
@Component({selector: 'needs-query-desc'})
@View({directives: [NgFor], template: '<div *ng-for="var dir of query">{{dir.text}}|</div>'})
@Injectable()
class NeedsQueryDesc {
query: QueryList<TextDirective>;
constructor(@Query(TextDirective, {descendants: true}) query: QueryList<TextDirective>) {
this.query = query;
}
}
@Component({selector: 'needs-query-by-var-binding'})
@View({directives: [], template: '<ng-content>'})
@Injectable()
class NeedsQueryByLabel {
query: QueryList<any>;
constructor(@Query("textLabel", {descendants: true}) query: QueryList<any>) {
this.query = query;
}
}
@Component({selector: 'needs-view-query-by-var-binding'})
@View({directives: [], template: '<div #text-label>text</div>'})
@Injectable()
class NeedsViewQueryByLabel {
query: QueryList<any>;
constructor(@ViewQuery("textLabel") query: QueryList<any>) { this.query = query; }
}
@Component({selector: 'needs-query-by-var-bindings'})
@View({directives: [], template: '<ng-content>'})
@Injectable()
class NeedsQueryByTwoLabels {
query: QueryList<any>;
constructor(@Query("textLabel1,textLabel2", {descendants: true}) query: QueryList<any>) {
this.query = query;
}
}
@Component({selector: 'needs-query-and-project'})
@View({
directives: [NgFor],
template: '<div *ng-for="var dir of query">{{dir.text}}|</div><ng-content></ng-content>'
})
@Injectable()
class NeedsQueryAndProject {
query: QueryList<TextDirective>;
constructor(@Query(TextDirective) query: QueryList<TextDirective>) { this.query = query; }
}
@Component({selector: 'needs-view-query'})
@View({
directives: [TextDirective],
template: '<div text="1"><div text="2"></div></div>' +
'<div text="3"></div><div text="4"></div>'
})
@Injectable()
class NeedsViewQuery {
query: QueryList<TextDirective>;
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) { this.query = query; }
}
@Component({selector: 'needs-view-query-if'})
@View({directives: [NgIf, TextDirective], template: '<div *ng-if="show" text="1"></div>'})
@Injectable()
class NeedsViewQueryIf {
show: boolean;
query: QueryList<TextDirective>;
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) {
this.query = query;
this.show = false;
}
}
@Component({selector: 'needs-view-query-nested-if'})
@View({
directives: [NgIf, InertDirective, TextDirective],
template: '<div text="1"><div *ng-if="show"><div dir></div></div></div>'
})
@Injectable()
class NeedsViewQueryNestedIf {
show: boolean;
query: QueryList<TextDirective>;
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) {
this.query = query;
this.show = true;
}
}
@Component({selector: 'needs-view-query-order'})
@View({
directives: [NgFor, TextDirective, InertDirective],
template: '<div text="1"></div>' +
'<div *ng-for="var i of list" [text]="i"></div>' +
'<div text="4"></div>'
})
@Injectable()
class NeedsViewQueryOrder {
query: QueryList<TextDirective>;
list: string[];
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) {
this.query = query;
this.list = ['2', '3'];
}
}
@Component({selector: 'needs-view-query-order-with-p'})
@View({
directives: [NgFor, TextDirective, InertDirective],
template: '<div dir><div text="1"></div>' +
'<div *ng-for="var i of list" [text]="i"></div>' +
'<div text="4"></div></div>'
})
@Injectable()
class NeedsViewQueryOrderWithParent {
query: QueryList<TextDirective>;
list: string[];
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) {
this.query = query;
this.list = ['2', '3'];
}
}
@Component({selector: 'needs-tpl'})
@View({template: '<template var-x="shadow"></template>'})
class NeedsTpl {
viewQuery: QueryList<TemplateRef>;
query: QueryList<TemplateRef>;
constructor(@ViewQuery(TemplateRef) viewQuery: QueryList<TemplateRef>,
@Query(TemplateRef) query: QueryList<TemplateRef>) {
this.viewQuery = viewQuery;
this.query = query;
}
}
@Component({selector: 'my-comp'})
@View({
directives: [
NeedsQuery,
NeedsQueryDesc,
NeedsQueryByLabel,
NeedsQueryByTwoLabels,
NeedsQueryAndProject,
NeedsViewQuery,
NeedsViewQueryIf,
NeedsViewQueryNestedIf,
NeedsViewQueryOrder,
NeedsViewQueryByLabel,
NeedsViewQueryOrderWithParent,
NeedsContentChildren,
NeedsViewChildren,
NeedsViewChild,
NeedsContentChild,
NeedsTpl,
TextDirective,
InertDirective,
NgIf,
NgFor,
NeedsFourQueries
]
})
@Injectable()
class MyComp {
shouldShow: boolean;
list;
constructor() {
this.shouldShow = false;
this.list = ['1d', '2d', '3d'];
}
}

View File

@ -1,92 +0,0 @@
import {
describe,
it,
expect,
beforeEach,
ddescribe,
iit,
xit,
el,
fakeAsync,
tick
} from 'angular2/test_lib';
import {MapWrapper, ListWrapper, iterateListLike} from 'angular2/src/core/facade/collection';
import {StringWrapper} from 'angular2/src/core/facade/lang';
import {ObservableWrapper} from 'angular2/src/core/facade/async';
import {QueryList} from 'angular2/src/core/compiler/query_list';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
export function main() {
describe('QueryList', () => {
var queryList: QueryList<string>;
var log: string;
beforeEach(() => {
queryList = new QueryList<string>();
log = '';
});
function logAppend(item) { log += (log.length == 0 ? '' : ', ') + item; }
it('should support resetting and iterating over the new objects', () => {
queryList.reset(['one']);
queryList.reset(['two']);
iterateListLike(queryList, logAppend);
expect(log).toEqual('two');
});
it('should support length', () => {
queryList.reset(['one', 'two']);
expect(queryList.length).toEqual(2);
});
it('should support map', () => {
queryList.reset(['one', 'two']);
expect(queryList.map((x) => x)).toEqual(['one', 'two']);
});
it('should support toString', () => {
queryList.reset(['one', 'two']);
var listString = queryList.toString();
expect(StringWrapper.contains(listString, 'one')).toBeTruthy();
expect(StringWrapper.contains(listString, 'two')).toBeTruthy();
});
it('should support first and last', () => {
queryList.reset(['one', 'two', 'three']);
expect(queryList.first).toEqual('one');
expect(queryList.last).toEqual('three');
});
if (DOM.supportsDOMEvents()) {
describe('simple observable interface', () => {
it('should fire callbacks on change', fakeAsync(() => {
var fires = 0;
ObservableWrapper.subscribe(queryList.changes, (_) => { fires += 1; });
queryList.notifyOnChanges();
tick();
expect(fires).toEqual(1);
queryList.notifyOnChanges();
tick();
expect(fires).toEqual(2);
}));
it('should provides query list as an argument', fakeAsync(() => {
var recorded;
ObservableWrapper.subscribe(queryList.changes, (v: any) => { recorded = v; });
queryList.reset(["one"]);
queryList.notifyOnChanges();
tick();
expect(recorded).toBe(queryList);
}));
});
}
});
}

View File

@ -1,60 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit
} from 'angular2/test_lib';
import {SpyView, SpyAppViewManager} from '../spies';
import {AppView, AppViewContainer} from 'angular2/src/core/compiler/view';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {ViewRef} from 'angular2/src/core/compiler/view_ref';
export function main() {
// TODO(tbosch): add missing tests
describe('ViewContainerRef', () => {
var location;
var view;
var viewManager;
function createViewContainer() { return new ViewContainerRef(viewManager, location); }
beforeEach(() => {
viewManager = new SpyAppViewManager();
view = new SpyView();
view.prop("viewContainers", [null]);
location = new ElementRef(new ViewRef(view), 0, null);
});
describe('length', () => {
it('should return a 0 length if there is no underlying AppViewContainer', () => {
var vc = createViewContainer();
expect(vc.length).toBe(0);
});
it('should return the size of the underlying AppViewContainer', () => {
var vc = createViewContainer();
var appVc = new AppViewContainer();
view.prop("viewContainers", [appVc]);
appVc.views = [<any>new SpyView()];
expect(vc.length).toBe(1);
});
});
// TODO: add missing tests here!
});
}

View File

@ -1,515 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit
} from 'angular2/test_lib';
import {SpyRenderer, SpyAppViewPool, SpyAppViewListener, SpyProtoViewFactory} from '../spies';
import {Injector, bind} from 'angular2/core';
import {AppProtoView, AppView, AppViewContainer} from 'angular2/src/core/compiler/view';
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
import {
Renderer,
RenderViewRef,
RenderProtoViewRef,
RenderFragmentRef,
ViewType,
RenderViewWithFragments
} from 'angular2/src/core/render/api';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
import {
createHostPv,
createComponentPv,
createEmbeddedPv,
createEmptyElBinder,
createNestedElBinder,
createProtoElInjector
} from './view_manager_utils_spec';
export function main() {
// TODO(tbosch): add missing tests
describe('AppViewManager', () => {
var renderer;
var utils: AppViewManagerUtils;
var viewListener;
var viewPool;
var linker;
var manager: AppViewManager;
var createdRenderViews: RenderViewWithFragments[];
function wrapPv(protoView: AppProtoView): ProtoViewRef { return new ProtoViewRef(protoView); }
function wrapView(view: AppView): ViewRef { return new ViewRef(view); }
function resetSpies() {
viewListener.spy('viewCreated').reset();
viewListener.spy('viewDestroyed').reset();
renderer.spy('createView').reset();
renderer.spy('destroyView').reset();
renderer.spy('createRootHostView').reset();
renderer.spy('setEventDispatcher').reset();
renderer.spy('hydrateView').reset();
renderer.spy('dehydrateView').reset();
viewPool.spy('returnView').reset();
}
beforeEach(() => {
renderer = new SpyRenderer();
utils = new AppViewManagerUtils();
viewListener = new SpyAppViewListener();
viewPool = new SpyAppViewPool();
linker = new SpyProtoViewFactory();
manager = new AppViewManager(viewPool, viewListener, utils, renderer, linker);
createdRenderViews = [];
renderer.spy('createRootHostView')
.andCallFake((_a, renderFragmentCount, _b) => {
var fragments = [];
for (var i = 0; i < renderFragmentCount; i++) {
fragments.push(new RenderFragmentRef());
}
var rv = new RenderViewWithFragments(new RenderViewRef(), fragments);
createdRenderViews.push(rv);
return rv;
});
renderer.spy('createView')
.andCallFake((_a, renderFragmentCount) => {
var fragments = [];
for (var i = 0; i < renderFragmentCount; i++) {
fragments.push(new RenderFragmentRef());
}
var rv = new RenderViewWithFragments(new RenderViewRef(), fragments);
createdRenderViews.push(rv);
return rv;
});
viewPool.spy('returnView').andReturn(true);
});
describe('createRootHostView', () => {
var hostProtoView: AppProtoView;
beforeEach(
() => { hostProtoView = createHostPv([createNestedElBinder(createComponentPv())]); });
it('should initialize the ProtoView', () => {
manager.createRootHostView(wrapPv(hostProtoView), null, null);
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(hostProtoView);
});
it('should create the view', () => {
var rootView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
expect(rootView.proto).toBe(hostProtoView);
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(rootView);
});
it('should hydrate the view', () => {
var injector = Injector.resolveAndCreate([]);
var rootView = internalView(
<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, injector));
expect(rootView.hydrated()).toBe(true);
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(rootView.render);
});
it('should create and set the render view using the component selector', () => {
var rootView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
expect(renderer.spy('createRootHostView'))
.toHaveBeenCalledWith(hostProtoView.render,
hostProtoView.mergeInfo.embeddedViewCount + 1, 'someComponent');
expect(rootView.render).toBe(createdRenderViews[0].viewRef);
expect(rootView.renderFragment).toBe(createdRenderViews[0].fragmentRefs[0]);
});
it('should allow to override the selector', () => {
var selector = 'someOtherSelector';
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), selector, null));
expect(renderer.spy('createRootHostView'))
.toHaveBeenCalledWith(hostProtoView.render,
hostProtoView.mergeInfo.embeddedViewCount + 1, selector);
});
it('should set the event dispatcher', () => {
var rootView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
expect(renderer.spy('setEventDispatcher')).toHaveBeenCalledWith(rootView.render, rootView);
});
});
describe('destroyRootHostView', () => {
var hostProtoView: AppProtoView;
var hostView: AppView;
var hostRenderViewRef: RenderViewRef;
beforeEach(() => {
hostProtoView = createHostPv([createNestedElBinder(createComponentPv())]);
hostView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
hostRenderViewRef = hostView.render;
});
it('should dehydrate', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(hostView.hydrated()).toBe(false);
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(hostView.render);
});
it('should destroy the render view', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(renderer.spy('destroyView')).toHaveBeenCalledWith(hostRenderViewRef);
expect(viewListener.spy('viewDestroyed')).toHaveBeenCalledWith(hostView);
});
it('should not return the view to the pool', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(viewPool.spy('returnView')).not.toHaveBeenCalled();
});
});
describe('createEmbeddedViewInContainer', () => {
describe('basic functionality', () => {
var hostView: AppView;
var childProtoView: AppProtoView;
var vcRef: ElementRef;
var templateRef: TemplateRef;
beforeEach(() => {
childProtoView = createEmbeddedPv();
var hostProtoView = createHostPv(
[createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]);
hostView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
vcRef = hostView.elementRefs[1];
templateRef = new TemplateRef(hostView.elementRefs[1]);
resetSpies();
});
it('should initialize the ProtoView', () => {
manager.createEmbeddedViewInContainer(vcRef, 0, templateRef);
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(childProtoView);
});
describe('create the first view', () => {
it('should create an AppViewContainer if not yet existing', () => {
manager.createEmbeddedViewInContainer(vcRef, 0, templateRef);
expect(hostView.viewContainers[1]).toBeTruthy();
});
it('should use an existing nested view', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
expect(childView.proto).toBe(childProtoView);
expect(childView).toBe(hostView.views[2]);
expect(viewListener.spy('viewCreated')).not.toHaveBeenCalled();
expect(renderer.spy('createView')).not.toHaveBeenCalled();
});
it('should attach the fragment', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
expect(childView.proto).toBe(childProtoView);
expect(hostView.viewContainers[1].views.length).toBe(1);
expect(hostView.viewContainers[1].views[0]).toBe(childView);
expect(renderer.spy('attachFragmentAfterElement'))
.toHaveBeenCalledWith(vcRef, childView.renderFragment);
});
it('should hydrate the view but not the render view', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
expect(childView.hydrated()).toBe(true);
expect(renderer.spy('hydrateView')).not.toHaveBeenCalled();
});
it('should not set the EventDispatcher', () => {
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
expect(renderer.spy('setEventDispatcher')).not.toHaveBeenCalled();
});
});
describe('create the second view', () => {
var firstChildView;
beforeEach(() => {
firstChildView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
resetSpies();
});
it('should create a new view', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
expect(childView.proto).toBe(childProtoView);
expect(childView).not.toBe(firstChildView);
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(childView);
expect(renderer.spy('createView'))
.toHaveBeenCalledWith(childProtoView.render,
childProtoView.mergeInfo.embeddedViewCount + 1);
expect(childView.render).toBe(createdRenderViews[1].viewRef);
expect(childView.renderFragment).toBe(createdRenderViews[1].fragmentRefs[0]);
});
it('should attach the fragment', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
expect(childView.proto).toBe(childProtoView);
expect(hostView.viewContainers[1].views[1]).toBe(childView);
expect(renderer.spy('attachFragmentAfterFragment'))
.toHaveBeenCalledWith(firstChildView.renderFragment, childView.renderFragment);
});
it('should hydrate the view', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
expect(childView.hydrated()).toBe(true);
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(childView.render);
});
it('should set the EventDispatcher', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
expect(renderer.spy('setEventDispatcher'))
.toHaveBeenCalledWith(childView.render, childView);
});
});
describe('create another view when the first view has been returned', () => {
beforeEach(() => {
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
manager.destroyViewInContainer(vcRef, 0);
resetSpies();
});
it('should use an existing nested view', () => {
var childView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
expect(childView.proto).toBe(childProtoView);
expect(childView).toBe(hostView.views[2]);
expect(viewListener.spy('viewCreated')).not.toHaveBeenCalled();
expect(renderer.spy('createView')).not.toHaveBeenCalled();
});
});
describe('create a host view', () => {
it('should initialize the ProtoView', () => {
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
manager.createHostViewInContainer(vcRef, 0, wrapPv(newHostPv), null);
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(newHostPv);
});
it('should always create a new view and not use the embedded view', () => {
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
var newHostView = internalView(
<ViewRef>manager.createHostViewInContainer(vcRef, 0, wrapPv(newHostPv), null));
expect(newHostView.proto).toBe(newHostPv);
expect(newHostView).not.toBe(hostView.views[2]);
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(newHostView);
expect(renderer.spy('createView'))
.toHaveBeenCalledWith(newHostPv.render, newHostPv.mergeInfo.embeddedViewCount + 1);
});
});
});
});
describe('destroyViewInContainer', () => {
describe('basic functionality', () => {
var hostView: AppView;
var childProtoView: AppProtoView;
var vcRef: ElementRef;
var templateRef: TemplateRef;
var firstChildView: AppView;
beforeEach(() => {
childProtoView = createEmbeddedPv();
var hostProtoView = createHostPv(
[createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]);
hostView =
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
vcRef = hostView.elementRefs[1];
templateRef = new TemplateRef(hostView.elementRefs[1]);
firstChildView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
resetSpies();
});
describe('destroy the first view', () => {
it('should dehydrate the app view but not the render view', () => {
manager.destroyViewInContainer(vcRef, 0);
expect(firstChildView.hydrated()).toBe(false);
expect(renderer.spy('dehydrateView')).not.toHaveBeenCalled();
});
it('should detach', () => {
manager.destroyViewInContainer(vcRef, 0);
expect(hostView.viewContainers[1].views).toEqual([]);
expect(renderer.spy('detachFragment'))
.toHaveBeenCalledWith(firstChildView.renderFragment);
});
it('should not return the view to the pool', () => {
manager.destroyViewInContainer(vcRef, 0);
expect(viewPool.spy('returnView')).not.toHaveBeenCalled();
});
});
describe('destroy another view', () => {
var secondChildView;
beforeEach(() => {
secondChildView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
resetSpies();
});
it('should dehydrate', () => {
manager.destroyViewInContainer(vcRef, 1);
expect(secondChildView.hydrated()).toBe(false);
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(secondChildView.render);
});
it('should detach', () => {
manager.destroyViewInContainer(vcRef, 1);
expect(hostView.viewContainers[1].views[0]).toBe(firstChildView);
expect(renderer.spy('detachFragment'))
.toHaveBeenCalledWith(secondChildView.renderFragment);
});
it('should return the view to the pool', () => {
manager.destroyViewInContainer(vcRef, 1);
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(secondChildView);
});
});
});
describe('recursively destroy views in ViewContainers', () => {
describe('destroy child views when a component is destroyed', () => {
var hostView: AppView;
var childProtoView: AppProtoView;
var vcRef: ElementRef;
var templateRef: TemplateRef;
var firstChildView: AppView;
var secondChildView: AppView;
beforeEach(() => {
childProtoView = createEmbeddedPv();
var hostProtoView = createHostPv(
[createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]);
hostView = internalView(
<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
vcRef = hostView.elementRefs[1];
templateRef = new TemplateRef(hostView.elementRefs[1]);
firstChildView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef));
secondChildView =
internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef));
resetSpies();
});
it('should dehydrate', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(firstChildView.hydrated()).toBe(false);
expect(secondChildView.hydrated()).toBe(false);
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(hostView.render);
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(secondChildView.render);
});
it('should detach', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(hostView.viewContainers[1].views).toEqual([]);
expect(renderer.spy('detachFragment'))
.toHaveBeenCalledWith(firstChildView.renderFragment);
expect(renderer.spy('detachFragment'))
.toHaveBeenCalledWith(secondChildView.renderFragment);
});
it('should return the view to the pool', () => {
manager.destroyRootHostView(wrapView(hostView));
expect(viewPool.spy('returnView')).not.toHaveBeenCalledWith(firstChildView);
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(secondChildView);
});
});
describe('destroy child views over multiple levels', () => {
var hostView: AppView;
var childProtoView: AppProtoView;
var nestedChildProtoView: AppProtoView;
var vcRef: ElementRef;
var templateRef: TemplateRef;
var nestedVcRefs: ElementRef[];
var childViews: AppView[];
var nestedChildViews: AppView[];
beforeEach(() => {
nestedChildProtoView = createEmbeddedPv();
childProtoView = createEmbeddedPv([
createNestedElBinder(
createComponentPv([createNestedElBinder(nestedChildProtoView)]))
]);
var hostProtoView = createHostPv(
[createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]);
hostView = internalView(
<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
vcRef = hostView.elementRefs[1];
templateRef = new TemplateRef(hostView.elementRefs[1]);
nestedChildViews = [];
childViews = [];
nestedVcRefs = [];
for (var i = 0; i < 2; i++) {
var view = internalView(manager.createEmbeddedViewInContainer(vcRef, i, templateRef));
childViews.push(view);
var nestedVcRef = view.elementRefs[view.elementOffset];
nestedVcRefs.push(nestedVcRef);
for (var j = 0; j < 2; j++) {
var nestedView = internalView(
manager.createEmbeddedViewInContainer(nestedVcRef, j, templateRef));
nestedChildViews.push(nestedView);
}
}
resetSpies();
});
it('should dehydrate all child views', () => {
manager.destroyRootHostView(wrapView(hostView));
childViews.forEach((childView) => expect(childView.hydrated()).toBe(false));
nestedChildViews.forEach((childView) => expect(childView.hydrated()).toBe(false));
});
});
});
});
describe('attachViewInContainer', () => {
});
describe('detachViewInContainer', () => {
});
});
}

View File

@ -1,288 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit,
Log,
SpyObject
} from 'angular2/test_lib';
import {
SpyChangeDetector,
SpyProtoElementInjector,
SpyElementInjector,
SpyPreBuiltObjects
} from '../spies';
import {Injector, bind} from 'angular2/core';
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
import {AppProtoView, AppView, AppProtoViewMergeInfo} from 'angular2/src/core/compiler/view';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {
DirectiveBinding,
ElementInjector,
PreBuiltObjects,
ProtoElementInjector
} from 'angular2/src/core/compiler/element_injector';
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 {ViewType, RenderViewWithFragments} from 'angular2/src/core/render/render';
export function main() {
// TODO(tbosch): add more tests here!
describe('AppViewManagerUtils', () => {
var utils: AppViewManagerUtils;
beforeEach(() => { utils = new AppViewManagerUtils(); });
function createViewWithChildren(pv: AppProtoView): AppView {
var renderViewWithFragments = new RenderViewWithFragments(null, [null, null]);
return utils.createView(pv, renderViewWithFragments, null, null);
}
describe('shared hydrate functionality', () => {
it("should hydrate the change detector after hydrating element injectors", () => {
var log = new Log();
var componentProtoView = createComponentPv([createEmptyElBinder()]);
var hostView =
createViewWithChildren(createHostPv([createNestedElBinder(componentProtoView)]));
var componentView = hostView.views[1];
var spyEi = <any>componentView.elementInjectors[0];
spyEi.spy('hydrate').andCallFake(log.fn('hydrate'));
var spyCd = <any>componentView.changeDetector;
spyCd.spy('hydrate').andCallFake(log.fn('hydrateCD'));
utils.hydrateRootHostView(hostView, createInjector());
expect(log.result()).toEqual('hydrate; hydrateCD');
});
it("should set up event listeners", () => {
var dir = new Object();
var hostPv =
createHostPv([createNestedElBinder(createComponentPv()), createEmptyElBinder()]);
var hostView = createViewWithChildren(hostPv);
var spyEventAccessor1 = SpyObject.stub({"subscribe": null});
SpyObject.stub(
hostView.elementInjectors[0],
{'getEventEmitterAccessors': [[spyEventAccessor1]], 'getDirectiveAtIndex': dir});
var spyEventAccessor2 = SpyObject.stub({"subscribe": null});
SpyObject.stub(
hostView.elementInjectors[1],
{'getEventEmitterAccessors': [[spyEventAccessor2]], 'getDirectiveAtIndex': dir});
utils.hydrateRootHostView(hostView, createInjector());
expect(spyEventAccessor1.spy('subscribe')).toHaveBeenCalledWith(hostView, 0, dir);
expect(spyEventAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
});
it("should not hydrate element injectors of component views inside of embedded fragments",
() => {
var hostView = createViewWithChildren(createHostPv([
createNestedElBinder(createComponentPv([
createNestedElBinder(createEmbeddedPv(
[createNestedElBinder(createComponentPv([createEmptyElBinder()]))]))
]))
]));
utils.hydrateRootHostView(hostView, createInjector());
expect(hostView.elementInjectors.length).toBe(4);
expect((<any>hostView.elementInjectors[3]).spy('hydrate')).not.toHaveBeenCalled();
});
});
describe('attachViewInContainer', () => {
var parentView, contextView, childView;
function createViews(numInj = 1) {
var childPv = createEmbeddedPv([createEmptyElBinder()]);
childView = createViewWithChildren(childPv);
var parentPv = createHostPv([createEmptyElBinder()]);
parentView = createViewWithChildren(parentPv);
var binders = [];
for (var i = 0; i < numInj; i++) {
binders.push(createEmptyElBinder(i > 0 ? binders[i - 1] : null))
}
var contextPv = createHostPv(binders);
contextView = createViewWithChildren(contextPv);
}
it('should not modify the rootElementInjectors at the given context view', () => {
createViews();
utils.attachViewInContainer(parentView, 0, contextView, 0, 0, childView);
expect(contextView.rootElementInjectors.length).toEqual(1);
});
it('should link the views rootElementInjectors after the elementInjector at the given context',
() => {
createViews(2);
utils.attachViewInContainer(parentView, 0, contextView, 1, 0, childView);
expect(childView.rootElementInjectors[0].spy('link'))
.toHaveBeenCalledWith(contextView.elementInjectors[0]);
});
});
describe('hydrateViewInContainer', () => {
var parentView, contextView, childView;
function createViews() {
var parentPv = createHostPv([createEmptyElBinder()]);
parentView = createViewWithChildren(parentPv);
var contextPv = createHostPv([createEmptyElBinder()]);
contextView = createViewWithChildren(contextPv);
var childPv = createEmbeddedPv([createEmptyElBinder()]);
childView = createViewWithChildren(childPv);
utils.attachViewInContainer(parentView, 0, contextView, 0, 0, childView);
}
it("should instantiate the elementInjectors with the host of the context's elementInjector",
() => {
createViews();
utils.hydrateViewInContainer(parentView, 0, contextView, 0, 0, null);
expect(childView.rootElementInjectors[0].spy('hydrate'))
.toHaveBeenCalledWith(null, contextView.elementInjectors[0].getHost(),
childView.preBuiltObjects[0]);
});
});
describe('hydrateRootHostView', () => {
var hostView;
function createViews() {
var hostPv = createHostPv([createNestedElBinder(createComponentPv())]);
hostView = createViewWithChildren(hostPv);
}
it("should instantiate the elementInjectors with the given injector and an empty host element injector",
() => {
var injector = createInjector();
createViews();
utils.hydrateRootHostView(hostView, injector);
expect(hostView.rootElementInjectors[0].spy('hydrate'))
.toHaveBeenCalledWith(injector, null, hostView.preBuiltObjects[0]);
});
});
});
}
export function createInjector() {
return Injector.resolveAndCreate([]);
}
function createElementInjector(parent = null) {
var host = new SpyElementInjector();
var elementInjector = new SpyElementInjector();
var _preBuiltObjects = null;
var res = SpyObject.stub(elementInjector, {
'isExportingComponent': false,
'isExportingElement': false,
'getEventEmitterAccessors': [],
'getHostActionAccessors': [],
'getComponent': new Object(),
'getHost': host
});
res.spy('getNestedView').andCallFake(() => _preBuiltObjects.nestedView);
res.spy('hydrate')
.andCallFake((mperativelyCreatedInjector: Injector, host: ElementInjector,
preBuiltObjects: PreBuiltObjects) => { _preBuiltObjects = preBuiltObjects; });
res.prop('parent', parent);
return res;
}
export function createProtoElInjector(parent: ProtoElementInjector = null): ProtoElementInjector {
var pei = new SpyProtoElementInjector();
pei.prop("parent", parent);
pei.prop("index", 0);
pei.spy('instantiate').andCallFake((parentEli) => createElementInjector(parentEli));
return <any>pei;
}
export function createEmptyElBinder(parent: ElementBinder = null) {
var parentPeli = isPresent(parent) ? parent.protoElementInjector : null;
return new ElementBinder(0, null, 0, createProtoElInjector(parentPeli), null, null);
}
export function createNestedElBinder(nestedProtoView: AppProtoView) {
var componentBinding = null;
if (nestedProtoView.type === ViewType.COMPONENT) {
var annotation = new DirectiveResolver().resolve(SomeComponent);
componentBinding = DirectiveBinding.createFromType(SomeComponent, annotation);
}
return new ElementBinder(0, null, 0, createProtoElInjector(), componentBinding, nestedProtoView);
}
function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
if (isBlank(binders)) {
binders = [];
}
var res = new AppProtoView([], type, true, (_) => new SpyChangeDetector(), new Map<string, any>(),
null);
var mergedElementCount = 0;
var mergedEmbeddedViewCount = 0;
var mergedViewCount = 1;
for (var i = 0; i < binders.length; i++) {
var binder = binders[i];
binder.protoElementInjector.index = i;
mergedElementCount++;
var nestedPv = binder.nestedProtoView;
if (isPresent(nestedPv)) {
mergedElementCount += nestedPv.mergeInfo.elementCount;
mergedEmbeddedViewCount += nestedPv.mergeInfo.embeddedViewCount;
mergedViewCount += nestedPv.mergeInfo.viewCount;
if (nestedPv.type === ViewType.EMBEDDED) {
mergedEmbeddedViewCount++;
}
}
}
var mergeInfo =
new AppProtoViewMergeInfo(mergedEmbeddedViewCount, mergedElementCount, mergedViewCount);
res.init(null, binders, 0, mergeInfo, new Map<string, number>());
return res;
}
export function createHostPv(binders: ElementBinder[] = null) {
return _createProtoView(ViewType.HOST, binders);
}
export function createComponentPv(binders: ElementBinder[] = null) {
return _createProtoView(ViewType.COMPONENT, binders);
}
export function createEmbeddedPv(binders: ElementBinder[] = null) {
return _createProtoView(ViewType.EMBEDDED, binders);
}
@Component({selector: 'someComponent'})
class SomeComponent {
}

View File

@ -1,72 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
el,
dispatchEvent,
expect,
iit,
inject,
beforeEachBindings,
it,
xit,
SpyObject,
proxy
} from 'angular2/test_lib';
import {AppViewPool} from 'angular2/src/core/compiler/view_pool';
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
import {MapWrapper, Map} from 'angular2/src/core/facade/collection';
export function main() {
describe('AppViewPool', () => {
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
function createProtoView() { return new AppProtoView(null, null, null, null, null, null); }
function createView(pv) {
return new AppView(null, pv, null, null, null, new Map<string, any>(), null, null, null);
}
it('should support multiple AppProtoViews', () => {
var vf = createViewPool({capacity: 2});
var pv1 = createProtoView();
var pv2 = createProtoView();
var view1 = createView(pv1);
var view2 = createView(pv2);
vf.returnView(view1);
vf.returnView(view2);
expect(vf.getView(pv1)).toBe(view1);
expect(vf.getView(pv2)).toBe(view2);
});
it('should reuse the newest view that has been returned', () => {
var pv = createProtoView();
var vf = createViewPool({capacity: 2});
var view1 = createView(pv);
var view2 = createView(pv);
vf.returnView(view1);
vf.returnView(view2);
expect(vf.getView(pv)).toBe(view2);
});
it('should not add views when the capacity has been reached', () => {
var pv = createProtoView();
var vf = createViewPool({capacity: 2});
var view1 = createView(pv);
var view2 = createView(pv);
var view3 = createView(pv);
expect(vf.returnView(view1)).toBe(true);
expect(vf.returnView(view2)).toBe(true);
expect(vf.returnView(view3)).toBe(false);
expect(vf.getView(pv)).toBe(view2);
expect(vf.getView(pv)).toBe(view1);
});
});
}