如何在Angular中测试keyup回车按钮?

如何在Angular中测试keyup回车按钮?,angular,unit-testing,Angular,Unit Testing,我正在开发一个可访问性非常重要的应用程序。作为其中的一部分,我们有许多不同的组件,我们希望确保可以通过鼠标事件和键盘事件访问这些组件。我们正试图围绕这些需求设置单元测试,以确保对这些组件所做的任何更改仍然符合这些标准。我们遇到了按钮问题。我有一个示例应用程序来演示: app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './

我正在开发一个可访问性非常重要的应用程序。作为其中的一部分,我们有许多不同的组件,我们希望确保可以通过鼠标事件和键盘事件访问这些组件。我们正试图围绕这些需求设置单元测试,以确保对这些组件所做的任何更改仍然符合这些标准。我们遇到了按钮问题。我有一个示例应用程序来演示:

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  console = console;

  actionTaken($event) {
    this.console.log($event);
  }
}
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  }));

  it('clicking on button should take action', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const component = fixture.componentInstance;
    spyOn(component, 'actionTaken');

    fixture.nativeElement
           .querySelector('button')
           .click();

    expect(component.actionTaken).toHaveBeenCalledTimes(1);
  });

  it('clicking on button should log to console', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const component = fixture.componentInstance;
    spyOn(component.console, 'log');

    fixture.nativeElement
           .querySelector('button')
           .click();

    expect(component.console.log).toHaveBeenCalledTimes(1);
  });

  it('pressing enter on button should take action', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const component = fixture.componentInstance;
    spyOn(component, 'actionTaken');

    fixture.nativeElement
           .querySelector('button')
           .dispatchEvent(new KeyboardEvent('keyup', { key: 'enter', bubbles: true }));

    expect(component.actionTaken).toHaveBeenCalledTimes(1);
  });

  it('pressing enter on button should log to console', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const component = fixture.componentInstance;
    spyOn(component.console, 'log');

    fixture.nativeElement
           .querySelector('button')
           .dispatchEvent(new KeyboardEvent('keyup', { key: 'enter', bubbles: true }));

    expect(component.console.log).toHaveBeenCalledTimes(1);
  });
});
app.component.html

<!-- <button
  (click)="actionTaken($event)"
  (keyup.enter)="actionTaken($event)">
    Take Action
</button> -->

<button
  (click)="actionTaken($event)">
    Take Action
</button>
使用按钮监听这两个事件,所有这些测试都通过了,但是当我在浏览器中运行代码时,我可以看到测试并不真实,因为enter键实际上触发了两次方法,而不是像测试所指示的那样触发了一次

尽管“回车”键测试失败,但使用按钮仅监听单击事件,尽管该功能似乎在浏览器中工作

这似乎只是按钮的问题。其他类型的HTML元素似乎不是这样工作的

编写组件、事件和测试的正确方法是什么?这样,只需单击鼠标并按enter键即可调用所需的方法一次,并且测试将正确设置以验证这一点?

具有元素
激活的概念。按
enter
键只是激活按钮的一种方式。用户也可以按
space
键或使用其他方法激活按钮(语音控制等)。通常,
激活
会在该元素上的
点击事件中达到高潮。问题是:所有浏览器是否都以相同的方式实现规范?是否在每个浏览器中都使用
enter
键激活按钮

如果要确保按钮对
enter
键做出反应,可以将两个处理程序都保留在按钮上,然后在
单击
处理程序中检查事件是
合成的还是
真实的

你们的测试对你们撒谎并说一切都是正确的问题可能有多个来源。首先,它取决于运行测试的浏览器。PhantomJS的行为可能与其他浏览器不同。第二个问题可能是您正在测试中创建合成的
keyup
事件,并且浏览器在激活过程中对合成事件的行为可能不同。我已经在Chrome上测试过了,事实上Chrome在合成事件时不会激活按钮


我只需使用
单击
处理程序,将激活过程留在浏览器上,并手动测试应用程序支持的不同浏览器的行为。在测试中,我只会发出
click
事件。

我认为按钮type=“submit”总是响应Enter键感谢您的评论。type=“submit”似乎是默认类型。我还尝试了type=“button”,根据,它应该没有默认行为,并且我仍然看到相同的功能。感谢您提供的信息。标准角度设置通过Chrome运行测试。如果我理解正确,按下
enter
键将是一个
synthetic
事件?另外,如果我选择忽略
合成的
点击事件,我会失去你所说的其他事件,比如
空间
?而且,这并不能回答这个问题。你的建议是手动测试,这是我希望避免的。今天它是一个
按钮
,也许明天设计团队会将其更改为
a
div
,此时我们需要知道如何再次手动测试它们。是的,当用户按下
enter
时,浏览器会创建合成点击事件。是的,当您处理
keyup
事件并仅处理
enter
key事件并忽略所有synthetic单击事件时,您将丢失导致按钮激活的所有synthetic事件。所以这看起来是个坏主意:)我的建议是只对点击处理程序进行单元测试,而不要费心测试所有可能的合成点击事件和浏览器的不同行为。但如果您真的想测试keyup,那么您必须找到一种方法来调度触发单击的键事件(如果可能的话)。也许一些能够复制本地用户键盘输入的e2e测试框架会有所帮助。