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!!