Best JavaScript code snippet using ng-mocks
integration_spec.ts
Source:integration_spec.ts  
1/**2 * @license3 * Copyright Google Inc. All Rights Reserved.4 *5 * Use of this source code is governed by an MIT-style license that can be6 * found in the LICENSE file at https://angular.io/license7 */8import {CommonModule} from '@angular/common';9import {ComponentFactory, Host, Inject, Injectable, Injector, NO_ERRORS_SCHEMA, NgModule, OnDestroy, OpaqueToken, ReflectiveInjector, SkipSelf} from '@angular/core';10import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';11import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';12import {ElementRef} from '@angular/core/src/linker/element_ref';13import {QueryList} from '@angular/core/src/linker/query_list';14import {TemplateRef, TemplateRef_} from '@angular/core/src/linker/template_ref';15import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';16import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';17import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';18import {Renderer} from '@angular/core/src/render';19import {TestBed, async, fakeAsync, getTestBed, tick} from '@angular/core/testing';20import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';21import {dispatchEvent, el} from '@angular/platform-browser/testing/browser_util';22import {expect} from '@angular/platform-browser/testing/matchers';23import {EventEmitter} from '../../src/facade/async';24import {isBlank, isPresent, stringify} from '../../src/facade/lang';25const ANCHOR_ELEMENT = new OpaqueToken('AnchorElement');26export function main() {27  describe('jit', () => { declareTests({useJit: true}); });28  describe('no jit', () => { declareTests({useJit: false}); });29}30function declareTests({useJit}: {useJit: boolean}) {31  describe('integration tests', function() {32    beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });33    describe('react to record changes', function() {34      it('should consume text node changes', () => {35        TestBed.configureTestingModule({declarations: [MyComp]});36        const template = '<div>{{ctxProp}}</div>';37        TestBed.overrideComponent(MyComp, {set: {template}});38        const fixture = TestBed.createComponent(MyComp);39        fixture.componentInstance.ctxProp = 'Hello World!';40        fixture.detectChanges();41        expect(fixture.nativeElement).toHaveText('Hello World!');42      });43      it('should update text node with a blank string when interpolation evaluates to null', () => {44        TestBed.configureTestingModule({declarations: [MyComp]});45        const template = '<div>{{null}}{{ctxProp}}</div>';46        TestBed.overrideComponent(MyComp, {set: {template}});47        const fixture = TestBed.createComponent(MyComp);48        fixture.componentInstance.ctxProp = null;49        fixture.detectChanges();50        expect(fixture.nativeElement).toHaveText('');51      });52      it('should consume element binding changes', () => {53        TestBed.configureTestingModule({declarations: [MyComp]});54        const template = '<div [id]="ctxProp"></div>';55        TestBed.overrideComponent(MyComp, {set: {template}});56        const fixture = TestBed.createComponent(MyComp);57        fixture.componentInstance.ctxProp = 'Hello World!';58        fixture.detectChanges();59        expect(fixture.debugElement.children[0].nativeElement.id).toEqual('Hello World!');60      });61      it('should consume binding to aria-* attributes', () => {62        TestBed.configureTestingModule({declarations: [MyComp]});63        const template = '<div [attr.aria-label]="ctxProp"></div>';64        TestBed.overrideComponent(MyComp, {set: {template}});65        const fixture = TestBed.createComponent(MyComp);66        fixture.componentInstance.ctxProp = 'Initial aria label';67        fixture.detectChanges();68        expect(getDOM().getAttribute(fixture.debugElement.children[0].nativeElement, 'aria-label'))69            .toEqual('Initial aria label');70        fixture.componentInstance.ctxProp = 'Changed aria label';71        fixture.detectChanges();72        expect(getDOM().getAttribute(fixture.debugElement.children[0].nativeElement, 'aria-label'))73            .toEqual('Changed aria label');74      });75      it('should remove an attribute when attribute expression evaluates to null', () => {76        TestBed.configureTestingModule({declarations: [MyComp]});77        const template = '<div [attr.foo]="ctxProp"></div>';78        TestBed.overrideComponent(MyComp, {set: {template}});79        const fixture = TestBed.createComponent(MyComp);80        fixture.componentInstance.ctxProp = 'bar';81        fixture.detectChanges();82        expect(getDOM().getAttribute(fixture.debugElement.children[0].nativeElement, 'foo'))83            .toEqual('bar');84        fixture.componentInstance.ctxProp = null;85        fixture.detectChanges();86        expect(getDOM().hasAttribute(fixture.debugElement.children[0].nativeElement, 'foo'))87            .toBeFalsy();88      });89      it('should remove style when when style expression evaluates to null', () => {90        TestBed.configureTestingModule({declarations: [MyComp]});91        const template = '<div [style.height.px]="ctxProp"></div>';92        TestBed.overrideComponent(MyComp, {set: {template}});93        const fixture = TestBed.createComponent(MyComp);94        fixture.componentInstance.ctxProp = '10';95        fixture.detectChanges();96        expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))97            .toEqual('10px');98        fixture.componentInstance.ctxProp = null;99        fixture.detectChanges();100        expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))101            .toEqual('');102      });103      it('should consume binding to property names where attr name and property name do not match',104         () => {105           TestBed.configureTestingModule({declarations: [MyComp]});106           const template = '<div [tabindex]="ctxNumProp"></div>';107           TestBed.overrideComponent(MyComp, {set: {template}});108           const fixture = TestBed.createComponent(MyComp);109           fixture.detectChanges();110           expect(fixture.debugElement.children[0].nativeElement.tabIndex).toEqual(0);111           fixture.componentInstance.ctxNumProp = 5;112           fixture.detectChanges();113           expect(fixture.debugElement.children[0].nativeElement.tabIndex).toEqual(5);114         });115      it('should consume binding to camel-cased properties', () => {116        TestBed.configureTestingModule({declarations: [MyComp]});117        const template = '<input [readOnly]="ctxBoolProp">';118        TestBed.overrideComponent(MyComp, {set: {template}});119        const fixture = TestBed.createComponent(MyComp);120        fixture.detectChanges();121        expect(fixture.debugElement.children[0].nativeElement.readOnly).toBeFalsy();122        fixture.componentInstance.ctxBoolProp = true;123        fixture.detectChanges();124        expect(fixture.debugElement.children[0].nativeElement.readOnly).toBeTruthy();125      });126      it('should consume binding to innerHtml', () => {127        TestBed.configureTestingModule({declarations: [MyComp]});128        const template = '<div innerHtml="{{ctxProp}}"></div>';129        TestBed.overrideComponent(MyComp, {set: {template}});130        const fixture = TestBed.createComponent(MyComp);131        fixture.componentInstance.ctxProp = 'Some <span>HTML</span>';132        fixture.detectChanges();133        expect(getDOM().getInnerHTML(fixture.debugElement.children[0].nativeElement))134            .toEqual('Some <span>HTML</span>');135        fixture.componentInstance.ctxProp = 'Some other <div>HTML</div>';136        fixture.detectChanges();137        expect(getDOM().getInnerHTML(fixture.debugElement.children[0].nativeElement))138            .toEqual('Some other <div>HTML</div>');139      });140      it('should consume binding to className using class alias', () => {141        TestBed.configureTestingModule({declarations: [MyComp]});142        const template = '<div class="initial" [class]="ctxProp"></div>';143        TestBed.overrideComponent(MyComp, {set: {template}});144        const fixture = TestBed.createComponent(MyComp);145        var nativeEl = fixture.debugElement.children[0].nativeElement;146        fixture.componentInstance.ctxProp = 'foo bar';147        fixture.detectChanges();148        expect(nativeEl).toHaveCssClass('foo');149        expect(nativeEl).toHaveCssClass('bar');150        expect(nativeEl).not.toHaveCssClass('initial');151      });152      it('should consume directive watch expression change.', () => {153        TestBed.configureTestingModule({declarations: [MyComp, MyDir]});154        const template = '<span>' +155            '<div my-dir [elprop]="ctxProp"></div>' +156            '<div my-dir elprop="Hi there!"></div>' +157            '<div my-dir elprop="Hi {{\'there!\'}}"></div>' +158            '<div my-dir elprop="One more {{ctxProp}}"></div>' +159            '</span>';160        TestBed.overrideComponent(MyComp, {set: {template}});161        const fixture = TestBed.createComponent(MyComp);162        fixture.componentInstance.ctxProp = 'Hello World!';163        fixture.detectChanges();164        var containerSpan = fixture.debugElement.children[0];165        expect(containerSpan.children[0].injector.get(MyDir).dirProp).toEqual('Hello World!');166        expect(containerSpan.children[1].injector.get(MyDir).dirProp).toEqual('Hi there!');167        expect(containerSpan.children[2].injector.get(MyDir).dirProp).toEqual('Hi there!');168        expect(containerSpan.children[3].injector.get(MyDir).dirProp)169            .toEqual('One more Hello World!');170      });171      describe('pipes', () => {172        it('should support pipes in bindings', () => {173          TestBed.configureTestingModule({declarations: [MyComp, MyDir, DoublePipe]});174          const template = '<div my-dir #dir="mydir" [elprop]="ctxProp | double"></div>';175          TestBed.overrideComponent(MyComp, {set: {template}});176          const fixture = TestBed.createComponent(MyComp);177          fixture.componentInstance.ctxProp = 'a';178          fixture.detectChanges();179          var dir = fixture.debugElement.children[0].references['dir'];180          expect(dir.dirProp).toEqual('aa');181        });182      });183      it('should support nested components.', () => {184        TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});185        const template = '<child-cmp></child-cmp>';186        TestBed.overrideComponent(MyComp, {set: {template}});187        const fixture = TestBed.createComponent(MyComp);188        fixture.detectChanges();189        expect(fixture.nativeElement).toHaveText('hello');190      });191      // GH issue 328 - https://github.com/angular/angular/issues/328192      it('should support different directive types on a single node', () => {193        TestBed.configureTestingModule({declarations: [MyComp, ChildComp, MyDir]});194        const template = '<child-cmp my-dir [elprop]="ctxProp"></child-cmp>';195        TestBed.overrideComponent(MyComp, {set: {template}});196        const fixture = TestBed.createComponent(MyComp);197        fixture.componentInstance.ctxProp = 'Hello World!';198        fixture.detectChanges();199        var tc = fixture.debugElement.children[0];200        expect(tc.injector.get(MyDir).dirProp).toEqual('Hello World!');201        expect(tc.injector.get(ChildComp).dirProp).toEqual(null);202      });203      it('should support directives where a binding attribute is not given', () => {204        TestBed.configureTestingModule({declarations: [MyComp, MyDir]});205        const template = '<p my-dir></p>';206        TestBed.overrideComponent(MyComp, {set: {template}});207        const fixture = TestBed.createComponent(MyComp);208      });209      it('should execute a given directive once, even if specified multiple times', () => {210        TestBed.configureTestingModule(211            {declarations: [MyComp, DuplicateDir, DuplicateDir, [DuplicateDir, [DuplicateDir]]]});212        const template = '<p no-duplicate></p>';213        TestBed.overrideComponent(MyComp, {set: {template}});214        const fixture = TestBed.createComponent(MyComp);215        expect(fixture.nativeElement).toHaveText('noduplicate');216      });217      it('should support directives where a selector matches property binding', () => {218        TestBed.configureTestingModule({declarations: [MyComp, IdDir]});219        const template = '<p [id]="ctxProp"></p>';220        TestBed.overrideComponent(MyComp, {set: {template}});221        const fixture = TestBed.createComponent(MyComp);222        var tc = fixture.debugElement.children[0];223        var idDir = tc.injector.get(IdDir);224        fixture.componentInstance.ctxProp = 'some_id';225        fixture.detectChanges();226        expect(idDir.id).toEqual('some_id');227        fixture.componentInstance.ctxProp = 'other_id';228        fixture.detectChanges();229        expect(idDir.id).toEqual('other_id');230      });231      it('should support directives where a selector matches event binding', () => {232        TestBed.configureTestingModule({declarations: [MyComp, EventDir]});233        const template = '<p (customEvent)="doNothing()"></p>';234        TestBed.overrideComponent(MyComp, {set: {template}});235        const fixture = TestBed.createComponent(MyComp);236        var tc = fixture.debugElement.children[0];237        expect(tc.injector.get(EventDir)).not.toBe(null);238      });239      it('should read directives metadata from their binding token', () => {240        TestBed.configureTestingModule({declarations: [MyComp, PrivateImpl, NeedsPublicApi]});241        const template = '<div public-api><div needs-public-api></div></div>';242        TestBed.overrideComponent(MyComp, {set: {template}});243        const fixture = TestBed.createComponent(MyComp);244      });245      it('should support template directives via `<template>` elements.', () => {246        TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});247        const template =248            '<template some-viewport let-greeting="someTmpl"><span>{{greeting}}</span></template>';249        TestBed.overrideComponent(MyComp, {set: {template}});250        const fixture = TestBed.createComponent(MyComp);251        fixture.detectChanges();252        var childNodesOfWrapper = getDOM().childNodes(fixture.nativeElement);253        // 1 template + 2 copies.254        expect(childNodesOfWrapper.length).toBe(3);255        expect(childNodesOfWrapper[1]).toHaveText('hello');256        expect(childNodesOfWrapper[2]).toHaveText('again');257      });258      it('should not share empty context for template directives - issue #10045', () => {259        TestBed.configureTestingModule({declarations: [MyComp, PollutedContext, NoContext]});260        const template =261            '<template pollutedContext let-foo="bar">{{foo}}</template><template noContext let-foo="bar">{{foo}}</template>';262        TestBed.overrideComponent(MyComp, {set: {template}});263        const fixture = TestBed.createComponent(MyComp);264        fixture.detectChanges();265        expect(fixture.nativeElement).toHaveText('baz');266      });267      it('should not detach views in ViewContainers when the parent view is destroyed.', () => {268        TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});269        const template =270            '<div *ngIf="ctxBoolProp"><template some-viewport let-greeting="someTmpl"><span>{{greeting}}</span></template></div>';271        TestBed.overrideComponent(MyComp, {set: {template}});272        const fixture = TestBed.createComponent(MyComp);273        fixture.componentInstance.ctxBoolProp = true;274        fixture.detectChanges();275        var ngIfEl = fixture.debugElement.children[0];276        var someViewport: SomeViewport = ngIfEl.childNodes[0].injector.get(SomeViewport);277        expect(someViewport.container.length).toBe(2);278        expect(ngIfEl.children.length).toBe(2);279        fixture.componentInstance.ctxBoolProp = false;280        fixture.detectChanges();281        expect(someViewport.container.length).toBe(2);282        expect(fixture.debugElement.children.length).toBe(0);283      });284      it('should use a comment while stamping out `<template>` elements.', () => {285        TestBed.configureTestingModule({declarations: [MyComp]});286        const template = '<template></template>';287        TestBed.overrideComponent(MyComp, {set: {template}});288        const fixture = TestBed.createComponent(MyComp);289        var childNodesOfWrapper = getDOM().childNodes(fixture.nativeElement);290        expect(childNodesOfWrapper.length).toBe(1);291        expect(getDOM().isCommentNode(childNodesOfWrapper[0])).toBe(true);292      });293      it('should support template directives via `template` attribute.', () => {294        TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});295        const template =296            '<span template="some-viewport: let greeting=someTmpl">{{greeting}}</span>';297        TestBed.overrideComponent(MyComp, {set: {template}});298        const fixture = TestBed.createComponent(MyComp);299        fixture.detectChanges();300        var childNodesOfWrapper = getDOM().childNodes(fixture.nativeElement);301        // 1 template + 2 copies.302        expect(childNodesOfWrapper.length).toBe(3);303        expect(childNodesOfWrapper[1]).toHaveText('hello');304        expect(childNodesOfWrapper[2]).toHaveText('again');305      });306      it('should allow to transplant TemplateRefs into other ViewContainers', () => {307        TestBed.configureTestingModule({308          declarations: [309            MyComp, SomeDirective, CompWithHost, ToolbarComponent, ToolbarViewContainer, ToolbarPart310          ],311          imports: [CommonModule],312          schemas: [NO_ERRORS_SCHEMA],313        });314        const template =315            '<some-directive><toolbar><template toolbarpart let-toolbarProp="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-host></cmp-with-host></template></toolbar></some-directive>';316        TestBed.overrideComponent(MyComp, {set: {template}});317        const fixture = TestBed.createComponent(MyComp);318        fixture.componentInstance.ctxProp = 'From myComp';319        fixture.detectChanges();320        expect(fixture.nativeElement)321            .toHaveText('TOOLBAR(From myComp,From toolbar,Component with an injected host)');322      });323      describe('reference bindings', () => {324        it('should assign a component to a ref-', () => {325          TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});326          const template = '<p><child-cmp ref-alice></child-cmp></p>';327          TestBed.overrideComponent(MyComp, {set: {template}});328          const fixture = TestBed.createComponent(MyComp);329          expect(fixture.debugElement.children[0].children[0].references['alice'])330              .toBeAnInstanceOf(ChildComp);331        });332        it('should assign a directive to a ref-', () => {333          TestBed.configureTestingModule({declarations: [MyComp, ExportDir]});334          const template = '<div><div export-dir #localdir="dir"></div></div>';335          TestBed.overrideComponent(MyComp, {set: {template}});336          const fixture = TestBed.createComponent(MyComp);337          expect(fixture.debugElement.children[0].children[0].references['localdir'])338              .toBeAnInstanceOf(ExportDir);339        });340        it('should make the assigned component accessible in property bindings, even if they were declared before the component',341           () => {342             TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});343             const template =344                 '<template [ngIf]="true">{{alice.ctxProp}}</template>|{{alice.ctxProp}}|<child-cmp ref-alice></child-cmp>';345             TestBed.overrideComponent(MyComp, {set: {template}});346             const fixture = TestBed.createComponent(MyComp);347             fixture.detectChanges();348             expect(fixture.nativeElement).toHaveText('hello|hello|hello');349           });350        it('should assign two component instances each with a ref-', () => {351          TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});352          const template =353              '<p><child-cmp ref-alice></child-cmp><child-cmp ref-bob></child-cmp></p>';354          TestBed.overrideComponent(MyComp, {set: {template}});355          const fixture = TestBed.createComponent(MyComp);356          var pEl = fixture.debugElement.children[0];357          var alice = pEl.children[0].references['alice'];358          var bob = pEl.children[1].references['bob'];359          expect(alice).toBeAnInstanceOf(ChildComp);360          expect(bob).toBeAnInstanceOf(ChildComp);361          expect(alice).not.toBe(bob);362        });363        it('should assign the component instance to a ref- with shorthand syntax', () => {364          TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});365          const template = '<child-cmp #alice></child-cmp>';366          TestBed.overrideComponent(MyComp, {set: {template}});367          const fixture = TestBed.createComponent(MyComp);368          expect(fixture.debugElement.children[0].references['alice']).toBeAnInstanceOf(ChildComp);369        });370        it('should assign the element instance to a user-defined variable', () => {371          TestBed.configureTestingModule({declarations: [MyComp]});372          const template = '<div><div ref-alice><i>Hello</i></div></div>';373          TestBed.overrideComponent(MyComp, {set: {template}});374          const fixture = TestBed.createComponent(MyComp);375          var value = fixture.debugElement.children[0].children[0].references['alice'];376          expect(value).not.toBe(null);377          expect(value.tagName.toLowerCase()).toEqual('div');378        });379        it('should assign the TemplateRef to a user-defined variable', () => {380          TestBed.configureTestingModule({declarations: [MyComp]});381          const template = '<template ref-alice></template>';382          TestBed.overrideComponent(MyComp, {set: {template}});383          const fixture = TestBed.createComponent(MyComp);384          var value = fixture.debugElement.childNodes[0].references['alice'];385          expect(value).toBeAnInstanceOf(TemplateRef_);386        });387        it('should preserve case', () => {388          TestBed.configureTestingModule({declarations: [MyComp, ChildComp]});389          const template = '<p><child-cmp ref-superAlice></child-cmp></p>';390          TestBed.overrideComponent(MyComp, {set: {template}});391          const fixture = TestBed.createComponent(MyComp);392          expect(fixture.debugElement.children[0].children[0].references['superAlice'])393              .toBeAnInstanceOf(ChildComp);394        });395      });396      describe('variables', () => {397        it('should allow to use variables in a for loop', () => {398          TestBed.configureTestingModule({declarations: [MyComp, ChildCompNoTemplate]});399          const template =400              '<template ngFor [ngForOf]="[1]" let-i><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</template>';401          TestBed.overrideComponent(MyComp, {set: {template}});402          const fixture = TestBed.createComponent(MyComp);403          fixture.detectChanges();404          // Get the element at index 2, since index 0 is the <template>.405          expect(getDOM().childNodes(fixture.nativeElement)[2]).toHaveText('1-hello');406        });407      });408      describe('OnPush components', () => {409        it('should use ChangeDetectorRef to manually request a check', () => {410          TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithRef]]]});411          const template = '<push-cmp-with-ref #cmp></push-cmp-with-ref>';412          TestBed.overrideComponent(MyComp, {set: {template}});413          const fixture = TestBed.createComponent(MyComp);414          var cmp = fixture.debugElement.children[0].references['cmp'];415          fixture.detectChanges();416          expect(cmp.numberOfChecks).toEqual(1);417          fixture.detectChanges();418          expect(cmp.numberOfChecks).toEqual(1);419          cmp.propagate();420          fixture.detectChanges();421          expect(cmp.numberOfChecks).toEqual(2);422        });423        it('should be checked when its bindings got updated', () => {424          TestBed.configureTestingModule(425              {declarations: [MyComp, PushCmp, EventCmp], imports: [CommonModule]});426          const template = '<push-cmp [prop]="ctxProp" #cmp></push-cmp>';427          TestBed.overrideComponent(MyComp, {set: {template}});428          const fixture = TestBed.createComponent(MyComp);429          var cmp = fixture.debugElement.children[0].references['cmp'];430          fixture.componentInstance.ctxProp = 'one';431          fixture.detectChanges();432          expect(cmp.numberOfChecks).toEqual(1);433          fixture.componentInstance.ctxProp = 'two';434          fixture.detectChanges();435          expect(cmp.numberOfChecks).toEqual(2);436        });437        if (getDOM().supportsDOMEvents()) {438          it('should allow to destroy a component from within a host event handler',439             fakeAsync(() => {440               TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithHostEvent]]]});441               const template = '<push-cmp-with-host-event></push-cmp-with-host-event>';442               TestBed.overrideComponent(MyComp, {set: {template}});443               const fixture = TestBed.createComponent(MyComp);444               tick();445               fixture.detectChanges();446               var cmpEl = fixture.debugElement.children[0];447               var cmp: PushCmpWithHostEvent = cmpEl.injector.get(PushCmpWithHostEvent);448               cmp.ctxCallback = (_: any) => fixture.destroy();449               expect(() => cmpEl.triggerEventHandler('click', <Event>{})).not.toThrow();450             }));451        }452        it('should be checked when an event is fired', () => {453          TestBed.configureTestingModule(454              {declarations: [MyComp, PushCmp, EventCmp], imports: [CommonModule]});455          const template = '<push-cmp [prop]="ctxProp" #cmp></push-cmp>';456          TestBed.overrideComponent(MyComp, {set: {template}});457          const fixture = TestBed.createComponent(MyComp);458          var cmpEl = fixture.debugElement.children[0];459          var cmp = cmpEl.componentInstance;460          fixture.detectChanges();461          fixture.detectChanges();462          expect(cmp.numberOfChecks).toEqual(1);463          cmpEl.children[0].triggerEventHandler('click', <Event>{});464          // regular element465          fixture.detectChanges();466          fixture.detectChanges();467          expect(cmp.numberOfChecks).toEqual(2);468          // element inside of an *ngIf469          cmpEl.children[1].triggerEventHandler('click', <Event>{});470          fixture.detectChanges();471          fixture.detectChanges();472          expect(cmp.numberOfChecks).toEqual(3);473          // element inside a nested component474          cmpEl.children[2].children[0].triggerEventHandler('click', <Event>{});475          fixture.detectChanges();476          fixture.detectChanges();477          expect(cmp.numberOfChecks).toEqual(4);478        });479        it('should not affect updating properties on the component', () => {480          TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithRef]]]});481          const template = '<push-cmp-with-ref [prop]="ctxProp" #cmp></push-cmp-with-ref>';482          TestBed.overrideComponent(MyComp, {set: {template}});483          const fixture = TestBed.createComponent(MyComp);484          var cmp = fixture.debugElement.children[0].references['cmp'];485          fixture.componentInstance.ctxProp = 'one';486          fixture.detectChanges();487          expect(cmp.prop).toEqual('one');488          fixture.componentInstance.ctxProp = 'two';489          fixture.detectChanges();490          expect(cmp.prop).toEqual('two');491        });492        if (getDOM().supportsDOMEvents()) {493          it('should be checked when an async pipe requests a check', fakeAsync(() => {494               TestBed.configureTestingModule(495                   {declarations: [MyComp, PushCmpWithAsyncPipe], imports: [CommonModule]});496               const template = '<push-cmp-with-async #cmp></push-cmp-with-async>';497               TestBed.overrideComponent(MyComp, {set: {template}});498               const fixture = TestBed.createComponent(MyComp);499               tick();500               var cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references['cmp'];501               fixture.detectChanges();502               expect(cmp.numberOfChecks).toEqual(1);503               fixture.detectChanges();504               fixture.detectChanges();505               expect(cmp.numberOfChecks).toEqual(1);506               cmp.resolve(2);507               tick();508               fixture.detectChanges();509               expect(cmp.numberOfChecks).toEqual(2);510             }));511        }512      });513      it('should create a component that injects an @Host', () => {514        TestBed.configureTestingModule({515          declarations: [MyComp, SomeDirective, CompWithHost],516          schemas: [NO_ERRORS_SCHEMA],517        });518        const template = `519            <some-directive>520              <p>521                <cmp-with-host #child></cmp-with-host>522              </p>523            </some-directive>`;524        TestBed.overrideComponent(MyComp, {set: {template}});525        const fixture = TestBed.createComponent(MyComp);526        var childComponent =527            fixture.debugElement.children[0].children[0].children[0].references['child'];528        expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);529      });530      it('should create a component that injects an @Host through viewcontainer directive', () => {531        TestBed.configureTestingModule({532          declarations: [MyComp, SomeDirective, CompWithHost],533          schemas: [NO_ERRORS_SCHEMA],534        });535        const template = `536            <some-directive>537              <p *ngIf="true">538                <cmp-with-host #child></cmp-with-host>539              </p>540            </some-directive>`;541        TestBed.overrideComponent(MyComp, {set: {template}});542        const fixture = TestBed.createComponent(MyComp);543        fixture.detectChanges();544        var tc = fixture.debugElement.children[0].children[0].children[0];545        var childComponent = tc.references['child'];546        expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);547      });548      it('should support events via EventEmitter on regular elements', async(() => {549           TestBed.configureTestingModule(550               {declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent]});551           const template = '<div emitter listener></div>';552           TestBed.overrideComponent(MyComp, {set: {template}});553           const fixture = TestBed.createComponent(MyComp);554           var tc = fixture.debugElement.children[0];555           var emitter = tc.injector.get(DirectiveEmittingEvent);556           var listener = tc.injector.get(DirectiveListeningEvent);557           expect(listener.msg).toEqual('');558           var eventCount = 0;559           emitter.event.subscribe({560             next: () => {561               eventCount++;562               if (eventCount === 1) {563                 expect(listener.msg).toEqual('fired !');564                 fixture.destroy();565                 emitter.fireEvent('fired again !');566               } else {567                 expect(listener.msg).toEqual('fired !');568               }569             }570           });571           emitter.fireEvent('fired !');572         }));573      it('should support events via EventEmitter on template elements', async(() => {574           TestBed.configureTestingModule(575               {declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent]});576           const template = '<template emitter listener (event)="ctxProp=$event"></template>';577           TestBed.overrideComponent(MyComp, {set: {template}});578           const fixture = TestBed.createComponent(MyComp);579           var tc = fixture.debugElement.childNodes[0];580           var emitter = tc.injector.get(DirectiveEmittingEvent);581           var myComp = fixture.debugElement.injector.get(MyComp);582           var listener = tc.injector.get(DirectiveListeningEvent);583           myComp.ctxProp = '';584           expect(listener.msg).toEqual('');585           emitter.event.subscribe({586             next: () => {587               expect(listener.msg).toEqual('fired !');588               expect(myComp.ctxProp).toEqual('fired !');589             }590           });591           emitter.fireEvent('fired !');592         }));593      it('should support [()] syntax', async(() => {594           TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithTwoWayBinding]});595           const template = '<div [(control)]="ctxProp" two-way></div>';596           TestBed.overrideComponent(MyComp, {set: {template}});597           const fixture = TestBed.createComponent(MyComp);598           var tc = fixture.debugElement.children[0];599           var dir = tc.injector.get(DirectiveWithTwoWayBinding);600           fixture.componentInstance.ctxProp = 'one';601           fixture.detectChanges();602           expect(dir.control).toEqual('one');603           dir.controlChange.subscribe(604               {next: () => { expect(fixture.componentInstance.ctxProp).toEqual('two'); }});605           dir.triggerChange('two');606         }));607      it('should support render events', () => {608        TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]});609        const template = '<div listener></div>';610        TestBed.overrideComponent(MyComp, {set: {template}});611        const fixture = TestBed.createComponent(MyComp);612        var tc = fixture.debugElement.children[0];613        var listener = tc.injector.get(DirectiveListeningDomEvent);614        dispatchEvent(tc.nativeElement, 'domEvent');615        expect(listener.eventTypes).toEqual([616          'domEvent', 'body_domEvent', 'document_domEvent', 'window_domEvent'617        ]);618        fixture.destroy();619        listener.eventTypes = [];620        dispatchEvent(tc.nativeElement, 'domEvent');621        expect(listener.eventTypes).toEqual([]);622      });623      it('should support render global events', () => {624        TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]});625        const template = '<div listener></div>';626        TestBed.overrideComponent(MyComp, {set: {template}});627        const fixture = TestBed.createComponent(MyComp);628        var tc = fixture.debugElement.children[0];629        var listener = tc.injector.get(DirectiveListeningDomEvent);630        dispatchEvent(getDOM().getGlobalEventTarget('window'), 'domEvent');631        expect(listener.eventTypes).toEqual(['window_domEvent']);632        listener.eventTypes = [];633        dispatchEvent(getDOM().getGlobalEventTarget('document'), 'domEvent');634        expect(listener.eventTypes).toEqual(['document_domEvent', 'window_domEvent']);635        fixture.destroy();636        listener.eventTypes = [];637        dispatchEvent(getDOM().getGlobalEventTarget('body'), 'domEvent');638        expect(listener.eventTypes).toEqual([]);639      });640      it('should support updating host element via hostAttributes', () => {641        TestBed.configureTestingModule({declarations: [MyComp, DirectiveUpdatingHostAttributes]});642        const template = '<div update-host-attributes></div>';643        TestBed.overrideComponent(MyComp, {set: {template}});644        const fixture = TestBed.createComponent(MyComp);645        fixture.detectChanges();646        expect(getDOM().getAttribute(fixture.debugElement.children[0].nativeElement, 'role'))647            .toEqual('button');648      });649      it('should support updating host element via hostProperties', () => {650        TestBed.configureTestingModule({declarations: [MyComp, DirectiveUpdatingHostProperties]});651        const template = '<div update-host-properties></div>';652        TestBed.overrideComponent(MyComp, {set: {template}});653        const fixture = TestBed.createComponent(MyComp);654        var tc = fixture.debugElement.children[0];655        var updateHost = tc.injector.get(DirectiveUpdatingHostProperties);656        updateHost.id = 'newId';657        fixture.detectChanges();658        expect(tc.nativeElement.id).toEqual('newId');659      });660      it('should not use template variables for expressions in hostProperties', () => {661        @Directive({selector: '[host-properties]', host: {'[id]': 'id', '[title]': 'unknownProp'}})662        class DirectiveWithHostProps {663          id = 'one';664        }665        const fixture =666            TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]})667                .overrideComponent(668                    MyComp,669                    {set: {template: `<div *ngFor="let id of ['forId']" host-properties></div>`}})670                .createComponent(MyComp);671        fixture.detectChanges();672        var tc = fixture.debugElement.children[0];673        expect(tc.properties['id']).toBe('one');674        expect(tc.properties['title']).toBe(undefined);675      });676      it('should not allow pipes in hostProperties', () => {677        @Directive({selector: '[host-properties]', host: {'[id]': 'id | uppercase'}})678        class DirectiveWithHostProps {679        }680        TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]});681        const template = '<div host-properties></div>';682        TestBed.overrideComponent(MyComp, {set: {template}});683        expect(() => TestBed.createComponent(MyComp))684            .toThrowError(/Host binding expression cannot contain pipes/);685      });686      it('should not use template variables for expressions in hostListeners', () => {687        @Directive({selector: '[host-listener]', host: {'(click)': 'doIt(id, unknownProp)'}})688        class DirectiveWithHostListener {689          id = 'one';690          receivedArgs: any[];691          doIt(...args: any[]) { this.receivedArgs = args; }692        }693        const fixture =694            TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostListener]})695                .overrideComponent(696                    MyComp,697                    {set: {template: `<div *ngFor="let id of ['forId']" host-listener></div>`}})698                .createComponent(MyComp);699        fixture.detectChanges();700        var tc = fixture.debugElement.children[0];701        tc.triggerEventHandler('click', {});702        var dir: DirectiveWithHostListener = tc.injector.get(DirectiveWithHostListener);703        expect(dir.receivedArgs).toEqual(['one', undefined]);704      });705      it('should not allow pipes in hostListeners', () => {706        @Directive({selector: '[host-listener]', host: {'(click)': 'doIt() | somePipe'}})707        class DirectiveWithHostListener {708        }709        TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostListener]});710        const template = '<div host-listener></div>';711        TestBed.overrideComponent(MyComp, {set: {template}});712        expect(() => TestBed.createComponent(MyComp))713            .toThrowError(/Cannot have a pipe in an action expression/);714      });715      if (getDOM().supportsDOMEvents()) {716        it('should support preventing default on render events', () => {717          TestBed.configureTestingModule({718            declarations:719                [MyComp, DirectiveListeningDomEventPrevent, DirectiveListeningDomEventNoPrevent]720          });721          const template =722              '<input type="checkbox" listenerprevent><input type="checkbox" listenernoprevent>';723          TestBed.overrideComponent(MyComp, {set: {template}});724          const fixture = TestBed.createComponent(MyComp);725          var dispatchedEvent = getDOM().createMouseEvent('click');726          var dispatchedEvent2 = getDOM().createMouseEvent('click');727          getDOM().dispatchEvent(fixture.debugElement.children[0].nativeElement, dispatchedEvent);728          getDOM().dispatchEvent(fixture.debugElement.children[1].nativeElement, dispatchedEvent2);729          expect(getDOM().isPrevented(dispatchedEvent)).toBe(true);730          expect(getDOM().isPrevented(dispatchedEvent2)).toBe(false);731          expect(getDOM().getChecked(fixture.debugElement.children[0].nativeElement)).toBeFalsy();732          expect(getDOM().getChecked(fixture.debugElement.children[1].nativeElement)).toBeTruthy();733        });734      }735      it('should support render global events from multiple directives', () => {736        TestBed.configureTestingModule(737            {declarations: [MyComp, DirectiveListeningDomEvent, DirectiveListeningDomEventOther]});738        const template = '<div *ngIf="ctxBoolProp" listener listenerother></div>';739        TestBed.overrideComponent(MyComp, {set: {template}});740        const fixture = TestBed.createComponent(MyComp);741        globalCounter = 0;742        fixture.componentInstance.ctxBoolProp = true;743        fixture.detectChanges();744        var tc = fixture.debugElement.children[0];745        var listener = tc.injector.get(DirectiveListeningDomEvent);746        var listenerother = tc.injector.get(DirectiveListeningDomEventOther);747        dispatchEvent(getDOM().getGlobalEventTarget('window'), 'domEvent');748        expect(listener.eventTypes).toEqual(['window_domEvent']);749        expect(listenerother.eventType).toEqual('other_domEvent');750        expect(globalCounter).toEqual(1);751        fixture.componentInstance.ctxBoolProp = false;752        fixture.detectChanges();753        dispatchEvent(getDOM().getGlobalEventTarget('window'), 'domEvent');754        expect(globalCounter).toEqual(1);755        fixture.componentInstance.ctxBoolProp = true;756        fixture.detectChanges();757        dispatchEvent(getDOM().getGlobalEventTarget('window'), 'domEvent');758        expect(globalCounter).toEqual(2);759        // need to destroy to release all remaining global event listeners760        fixture.destroy();761      });762      describe('dynamic ViewContainers', () => {763        beforeEach(() => {764          // we need a module to declarate ChildCompUsingService as an entryComponent otherwise the765          // factory doesn't get created766          @NgModule({767            declarations: [MyComp, DynamicViewport, ChildCompUsingService],768            entryComponents: [ChildCompUsingService],769            schemas: [NO_ERRORS_SCHEMA],770          })771          class MyModule {772          }773          TestBed.configureTestingModule({imports: [MyModule]});774          TestBed.overrideComponent(775              MyComp, {add: {template: '<div><dynamic-vp #dynamic></dynamic-vp></div>'}});776        });777        it('should allow to create a ViewContainerRef at any bound location', async(() => {778             var fixture = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]})779                               .createComponent(MyComp);780             var tc = fixture.debugElement.children[0].children[0];781             var dynamicVp: DynamicViewport = tc.injector.get(DynamicViewport);782             dynamicVp.done.then((_) => {783               fixture.detectChanges();784               expect(fixture.debugElement.children[0].children[1].nativeElement)785                   .toHaveText('dynamic greet');786             });787           }));788      });789      it('should support static attributes', () => {790        TestBed.configureTestingModule({declarations: [MyComp, NeedsAttribute]});791        const template = '<input static type="text" title>';792        TestBed.overrideComponent(MyComp, {set: {template}});793        const fixture = TestBed.createComponent(MyComp);794        var tc = fixture.debugElement.children[0];795        var needsAttribute = tc.injector.get(NeedsAttribute);796        expect(needsAttribute.typeAttribute).toEqual('text');797        expect(needsAttribute.staticAttribute).toEqual('');798        expect(needsAttribute.fooAttribute).toEqual(null);799      });800      it('should support custom interpolation', () => {801        TestBed.configureTestingModule({802          declarations: [803            MyComp, ComponentWithCustomInterpolationA, ComponentWithCustomInterpolationB,804            ComponentWithDefaultInterpolation805          ]806        });807        const template = `<div>{{ctxProp}}</div>808<cmp-with-custom-interpolation-a></cmp-with-custom-interpolation-a>809<cmp-with-custom-interpolation-b></cmp-with-custom-interpolation-b>`;810        TestBed.overrideComponent(MyComp, {set: {template}});811        const fixture = TestBed.createComponent(MyComp);812        fixture.componentInstance.ctxProp = 'Default Interpolation';813        fixture.detectChanges();814        expect(fixture.nativeElement)815            .toHaveText(816                'Default Interpolation\nCustom Interpolation A\nCustom Interpolation B (Default Interpolation)');817      });818    });819    describe('dependency injection', () => {820      it('should support bindings', () => {821        TestBed.configureTestingModule({822          declarations: [MyComp, DirectiveProvidingInjectable, DirectiveConsumingInjectable],823          schemas: [NO_ERRORS_SCHEMA],824        });825        const template = `826            <directive-providing-injectable >827              <directive-consuming-injectable #consuming>828              </directive-consuming-injectable>829            </directive-providing-injectable>830          `;831        TestBed.overrideComponent(MyComp, {set: {template}});832        const fixture = TestBed.createComponent(MyComp);833        var comp = fixture.debugElement.children[0].children[0].references['consuming'];834        expect(comp.injectable).toBeAnInstanceOf(InjectableService);835      });836      it('should support viewProviders', () => {837        TestBed.configureTestingModule({838          declarations: [MyComp, DirectiveProvidingInjectableInView, DirectiveConsumingInjectable],839          schemas: [NO_ERRORS_SCHEMA],840        });841        const template = `842              <directive-consuming-injectable #consuming>843              </directive-consuming-injectable>844          `;845        TestBed.overrideComponent(DirectiveProvidingInjectableInView, {set: {template}});846        const fixture = TestBed.createComponent(DirectiveProvidingInjectableInView);847        var comp = fixture.debugElement.children[0].references['consuming'];848        expect(comp.injectable).toBeAnInstanceOf(InjectableService);849      });850      it('should support unbounded lookup', () => {851        TestBed.configureTestingModule({852          declarations: [853            MyComp, DirectiveProvidingInjectable, DirectiveContainingDirectiveConsumingAnInjectable,854            DirectiveConsumingInjectableUnbounded855          ],856          schemas: [NO_ERRORS_SCHEMA],857        });858        const template = `859            <directive-providing-injectable>860              <directive-containing-directive-consuming-an-injectable #dir>861              </directive-containing-directive-consuming-an-injectable>862            </directive-providing-injectable>863          `;864        TestBed.overrideComponent(MyComp, {set: {template}});865        TestBed.overrideComponent(DirectiveContainingDirectiveConsumingAnInjectable, {866          set: {867            template: `868            <directive-consuming-injectable-unbounded></directive-consuming-injectable-unbounded>869          `870          }871        });872        const fixture = TestBed.createComponent(MyComp);873        var comp = fixture.debugElement.children[0].children[0].references['dir'];874        expect(comp.directive.injectable).toBeAnInstanceOf(InjectableService);875      });876      it('should support the event-bus scenario', () => {877        TestBed.configureTestingModule({878          declarations: [879            MyComp, GrandParentProvidingEventBus, ParentProvidingEventBus, ChildConsumingEventBus880          ],881          schemas: [NO_ERRORS_SCHEMA],882        });883        const template = `884            <grand-parent-providing-event-bus>885              <parent-providing-event-bus>886                <child-consuming-event-bus>887                </child-consuming-event-bus>888              </parent-providing-event-bus>889            </grand-parent-providing-event-bus>890          `;891        TestBed.overrideComponent(MyComp, {set: {template}});892        const fixture = TestBed.createComponent(MyComp);893        var gpComp = fixture.debugElement.children[0];894        var parentComp = gpComp.children[0];895        var childComp = parentComp.children[0];896        var grandParent = gpComp.injector.get(GrandParentProvidingEventBus);897        var parent = parentComp.injector.get(ParentProvidingEventBus);898        var child = childComp.injector.get(ChildConsumingEventBus);899        expect(grandParent.bus.name).toEqual('grandparent');900        expect(parent.bus.name).toEqual('parent');901        expect(parent.grandParentBus).toBe(grandParent.bus);902        expect(child.bus).toBe(parent.bus);903      });904      it('should instantiate bindings lazily', () => {905        TestBed.configureTestingModule({906          declarations: [MyComp, DirectiveConsumingInjectable, ComponentProvidingLoggingInjectable],907          schemas: [NO_ERRORS_SCHEMA],908        });909        const template = `910              <component-providing-logging-injectable #providing>911                <directive-consuming-injectable *ngIf="ctxBoolProp">912                </directive-consuming-injectable>913              </component-providing-logging-injectable>914          `;915        TestBed.overrideComponent(MyComp, {set: {template}});916        const fixture = TestBed.createComponent(MyComp);917        var providing = fixture.debugElement.children[0].references['providing'];918        expect(providing.created).toBe(false);919        fixture.componentInstance.ctxBoolProp = true;920        fixture.detectChanges();921        expect(providing.created).toBe(true);922      });923    });924    describe('corner cases', () => {925      it('should remove script tags from templates', () => {926        TestBed.configureTestingModule({declarations: [MyComp]});927        const template = `928            <script>alert("Ooops");</script>929            <div>before<script>alert("Ooops");</script><span>inside</span>after</div>`;930        TestBed.overrideComponent(MyComp, {set: {template}});931        const fixture = TestBed.createComponent(MyComp);932        expect(getDOM().querySelectorAll(fixture.nativeElement, 'script').length).toEqual(0);933      });934      it('should throw when using directives without selector', () => {935        @Directive({})936        class SomeDirective {937        }938        @Component({selector: 'comp', template: ''})939        class SomeComponent {940        }941        TestBed.configureTestingModule({declarations: [MyComp, SomeDirective, SomeComponent]});942        expect(() => TestBed.createComponent(MyComp))943            .toThrowError(`Directive ${stringify(SomeDirective)} has no selector, please add it!`);944      });945      it('should use a default element name for components without selectors', () => {946        let noSelectorComponentFactory: ComponentFactory<SomeComponent>;947        @Component({template: '----'})948        class NoSelectorComponent {949        }950        @Component({selector: 'some-comp', template: '', entryComponents: [NoSelectorComponent]})951        class SomeComponent {952          constructor(componentFactoryResolver: ComponentFactoryResolver) {953            // grab its own component factory954            noSelectorComponentFactory =955                componentFactoryResolver.resolveComponentFactory(NoSelectorComponent);956          }957        }958        TestBed.configureTestingModule({declarations: [SomeComponent, NoSelectorComponent]});959        // get the factory960        TestBed.createComponent(SomeComponent);961        expect(noSelectorComponentFactory.selector).toBe('ng-component');962        expect(963            getDOM()964                .nodeName(965                    noSelectorComponentFactory.create(TestBed.get(Injector)).location.nativeElement)966                .toLowerCase())967            .toEqual('ng-component');968      });969    });970    describe('error handling', () => {971      it('should report a meaningful error when a directive is missing annotation', () => {972        TestBed.configureTestingModule({declarations: [MyComp, SomeDirectiveMissingAnnotation]});973        expect(() => TestBed.createComponent(MyComp))974            .toThrowError(975                `Unexpected value '${stringify(SomeDirectiveMissingAnnotation)}' declared by the module 'DynamicTestModule'`);976      });977      it('should report a meaningful error when a component is missing view annotation', () => {978        TestBed.configureTestingModule({declarations: [MyComp, ComponentWithoutView]});979        try {980          TestBed.createComponent(ComponentWithoutView);981          expect(true).toBe(false);982        } catch (e) {983          expect(e.message).toContain(984              `No template specified for component ${stringify(ComponentWithoutView)}`);985        }986      });987      it('should provide an error context when an error happens in DI', () => {988        TestBed.configureTestingModule({989          declarations: [MyComp, DirectiveThrowingAnError],990          schemas: [NO_ERRORS_SCHEMA],991        });992        const template = `<directive-throwing-error></directive-throwing-error>`;993        TestBed.overrideComponent(MyComp, {set: {template}});994        try {995          TestBed.createComponent(MyComp);996          throw 'Should throw';997        } catch (e) {998          var c = e.context;999          expect(getDOM().nodeName(c.componentRenderElement).toUpperCase()).toEqual('DIV');1000          expect((<Injector>c.injector).get).toBeTruthy();1001        }1002      });1003      it('should provide an error context when an error happens in change detection', () => {1004        TestBed.configureTestingModule({declarations: [MyComp, DirectiveThrowingAnError]});1005        const template = `<input [value]="one.two.three" #local>`;1006        TestBed.overrideComponent(MyComp, {set: {template}});1007        const fixture = TestBed.createComponent(MyComp);1008        try {1009          fixture.detectChanges();1010          throw 'Should throw';1011        } catch (e) {1012          var c = e.context;1013          expect(getDOM().nodeName(c.renderNode).toUpperCase()).toEqual('INPUT');1014          expect(getDOM().nodeName(c.componentRenderElement).toUpperCase()).toEqual('DIV');1015          expect((<Injector>c.injector).get).toBeTruthy();1016          expect(c.source).toContain(':0:7');1017          expect(c.context).toBe(fixture.componentInstance);1018          expect(c.references['local']).toBeDefined();1019        }1020      });1021      it('should provide an error context when an error happens in change detection (text node)',1022         () => {1023           TestBed.configureTestingModule({declarations: [MyComp]});1024           const template = `<div>{{one.two.three}}</div>`;1025           TestBed.overrideComponent(MyComp, {set: {template}});1026           const fixture = TestBed.createComponent(MyComp);1027           try {1028             fixture.detectChanges();1029             throw 'Should throw';1030           } catch (e) {1031             var c = e.context;1032             expect(c.renderNode).toBeTruthy();1033             expect(c.source).toContain(':0:5');1034           }1035         });1036      if (getDOM().supportsDOMEvents()) {  // this is required to use fakeAsync1037        it('should provide an error context when an error happens in an event handler',1038           fakeAsync(() => {1039             TestBed.configureTestingModule({1040               declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent],1041               schemas: [NO_ERRORS_SCHEMA],1042             });1043             const template = `<span emitter listener (event)="throwError()" #local></span>`;1044             TestBed.overrideComponent(MyComp, {set: {template}});1045             const fixture = TestBed.createComponent(MyComp);1046             tick();1047             var tc = fixture.debugElement.children[0];1048             try {1049               tc.injector.get(DirectiveEmittingEvent).fireEvent('boom');1050             } catch (e) {1051               var c = e.context;1052               expect(getDOM().nodeName(c.renderNode).toUpperCase()).toEqual('SPAN');1053               expect(getDOM().nodeName(c.componentRenderElement).toUpperCase()).toEqual('DIV');1054               expect((<Injector>c.injector).get).toBeTruthy();1055               expect(c.context).toBe(fixture.componentInstance);1056               expect(c.references['local']).toBeDefined();1057             }1058           }));1059      }1060      it('should specify a location of an error that happened during change detection (text)',1061         () => {1062           TestBed.configureTestingModule({declarations: [MyComp]});1063           const template = '<div>{{a.b}}</div>';1064           TestBed.overrideComponent(MyComp, {set: {template}});1065           const fixture = TestBed.createComponent(MyComp);1066           expect(() => fixture.detectChanges()).toThrowError(/:0:5/);1067         });1068      it('should specify a location of an error that happened during change detection (element property)',1069         () => {1070           TestBed.configureTestingModule({declarations: [MyComp]});1071           const template = '<div [title]="a.b"></div>';1072           TestBed.overrideComponent(MyComp, {set: {template}});1073           const fixture = TestBed.createComponent(MyComp);1074           expect(() => fixture.detectChanges()).toThrowError(/:0:5/);1075         });1076      it('should specify a location of an error that happened during change detection (directive property)',1077         () => {1078           TestBed.configureTestingModule({declarations: [MyComp, ChildComp, MyDir]});1079           const template = '<child-cmp [dirProp]="a.b"></child-cmp>';1080           TestBed.overrideComponent(MyComp, {set: {template}});1081           const fixture = TestBed.createComponent(MyComp);1082           expect(() => fixture.detectChanges()).toThrowError(/:0:11/);1083         });1084    });1085    it('should support imperative views', () => {1086      TestBed.configureTestingModule({declarations: [MyComp, SimpleImperativeViewComponent]});1087      const template = '<simple-imp-cmp></simple-imp-cmp>';1088      TestBed.overrideComponent(MyComp, {set: {template}});1089      const fixture = TestBed.createComponent(MyComp);1090      expect(fixture.nativeElement).toHaveText('hello imp view');1091    });1092    it('should support moving embedded views around', () => {1093      TestBed.configureTestingModule({1094        declarations: [MyComp, SomeImperativeViewport],1095        providers: [{provide: ANCHOR_ELEMENT, useValue: el('<div></div>')}],1096      });1097      const template = '<div><div *someImpvp="ctxBoolProp">hello</div></div>';1098      TestBed.overrideComponent(MyComp, {set: {template}});1099      const anchorElement = getTestBed().get(ANCHOR_ELEMENT);1100      const fixture = TestBed.createComponent(MyComp);1101      fixture.detectChanges();1102      expect(anchorElement).toHaveText('');1103      fixture.componentInstance.ctxBoolProp = true;1104      fixture.detectChanges();1105      expect(anchorElement).toHaveText('hello');1106      fixture.componentInstance.ctxBoolProp = false;1107      fixture.detectChanges();1108      expect(fixture.nativeElement).toHaveText('');1109    });1110    describe('Property bindings', () => {1111      it('should throw on bindings to unknown properties', () => {1112        TestBed.configureTestingModule({declarations: [MyComp]});1113        const template = '<div unknown="{{ctxProp}}"></div>';1114        TestBed.overrideComponent(MyComp, {set: {template}});1115        try {1116          TestBed.createComponent(MyComp);1117          throw 'Should throw';1118        } catch (e) {1119          expect(e.message).toEqual(1120              `Template parse errors:\nCan't bind to 'unknown' since it isn't a known property of 'div'. ("<div [ERROR ->]unknown="{{ctxProp}}"></div>"): MyComp@0:5`);1121        }1122      });1123      it('should not throw for property binding to a non-existing property when there is a matching directive property',1124         () => {1125           TestBed.configureTestingModule({declarations: [MyComp, MyDir]});1126           const template = '<div my-dir [elprop]="ctxProp"></div>';1127           TestBed.overrideComponent(MyComp, {set: {template}});1128           expect(() => TestBed.createComponent(MyComp)).not.toThrow();1129         });1130      it('should not be created when there is a directive with the same property', () => {1131        TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithTitle]});1132        const template = '<span [title]="ctxProp"></span>';1133        TestBed.overrideComponent(MyComp, {set: {template}});1134        const fixture = TestBed.createComponent(MyComp);1135        fixture.componentInstance.ctxProp = 'TITLE';1136        fixture.detectChanges();1137        var el = getDOM().querySelector(fixture.nativeElement, 'span');1138        expect(isBlank(el.title) || el.title == '').toBeTruthy();1139      });1140      it('should work when a directive uses hostProperty to update the DOM element', () => {1141        TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithTitleAndHostProperty]});1142        const template = '<span [title]="ctxProp"></span>';1143        TestBed.overrideComponent(MyComp, {set: {template}});1144        const fixture = TestBed.createComponent(MyComp);1145        fixture.componentInstance.ctxProp = 'TITLE';1146        fixture.detectChanges();1147        var el = getDOM().querySelector(fixture.nativeElement, 'span');1148        expect(el.title).toEqual('TITLE');1149      });1150    });1151    describe('logging property updates', () => {1152      it('should reflect property values as attributes', () => {1153        TestBed.configureTestingModule({declarations: [MyComp, MyDir]});1154        const template = '<div>' +1155            '<div my-dir [elprop]="ctxProp"></div>' +1156            '</div>';1157        TestBed.overrideComponent(MyComp, {set: {template}});1158        const fixture = TestBed.createComponent(MyComp);1159        fixture.componentInstance.ctxProp = 'hello';1160        fixture.detectChanges();1161        expect(getDOM().getInnerHTML(fixture.nativeElement))1162            .toContain('ng-reflect-dir-prop="hello"');1163      });1164      it('should reflect property values on template comments', () => {1165        TestBed.configureTestingModule({declarations: [MyComp]});1166        const template = '<template [ngIf]="ctxBoolProp"></template>';1167        TestBed.overrideComponent(MyComp, {set: {template}});1168        const fixture = TestBed.createComponent(MyComp);1169        fixture.componentInstance.ctxBoolProp = true;1170        fixture.detectChanges();1171        expect(getDOM().getInnerHTML(fixture.nativeElement))1172            .toContain('"ng\-reflect\-ng\-if"\: "true"');1173      });1174      it('should indicate when toString() throws', () => {1175        TestBed.configureTestingModule({declarations: [MyComp, MyDir]});1176        const template = '<div my-dir [elprop]="toStringThrow"></div>';1177        TestBed.overrideComponent(MyComp, {set: {template}});1178        const fixture = TestBed.createComponent(MyComp);1179        fixture.detectChanges();1180        expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('[ERROR]');1181      });1182    });1183    describe('property decorators', () => {1184      it('should support property decorators', () => {1185        TestBed.configureTestingModule({1186          declarations: [MyComp, DirectiveWithPropDecorators],1187          schemas: [NO_ERRORS_SCHEMA],1188        });1189        const template = '<with-prop-decorators elProp="aaa"></with-prop-decorators>';1190        TestBed.overrideComponent(MyComp, {set: {template}});1191        const fixture = TestBed.createComponent(MyComp);1192        fixture.detectChanges();1193        var dir = fixture.debugElement.children[0].injector.get(DirectiveWithPropDecorators);1194        expect(dir.dirProp).toEqual('aaa');1195      });1196      it('should support host binding decorators', () => {1197        TestBed.configureTestingModule({1198          declarations: [MyComp, DirectiveWithPropDecorators],1199          schemas: [NO_ERRORS_SCHEMA],1200        });1201        const template = '<with-prop-decorators></with-prop-decorators>';1202        TestBed.overrideComponent(MyComp, {set: {template}});1203        const fixture = TestBed.createComponent(MyComp);1204        fixture.detectChanges();1205        var dir = fixture.debugElement.children[0].injector.get(DirectiveWithPropDecorators);1206        dir.myAttr = 'aaa';1207        fixture.detectChanges();1208        expect(getDOM().getOuterHTML(fixture.debugElement.children[0].nativeElement))1209            .toContain('my-attr="aaa"');1210      });1211      if (getDOM().supportsDOMEvents()) {1212        it('should support event decorators', fakeAsync(() => {1213             TestBed.configureTestingModule({1214               declarations: [MyComp, DirectiveWithPropDecorators],1215               schemas: [NO_ERRORS_SCHEMA],1216             });1217             const template = `<with-prop-decorators (elEvent)="ctxProp='called'">`;1218             TestBed.overrideComponent(MyComp, {set: {template}});1219             const fixture = TestBed.createComponent(MyComp);1220             tick();1221             var emitter =1222                 fixture.debugElement.children[0].injector.get(DirectiveWithPropDecorators);1223             emitter.fireEvent('fired !');1224             tick();1225             expect(fixture.componentInstance.ctxProp).toEqual('called');1226           }));1227        it('should support host listener decorators', () => {1228          TestBed.configureTestingModule({1229            declarations: [MyComp, DirectiveWithPropDecorators],1230            schemas: [NO_ERRORS_SCHEMA],1231          });1232          const template = '<with-prop-decorators></with-prop-decorators>';1233          TestBed.overrideComponent(MyComp, {set: {template}});1234          const fixture = TestBed.createComponent(MyComp);1235          fixture.detectChanges();1236          var dir = fixture.debugElement.children[0].injector.get(DirectiveWithPropDecorators);1237          var native = fixture.debugElement.children[0].nativeElement;1238          getDOM().dispatchEvent(native, getDOM().createMouseEvent('click'));1239          expect(dir.target).toBe(native);1240        });1241      }1242      it('should support defining views in the component decorator', () => {1243        TestBed.configureTestingModule({1244          declarations: [MyComp, ComponentWithTemplate],1245          imports: [CommonModule],1246          schemas: [NO_ERRORS_SCHEMA],1247        });1248        const template = '<component-with-template></component-with-template>';1249        TestBed.overrideComponent(MyComp, {set: {template}});1250        const fixture = TestBed.createComponent(MyComp);1251        fixture.detectChanges();1252        var native = fixture.debugElement.children[0].nativeElement;1253        expect(native).toHaveText('No View Decorator: 123');1254      });1255    });1256    if (getDOM().supportsDOMEvents()) {1257      describe('svg', () => {1258        it('should support svg elements', () => {1259          TestBed.configureTestingModule({declarations: [MyComp]});1260          const template = '<svg><use xlink:href="Port" /></svg>';1261          TestBed.overrideComponent(MyComp, {set: {template}});1262          const fixture = TestBed.createComponent(MyComp);1263          var el = fixture.nativeElement;1264          var svg = getDOM().childNodes(el)[0];1265          var use = getDOM().childNodes(svg)[0];1266          expect(getDOM().getProperty(<Element>svg, 'namespaceURI'))1267              .toEqual('http://www.w3.org/2000/svg');1268          expect(getDOM().getProperty(<Element>use, 'namespaceURI'))1269              .toEqual('http://www.w3.org/2000/svg');1270          var firstAttribute = getDOM().getProperty(<Element>use, 'attributes')[0];1271          expect(firstAttribute.name).toEqual('xlink:href');1272          expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');1273        });1274        it('should support foreignObjects with document fragments', () => {1275          TestBed.configureTestingModule({declarations: [MyComp]});1276          const template =1277              '<svg><foreignObject><xhtml:div><p>Test</p></xhtml:div></foreignObject></svg>';1278          TestBed.overrideComponent(MyComp, {set: {template}});1279          const fixture = TestBed.createComponent(MyComp);1280          var el = fixture.nativeElement;1281          var svg = getDOM().childNodes(el)[0];1282          var foreignObject = getDOM().childNodes(svg)[0];1283          var p = getDOM().childNodes(foreignObject)[0];1284          expect(getDOM().getProperty(<Element>svg, 'namespaceURI'))1285              .toEqual('http://www.w3.org/2000/svg');1286          expect(getDOM().getProperty(<Element>foreignObject, 'namespaceURI'))1287              .toEqual('http://www.w3.org/2000/svg');1288          expect(getDOM().getProperty(<Element>p, 'namespaceURI'))1289              .toEqual('http://www.w3.org/1999/xhtml');1290        });1291      });1292      describe('attributes', () => {1293        it('should support attributes with namespace', () => {1294          TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});1295          const template = '<svg:use xlink:href="#id" />';1296          TestBed.overrideComponent(SomeCmp, {set: {template}});1297          const fixture = TestBed.createComponent(SomeCmp);1298          let useEl = getDOM().firstChild(fixture.nativeElement);1299          expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href'))1300              .toEqual('#id');1301        });1302        it('should support binding to attributes with namespace', () => {1303          TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});1304          const template = '<svg:use [attr.xlink:href]="value" />';1305          TestBed.overrideComponent(SomeCmp, {set: {template}});1306          const fixture = TestBed.createComponent(SomeCmp);1307          let cmp = fixture.componentInstance;1308          let useEl = getDOM().firstChild(fixture.nativeElement);1309          cmp.value = '#id';1310          fixture.detectChanges();1311          expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href'))1312              .toEqual('#id');1313          cmp.value = null;1314          fixture.detectChanges();1315          expect(getDOM().hasAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href'))1316              .toEqual(false);1317        });1318      });1319    }1320  });1321}1322@Component({selector: 'cmp-with-default-interpolation', template: `{{text}}`})1323class ComponentWithDefaultInterpolation {1324  text = 'Default Interpolation';1325}1326@Component({1327  selector: 'cmp-with-custom-interpolation-a',1328  template: `<div>{%text%}</div>`,1329  interpolation: ['{%', '%}']1330})1331class ComponentWithCustomInterpolationA {1332  text = 'Custom Interpolation A';1333}1334@Component({1335  selector: 'cmp-with-custom-interpolation-b',1336  template:1337      `<div>{**text%}</div> (<cmp-with-default-interpolation></cmp-with-default-interpolation>)`,1338  interpolation: ['{**', '%}']1339})1340class ComponentWithCustomInterpolationB {1341  text = 'Custom Interpolation B';1342}1343@Injectable()1344class MyService {1345  greeting: string;1346  constructor() { this.greeting = 'hello'; }1347}1348@Component({selector: 'simple-imp-cmp', template: ''})1349class SimpleImperativeViewComponent {1350  done: any;1351  constructor(self: ElementRef, renderer: Renderer) {1352    var hostElement = self.nativeElement;1353    getDOM().appendChild(hostElement, el('hello imp view'));1354  }1355}1356@Directive({selector: 'dynamic-vp'})1357class DynamicViewport {1358  done: Promise<any>;1359  constructor(vc: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver) {1360    var myService = new MyService();1361    myService.greeting = 'dynamic greet';1362    var injector = ReflectiveInjector.resolveAndCreate(1363        [{provide: MyService, useValue: myService}], vc.injector);1364    this.done =1365        Promise.resolve(componentFactoryResolver.resolveComponentFactory(ChildCompUsingService))1366            .then((componentFactory) => vc.createComponent(componentFactory, 0, injector));1367  }1368}1369@Directive({selector: '[my-dir]', inputs: ['dirProp: elprop'], exportAs: 'mydir'})1370class MyDir {1371  dirProp: string;1372  constructor() { this.dirProp = ''; }1373}1374@Directive({selector: '[title]', inputs: ['title']})1375class DirectiveWithTitle {1376  title: string;1377}1378@Directive({selector: '[title]', inputs: ['title'], host: {'[title]': 'title'}})1379class DirectiveWithTitleAndHostProperty {1380  title: string;1381}1382@Component({selector: 'event-cmp', template: '<div (click)="noop()"></div>'})1383class EventCmp {1384  noop() {}1385}1386@Component({1387  selector: 'push-cmp',1388  inputs: ['prop'],1389  changeDetection: ChangeDetectionStrategy.OnPush,1390  template:1391      '{{field}}<div (click)="noop()"></div><div *ngIf="true" (click)="noop()"></div><event-cmp></event-cmp>'1392})1393class PushCmp {1394  numberOfChecks: number;1395  prop: any;1396  constructor() { this.numberOfChecks = 0; }1397  noop() {}1398  get field() {1399    this.numberOfChecks++;1400    return 'fixed';1401  }1402}1403@Component({1404  selector: 'push-cmp-with-ref',1405  inputs: ['prop'],1406  changeDetection: ChangeDetectionStrategy.OnPush,1407  template: '{{field}}'1408})1409class PushCmpWithRef {1410  numberOfChecks: number;1411  ref: ChangeDetectorRef;1412  prop: any;1413  constructor(ref: ChangeDetectorRef) {1414    this.numberOfChecks = 0;1415    this.ref = ref;1416  }1417  get field() {1418    this.numberOfChecks++;1419    return 'fixed';1420  }1421  propagate() { this.ref.markForCheck(); }1422}1423@Component({1424  selector: 'push-cmp-with-host-event',1425  host: {'(click)': 'ctxCallback($event)'},1426  changeDetection: ChangeDetectionStrategy.OnPush,1427  template: ''1428})1429class PushCmpWithHostEvent {1430  ctxCallback: Function = (_: any) => {};1431}1432@Component({1433  selector: 'push-cmp-with-async',1434  changeDetection: ChangeDetectionStrategy.OnPush,1435  template: '{{field | async}}'1436})1437class PushCmpWithAsyncPipe {1438  numberOfChecks: number = 0;1439  resolve: (result: any) => void;1440  promise: Promise<any>;1441  constructor() {1442    this.promise = new Promise((resolve) => { this.resolve = resolve; });1443  }1444  get field() {1445    this.numberOfChecks++;1446    return this.promise;1447  }1448}1449@Component({selector: 'my-comp', template: ''})1450class MyComp {1451  ctxProp: string;1452  ctxNumProp: number;1453  ctxBoolProp: boolean;1454  toStringThrow = {toString: function() { throw 'boom'; }};1455  constructor() {1456    this.ctxProp = 'initial value';1457    this.ctxNumProp = 0;1458    this.ctxBoolProp = false;1459  }1460  throwError() { throw 'boom'; }1461}1462@Component({1463  selector: 'child-cmp',1464  inputs: ['dirProp'],1465  viewProviders: [MyService],1466  template: '{{ctxProp}}'1467})1468class ChildComp {1469  ctxProp: string;1470  dirProp: string;1471  constructor(service: MyService) {1472    this.ctxProp = service.greeting;1473    this.dirProp = null;1474  }1475}1476@Component({selector: 'child-cmp-no-template', template: ''})1477class ChildCompNoTemplate {1478  ctxProp: string = 'hello';1479}1480@Component({selector: 'child-cmp-svc', template: '{{ctxProp}}'})1481class ChildCompUsingService {1482  ctxProp: string;1483  constructor(service: MyService) { this.ctxProp = service.greeting; }1484}1485@Directive({selector: 'some-directive'})1486class SomeDirective {1487}1488class SomeDirectiveMissingAnnotation {}1489@Component({1490  selector: 'cmp-with-host',1491  template: '<p>Component with an injected host</p>',1492})1493class CompWithHost {1494  myHost: SomeDirective;1495  constructor(@Host() someComp: SomeDirective) { this.myHost = someComp; }1496}1497@Component({selector: '[child-cmp2]', viewProviders: [MyService]})1498class ChildComp2 {1499  ctxProp: string;1500  dirProp: string;1501  constructor(service: MyService) {1502    this.ctxProp = service.greeting;1503    this.dirProp = null;1504  }1505}1506class SomeViewportContext {1507  constructor(public someTmpl: string) {}1508}1509@Directive({selector: '[some-viewport]'})1510class SomeViewport {1511  constructor(public container: ViewContainerRef, templateRef: TemplateRef<SomeViewportContext>) {1512    container.createEmbeddedView(templateRef, new SomeViewportContext('hello'));1513    container.createEmbeddedView(templateRef, new SomeViewportContext('again'));1514  }1515}1516@Directive({selector: '[pollutedContext]'})1517class PollutedContext {1518  constructor(private tplRef: TemplateRef<any>, private vcRef: ViewContainerRef) {1519    const evRef = this.vcRef.createEmbeddedView(this.tplRef);1520    evRef.context.bar = 'baz';1521  }1522}1523@Directive({selector: '[noContext]'})1524class NoContext {1525  constructor(private tplRef: TemplateRef<any>, private vcRef: ViewContainerRef) {1526    this.vcRef.createEmbeddedView(this.tplRef);1527  }1528}1529@Pipe({name: 'double'})1530class DoublePipe implements PipeTransform, OnDestroy {1531  ngOnDestroy() {}1532  transform(value: any) { return `${value}${value}`; }1533}1534@Directive({selector: '[emitter]', outputs: ['event']})1535class DirectiveEmittingEvent {1536  msg: string;1537  event: EventEmitter<any>;1538  constructor() {1539    this.msg = '';1540    this.event = new EventEmitter();1541  }1542  fireEvent(msg: string) { this.event.emit(msg); }1543}1544@Directive({selector: '[update-host-attributes]', host: {'role': 'button'}})1545class DirectiveUpdatingHostAttributes {1546}1547@Directive({selector: '[update-host-properties]', host: {'[id]': 'id'}})1548class DirectiveUpdatingHostProperties {1549  id: string;1550  constructor() { this.id = 'one'; }1551}1552@Directive({selector: '[listener]', host: {'(event)': 'onEvent($event)'}})1553class DirectiveListeningEvent {1554  msg: string;1555  constructor() { this.msg = ''; }1556  onEvent(msg: string) { this.msg = msg; }1557}1558@Directive({1559  selector: '[listener]',1560  host: {1561    '(domEvent)': 'onEvent($event.type)',1562    '(window:domEvent)': 'onWindowEvent($event.type)',1563    '(document:domEvent)': 'onDocumentEvent($event.type)',1564    '(body:domEvent)': 'onBodyEvent($event.type)'1565  }1566})1567class DirectiveListeningDomEvent {1568  eventTypes: string[] = [];1569  onEvent(eventType: string) { this.eventTypes.push(eventType); }1570  onWindowEvent(eventType: string) { this.eventTypes.push('window_' + eventType); }1571  onDocumentEvent(eventType: string) { this.eventTypes.push('document_' + eventType); }1572  onBodyEvent(eventType: string) { this.eventTypes.push('body_' + eventType); }1573}1574var globalCounter = 0;1575@Directive({selector: '[listenerother]', host: {'(window:domEvent)': 'onEvent($event.type)'}})1576class DirectiveListeningDomEventOther {1577  eventType: string;1578  constructor() { this.eventType = ''; }1579  onEvent(eventType: string) {1580    globalCounter++;1581    this.eventType = 'other_' + eventType;1582  }1583}1584@Directive({selector: '[listenerprevent]', host: {'(click)': 'onEvent($event)'}})1585class DirectiveListeningDomEventPrevent {1586  onEvent(event: any) { return false; }1587}1588@Directive({selector: '[listenernoprevent]', host: {'(click)': 'onEvent($event)'}})1589class DirectiveListeningDomEventNoPrevent {1590  onEvent(event: any) { return true; }1591}1592@Directive({selector: '[id]', inputs: ['id']})1593class IdDir {1594  id: string;1595}1596@Directive({selector: '[customEvent]'})1597class EventDir {1598  @Output() customEvent = new EventEmitter();1599  doSomething() {}1600}1601@Directive({selector: '[static]'})1602class NeedsAttribute {1603  typeAttribute: string;1604  staticAttribute: string;1605  fooAttribute: string;1606  constructor(1607      @Attribute('type') typeAttribute: string, @Attribute('static') staticAttribute: string,1608      @Attribute('foo') fooAttribute: string) {1609    this.typeAttribute = typeAttribute;1610    this.staticAttribute = staticAttribute;1611    this.fooAttribute = fooAttribute;1612  }1613}1614@Injectable()1615class PublicApi {1616}1617@Directive({1618  selector: '[public-api]',1619  providers: [{provide: PublicApi, useExisting: PrivateImpl, deps: []}]1620})1621class PrivateImpl extends PublicApi {1622}1623@Directive({selector: '[needs-public-api]'})1624class NeedsPublicApi {1625  constructor(@Host() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }1626}1627class ToolbarContext {1628  constructor(public toolbarProp: string) {}1629}1630@Directive({selector: '[toolbarpart]'})1631class ToolbarPart {1632  templateRef: TemplateRef<ToolbarContext>;1633  constructor(templateRef: TemplateRef<ToolbarContext>) { this.templateRef = templateRef; }1634}1635@Directive({selector: '[toolbarVc]', inputs: ['toolbarVc']})1636class ToolbarViewContainer {1637  vc: ViewContainerRef;1638  constructor(vc: ViewContainerRef) { this.vc = vc; }1639  set toolbarVc(part: ToolbarPart) {1640    this.vc.createEmbeddedView(part.templateRef, new ToolbarContext('From toolbar'), 0);1641  }1642}1643@Component({1644  selector: 'toolbar',1645  template: 'TOOLBAR(<div *ngFor="let  part of query" [toolbarVc]="part"></div>)',1646})1647class ToolbarComponent {1648  @ContentChildren(ToolbarPart) query: QueryList<ToolbarPart>;1649  ctxProp: string;1650  constructor() { this.ctxProp = 'hello world'; }1651}1652@Directive({selector: '[two-way]', inputs: ['control'], outputs: ['controlChange']})1653class DirectiveWithTwoWayBinding {1654  controlChange = new EventEmitter();1655  control: any = null;1656  triggerChange(value: any) { this.controlChange.emit(value); }1657}1658@Injectable()1659class InjectableService {1660}1661function createInjectableWithLogging(inj: Injector) {1662  inj.get(ComponentProvidingLoggingInjectable).created = true;1663  return new InjectableService();1664}1665@Component({1666  selector: 'component-providing-logging-injectable',1667  providers:1668      [{provide: InjectableService, useFactory: createInjectableWithLogging, deps: [Injector]}],1669  template: ''1670})1671class ComponentProvidingLoggingInjectable {1672  created: boolean = false;1673}1674@Directive({selector: 'directive-providing-injectable', providers: [[InjectableService]]})1675class DirectiveProvidingInjectable {1676}1677@Component({1678  selector: 'directive-providing-injectable',1679  viewProviders: [[InjectableService]],1680  template: ''1681})1682class DirectiveProvidingInjectableInView {1683}1684@Component({1685  selector: 'directive-providing-injectable',1686  providers: [{provide: InjectableService, useValue: 'host'}],1687  viewProviders: [{provide: InjectableService, useValue: 'view'}],1688  template: ''1689})1690class DirectiveProvidingInjectableInHostAndView {1691}1692@Component({selector: 'directive-consuming-injectable', template: ''})1693class DirectiveConsumingInjectable {1694  injectable: any;1695  constructor(@Host() @Inject(InjectableService) injectable: any) { this.injectable = injectable; }1696}1697@Component({selector: 'directive-containing-directive-consuming-an-injectable'})1698class DirectiveContainingDirectiveConsumingAnInjectable {1699  directive: any;1700}1701@Component({selector: 'directive-consuming-injectable-unbounded', template: ''})1702class DirectiveConsumingInjectableUnbounded {1703  injectable: any;1704  constructor(1705      injectable: InjectableService,1706      @SkipSelf() parent: DirectiveContainingDirectiveConsumingAnInjectable) {1707    this.injectable = injectable;1708    parent.directive = this;1709  }1710}1711class EventBus {1712  parentEventBus: EventBus;1713  name: string;1714  constructor(parentEventBus: EventBus, name: string) {1715    this.parentEventBus = parentEventBus;1716    this.name = name;1717  }1718}1719@Directive({1720  selector: 'grand-parent-providing-event-bus',1721  providers: [{provide: EventBus, useValue: new EventBus(null, 'grandparent')}]1722})1723class GrandParentProvidingEventBus {1724  bus: EventBus;1725  constructor(bus: EventBus) { this.bus = bus; }1726}1727function createParentBus(peb: EventBus) {1728  return new EventBus(peb, 'parent');1729}1730@Component({1731  selector: 'parent-providing-event-bus',1732  providers: [{provide: EventBus, useFactory: createParentBus, deps: [[EventBus, new SkipSelf()]]}],1733  template: `<child-consuming-event-bus></child-consuming-event-bus>`1734})1735class ParentProvidingEventBus {1736  bus: EventBus;1737  grandParentBus: EventBus;1738  constructor(bus: EventBus, @SkipSelf() grandParentBus: EventBus) {1739    this.bus = bus;1740    this.grandParentBus = grandParentBus;1741  }1742}1743@Directive({selector: 'child-consuming-event-bus'})1744class ChildConsumingEventBus {1745  bus: EventBus;1746  constructor(@SkipSelf() bus: EventBus) { this.bus = bus; }1747}1748@Directive({selector: '[someImpvp]', inputs: ['someImpvp']})1749class SomeImperativeViewport {1750  view: EmbeddedViewRef<Object>;1751  anchor: any;1752  constructor(1753      public vc: ViewContainerRef, public templateRef: TemplateRef<Object>,1754      @Inject(ANCHOR_ELEMENT) anchor: any) {1755    this.view = null;1756    this.anchor = anchor;1757  }1758  set someImpvp(value: boolean) {1759    if (isPresent(this.view)) {1760      this.vc.clear();1761      this.view = null;1762    }1763    if (value) {1764      this.view = this.vc.createEmbeddedView(this.templateRef);1765      var nodes = this.view.rootNodes;1766      for (var i = 0; i < nodes.length; i++) {1767        getDOM().appendChild(this.anchor, nodes[i]);1768      }1769    }1770  }1771}1772@Directive({selector: '[export-dir]', exportAs: 'dir'})1773class ExportDir {1774}1775@Component({selector: 'comp'})1776class ComponentWithoutView {1777}1778@Directive({selector: '[no-duplicate]'})1779class DuplicateDir {1780  constructor(elRef: ElementRef) {1781    getDOM().setText(elRef.nativeElement, getDOM().getText(elRef.nativeElement) + 'noduplicate');1782  }1783}1784@Directive({selector: '[no-duplicate]'})1785class OtherDuplicateDir {1786  constructor(elRef: ElementRef) {1787    getDOM().setText(1788        elRef.nativeElement, getDOM().getText(elRef.nativeElement) + 'othernoduplicate');1789  }1790}1791@Directive({selector: 'directive-throwing-error'})1792class DirectiveThrowingAnError {1793  constructor() { throw new Error('BOOM'); }1794}1795@Component({1796  selector: 'component-with-template',1797  template: `No View Decorator: <div *ngFor="let item of items">{{item}}</div>`1798})1799class ComponentWithTemplate {1800  items = [1, 2, 3];1801}1802@Directive({selector: 'with-prop-decorators'})1803class DirectiveWithPropDecorators {1804  target: any;1805  @Input('elProp') dirProp: string;1806  @Output('elEvent') event = new EventEmitter();1807  @HostBinding('attr.my-attr') myAttr: string;1808  @HostListener('click', ['$event.target'])1809  onClick(target: any) { this.target = target; }1810  fireEvent(msg: any) { this.event.emit(msg); }1811}1812@Component({selector: 'some-cmp'})1813class SomeCmp {1814  value: any;...projection_integration_spec.ts
Source:projection_integration_spec.ts  
1/**2 * @license3 * Copyright Google Inc. All Rights Reserved.4 *5 * Use of this source code is governed by an MIT-style license that can be6 * found in the LICENSE file at https://angular.io/license7 */8import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';9import {getAllDebugNodes} from '@angular/core/src/debug/debug_node';10import {TestBed} from '@angular/core/testing';11import {beforeEach, describe, it} from '@angular/core/testing/testing_internal';12import {By} from '@angular/platform-browser/src/dom/debug/by';13import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';14import {expect} from '@angular/platform-browser/testing/matchers';15export function main() {16  describe('projection', () => {17    beforeEach(() => TestBed.configureTestingModule({declarations: [MainComp, OtherComp, Simple]}));18    it('should support simple components', () => {19      const template = '<simple><div>A</div></simple>';20      TestBed.overrideComponent(MainComp, {set: {template}});21      const main = TestBed.createComponent(MainComp);22      expect(main.nativeElement).toHaveText('SIMPLE(A)');23    });24    it('should support simple components with text interpolation as direct children', () => {25      const template = '{{\'START(\'}}<simple>' +26          '{{text}}' +27          '</simple>{{\')END\'}}';28      TestBed.overrideComponent(MainComp, {set: {template}});29      const main = TestBed.createComponent(MainComp);30      main.componentInstance.text = 'A';31      main.detectChanges();32      expect(main.nativeElement).toHaveText('START(SIMPLE(A))END');33    });34    it('should support projecting text interpolation to a non bound element', () => {35      TestBed.overrideComponent(36          Simple, {set: {template: 'SIMPLE(<div><ng-content></ng-content></div>)'}});37      TestBed.overrideComponent(MainComp, {set: {template: '<simple>{{text}}</simple>'}});38      const main = TestBed.createComponent(MainComp);39      main.componentInstance.text = 'A';40      main.detectChanges();41      expect(main.nativeElement).toHaveText('SIMPLE(A)');42    });43    it('should support projecting text interpolation to a non bound element with other bound elements after it',44       () => {45         TestBed.overrideComponent(Simple, {46           set: {47             template: 'SIMPLE(<div><ng-content></ng-content></div><div [tabIndex]="0">EL</div>)'48           }49         });50         TestBed.overrideComponent(MainComp, {set: {template: '<simple>{{text}}</simple>'}});51         const main = TestBed.createComponent(MainComp);52         main.componentInstance.text = 'A';53         main.detectChanges();54         expect(main.nativeElement).toHaveText('SIMPLE(AEL)');55       });56    it('should project content components', () => {57      TestBed.overrideComponent(58          Simple, {set: {template: 'SIMPLE({{0}}|<ng-content></ng-content>|{{2}})'}});59      TestBed.overrideComponent(OtherComp, {set: {template: '{{1}}'}});60      TestBed.overrideComponent(MainComp, {set: {template: '<simple><other></other></simple>'}});61      const main = TestBed.createComponent(MainComp);62      main.detectChanges();63      expect(main.nativeElement).toHaveText('SIMPLE(0|1|2)');64    });65    it('should not show the light dom even if there is no content tag', () => {66      TestBed.configureTestingModule({declarations: [Empty]});67      TestBed.overrideComponent(MainComp, {set: {template: '<empty>A</empty>'}});68      const main = TestBed.createComponent(MainComp);69      expect(main.nativeElement).toHaveText('');70    });71    it('should support multiple content tags', () => {72      TestBed.configureTestingModule({declarations: [MultipleContentTagsComponent]});73      TestBed.overrideComponent(MainComp, {74        set: {75          template: '<multiple-content-tags>' +76              '<div>B</div>' +77              '<div>C</div>' +78              '<div class="left">A</div>' +79              '</multiple-content-tags>'80        }81      });82      const main = TestBed.createComponent(MainComp);83      expect(main.nativeElement).toHaveText('(A, BC)');84    });85    it('should redistribute only direct children', () => {86      TestBed.configureTestingModule({declarations: [MultipleContentTagsComponent]});87      TestBed.overrideComponent(MainComp, {88        set: {89          template: '<multiple-content-tags>' +90              '<div>B<div class="left">A</div></div>' +91              '<div>C</div>' +92              '</multiple-content-tags>'93        }94      });95      const main = TestBed.createComponent(MainComp);96      expect(main.nativeElement).toHaveText('(, BAC)');97    });98    it('should redistribute direct child viewcontainers when the light dom changes', () => {99      TestBed.configureTestingModule(100          {declarations: [MultipleContentTagsComponent, ManualViewportDirective]});101      TestBed.overrideComponent(MainComp, {102        set: {103          template: '<multiple-content-tags>' +104              '<template manual class="left"><div>A1</div></template>' +105              '<div>B</div>' +106              '</multiple-content-tags>'107        }108      });109      const main = TestBed.createComponent(MainComp);110      var viewportDirectives = main.debugElement.children[0]111                                   .childNodes.filter(By.directive(ManualViewportDirective))112                                   .map(de => de.injector.get(ManualViewportDirective));113      expect(main.nativeElement).toHaveText('(, B)');114      viewportDirectives.forEach(d => d.show());115      expect(main.nativeElement).toHaveText('(A1, B)');116      viewportDirectives.forEach(d => d.hide());117      expect(main.nativeElement).toHaveText('(, B)');118    });119    it('should support nested components', () => {120      TestBed.configureTestingModule({declarations: [OuterWithIndirectNestedComponent]});121      TestBed.overrideComponent(MainComp, {122        set: {123          template: '<outer-with-indirect-nested>' +124              '<div>A</div>' +125              '<div>B</div>' +126              '</outer-with-indirect-nested>'127        }128      });129      const main = TestBed.createComponent(MainComp);130      expect(main.nativeElement).toHaveText('OUTER(SIMPLE(AB))');131    });132    it('should support nesting with content being direct child of a nested component', () => {133      TestBed.configureTestingModule({134        declarations:135            [InnerComponent, InnerInnerComponent, OuterComponent, ManualViewportDirective]136      });137      TestBed.overrideComponent(MainComp, {138        set: {139          template: '<outer>' +140              '<template manual class="left"><div>A</div></template>' +141              '<div>B</div>' +142              '<div>C</div>' +143              '</outer>'144        }145      });146      const main = TestBed.createComponent(MainComp);147      var viewportDirective =148          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(149              ManualViewportDirective);150      expect(main.nativeElement).toHaveText('OUTER(INNER(INNERINNER(,BC)))');151      viewportDirective.show();152      expect(main.nativeElement).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');153    });154    it('should redistribute when the shadow dom changes', () => {155      TestBed.configureTestingModule(156          {declarations: [ConditionalContentComponent, ManualViewportDirective]});157      TestBed.overrideComponent(MainComp, {158        set: {159          template: '<conditional-content>' +160              '<div class="left">A</div>' +161              '<div>B</div>' +162              '<div>C</div>' +163              '</conditional-content>'164        }165      });166      const main = TestBed.createComponent(MainComp);167      var viewportDirective =168          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(169              ManualViewportDirective);170      expect(main.nativeElement).toHaveText('(, BC)');171      viewportDirective.show();172      expect(main.nativeElement).toHaveText('(A, BC)');173      viewportDirective.hide();174      expect(main.nativeElement).toHaveText('(, BC)');175    });176    // GH-2095 - https://github.com/angular/angular/issues/2095177    // important as we are removing the ng-content element during compilation,178    // which could skrew up text node indices.179    it('should support text nodes after content tags', () => {180      TestBed.overrideComponent(MainComp, {set: {template: '<simple stringProp="text"></simple>'}});181      TestBed.overrideComponent(182          Simple, {set: {template: '<ng-content></ng-content><p>P,</p>{{stringProp}}'}});183      const main = TestBed.createComponent(MainComp);184      main.detectChanges();185      expect(main.nativeElement).toHaveText('P,text');186    });187    // important as we are moving style tags around during compilation,188    // which could skrew up text node indices.189    it('should support text nodes after style tags', () => {190      TestBed.overrideComponent(MainComp, {set: {template: '<simple stringProp="text"></simple>'}});191      TestBed.overrideComponent(192          Simple, {set: {template: '<style></style><p>P,</p>{{stringProp}}'}});193      const main = TestBed.createComponent(MainComp);194      main.detectChanges();195      expect(main.nativeElement).toHaveText('P,text');196    });197    it('should support moving non projected light dom around', () => {198      TestBed.configureTestingModule(199          {declarations: [Empty, ProjectDirective, ManualViewportDirective]});200      TestBed.overrideComponent(MainComp, {201        set: {202          template: '<empty>' +203              '  <template manual><div>A</div></template>' +204              '</empty>' +205              'START(<div project></div>)END'206        }207      });208      const main = TestBed.createComponent(MainComp);209      var sourceDirective: any;210      // We can't use the child nodes to get a hold of this because it's not in the dom211      // at212      // all.213      getAllDebugNodes().forEach((debug) => {214        if (debug.providerTokens.indexOf(ManualViewportDirective) !== -1) {215          sourceDirective = debug.injector.get(ManualViewportDirective);216        }217      });218      var projectDirective: ProjectDirective =219          main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get(220              ProjectDirective);221      expect(main.nativeElement).toHaveText('START()END');222      projectDirective.show(sourceDirective.templateRef);223      expect(main.nativeElement).toHaveText('START(A)END');224    });225    it('should support moving projected light dom around', () => {226      TestBed.configureTestingModule(227          {declarations: [Empty, ProjectDirective, ManualViewportDirective]});228      TestBed.overrideComponent(MainComp, {229        set: {230          template: '<simple><template manual><div>A</div></template></simple>' +231              'START(<div project></div>)END'232        }233      });234      const main = TestBed.createComponent(MainComp);235      var sourceDirective: ManualViewportDirective =236          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(237              ManualViewportDirective);238      var projectDirective: ProjectDirective =239          main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get(240              ProjectDirective);241      expect(main.nativeElement).toHaveText('SIMPLE()START()END');242      projectDirective.show(sourceDirective.templateRef);243      expect(main.nativeElement).toHaveText('SIMPLE()START(A)END');244    });245    it('should support moving ng-content around', () => {246      TestBed.configureTestingModule(247          {declarations: [ConditionalContentComponent, ProjectDirective, ManualViewportDirective]});248      TestBed.overrideComponent(MainComp, {249        set: {250          template: '<conditional-content>' +251              '<div class="left">A</div>' +252              '<div>B</div>' +253              '</conditional-content>' +254              'START(<div project></div>)END'255        }256      });257      const main = TestBed.createComponent(MainComp);258      var sourceDirective: ManualViewportDirective =259          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(260              ManualViewportDirective);261      var projectDirective: ProjectDirective =262          main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get(263              ProjectDirective);264      expect(main.nativeElement).toHaveText('(, B)START()END');265      projectDirective.show(sourceDirective.templateRef);266      expect(main.nativeElement).toHaveText('(, B)START(A)END');267      // Stamping ng-content multiple times should not produce the content multiple268      // times...269      projectDirective.show(sourceDirective.templateRef);270      expect(main.nativeElement).toHaveText('(, B)START(A)END');271    });272    // Note: This does not use a ng-content element, but273    // is still important as we are merging proto views independent of274    // the presence of ng-content elements!275    it('should still allow to implement a recursive trees', () => {276      TestBed.configureTestingModule({declarations: [Tree, ManualViewportDirective]});277      TestBed.overrideComponent(MainComp, {set: {template: '<tree></tree>'}});278      const main = TestBed.createComponent(MainComp);279      main.detectChanges();280      var manualDirective: ManualViewportDirective =281          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(282              ManualViewportDirective);283      expect(main.nativeElement).toHaveText('TREE(0:)');284      manualDirective.show();285      main.detectChanges();286      expect(main.nativeElement).toHaveText('TREE(0:TREE(1:))');287    });288    // Note: This does not use a ng-content element, but289    // is still important as we are merging proto views independent of290    // the presence of ng-content elements!291    it('should still allow to implement a recursive trees via multiple components', () => {292      TestBed.configureTestingModule({declarations: [Tree, Tree2, ManualViewportDirective]});293      TestBed.overrideComponent(MainComp, {set: {template: '<tree></tree>'}});294      TestBed.overrideComponent(295          Tree, {set: {template: 'TREE({{depth}}:<tree2 *manual [depth]="depth+1"></tree2>)'}});296      const main = TestBed.createComponent(MainComp);297      main.detectChanges();298      expect(main.nativeElement).toHaveText('TREE(0:)');299      var tree = main.debugElement.query(By.directive(Tree));300      var manualDirective: ManualViewportDirective = tree.queryAllNodes(By.directive(301          ManualViewportDirective))[0].injector.get(ManualViewportDirective);302      manualDirective.show();303      main.detectChanges();304      expect(main.nativeElement).toHaveText('TREE(0:TREE2(1:))');305      var tree2 = main.debugElement.query(By.directive(Tree2));306      manualDirective = tree2.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(307          ManualViewportDirective);308      manualDirective.show();309      main.detectChanges();310      expect(main.nativeElement).toHaveText('TREE(0:TREE2(1:TREE(2:)))');311    });312    if (getDOM().supportsNativeShadowDOM()) {313      it('should support native content projection and isolate styles per component', () => {314        TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});315        TestBed.overrideComponent(MainComp, {316          set: {317            template: '<simple-native1><div>A</div></simple-native1>' +318                '<simple-native2><div>B</div></simple-native2>'319          }320        });321        const main = TestBed.createComponent(MainComp);322        var childNodes = getDOM().childNodes(main.nativeElement);323        expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)');324        expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)');325        main.destroy();326      });327    }328    if (getDOM().supportsDOMEvents()) {329      it('should support non emulated styles', () => {330        TestBed.configureTestingModule({declarations: [OtherComp]});331        TestBed.overrideComponent(MainComp, {332          set: {333            template: '<div class="redStyle"></div>',334            styles: ['.redStyle { color: red}'],335            encapsulation: ViewEncapsulation.None,336          }337        });338        const main = TestBed.createComponent(MainComp);339        var mainEl = main.nativeElement;340        var div1 = getDOM().firstChild(mainEl);341        var div2 = getDOM().createElement('div');342        getDOM().setAttribute(div2, 'class', 'redStyle');343        getDOM().appendChild(mainEl, div2);344        expect(getDOM().getComputedStyle(div1).color).toEqual('rgb(255, 0, 0)');345        expect(getDOM().getComputedStyle(div2).color).toEqual('rgb(255, 0, 0)');346      });347      it('should support emulated style encapsulation', () => {348        TestBed.configureTestingModule({declarations: [OtherComp]});349        TestBed.overrideComponent(MainComp, {350          set: {351            template: '<div></div>',352            styles: ['div { color: red}'],353            encapsulation: ViewEncapsulation.Emulated,354          }355        });356        const main = TestBed.createComponent(MainComp);357        var mainEl = main.nativeElement;358        var div1 = getDOM().firstChild(mainEl);359        var div2 = getDOM().createElement('div');360        getDOM().appendChild(mainEl, div2);361        expect(getDOM().getComputedStyle(div1).color).toEqual('rgb(255, 0, 0)');362        expect(getDOM().getComputedStyle(div2).color).toEqual('rgb(0, 0, 0)');363      });364    }365    it('should support nested conditionals that contain ng-contents', () => {366      TestBed.configureTestingModule(367          {declarations: [ConditionalTextComponent, ManualViewportDirective]});368      TestBed.overrideComponent(369          MainComp, {set: {template: `<conditional-text>a</conditional-text>`}});370      const main = TestBed.createComponent(MainComp);371      expect(main.nativeElement).toHaveText('MAIN()');372      var viewportElement =373          main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0];374      viewportElement.injector.get(ManualViewportDirective).show();375      expect(main.nativeElement).toHaveText('MAIN(FIRST())');376      viewportElement = main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[1];377      viewportElement.injector.get(ManualViewportDirective).show();378      expect(main.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))');379    });380    it('should allow to switch the order of nested components via ng-content', () => {381      TestBed.configureTestingModule({declarations: [CmpA, CmpB, CmpD, CmpC]});382      TestBed.overrideComponent(MainComp, {set: {template: `<cmp-a><cmp-b></cmp-b></cmp-a>`}});383      const main = TestBed.createComponent(MainComp);384      main.detectChanges();385      expect(getDOM().getInnerHTML(main.nativeElement))386          .toEqual(387              '<cmp-a><cmp-b><cmp-d><i>cmp-d</i></cmp-d></cmp-b>' +388              '<cmp-c><b>cmp-c</b></cmp-c></cmp-a>');389    });390    it('should create nested components in the right order', () => {391      TestBed.configureTestingModule(392          {declarations: [CmpA1, CmpA2, CmpB11, CmpB12, CmpB21, CmpB22]});393      TestBed.overrideComponent(MainComp, {set: {template: `<cmp-a1></cmp-a1><cmp-a2></cmp-a2>`}});394      const main = TestBed.createComponent(MainComp);395      main.detectChanges();396      expect(getDOM().getInnerHTML(main.nativeElement))397          .toEqual(398              '<cmp-a1>a1<cmp-b11>b11</cmp-b11><cmp-b12>b12</cmp-b12></cmp-a1>' +399              '<cmp-a2>a2<cmp-b21>b21</cmp-b21><cmp-b22>b22</cmp-b22></cmp-a2>');400    });401    it('should project filled view containers into a view container', () => {402      TestBed.configureTestingModule(403          {declarations: [ConditionalContentComponent, ManualViewportDirective]});404      TestBed.overrideComponent(MainComp, {405        set: {406          template: '<conditional-content>' +407              '<div class="left">A</div>' +408              '<template manual class="left">B</template>' +409              '<div class="left">C</div>' +410              '<div>D</div>' +411              '</conditional-content>'412        }413      });414      const main = TestBed.createComponent(MainComp);415      var conditionalComp = main.debugElement.query(By.directive(ConditionalContentComponent));416      var viewViewportDir =417          conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get(418              ManualViewportDirective);419      expect(main.nativeElement).toHaveText('(, D)');420      expect(main.nativeElement).toHaveText('(, D)');421      viewViewportDir.show();422      expect(main.nativeElement).toHaveText('(AC, D)');423      var contentViewportDir =424          conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[1].injector.get(425              ManualViewportDirective);426      contentViewportDir.show();427      expect(main.nativeElement).toHaveText('(ABC, D)');428      // hide view viewport, and test that it also hides429      // the content viewport's views430      viewViewportDir.hide();431      expect(main.nativeElement).toHaveText('(, D)');432    });433  });434}435@Component({selector: 'main', template: ''})436class MainComp {437  text: string = '';438}439@Component({selector: 'other', template: ''})440class OtherComp {441  text: string = '';442}443@Component({444  selector: 'simple',445  inputs: ['stringProp'],446  template: 'SIMPLE(<ng-content></ng-content>)',447})448class Simple {449  stringProp: string = '';450}451@Component({452  selector: 'simple-native1',453  template: 'SIMPLE1(<content></content>)',454  encapsulation: ViewEncapsulation.Native,455  styles: ['div {color: red}']456})457class SimpleNative1 {458}459@Component({460  selector: 'simple-native2',461  template: 'SIMPLE2(<content></content>)',462  encapsulation: ViewEncapsulation.Native,463  styles: ['div {color: blue}']464})465class SimpleNative2 {466}467@Component({selector: 'empty', template: ''})468class Empty {469}470@Component({471  selector: 'multiple-content-tags',472  template: '(<ng-content SELECT=".left"></ng-content>, <ng-content></ng-content>)',473})474class MultipleContentTagsComponent {475}476@Directive({selector: '[manual]'})477class ManualViewportDirective {478  constructor(public vc: ViewContainerRef, public templateRef: TemplateRef<Object>) {}479  show() { this.vc.createEmbeddedView(this.templateRef); }480  hide() { this.vc.clear(); }481}482@Directive({selector: '[project]'})483class ProjectDirective {484  constructor(public vc: ViewContainerRef) {}485  show(templateRef: TemplateRef<Object>) { this.vc.createEmbeddedView(templateRef); }486  hide() { this.vc.clear(); }487}488@Component({489  selector: 'outer-with-indirect-nested',490  template: 'OUTER(<simple><div><ng-content></ng-content></div></simple>)',491})492class OuterWithIndirectNestedComponent {493}494@Component({495  selector: 'outer',496  template:497      'OUTER(<inner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></inner>)',498})499class OuterComponent {500}501@Component({502  selector: 'inner',503  template:504      'INNER(<innerinner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></innerinner>)',505})506class InnerComponent {507}508@Component({509  selector: 'innerinner',510  template: 'INNERINNER(<ng-content select=".left"></ng-content>,<ng-content></ng-content>)',511})512class InnerInnerComponent {513}514@Component({515  selector: 'conditional-content',516  template:517      '<div>(<div *manual><ng-content select=".left"></ng-content></div>, <ng-content></ng-content>)</div>',518})519class ConditionalContentComponent {520}521@Component({522  selector: 'conditional-text',523  template:524      'MAIN(<template manual>FIRST(<template manual>SECOND(<ng-content></ng-content>)</template>)</template>)',525})526class ConditionalTextComponent {527}528@Component({529  selector: 'tab',530  template: '<div><div *manual>TAB(<ng-content></ng-content>)</div></div>',531})532class Tab {533}534@Component({535  selector: 'tree2',536  inputs: ['depth'],537  template: 'TREE2({{depth}}:<tree *manual [depth]="depth+1"></tree>)',538})539class Tree2 {540  depth = 0;541}542@Component({543  selector: 'tree',544  inputs: ['depth'],545  template: 'TREE({{depth}}:<tree *manual [depth]="depth+1"></tree>)',546})547class Tree {548  depth = 0;549}550@Component({selector: 'cmp-d', template: `<i>{{tagName}}</i>`})551class CmpD {552  tagName: string;553  constructor(elementRef: ElementRef) {554    this.tagName = getDOM().tagName(elementRef.nativeElement).toLowerCase();555  }556}557@Component({selector: 'cmp-c', template: `<b>{{tagName}}</b>`})558class CmpC {559  tagName: string;560  constructor(elementRef: ElementRef) {561    this.tagName = getDOM().tagName(elementRef.nativeElement).toLowerCase();562  }563}564@Component({selector: 'cmp-b', template: `<ng-content></ng-content><cmp-d></cmp-d>`})565class CmpB {566}567@Component({selector: 'cmp-a', template: `<ng-content></ng-content><cmp-c></cmp-c>`})568class CmpA {569}570@Component({selector: 'cmp-b11', template: `{{'b11'}}`})571class CmpB11 {572}573@Component({selector: 'cmp-b12', template: `{{'b12'}}`})574class CmpB12 {575}576@Component({selector: 'cmp-b21', template: `{{'b21'}}`})577class CmpB21 {578}579@Component({selector: 'cmp-b22', template: `{{'b22'}}`})580class CmpB22 {581}582@Component({583  selector: 'cmp-a1',584  template: `{{'a1'}}<cmp-b11></cmp-b11><cmp-b12></cmp-b12>`,585})586class CmpA1 {587}588@Component({589  selector: 'cmp-a2',590  template: `{{'a2'}}<cmp-b21></cmp-b21><cmp-b22></cmp-b22>`,591})592class CmpA2 {...password-checker-lib.spec.ts
Source:password-checker-lib.spec.ts  
1import { TestBed, async, tick } from '@angular/core/testing';2import { HttpClientTestingModule, HttpTestingController, } from '@angular/common/http/testing';3import { Component } from '@angular/core';4import {5  UntypedFormBuilder,6  UntypedFormControl,7  FormsModule,8  ReactiveFormsModule,9  Validators,10} from '@angular/forms';11import { By } from '@angular/platform-browser';12import { fakeSchedulers } from 'rxjs-marbles/jasmine/angular';13import { PasswordCheckerLibDirective } from '../lib/password-checker-lib.directive';14import { PasswordCheckerConfigValue } from '../lib/password-checker.config';15@Component({16  selector: 'pwc-my-test-component',17  template: ''18})19class TestComponent {20  constructor(private fb: UntypedFormBuilder) {}21  form = this.fb.group( {22    password: ['', Validators.required],23  });24  formControl = new UntypedFormControl('', [Validators.required]);25  model = '';26  get pw() { return this.form.get('password'); }27}28describe('PasswordCheckerDirective Module', () => {29  beforeEach(async(() => {30    TestBed.configureTestingModule({31      declarations: [32        TestComponent,33        PasswordCheckerLibDirective,34      ],35      imports: [36        HttpClientTestingModule,37        FormsModule,38        ReactiveFormsModule,39      ],40    });41  }));42  describe('configuration and attaching of directive', () => {43    it('should be able to create the directive on a [form] formControlName without a provider and default configuration', async(() => {44      TestBed.overrideComponent(TestComponent, {45        set: {46          template: `<form [formGroup]="form">47  <input type="password" formControlName="password" pwnedPasswordValidator>48</form>`49        }50      });51      TestBed.compileComponents().then(() => {52        const fixture = TestBed.createComponent(TestComponent);53        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));54        expect(directiveEl).not.toBeNull();55        fixture.detectChanges();56        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);57        expect(directiveInstance.pwnedPasswordApi).toBe('https://api.pwnedpasswords.com/range/');58        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe(400);59        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe(1);60      });61    }));62    it('should be able to create the directive on a [form] formControlName with a provider overriding the configuration', async(() => {63      TestBed.overrideComponent(TestComponent, {64        set: {65          template: `<form [formGroup]="form">66  <input type="password" formControlName="password" pwnedPasswordValidator>67</form>`,68          providers: [{69            provide: PasswordCheckerConfigValue, useValue: {70              pwnedPasswordApi: 'a',71              pwnedPasswordApiCallDebounceTime: 16,72              pwnedPasswordMinimumOccurrenceForError: 2,73            }74          }]75        }76      });77      TestBed.compileComponents().then(() => {78        const fixture = TestBed.createComponent(TestComponent);79        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));80        expect(directiveEl).not.toBeNull();81        fixture.detectChanges();82        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);83        expect(directiveInstance.pwnedPasswordApi).toBe('a');84        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe(16);85        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe(2);86      });87    }));88    it('should be able to create the directive with a provider overriding the configuration with an incomplete object', async(() => {89      TestBed.overrideComponent(TestComponent, {90        set: {91          template: `<form [formGroup]="form">92  <input type="password" formControlName="password" pwnedPasswordValidator>93</form>`,94          providers: [{95            provide: PasswordCheckerConfigValue, useValue: {96              pwnedPasswordApi: 'b',97            }98          }]99        }100      });101      TestBed.compileComponents().then(() => {102        const fixture = TestBed.createComponent(TestComponent);103        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));104        expect(directiveEl).not.toBeNull();105        fixture.detectChanges();106        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);107        expect(directiveInstance.pwnedPasswordApi).toBe('b');108        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe(400);109        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe(1);110      });111    }));112    it('should be possible to override the module config with @Input()', async(() => {113      TestBed.overrideComponent(TestComponent, {114        set: {115          template: `<form [formGroup]="form">116  <input type="password" formControlName="password"117  pwnedPasswordValidator118  pwnedPasswordApi="e"119  pwnedPasswordApiCallDebounceTime="32"120  pwnedPasswordMinimumOccurrenceForError="3"121  >122</form>`,123          providers: [{124            provide: PasswordCheckerConfigValue, useValue: {125              pwnedPasswordApi: 'a',126              pwnedPasswordApiCallDebounceTime: 16,127              pwnedPasswordMinimumOccurrenceForError: 2,128            }129          }]130        }131      });132      TestBed.compileComponents().then(() => {133        const fixture = TestBed.createComponent(TestComponent);134        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));135        expect(directiveEl).not.toBeNull();136        fixture.detectChanges();137        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);138        expect(directiveInstance.pwnedPasswordApi).toBe('e');139        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe('32' as any);140        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe('3' as any);141      });142    }));143    it('should be possible to attach the directive to a formcontrol', async(() => {144      TestBed.overrideComponent(TestComponent, {145        set: {146          template: `<input type="password" [formControl]="formControl"147  pwnedPasswordValidator148  >`,149        }150      });151      TestBed.compileComponents().then(() => {152        const fixture = TestBed.createComponent(TestComponent);153        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));154        expect(directiveEl).not.toBeNull();155        fixture.detectChanges();156        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);157        expect(directiveInstance.pwnedPasswordApi).toBe('https://api.pwnedpasswords.com/range/');158        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe(400);159        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe(1);160      });161    }));162    it('should be possible to be on a model', async(() => {163      TestBed.overrideComponent(TestComponent, {164        set: {165          template: `<input type="password" [(ngModel)]="model"166  pwnedPasswordValidator167  >`,168        }169      });170      TestBed.compileComponents().then(() => {171        const fixture = TestBed.createComponent(TestComponent);172        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));173        expect(directiveEl).not.toBeNull();174        fixture.detectChanges();175        const directiveInstance = directiveEl.injector.get(PasswordCheckerLibDirective);176        expect(directiveInstance.pwnedPasswordApi).toBe('https://api.pwnedpasswords.com/range/');177        expect(directiveInstance.pwnedPasswordApiCallDebounceTime).toBe(400);178        expect(directiveInstance.pwnedPasswordMinimumOccurrenceForError).toBe(1);179      });180    }));181    it('should be null, if the selectors are missing', async(() => {182      TestBed.overrideComponent(TestComponent, {183        set: {184          template: `<input type="password" pwnedPasswordValidator185  >`,186        }187      });188      TestBed.compileComponents().then(() => {189        const fixture = TestBed.createComponent(TestComponent);190        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));191        expect(directiveEl).toBeNull();192        fixture.detectChanges();193      });194    }));195  });196  describe(' calling the API after setting a value to the input', () => {197    const passwordSearchResult = `D0A4AA2E841C50022BB2EA424E43F8FC403:16198D10B1F9D5901978256CE5B2AD832F292D5A:1199D09CA3762AF61E59520943DC26494F8941B:23174662200D1618FACC3854462B7A0EF41914D22C41B6:2201D21307CAE168387A4C8E7559BC65382D1DB:49`;202    it('should call the API and set the form invalid for bad passwords', fakeSchedulers(() => {203      TestBed.overrideComponent(TestComponent, {204        set: {205          template: `<form [formGroup]="form">206  <input type="password" formControlName="password" pwnedPasswordValidator>207</form>`208        }209      });210      TestBed.compileComponents().then(() => {211        const fixture = TestBed.createComponent(TestComponent);212        const component = fixture.componentInstance;213        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));214        expect(directiveEl).not.toBeNull();215        expect(component.pw.value).toBe('');216        component.pw.patchValue('123456');217        fixture.detectChanges();218        expect(component.pw.value).toBe('123456');219        tick(400);220        const httpTestingController = TestBed.get(HttpTestingController);221        const req = httpTestingController.expectOne('https://api.pwnedpasswords.com/range/7C4A8');222        expect(req.request.method).toEqual('GET');223        req.flush(passwordSearchResult);224        fixture.detectChanges();225        expect(component.pw.errors.pwnedPasswordOccurrence).not.toBe(null);226        expect(component.pw.errors.pwnedPasswordOccurrence).toBe(23174662);227        httpTestingController.verify();228      });229    }));230    it('should call the API and set the form valid for good passwords', fakeSchedulers(() => {231      TestBed.overrideComponent(TestComponent, {232        set: {233          template: `<form [formGroup]="form">234  <input type="password" formControlName="password" pwnedPasswordValidator>235</form>`236        }237      });238      TestBed.compileComponents().then(() => {239        const fixture = TestBed.createComponent(TestComponent);240        const component = fixture.componentInstance;241        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));242        expect(directiveEl).not.toBeNull();243        expect(component.pw.value).toBe('');244        component.pw.patchValue('Angular Pwned Password Checker Directive');245        fixture.detectChanges();246        expect(component.pw.value).toBe('Angular Pwned Password Checker Directive');247        const httpTestingController = TestBed.get(HttpTestingController);248        httpTestingController.verify();249        fixture.detectChanges();250        tick(200);251        fixture.detectChanges();252        httpTestingController.verify();253        tick(200);254        fixture.detectChanges();255        const req = httpTestingController.expectOne('https://api.pwnedpasswords.com/range/7072F');256        expect(req.request.method).toEqual('GET');257        req.flush(passwordSearchResult);258        fixture.detectChanges();259        expect(component.pw.errors).toBe(null);260        httpTestingController.verify();261      });262    }));263    it('should be configurable', fakeSchedulers(() => {264      TestBed.overrideComponent(TestComponent, {265        set: {266          template: `<form [formGroup]="form">267  <input type="password" formControlName="password" pwnedPasswordValidator>268</form>`,269          providers: [{270            provide: PasswordCheckerConfigValue, useValue: {271              pwnedPasswordApiCallDebounceTime: 1000,272              pwnedPasswordMinimumOccurrenceForError: 23174663,273            }274          }],275        }276      });277      TestBed.compileComponents().then(() => {278        const fixture = TestBed.createComponent(TestComponent);279        const component = fixture.componentInstance;280        const directiveEl = fixture.debugElement.query(By.directive(PasswordCheckerLibDirective));281        expect(directiveEl).not.toBeNull();282        expect(component.pw.value).toBe('');283        component.pw.patchValue('123456');284        fixture.detectChanges();285        expect(component.pw.value).toBe('123456');286        tick(400);287        const httpTestingController = TestBed.get(HttpTestingController);288        httpTestingController.verify();289        tick(600);290        const req = httpTestingController.expectOne('https://api.pwnedpasswords.com/range/7C4A8');291        expect(req.request.method).toEqual('GET');292        req.flush(passwordSearchResult);293        fixture.detectChanges();294        expect(component.pw.errors).toBe(null);295        httpTestingController.verify();296      });297    }));298  });...Using AI Code Generation
1import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';2import { AppComponent } from './app.component';3import { TestComponent } from './test.component';4describe('AppComponent', () => {5  beforeEach(() => MockBuilder(AppComponent, TestComponent));6  it('should create the app', () => {7    const fixture = MockRender(AppComponent);8    const app = fixture.debugElement.componentInstance;9    expect(app).toBeTruthy();10  });11});12import { Component } from '@angular/core';13@Component({14})15export class TestComponent {}16import { Component } from '@angular/core';17@Component({18})19export class AppComponent {}Using AI Code Generation
1import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';2import { AppComponent } from './app.component';3import { ChildComponent } from './child.component';4describe('AppComponent', () => {5  beforeEach(() => MockBuilder(AppComponent).mock(ChildComponent));6  it('should create the app', () => {7    const fixture = MockRender(AppComponent);8    const app = fixture.point.componentInstance;9    expect(app).toBeTruthy();10  });11});12import { Component, Input } from '@angular/core';13@Component({14})15export class ChildComponent {16  @Input() childInput: string;17}18import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';19import { ChildComponent } from './child.component';20describe('ChildComponent', () => {21  beforeEach(() =>22    MockBuilder(ChildComponent).mock(OverrideComponent)23  );24  it('should create the child', () => {25    const fixture = MockRender(ChildComponent);26    const child = fixture.point.componentInstance;27    expect(child).toBeTruthy();28  });29});30module.exports = {31};32import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';33import { AppComponent } from './app.component';34import { ChildComponent } from './child.component';35describe('AppComponent', () => {36  beforeEach(() =>37    MockBuilder(AppComponent).mock(ChildComponent)38  );39  it('should create the app', () => {40    const fixture = MockRender(AppComponent);Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2import { MyComponent } from './my-component.component';3import { MyMockComponent } from './my-mock-component.component';4OverrideComponent(MyComponent, MyMockComponent);5import { Component } from '@angular/core';6@Component({7})8export class MyComponent {}9import { Component } from '@angular/core';10@Component({11})12export class MyMockComponent {}13import { ComponentFixture, TestBed } from '@angular/core/testing';14import { MyComponent } from './my-component.component';15import { MyMockComponent } from './my-mock-component.component';16describe('MyComponent', () => {17  let component: MyComponent;18  let fixture: ComponentFixture<MyComponent>;19  beforeEach(async () => {20    await TestBed.configureTestingModule({21    }).compileComponents();22  });23  beforeEach(() => {24    fixture = TestBed.createComponent(MyComponent);25    component = fixture.componentInstance;26    fixture.detectChanges();27  });28  it('should create', () => {29    expect(component).toBeTruthy();30  });31});32import { OverrideComponent } from 'ng-mocks';33import { MyComponent } from './my-component.component';34OverrideComponent(MyComponent, {35});36import { Component } from '@angular/core';Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2import { MockComponent } from 'ng-mocks';3import { MockRender } from 'ng-mocks';4import { TestingModule } from './testing.module';5import { TestComponent } from './test.component';6describe('TestComponent', () => {7  it('should render component', () => {8    const MockedComponent = OverrideComponent(TestComponent, {9    });10    MockRender(MockedComponent, {11      imports: [TestingModule],12    });13    expect(document.body.textContent).toContain('MockedComponent');14  });15});16import { Component } from '@angular/core';17@Component({18})19export class TestComponent {}20import { NgModule } from '@angular/core';21import { CommonModule } from '@angular/common';22import { TestComponent } from './test.component';23@NgModule({24  imports: [CommonModule],25})26export class TestingModule {}27import { TestBed } from '@angular/core/testing';28import { TestComponent } from './test.component';29describe('TestComponent', () => {30  let component: TestComponent;31  beforeEach(async () => {32    await TestBed.configureTestingModule({33    }).compileComponents();34  });35  beforeEach(() => {36    const fixture = TestBed.createComponent(TestComponent);37    component = fixture.componentInstance;38    fixture.detectChanges();39  });40  it('should create', () => {41    expect(component).toBeTruthy();42  });43});44import { MockComponent } from 'ng-mocks';45import { MockRender } from 'ng-mocks';46import { TestingModule } from './testing.module';47import { TestComponent } from './test.component';48describe('TestComponent', () => {49  it('should render component', () => {50    const MockedComponent = MockComponent(TestComponent);51    MockRender(MockedComponent, {52      imports: [TestingModule],53    });54    expect(document.body.textContent).toContain('MockedComponent');55  });56});Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2import { Component } from '@angular/core';3import { MyComponent } from './my.component';4describe('Test', () => {5  it('should override component', () => {6    const component = OverrideComponent(MyComponent, `<div>Test</div>`);7    const fixture = TestBed.createComponent(component);8    const instance = fixture.componentInstance;9    instance.ngOnInit();10    fixture.detectChanges();11    const element = fixture.nativeElement;12    const innerHTML = element.innerHTML;13    expect(innerHTML).toBe('Test');14  });15});16import { OverrideComponent } from 'ng-mocks';17import { Component } from '@angular/core';18import { MyComponent } from './my.component';19describe('Test', () => {20  it('should override component', () => {21    const component = OverrideComponent(MyComponent);22    const fixture = TestBed.createComponent(component);23    const instance = fixture.componentInstance;24    instance.ngOnInit();25    fixture.detectChanges();26    const element = fixture.nativeElement;27    const innerHTML = element.innerHTML;28    expect(innerHTML).toBe('Test');29  });30});31import { OverrideComponent } from 'ng-mocks';32import { Component } from '@angular/core';33import { MyComponent } from './my.component';34describe('Test', () => {35  it('should override component', ()Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2const MockComponent = OverrideComponent(OriginalComponent, {3});4describe('MockComponent', () => {5  it('should render mock template', () => {6    const fixture = TestBed.configureTestingModule({7    }).createComponent(MockComponent);8    fixture.detectChanges();9    expect(fixture.debugElement.nativeElement.innerHTML).toEqual('mock template');10  });11});12import { OverrideComponent } from 'ng-mocks';13const MockComponent = OverrideComponent(OriginalComponent, {14});15describe('MockComponent', () => {16  it('should render mock template', () => {17    const fixture = TestBed.configureTestingModule({18    }).createComponent(MockComponent);19    fixture.detectChanges();20    expect(fixture.debugElement.nativeElement.innerHTML).toEqual('mock template');21  });22});23import { OverrideComponent } from 'ng-mocks';24const MockComponent = OverrideComponent(OriginalComponent, {25});26describe('MockComponent', () => {27  it('should render mock template', () => {28    const fixture = TestBed.configureTestingModule({29    }).createComponent(MockComponent);30    fixture.detectChanges();31    expect(fixture.debugElement.nativeElement.innerHTML).toEqual('mock template');32  });33});34import { OverrideComponent } from 'ng-mocks';35const MockComponent = OverrideComponent(OriginalComponent, {36});37describe('MockComponent', () => {38  it('should render mock template', () => {39    const fixture = TestBed.configureTestingModule({40    }).createComponent(MockComponent);41    fixture.detectChanges();42    expect(fixture.debugElement.nativeElement.innerHTML).toEqual('mock template');43  });44});45import { OverrideComponent } from 'ng-mocks';46const MockComponent = OverrideComponent(OriginalComponent, {47});48describe('Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2import { MyComponent } from './my.component';3const MyMockComponent = OverrideComponent(MyComponent, {4});5describe('MyComponent', () => {6  it('should override the template', () => {7    const fixture = TestBed.configureTestingModule({8    }).createComponent(MyMockComponent);9    fixture.detectChanges();10    expect(fixture.nativeElement.innerHTML).toContain('mocked');11  });12});13Angular provides a helper function called MockComponent that can be used to mock a component. MockComponent can be imported from @angular/core/testing . The MockComponent function takes two parameters:14import { MockComponent } from '@angular/core/testing';15import { MyComponent } from './my.component';16const MyMockComponent = MockComponent(MyComponent, {17});18describe('MyComponent', () => {19  it('should override the template', () => {20    const fixture = TestBed.configureTestingModule({21    }).createComponent(MyMockComponent);22    fixture.detectChanges();23    expect(fixture.nativeElement.innerHTML).toContain('mocked');24  });25});Using AI Code Generation
1import { OverrideComponent } from 'ng-mocks';2import { MyComponent } from './my.component';3import { MyComponentMock } from './my.component.mock';4const component = OverrideComponent(MyComponent, MyComponentMock);5import { Component } from '@angular/core';6@Component({7})8export class MyComponentMock {}9import { Component } from '@angular/core';10@Component({11})12export class MyComponent {}13import { TestBed } from '@angular/core/testing';14import { MyComponent } from './my.component';15import { MyComponentMock } from './my.component.mock';16describe('MyComponent', () => {17  beforeEach(async () => {18    await TestBed.configureTestingModule({19    }).compileComponents();20  });21  it('should create the component', () => {22    const fixture = TestBed.createComponent(MyComponent);23    const component = fixture.componentInstance;24    expect(component).toBeTruthy();25  });26});27import { TestBed } from '@angular/core/testing';28import { MyComponent } from './my.component';29import { MyComponentMock } from './my.component.mock';30describe('MyComponent', () => {31  beforeEach(async () => {32    await TestBed.configureTestingModule({33    }).compileComponents();34  });35  it('should create the component', () => {36    const fixture = TestBed.createComponent(MyComponent);37    const component = fixture.componentInstance;38    expect(component).toBeTruthy();39  });40});41import { TestBed } from '@angular/core/testing';42import { MyComponent } from './my.component';43import { MyComponentMock } from './my.component.mock';44describe('MyComponent', () => {45  beforeEach(async () => {46    await TestBed.configureTestingModule({47    }).compileComponents();48  });49  it('should create the component', () => {50    const fixture = TestBed.createComponent(MyComponent);51    const component = fixture.componentInstance;Using AI Code Generation
1import { TestBed } from '@angular/core/testing';2import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';3import { TestComponent } from './test.component';4import { Test2Component } from './test2.component';5describe('TestComponent', () => {6  beforeEach(() => MockBuilder(TestComponent, Test2Component));7  it('should create', () => {8    const fixture = MockRender(TestComponent);9    expect(fixture.point.componentInstance).toBeDefined();10  });11  it('should override component', () => {12    const fixture = MockRender(TestComponent);13    OverrideComponent(Test2Component, TestComponent);14    expect(fixture.point.componentInstance).toBeDefined();15  });16});17import { Component } from '@angular/core';18@Component({19})20export class Test2Component { }21import { Component } from '@angular/core';22@Component({23})24export class TestComponent { }25import './test';26import './test2';27import './test';28import './test2';29import { TestBed } from '@angular/core/testing';30import { MockBuilder, MockRender, OverrideComponent } from 'ng-mocks';31import { TestComponent } from './test.component';32import { Test2Component } from './test2.component';33describe('TestComponent', () => {34  beforeEach(() => MockBuilder(TestComponent, Test2Component));35  it('should create', () => {36    const fixture = MockRender(TestComponent);37    expect(fixture.point.componentInstance).toBeDefined();38  });39  it('should override component', () => {Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
