diff --git a/lib/mock-directive/mock-directive.spec.ts b/lib/mock-directive/mock-directive.spec.ts index 2968855247..c971afda98 100644 --- a/lib/mock-directive/mock-directive.spec.ts +++ b/lib/mock-directive/mock-directive.spec.ts @@ -1,4 +1,4 @@ -import { Component, Directive, EventEmitter, Input, Output } from '@angular/core'; +import { Component, Directive, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl, FormControlDirective } from '@angular/forms'; import { By } from '@angular/platform-browser'; @@ -13,6 +13,10 @@ export class ExampleDirective { @Input() exampleDirective: string; @Output() someOutput = new EventEmitter(); @Input('bah') something: string; + + performAction(s: string) { + return this; + } } @Directive({ @@ -34,12 +38,18 @@ export class ExampleStructuralDirective { ` }) export class ExampleComponentContainer { + @ViewChild(ExampleDirective) childDirective: ExampleDirective; emitted = false; foo = new FormControl(''); + + performActionOnChild(s: string): void { + this.childDirective.performAction(s); + } } // tslint:enable:max-classes-per-file describe('MockDirective', () => { + let component: ExampleComponentContainer; let fixture: ComponentFixture; beforeEach(async(() => { @@ -56,6 +66,7 @@ describe('MockDirective', () => { beforeEach(() => { fixture = TestBed.createComponent(ExampleComponentContainer); + component = fixture.componentInstance; fixture.detectChanges(); }); @@ -76,7 +87,7 @@ describe('MockDirective', () => { const element = debugElement.injector.get(MockDirective(ExampleDirective)); // tslint:disable-line element.someOutput.emit(true); - expect(fixture.componentInstance.emitted).toEqual(true); + expect(component.emitted).toEqual(true); }); it('should memoize the return value by argument', () => { @@ -97,4 +108,15 @@ describe('MockDirective', () => { const debugElement = fixture.debugElement.query(By.css('#example-structural-directive')); expect(debugElement.nativeElement.innerHTML).toContain('hi'); }); + + it('should set ViewChild directives correctly', () => { + fixture.detectChanges(); + expect(component.childDirective).toBeTruthy(); + }); + + it('should allow spying of viewchild directive methods', () => { + const spy = spyOn(component.childDirective, 'performAction'); + component.performActionOnChild('test'); + expect(spy).toHaveBeenCalledWith('test'); + }); }); diff --git a/lib/mock-directive/mock-directive.ts b/lib/mock-directive/mock-directive.ts index 4e5e80c4f0..7df319e60c 100644 --- a/lib/mock-directive/mock-directive.ts +++ b/lib/mock-directive/mock-directive.ts @@ -1,4 +1,6 @@ -import { Directive, EventEmitter, Inject, Optional, TemplateRef, Type, ViewContainerRef } from '@angular/core'; +import { + Directive, EventEmitter, forwardRef, Inject, Optional, TemplateRef, Type, ViewContainerRef +} from '@angular/core'; import { MockOf } from '../common'; import { directiveResolver } from '../common/reflect'; @@ -15,12 +17,29 @@ export function MockDirective(directive: Type): Type DirectiveMock) + }], + selector + }) class DirectiveMock { constructor(@Optional() @Inject(TemplateRef) templateRef?: TemplateRef, @Optional() @Inject(ViewContainerRef) viewContainer?: ViewContainerRef) { + + Object.keys(directive.prototype).forEach((method) => { + if (!(this as any)[method]) { + (this as any)[method] = () => {}; + } + }); + (outputs || []).forEach((output) => { (this as any)[output.split(':')[0]] = new EventEmitter(); });