【问题标题】:Angular - Unit testing keypressAngular - 单元测试按键
【发布时间】:2018-08-30 11:02:17
【问题描述】:

我有一个检测按键的函数,如果按键 = 转义,则触发一个函数。

我在伪造要传入的 KeyboardEvent 本身时遇到问题。

我看到 this post,但实施此解决方案会产生以下输出(我 console.logged 事件本身):

日志:KeyboardEvent{isTrusted: false} Chrome 68.0.3440 (Mac OS X 10.13.6) ConfirmationComponent 应在按下 ESCAPE 按钮失败时调用 onDeny 预计 spy onDeny 已被调用。

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

【问题讨论】:

    标签: javascript angular testing karma-runner


    【解决方案1】:

    不必费心实现键盘事件:它在每个浏览器上都会发生变化,而且通常甚至不起作用。

    相反,测试您的函数本身(将 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 更重要的是,它忽略了 Angular 对键盘事件的实现。例如,如果 Angular 将 KeyboardEvent 转换为 ngKeyEvent,您可以尝试模拟您的键盘事件,但它永远不会起作用。这就是为什么单元测试要测试单个单元并模拟依赖项的原因:它们必须抽象它们的行为!
    • 啊,我明白了。我没有意识到 KeyboardEvent 是一个特定的 Angular 特征。现在更有意义了。
    • @physicsboy 不是,它是原生 JS,但 Angular 可以抽象它以简化它。例如,Angular 可以将其抽象为 const evt = ngEvent.keyboard.create('Escape'),而不是 const evt = new KeybaordEvent('keydown', {code: 'Escape'})。由于您并不真正知道它的作用,最好是简单地测试您可以控制的内容,即您自己的代码
    【解决方案2】:

    试试下面的 -

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 2020-08-08
      • 2017-04-04
      • 2019-03-24
      • 2016-12-29
      • 2021-02-12
      相关资源
      最近更新 更多