I'm trying to Unit test a method in my Angular application. I have written a test that passes and checks two elements - the global variable returns true and the method is called. I am not sure what else I could test here but the line is still not covered.
.ts file
clickout(event) {
this.isActive = this.eRef.nativeElement.contains(event.target); //not covered!
}
.html file
<div (document:click)="clickout($event)" id="clickout" class="actions__container">
click me
</div>
.spec file
it('should call func and return true', fakeAsync(() => {
component.isActive = true;
fixture.detectChanges();
spyOn(component, 'clickout');
let btn = fixture.debugElement.nativeElement.querySelector('#clickout');
btn.click();
tick();
fixture.detectChanges();
expect(component.clickout).toHaveBeenCalled();
expect(component.isActive).toBe(true);
}));
How can I firm up this test? I assume its because I am not looking to see if .nativeElement is containing something? Any help appreciated. I have created this stackBlitz example with jasmine installed.
Cool StackBlitz link, it can come handy.
The reason why it is not covered is because spyOn(component, 'clickout') gets rid of the implementation details of clickout. Once we spy on the method, we are saying stub this method (don't call it when it is called) but we get access to if it was called, with what arguments it was called, and how many times it was called.
To get the best of both worlds, you have to tack on a .and.callThrough() on the spyOn to not lose the implementation details.
it('should call func and return true', fakeAsync(() => {
component.isActive = true;
fixture.detectChanges();
// spy on the method and call its actual implementation when it is called
spyOn(component, 'clickout').and.callThrough();
let btn = fixture.debugElement.nativeElement.querySelector('#clickout');
btn.click();
tick();
fixture.detectChanges();
expect(component.clickout).toHaveBeenCalled();
expect(component.isActive).toBe(true);
}));
With the .and.callThrough(), the line that is not covered should now be covered. That being said, it might cause an error of nativeElement or contains of undefined.