JavaScript 的聚焦测试

StephanieMT 9年前

来自: http://www.oschina.net/translate/testing-focus-in-javascript

这篇博文是关于在浏览器中测试焦点行为的一个概述。

在 Azure Portal 工作中,我花了相当多的时间来确保丰富的键盘支持。这就需要对焦点进行适当的管理。当用户按下一些快捷键时,焦点应该移动到相应的元素上。焦点行为还应当非常便于测试,因为它很容易在 HTML 或 JavaScript 进行了细微变化时 被改变(打断)。

标准测试流程如下:

  • 准备:打开一些页面

  • 进行:执行一些应该能打开一个指定页面并(或)在相应元素上设置焦点的快捷键

  • 断言:检测预期的元素是否获得焦点

如何检查元素是否获得焦点

最简单的方式是使用 jQuery:

expect($(element).is(':focus')).equals(true);

然而,这可能不是在任何时候都好使,特别是当你并行运行你的单元测试的话,因为 当窗口没有获得焦点时 $element.is(‘:focus’)   将无法正常工作

更好(正确)的方式是使用  document.activeElement

expect(document.activeElement).equals(element);

就算浏览器窗口没有获得焦点时其也能正常工作。

测试异步操作

有时,键盘调用异步操作最终会改变焦点。这可能会导致:

  • 漏报(false negative):断言在焦点被设置之前执行

  • 误报(false positives):最终聚焦的元素,是在断言执行之后才获得焦点的

对于第一个问题最简单的方案就是延迟进行断言:

setTimeout(() => {      expect(document.activeElement).equals(element);      done();  }, 100);

这种方法的难点在于选择合适的延迟时间。因此,最好避免使用原生的 setTimeout, 而是使用我在  setTimeout 被认为是有害的 一文中写的这种轮询方法:

poll(      () => document.activeElement === element,       () => {         assert(true);         start();    },      () => {         assert(false);         start();    }      );

轮询函数也可以用来解决第二个问题(通过改变回调函数中的断言顺序)。然而,对于误报的问题,简单的 setTimeout 已经足够了,因为相比于等待某些特定的时间执行断言我们没有其他选择。

调用键盘操作

有下列 3 种可以让我们用来模拟键盘操作的事件:

  • keydown

  • keyup

  • keypress

最安全的方式是使用 keydown。为啥呢? 一个示例中可能使用了特殊的功能键。而在使用  keypress 的情况下 —— 各个浏览器对其进行的处理是不同的(例如,不触发事件),而  keydown 的行为则是相当一致的。如果你对细节感兴趣的话,我建议你看看 这篇文章

为了检测 键盘操作, 你可以在 捕获和冒泡阶段 处理事件。你应该选择符合你需求的模型,但通常冒泡阶段是最佳的解决方案。此外,它是被 jQuery 支持的,可以为你兼容浏览器。

为了在测试中调用 keydown 事件,你首先需要在元素上设置焦点:

$(element)    .focus()    .trigger("keydown", { which: keyCode });

你可以在 这里 找到 JavaScript 键码。

总结

  • 使用 document.activeElement 检查哪个元素获得了焦点。

  • 使用轮询的方法来测试异步操作。

  • 使用 keydown 事件,以及冒泡阶段调用(处理)键盘操作。

</div>