使用Jest编写JS单元测试时无法inject/mock document该如何解决?
问题解决方法
1. 修复document is not defined报错
该报错是因为Jest默认运行在Node.js环境,没有浏览器端的document、window等全局对象,同时你的业务代码还依赖全局变量Granite.$,未提前模拟就导入文件会触发报错,解决步骤如下:
- 安装jsdom环境依赖:
npm install jest-environment-jsdom --save-dev
- 在项目根目录的
jest.config.js中添加配置,指定测试环境为jsdom:
module.exports = { testEnvironment: "jsdom", // 其余原有配置保持不变 }
- 在测试文件顶部先模拟全局对象,再导入业务JS文件,避免导入时找不到依赖:
const $ = require('jquery'); // 提前模拟全局Granite对象 global.Granite = { $ }; // 模拟完成后再导入业务代码 require('./你的业务JS文件路径.js');
2. 修复测试用例逻辑错误
你编写的测试存在多处逻辑问题:
showHide是业务JS内部定义的函数,没有对外暴露,测试中无法直接访问toBeCalled是Jest spy对象的方法,用来验证被监听的函数是否被调用,不能直接用在普通函数上- 构造的测试DOM没有匹配业务逻辑的
data-dialog-checkbox-showhide属性元素,无法触发对应逻辑
建议优先测试业务行为而非内部函数调用,无需刻意验证showHide是否被调用,直接验证DOM操作结果即可,测试用例示例如下:
const $ = require('jquery'); global.Granite = { $ }; require('./你的业务JS文件路径.js'); describe("checkboxshowhide 功能测试", () => { // 每个测试用例执行前重置DOM beforeEach(() => { document.body.innerHTML = ` <input type="checkbox" data-dialog-checkbox-showhide data-dialog-checkbox-showhide-target=".test-target" /> <div class="test-target-parent"> <input class="test-target" type="text" /> </div> `; }) test("foundation-contentloaded事件触发时会自动初始化复选框状态", () => { // 触发初始化事件 $(document).trigger('foundation-contentloaded'); const target = $('.test-target'); // 默认未勾选状态下,目标元素父容器可见,aria-required为true expect(target.attr('aria-required')).toBe('true'); expect(target.parent().is(':visible')).toBe(true); }) test("复选框勾选时会隐藏目标元素、清空值、关闭必填校验", () => { const checkbox = $('[data-dialog-checkbox-showhide]'); const target = $('.test-target'); target.val('预设测试内容'); // 勾选复选框触发change事件 checkbox.prop('checked', true).trigger('change'); expect(target.val()).toBe(''); expect(target.attr('aria-required')).toBe('false'); expect(target.parent().is(':visible')).toBe(false); }) test("复选框取消勾选时会显示目标元素、开启必填校验", () => { const checkbox = $('[data-dialog-checkbox-showhide]'); const target = $('.test-target'); // 先勾选再取消 checkbox.prop('checked', true).trigger('change'); checkbox.prop('checked', false).trigger('change'); expect(target.attr('aria-required')).toBe('true'); expect(target.parent().is(':visible')).toBe(true); }) });
3. 其他测试扩展指引
- 边界场景测试:可覆盖单个复选框绑定多个目标元素、复选框默认勾选初始化、动态添加复选框元素等场景
- 事件监听验证:如果需要验证事件绑定逻辑,可以通过
jest.spyOn监听$(document).on方法,验证对应事件的回调是否正确注册 - 若需要直接测试
showHide函数,可以在业务代码的IIFE末尾添加测试环境专属的暴露逻辑,不会影响生产环境运行:
// 业务代码IIFE最后添加 if (process.env.NODE_ENV === 'test') { window.checkboxShowHideUtil = { showHide }; } })(document, Granite.$);
测试中就可以通过window.checkboxShowHideUtil.showHide直接调用函数做单测。
内容的提问来源于stack exchange,提问作者Knu8
相关产品推荐
相关产品推荐

