import {beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal'; import {containsRegexp, fakeAsync, tick, clearPendingTimers} from '@angular/core/testing'; import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; import {AsyncTestCompleter} from '@angular/core/testing/testing_internal'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {isPresent, stringify, isBlank,} from '../../src/facade/lang'; import {BaseException} from '../../src/facade/exceptions'; import {PromiseWrapper, EventEmitter, ObservableWrapper, PromiseCompleter,} from '../../src/facade/async'; import {Injector, Injectable, forwardRef, OpaqueToken, Inject, Host, SkipSelf, SkipSelfMetadata, OnDestroy, ReflectiveInjector} from '@angular/core'; import {NgIf, NgFor, AsyncPipe} from '@angular/common'; import {PipeTransform, ChangeDetectorRef, ChangeDetectionStrategy} from '@angular/core/src/change_detection/change_detection'; import {CompilerConfig} from '@angular/compiler'; import {Directive, Component, ViewMetadata, Attribute, Query, Pipe, Input, Output, HostBinding, HostListener} from '@angular/core/src/metadata'; import {QueryList} from '@angular/core/src/linker/query_list'; import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref'; import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref'; import {ComponentResolver} from '@angular/core/src/linker/component_resolver'; import {ElementRef} from '@angular/core/src/linker/element_ref'; import {TemplateRef, TemplateRef_} from '@angular/core/src/linker/template_ref'; import {Renderer} from '@angular/core/src/render'; import {IS_DART} from '../../src/facade/lang'; import {el, dispatchEvent} from '@angular/platform-browser/testing'; const ANCHOR_ELEMENT = /*@ts2dart_const*/ new OpaqueToken('AnchorElement'); export function main() { if (IS_DART) { declareTests({useJit: false}); } else { describe('jit', () => { declareTests({useJit: true}); }); describe('no jit', () => { declareTests({useJit: false}); }); } } function declareTests({useJit}: {useJit: boolean}) { describe('integration tests', function() { beforeEachProviders( () => [{ provide: CompilerConfig, useValue: new CompilerConfig({genDebugInfo: true, useJit: useJit}) }, {provide: ANCHOR_ELEMENT, useValue: el('
')}]); describe('react to record changes', function() { it('should consume text node changes', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({template: '
{{ctxProp}}
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Hello World!'; fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('Hello World!'); async.done(); }); })); it('should update text node with a blank string when interpolation evaluates to null', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
{{null}}{{ctxProp}}
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = null; fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText(''); async.done(); }); })); it('should consume element binding changes', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Hello World!'; fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.id) .toEqual('Hello World!'); async.done(); }); })); it('should consume binding to aria-* attributes', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Initial aria label'; fixture.detectChanges(); expect(getDOM().getAttribute( fixture.debugElement.children[0].nativeElement, 'aria-label')) .toEqual('Initial aria label'); fixture.debugElement.componentInstance.ctxProp = 'Changed aria label'; fixture.detectChanges(); expect(getDOM().getAttribute( fixture.debugElement.children[0].nativeElement, 'aria-label')) .toEqual('Changed aria label'); async.done(); }); })); it('should remove an attribute when attribute expression evaluates to null', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'bar'; fixture.detectChanges(); expect(getDOM().getAttribute( fixture.debugElement.children[0].nativeElement, 'foo')) .toEqual('bar'); fixture.debugElement.componentInstance.ctxProp = null; fixture.detectChanges(); expect(getDOM().hasAttribute( fixture.debugElement.children[0].nativeElement, 'foo')) .toBeFalsy(); async.done(); }); })); it('should remove style when when style expression evaluates to null', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = '10'; fixture.detectChanges(); expect(getDOM().getStyle( fixture.debugElement.children[0].nativeElement, 'height')) .toEqual('10px'); fixture.debugElement.componentInstance.ctxProp = null; fixture.detectChanges(); expect(getDOM().getStyle( fixture.debugElement.children[0].nativeElement, 'height')) .toEqual(''); async.done(); }); })); it('should consume binding to property names where attr name and property name do not match', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.tabIndex).toEqual(0); fixture.debugElement.componentInstance.ctxNumProp = 5; fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.tabIndex).toEqual(5); async.done(); }); })); it('should consume binding to camel-cased properties', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: ''})) .createAsync(MyComp) .then((fixture) => { fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.readOnly).toBeFalsy(); fixture.debugElement.componentInstance.ctxBoolProp = true; fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.readOnly).toBeTruthy(); async.done(); }); })); it('should consume binding to innerHtml', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Some HTML'; fixture.detectChanges(); expect(getDOM().getInnerHTML(fixture.debugElement.children[0].nativeElement)) .toEqual('Some HTML'); fixture.debugElement.componentInstance.ctxProp = 'Some other
HTML
'; fixture.detectChanges(); expect(getDOM().getInnerHTML(fixture.debugElement.children[0].nativeElement)) .toEqual('Some other
HTML
'); async.done(); }); })); it('should consume binding to className using class alias', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '
'})) .createAsync(MyComp) .then((fixture) => { var nativeEl = fixture.debugElement.children[0].nativeElement; fixture.debugElement.componentInstance.ctxProp = 'foo bar'; fixture.detectChanges(); expect(nativeEl).toHaveCssClass('foo'); expect(nativeEl).toHaveCssClass('bar'); expect(nativeEl).not.toHaveCssClass('initial'); async.done(); }); })); it('should consume directive watch expression change.', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { var tpl = '' + '
' + '
' + '
' + '
' + '
'; tcb.overrideView(MyComp, new ViewMetadata({template: tpl, directives: [MyDir]})) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Hello World!'; fixture.detectChanges(); var containerSpan = fixture.debugElement.children[0]; expect(containerSpan.children[0].injector.get(MyDir).dirProp) .toEqual('Hello World!'); expect(containerSpan.children[1].injector.get(MyDir).dirProp) .toEqual('Hi there!'); expect(containerSpan.children[2].injector.get(MyDir).dirProp) .toEqual('Hi there!'); expect(containerSpan.children[3].injector.get(MyDir).dirProp) .toEqual('One more Hello World!'); async.done(); }); })); describe('pipes', () => { it('should support pipes in bindings', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({ template: '
', directives: [MyDir], pipes: [DoublePipe] })) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'a'; fixture.detectChanges(); var dir = fixture.debugElement.children[0].references['dir']; expect(dir.dirProp).toEqual('aa'); async.done(); }); })); }); it('should support nested components.', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata( {template: '', directives: [ChildComp]})) .createAsync(MyComp) .then((fixture) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('hello'); async.done(); }); })); // GH issue 328 - https://github.com/angular/angular/issues/328 it('should support different directive types on a single node', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({ template: '', directives: [MyDir, ChildComp] })) .createAsync(MyComp) .then((fixture) => { fixture.debugElement.componentInstance.ctxProp = 'Hello World!'; fixture.detectChanges(); var tc = fixture.debugElement.children[0]; expect(tc.injector.get(MyDir).dirProp).toEqual('Hello World!'); expect(tc.injector.get(ChildComp).dirProp).toEqual(null); async.done(); }); })); it('should support directives where a binding attribute is not given', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({ // No attribute "el-prop" specified. template: '

', directives: [MyDir] })) .createAsync(MyComp) .then((fixture) => { async.done(); }); })); it('should execute a given directive once, even if specified multiple times', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({ template: '

', directives: [DuplicateDir, DuplicateDir, [DuplicateDir, [DuplicateDir]]] })) .createAsync(MyComp) .then((fixture) => { expect(fixture.debugElement.nativeElement).toHaveText('noduplicate'); async.done(); }); })); it('should support directives where a selector matches property binding', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView( MyComp, new ViewMetadata({template: '

', directives: [IdDir]})) .createAsync(MyComp) .then((fixture) => { var tc = fixture.debugElement.children[0]; var idDir = tc.injector.get(IdDir); fixture.debugElement.componentInstance.ctxProp = 'some_id'; fixture.detectChanges(); expect(idDir.id).toEqual('some_id'); fixture.debugElement.componentInstance.ctxProp = 'other_id'; fixture.detectChanges(); expect(idDir.id).toEqual('other_id'); async.done(); }); })); it('should support directives where a selector matches event binding', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({ template: '

', directives: [EventDir] })) .createAsync(MyComp) .then((fixture) => { var tc = fixture.debugElement.children[0]; expect(tc.injector.get(EventDir)).not.toBe(null); async.done(); }); })); it('should read directives metadata from their binding token', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideView(MyComp, new ViewMetadata({ template: '
', directives: [PrivateImpl, NeedsPublicApi] })) .createAsync(MyComp) .then((fixture) => { async.done(); }); })); it('should support template directives via `