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.
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.
find('ChildComponent'); const child1 = element.at(0); const child2 = element.at(1); expect(element. length). toBe(2); expect(child1.name()). toBe('ChildComponent'); expect(child1.
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(); }); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With