Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing angular 5 component with @ViewChild

Tags:

I am using angular 5.2.0. I have a child component

import { Component } from '@angular/core';  @Component({   template: `<div><div></div></div>`, }) export class ChildComponent {    public childMethod() {     ...   } } 

and a parent component which accesses the child via ViewChild

import { Component, ViewChild } from "@angular/core"; import { ChildComponent } from "child.component";  @Component({   template: `   <child-component #child>     <child-component></child-component>   </child-component>   `, }) export class ParentComponent {   @ViewChild("child") child: ChildComponent;    public parentMethod() {     this.child.childMethod();   } } 

I want a unit test proving that an invocation of parentMethod causes an invocation of childMethod. I have the following:

 import { NO_ERRORS_SCHEMA } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ChildComponent } from "./child.component"; import { ParentComponent } from "./parent.component";  describe("ParentComponent", () => {   let component: Parentcomponent;   let fixture: ComponentFixture<Parentcomponent>;    beforeEach(() => {     TestBed.configureTestingModule({       declarations: [ParentComponent, ChildComponent],       schemas: [NO_ERRORS_SCHEMA],     }).compileComponents();   });    beforeEach(() => {     fixture = TestBed.createComponent(TaskListPaginatorComponent);     component = fixture.componentInstance;     fixture.detectChanges();   });    it("should invoke childMethod when parentMethod is invoked", () => {     const childMethodSpy: jasmine.Spy = spyOn(component.child, "childMethod");     component.parentMethod();     expect(childMethodSpy).toHaveBeenCalled();   }); }); 

Yet, this does not work, and I get Error: <spyOn> : could not find an object to spy upon for childMethod().

Moreover, this is not a unit test, because I use the real ChildComponent instead of a mock. I tried creating a MockChildComponent and adding it to declarations and export but I got the same result. Any help?

I know there are similar post, but they are for different versions of angular, and they did not help.

like image 411
Jacopo Lanzoni Avatar asked Jul 25 '18 09:07

Jacopo Lanzoni


People also ask

What does @ViewChild does in Angular?

The @ViewChild decorator allows us to inject into a component class references to elements used inside its template, that's what we should use it for. Using @ViewChild we can easily inject components, directives or plain DOM elements.

How do you test a child's component of an enzyme?

find('ChildComponent'); const child1 = element.at(0); const child2 = element.at(1); expect(element. length). toBe(2); expect(child1.name()). toBe('ChildComponent'); expect(child1.


1 Answers

You can do something like this.

Create a spy object for the ChildComponent like this.

const childComponent = jasmine.createSpyObj('ChildComponent', ['childMethod']); 

Then in the test, set the component's childComponent property to the spy that you have created.

component.childComponent =  childComponent; 

Your test file should look like this.

import { NO_ERRORS_SCHEMA } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ChildComponent } from "./child.component"; import { ParentComponent } from "./parent.component";  describe("ParentComponent", () => {   let component: ParentComponent;   let fixture: ComponentFixture<ParentComponent>;    const childComponent = jasmine.createSpyObj("ChildComponent", [     "childMethod",   ]);    beforeEach(() => {     TestBed.configureTestingModule({       declarations: [ParentComponent, ChildComponent],       schemas: [NO_ERRORS_SCHEMA],     }).compileComponents();   });    beforeEach(() => {     fixture = TestBed.createComponent(ParentComponent);     component = fixture.componentInstance;     fixture.detectChanges();   });    it("should invoke childMethod when parentMethod is invoked", () => {     component.childComponent = childComponent;     component.parentMethod();     expect(childComponent.childMethod).toHaveBeenCalled();   }); });   
like image 123
Anuradha Gunasekara Avatar answered Sep 21 '22 04:09

Anuradha Gunasekara