首页 > 解决方案 > Angular Jest Spectator - 焦点功能不起作用

问题描述

所以,我有看起来像这样的 Angular 组件

<div class="hello" (keydown.enter)="doSomething()"></div>

我正在尝试为案例编写测试 - 当用户专注于 div 时,按 enter 应该调用 doSomething()。不幸的是,我不能用 Spectator 来模拟这种情况。我已经尝试过:

spectator.focus(spectator.query('.hello'));
expect(spectator.query('.hello')).toBeFocused(); // test failed
spectator.keyboard.pressEnter();

spectator.query('.hello').dispatchEvent(new Event('focus'));

并且都与

spectator.detectChanges(); // without success

我想,这个问题出在我的 HTML 模板中,但这些功能也不适用于:

<div class="hello" tabindex="0">

甚至与

<input class="hello" type="text">

请给予一些支持,如何专注于 div 元素,然后按 Enter 键。

标签: angularjestjsspectator

解决方案


首先,您需要了解spectator.focus()方法的作用。

我们来看看Spectator 源码中的这个方法:

public focus(selector: SpectatorElement = this.element): void {
    const element = this.getNativeElement(selector);

    if (!(element instanceof HTMLElement)) {
        throw new Error(`Cannot focus: ${selector} is not a HTMLElement`);
    }

    patchElementFocus(element);
    element.focus();
    this.detectChanges();
}

我们可以注意到,在触发原生element.focus()方法之前,它还调用了这个方法patchElementFocus(element);代码

export function patchElementFocus(element: HTMLElement): void {
  element.focus = () => dispatchFakeEvent(element, 'focus');
  element.blur = () => dispatchFakeEvent(element, 'blur');
}

where在引擎盖下dispatchFakeEvent调用本机方法。node.dispatchEvent(event);

所以,spectator.focus(element)触发器node.dispatchEvent(...)

现在,您需要了解可信事件和不可信事件之间的区别。

使用 node.dispatchEvent 触发的事件称为不可信事件,它们不会触发默认浏览器操作w3.org 参考

这意味着手动触发事件不会生成与该事件关联的默认操作。例如,手动触发焦点事件不会导致元素接收焦点,手动触发提交事件不会提交表单。

您只能通过事件处理程序收听手动创建的事件。这就是旁观者向我们展示的。(测试https://github.com/ngneat/spectator/blob/fcdb6a809571706fac3d7b5d8da5bf2f7ba0e305/projects/spectator/test/events/events.component.spec.ts#L13)(监听器https://github.com/ngneat/spectator/ blob/fcdb6a809571706fac3d7b5d8da5bf2f7ba0e305/projects/spectator/test/events/events.component.html#L2

最后,这里的解决方案是使用原生element.focus()方法能够将焦点设置在您的 div 上。另外,tabindex attribute这里需要。

spectator.query<HTMLDivElement>('.hello').focus();
expect(spectator.query('.hello')).toBeFocused();

Stackblitz 示例


推荐阅读