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

如何在Jest中mock document.activeElement以测试DOM焦点切换逻辑?

如何测试依赖document.activeElement的DOM函数分支

嘿,这个问题我之前踩过坑!document.activeElement是个只读属性(只有getter没有setter),所以你直接赋值global.document.activeElement = ...才会抛那个错误。要验证this.lastTabStop.focus()是否被调用,得通过重定义它的getter来模拟值,下面是具体的实现方案(以Jest为例,其他测试框架思路一致):

1. 先模拟需要的DOM元素

首先得创建模拟的firstTabStop和lastTabStop,重点是给lastTabStop加一个可跟踪的focus方法,方便后面断言:

// 模拟第一个tab元素
const mockFirstTabStop = {};
// 模拟最后一个tab元素,用jest.fn()创建可监控的focus方法
const mockLastTabStop = {
  focus: jest.fn()
};

2. 重定义document.activeElement的getter

用Object.defineProperty来覆盖原生的activeElement getter,让它返回我们的模拟元素:

Object.defineProperty(document, 'activeElement', {
  // 每次获取activeElement时返回mockFirstTabStop
  get: () => mockFirstTabStop,
  // 设为可配置,这样测试结束后能恢复,避免污染其他测试
  configurable: true
});

3. 绑定上下文并调用init方法

因为trap.init里的this指向trap对象本身,所以要确保trap的firstTabStop和lastTabStop指向我们的模拟对象,然后调用init:

// 导入你的trap模块
const trapInit = require('./path-to-your-trap-module');
// 构建trap实例,关联模拟元素
const trap = {
  firstTabStop: mockFirstTabStop,
  lastTabStop: mockLastTabStop,
  init: trapInit
};

// 调用要测试的init方法
trap.init();

4. 断言focus方法被正确调用

最后验证lastTabStop.focus是否被调用了一次:

expect(mockLastTabStop.focus).toHaveBeenCalledTimes(1);

额外提示:测试后清理

为了不影响其他测试用例,记得在测试结束后恢复document.activeElement的原始状态:

afterEach(() => {
  // 恢复activeElement到默认值(一般是document.body)
  Object.defineProperty(document, 'activeElement', {
    get: () => document.body,
    configurable: true
  });
  // 清空模拟函数的调用记录
  jest.clearAllMocks();
});

如果用的是Mocha+Sinon这类测试框架,逻辑也是一样的:用Object.defineProperty重定义getter,用Sinon的spy来跟踪focus方法的调用就行。


内容的提问来源于stack exchange,提问作者sandrina-p

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:25:14