I'm having trouble creating a unit test for an Angular Attribute Directive that I've written. The directive is called TrackClickDirective, and I'm trying to test the following.
I suspect it's a problem with my unit test configuration.
Please see my implementation on StackBlitz, where you can see the test running:
StackBltiz: https://stackblitz.com/edit/angular-test-click-on-attribute-directive-with-hostlistener
Here is my unit test code - track-click.directive.spec.ts:
import { Component, ElementRef, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from "@angular/platform-browser";
import { TrackClickDirective } from './track-click.directive';
import { Analytics} from './analytics.service';
class MockAnalytics {
eventTrack() {}
};
class MockElementRef {
}
@Component({
template: '<button appTrackClick>Test</button>'
})
export class TestButtonWithoutNameComponent { }
describe('TrackClickDirective', () => {
let component: TestButtonWithoutNameComponent;
let fixture: ComponentFixture<TestButtonWithoutNameComponent>;
let directive: TrackClickDirective;
let inputEl: DebugElement;
let spy: any;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestButtonWithoutNameComponent
],
providers: [
TrackClickDirective,
{ provide: Analytics, useClass: MockAnalytics },
{ provide: ElementRef, useClass: MockElementRef }
]
});
fixture = TestBed.createComponent(TestButtonWithoutNameComponent);
component = fixture.componentInstance;
directive = TestBed.get(TrackClickDirective);
inputEl = fixture.debugElement.query(By.css('button'));
});
it('should call the trackClick methoe when the button is clicked', () => {
spy = spyOn(directive, 'trackClick');
inputEl.triggerEventHandler('click', null);
fixture.detectChanges();
expect(directive.trackClick).toHaveBeenCalled();
});
});
What am I doing wrong here? When I run the unit test, I get the following:
FAILED TESTS:
TrackClickDirective
✖ should call the trackClick method when the button is clicked
HeadlessChrome 72.0.3626 (Mac OS X 10.14.0)
Expected spy trackClick to have been called.
Following the example on Angular's docs.
The following should do the trick:
import { Component, ElementRef, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from "@angular/platform-browser";
import { TrackClickDirective } from './track-click.directive';
import { Analytics} from './analytics.service';
class MockAnalytics {
eventTrack() {}
};
class MockElementRef {
}
@Component({
template: '<button appTrackClick>Test</button>'
})
export class TestButtonWithoutNameComponent { }
describe('TrackClickDirective', () => {
let component: TestButtonWithoutNameComponent;
let fixture: ComponentFixture<TestButtonWithoutNameComponent>;
let directive: TrackClickDirective;
let inputEl: DebugElement;
let spy: any;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestButtonWithoutNameComponent,
TrackClickDirective
],
providers: [
TrackClickDirective,
{ provide: Analytics, useClass: MockAnalytics },
{ provide: ElementRef, useClass: MockElementRef }
]
});
fixture = TestBed.createComponent(TestButtonWithoutNameComponent);
component = fixture.componentInstance;
directive = TestBed.get(TrackClickDirective);
inputEl = fixture.debugElement.query(By.css('button'));
});
it('should call the trackClick method when the button is clicked', () => {
directive = fixture.debugElement.query(By.directive(TrackClickDirective)).injector.get(TrackClickDirective) as TrackClickDirective;
spy = spyOn(directive, 'trackClick');
inputEl.triggerEventHandler('click', null);
fixture.detectChanges();
expect(directive.trackClick).toHaveBeenCalled();
});
});
The key is in this line:
fixture.debugElement.query(By.directive(TrackClickDirective)).injector.get(TrackClickDirective) as TrackClickDirective;
While very verbose, it allows you to get the actual instance of your directive that was created and is used in the component which in turns allows you to spy on its methods.
Updated StackBlitz example: https://stackblitz.com/edit/angular-test-click-on-attribute-directive-with-hostlistener