Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to invoke @HostListener method in the Unit Test case

I have created a custom Directive using @Directive in which I am using @HostListener and the code works fine.
Now, when writing the test case I need to invoke the @HostListener method from the unit test case. Also I can see that in the code coverage the code is not covered.
Following is the code:

focus-encapsulation.directive.ts

import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[appFocusEncapsulation]'
})
export class FocusEncapsulationDirective {

  constructor(private el: ElementRef) { }

  @HostListener('keydown', ['$event'])
  keyDown(event: Event) {
    console.log('event : ', event);
    event.preventDefault();
  }

}

focus-encapsulation.directive.spec.ts

import { FocusEncapsulationDirective } from './focus-encapsulation.directive';
import { Component, ElementRef, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from "@angular/platform-browser";

@Component({
  template: `<div appFocusEncapsulation><button type="button" (click)="add()">ADD</button></div>`
})
class TestHoverFocusComponent {
  constructor(private el: ElementRef) { 
    console.log('in constructor')
  }
}

fdescribe('FocusEncapsulationDirective', () => {

  let component: TestHoverFocusComponent;
  let fixture: ComponentFixture<TestHoverFocusComponent>;
  let inputEl: DebugElement;
  let elementRef: ElementRef

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TestHoverFocusComponent, FocusEncapsulationDirective]
    });
    fixture = TestBed.createComponent(TestHoverFocusComponent);
    component = fixture.componentInstance;
    elementRef = fixture.nativeElement;
    inputEl = fixture.debugElement.query(By.css('button'));
  });

  it('should create an instance', () => {
    const directive = new FocusEncapsulationDirective(elementRef)
    expect(directive).toBeTruthy();
  });

  it('Focus over elements', () => {
    fixture.detectChanges();
    const event = {
      which : 9,
      keyCode : 9,
      srcElement :{
        innerText : 'ADD'
      },
      preventDefault: function() {
        console.log('preventDefault() method called');
      }
    }
    spyOn(event, 'preventDefault');
    inputEl.triggerEventHandler('keydown', event);
    expect(event.preventDefault()).toHaveBeenCalled();
  });

});

Below you can also see the code coverage report:
enter image description here

Here I need to cover the code and get the proper test case executed required for this method. Thanks.

like image 541
Shaggy Avatar asked Sep 19 '25 08:09

Shaggy


1 Answers

Here's a fixed version of your test:

fdescribe('FocusEncapsulationDirective', () => {

  let fixture: ComponentFixture<TestHoverFocusComponent>;
  let inputEl: HTMLElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TestHoverFocusComponent, FocusEncapsulationDirective]
    });
    fixture = TestBed.createComponent(TestHoverFocusComponent);
    inputEl = fixture.nativeElement.querySelector('button');
  });

  it('Focus over elements', () => {
    fixture.detectChanges();
    const event = new Event('keydown', { bubbles: true });
    spyOn(event, 'preventDefault');
    inputEl.dispatchEvent(event);
    expect(event.preventDefault).toHaveBeenCalled();
  });

});

Key points:

  • you need to pass the spied function itself, to expect(), to check that it has been called. Your code calls the spied function, and passes what it returns to epect().
  • You need to pass an actual event (and especially one that has its bubbles flag set to true, otherwise the event won't bubble, and the listener on the enclosing div will thus not be notified of the event triggered on the enclosed button) to the native DOM element .
like image 137
JB Nizet Avatar answered Sep 22 '25 03:09

JB Nizet