Angular - 单元测试键盘按键事件

4
我有一个函数,它检测按键,并且如果按下的键等于 escape,则会触发一个函数。

我遇到了模拟传递按键事件的问题。

我看到了这个帖子:(链接) ,但是实现此解决方法会输出以下内容(我在控制台记录了事件本身):

LOG: KeyboardEvent{isTrusted: false} Chrome 68.0.3440 (Mac OS X 10.13.6) ConfirmationComponent should call onDeny when ESCAPE button pressed FAILED Expected spy onDeny to have been called.

component.ts

@HostListener('window:keyup', ['$event'])
  keyEvent(event: KeyboardEvent) {
    console.log(event);
    // Press escape - close dialog with simulated 'cancel' click
    if (event.code === 'Escape') {
      this.onDeny();
    }
  }

  onDeny() {
     // something is done here
  }

test.ts

it('should autofocus on cancel button on init', () => {
    spyOn(component, 'onDeny');
    component.keyEvent(ESCAPE);
    expect(component.onDeny).toHaveBeenCalled();
  });
2个回答

6

不必实现键盘事件:它在每个浏览器上都会有所变化,并且通常甚至无法正常工作。

相反,测试你的函数本身(将Angular的测试行为留给Angular自己):

it('should log event and call self.onDeny() when keyEvent', () => {
  const spy1 = spyOn(component, 'onDeny');
  const spy2 = spyOn(console, 'log');
  const eventMock = {code: 'Escape'};
  component.keyEvent(eventMock);
  expect(spy1).toHaveBeenCalledWith();
  expect(spy2).toHaveBeenCalledWith(eventMock);
});

啊,最后我意识到了我的问题。在我的模拟键盘事件中,我传递的是 keycode 而不是 code。但是,是的,按照你的建议,将其更加通用化会更好。 - physicsboy
@physicsboy 更重要的是,它忽略了Angular对键盘事件的实现。例如,如果Angular将KeyboardEvent转换为ngKeyEvent,您尝试模拟键盘事件,它永远不会起作用。这就是为什么单元测试测试单个单元并模拟依赖项:它们必须抽象化它们的行为! - user4676340
啊,我明白了。我没有意识到KeyboardEvent是一个特定的Angular特性。现在更有意义了。 - physicsboy
@physicsboy,这不是原生JS,但Angular可以将其抽象化以简化它。例如,Angular可以将const evt = new KeybaordEvent('keydown', {code: 'Escape'})抽象为const evt = ngEvent.keyboard.create('Escape')。由于您实际上不知道它的作用,最好的方法是测试您所控制的内容,也就是您自己的代码。 - user4676340

0
尝试以下操作 -
import { Component, OnInit, Input, EventEmitter, Output, HostListener, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-nav-header',
  templateUrl: './nav-header.component.html',
  styleUrls: ['./nav-header.component.scss']
})
export class NavHeaderComponent implements OnInit {
  @ViewChild('ham')
  hamburgerRef: ElementRef;

  @Output()
  toggleMenu: EventEmitter<void>;

  constructor() {
    this.toggleMenu = new EventEmitter<void>();
  }

  ngOnInit() {}

  emitToggle() {
    this.toggleMenu.emit();
  }

  @HostListener('keydown', ['$event'])
  public handleKeyboardEvent(event: any): void {
    event.stopPropagation();
    switch (event.key) {
      case 'Enter': {
        if (this.hamburgerRef.nativeElement.contains(event.target)) {
          this.emitToggle();
        }
        break;
      }
      case 'Tab': {
        break;
      }
    }
  }
}


 it('it should user emit toogle', () => {
   spyOn(component.toggleMenu, 'emit');
   spyOn(component.hamburgerRef.nativeElement, 'contains').and.returnValue(true);
   component.handleKeyboardEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
   expect(component.toggleMenu.emit).toHaveBeenCalled();
 });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接