无法在单元测试用例中调用 @HostListener 方法

Sha*_*ggy 2 unit-testing jasmine angular-directive angular

我创建了一个自定义指令@Directive,我正在使用@HostListener该指令并且代码工作正常。
现在,在编写测试用例时,我需要@HostListener从单元测试用例中调用该方法。我也可以看到在代码覆盖率中没有覆盖代码。
以下是代码:

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();
  }

}
Run Code Online (Sandbox Code Playgroud)

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();
  });

});
Run Code Online (Sandbox Code Playgroud)

您还可以在下面看到代码覆盖率报告:
在此处输入图片说明

在这里,我需要覆盖代码并执行此方法所需的正确测试用例。谢谢。

JB *_*zet 6

这是您的测试的固定版本:

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();
  });

});
Run Code Online (Sandbox Code Playgroud)

关键点:

  • 您需要将被监视的函数本身传递给 expect(),以检查它是否已被调用。您的代码调用spied 函数,并将它返回的内容传递给 epect()。
  • 您需要将一个实际事件(尤其是将其bubbles标志设置为 true 的事件,否则该事件不会冒泡,div因此封闭按钮上触发的事件不会通知封闭按钮上的侦听器)到本机DOM 元素。