You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jest单元测试中触发Tab事件聚焦到下一个div元素

问题核心原因

你当前的代码无法触发Tab键焦点移动,和事件写法无关,本质是Jest默认使用的jsdom环境不会自动执行键盘事件对应的浏览器原生默认行为:手动调用dispatchEvent派发的合成事件,只会触发绑定的事件监听器回调,不会自动执行焦点切换、表单提交这类内置交互逻辑。
你的现有代码还有两个细节问题:

  • 初始化KeyboardEvent时只传了keyCode: 9,没有传标准属性key: 'Tab',部分依赖event.key做判断的交互逻辑无法识别这个事件
  • 事件直接派发到document上不符合真实交互逻辑,实际用户按键盘时,事件会先派发到当前持有焦点的元素,再逐层冒泡
解决方案

方案1:使用@testing-library/user-event模拟(推荐,最贴近真实交互)

如果项目接入了Testing Library测试生态,直接用内置的tab模拟方法即可,它已经封装了完整的焦点移动逻辑,不需要手动合成事件:

import userEvent from '@testing-library/user-event';

describe("tests keyboard focus constrain", () => {
  it("tab press", async() => {
    const user = userEvent.setup();
    // 先将焦点定位到第一个可聚焦元素,模拟页面初始焦点状态
    const firstFocusable = document.querySelector(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    firstFocusable.focus();

    // 模拟Tab键按下,会自动按规则移动焦点到下一个可聚焦元素
    await user.tab();

    // 此处添加焦点位置的断言逻辑即可
  })
})

方案2:手动补全焦点移动逻辑(无额外依赖场景)

如果不想引入额外测试依赖,可以在测试用例中手动监听Tab事件,实现焦点移动逻辑,补全jsdom缺失的默认行为:

describe("tests keyboard focus constrain", () => {
  it("tab press", () => {
    // 获取页面所有可聚焦元素,过滤禁用状态元素
    const getFocusableList = () => Array.from(
      document.querySelectorAll(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      )
    ).filter(el => !el.hasAttribute('disabled'));

    // 手动实现Tab键焦点切换逻辑
    const tabKeyHandler = (e) => {
      if (e.key === 'Tab' || e.keyCode === 9) {
        e.preventDefault();
        const focusableList = getFocusableList();
        const currentIndex = focusableList.indexOf(document.activeElement);
        const nextIndex = e.shiftKey
          ? (currentIndex - 1 + focusableList.length) % focusableList.length
          : (currentIndex + 1) % focusableList.length;
        focusableList[nextIndex].focus();
      }
    };
    document.addEventListener('keydown', tabKeyHandler);

    // 构造符合标准的Tab键盘事件
    const tabEvent = new KeyboardEvent('keydown', {
      key: 'Tab',
      keyCode: 9,
      bubbles: true,
      cancelable: true // 必须配置,否则preventDefault调用无效
    });

    // 聚焦第一个元素后派发事件
    const focusableList = getFocusableList();
    focusableList[0].focus();
    focusableList[0].dispatchEvent(tabEvent);

    // 用例执行完成后移除事件监听器,避免污染其他测试用例
    document.removeEventListener('keydown', tabKeyHandler);

    // 此处添加焦点位置的断言逻辑即可
  })
})
注意事项
  • 所有jsdom环境下的原生交互默认行为(包括链接跳转、表单提交、焦点移动等)都不会随事件派发自动执行,要么使用专门的用户交互模拟库,要么手动补全对应逻辑
  • 合成键盘事件时必须配置cancelable: true,否则事件回调中调用e.preventDefault()会直接失效
  • 事件需要派发到当前持有焦点的元素上,不要直接派发到全局document,否则依赖事件冒泡顺序的组件逻辑可能无法正常触发

内容的提问来源于stack exchange,提问作者tg marcus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 12:03:21