使用JSDOM时遭遇ReferenceError: document is not defined问题求助
解决JSDOM测试中
document is not defined的问题 问题根源
我一眼就看出问题所在了——你的模块加载时机和JSDOM初始化顺序完全搞反了!当你在测试文件里执行var updateMsg = require('../module.js')时,Node.js会立刻执行整个module.js的所有代码,包括你写在最末尾的updateMsg("Changing message")。但这时候你的before钩子还没运行,global.document还没被JSDOM初始化出来,自然就会抛出ReferenceError: document is not defined的错误。
两种解决方案(结合使用效果最佳)
方案1:让模块仅在浏览器环境下自动执行初始化代码
修改你的module.js,给自动执行的代码加一个环境判断,只有在浏览器(存在window对象)的场景下才运行初始化逻辑:
function updateMsg(newMsg) { document.getElementById('msg').innerHTML = newMsg; } // 仅在浏览器环境执行初始化(Node环境中window为undefined) if (typeof window !== 'undefined') { updateMsg("Changing message"); } module.exports = updateMsg;
方案2:调整测试文件的加载顺序,先初始化JSDOM再加载模块
把require('../module.js')移到before钩子内部,确保JSDOM已经把document挂载到全局后,再加载你的业务模块:
const expect = require('chai').expect const { JSDOM } = require('jsdom'); describe('updateMsg', function () { let updateMsg; // 先声明变量占位 before(function() { return JSDOM.fromFile('index.html') .then((dom) => { global.window = dom.window; global.document = window.document; // 现在document已经就绪,再加载模块 updateMsg = require('../module.js'); }); }) it ('updates the innerHTML of element with id "msg"', function () { expect(document.getElementById('msg').innerHTML).to.equal('Hello, World!'); updateMsg('The new msg!'); expect(document.getElementById('msg').innerHTML).to.equal('The new msg!'); }); });
额外优化建议
如果你想让代码耦合度更低、测试更灵活,可以把document作为参数传递给updateMsg函数,彻底摆脱对全局document的依赖:
// 修改module.js function updateMsg(newMsg, doc = document) { doc.getElementById('msg').innerHTML = newMsg; } // 测试时调用方式 updateMsg('The new msg!', document);
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

