如何测试依赖document全局对象的函数?单元测试入门咨询
如何测试依赖document全局对象的函数?
嘿,你要测试的是那个适配浏览器前缀的过渡/动画结束事件函数对吧?这类依赖document全局对象的函数其实没那么难搞,我给你分享几个实用的方案,结合你的场景具体来说:
1. 用测试框架自带的浏览器环境模拟(以Jest为例)
像Jest这类现代测试框架自带了jsdom,能帮你模拟出浏览器里的document对象。你只需要在测试前手动修改document.body.style,就能模拟不同浏览器的属性支持情况,覆盖所有分支。
测试代码示例:
const animEndString = require('./你的函数文件路径.js'); describe('animEndString 函数测试', () => { // 每个测试前重置style属性,避免测试间互相影响 beforeEach(() => { // 清空过渡相关属性 delete document.body.style.OTransition; delete document.body.style.WebkitTransition; delete document.body.style.MozTransition; delete document.body.style.transition; // 清空动画相关属性 delete document.body.style.OAnimation; delete document.body.style.WebkitAnimation; delete document.body.style.MozAnimation; delete document.body.style.animation; }); test('标准浏览器下返回transitionend', () => { // 模拟支持标准transition属性 document.body.style.transition = ''; expect(animEndString('transition')).toBe('transitionend'); }); test('WebKit内核浏览器返回webkitTransitionEnd', () => { document.body.style.WebkitTransition = ''; expect(animEndString('transition')).toBe('webkitTransitionEnd'); }); test('旧版Opera浏览器返回oTransitionEnd', () => { document.body.style.OTransition = ''; expect(animEndString('transition')).toBe('oTransitionEnd'); }); // 动画类型的测试同理 test('WebKit内核下动画返回webkitAnimationEnd', () => { document.body.style.WebkitAnimation = ''; expect(animEndString('animation')).toBe('webkitAnimationEnd'); }); });
2. 抽离依赖,让函数更“好测”
另一种思路是把依赖document的部分抽成可选参数,让函数逻辑和浏览器环境解耦。这样测试的时候完全不需要碰真实或模拟的document,直接传个模拟对象就行。
修改后的函数代码:
const animEndString = (type = 'transition', styleEl = document.body.style) => { const types = type === 'transition' ? { OTransition: 'oTransitionEnd', WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', transition: 'transitionend' } : { OAnimation: 'oAnimationEnd', WebkitAnimation: 'webkitAnimationEnd', MozAnimation: 'animationend', animation: 'animationend' }; // 遍历找到第一个存在的属性对应的事件名 for (const prop in types) { if (prop in styleEl) { return types[prop]; } } // 兜底返回标准事件名 return type === 'transition' ? 'transitionend' : 'animationend'; };
对应的测试代码:
const animEndString = require('./你的函数文件路径.js'); describe('animEndString 函数测试', () => { test('标准过渡支持返回transitionend', () => { const mockStyle = { transition: '' }; expect(animEndString('transition', mockStyle)).toBe('transitionend'); }); test('WebKit过渡支持返回webkitTransitionEnd', () => { const mockStyle = { WebkitTransition: '' }; expect(animEndString('transition', mockStyle)).toBe('webkitTransitionEnd'); }); test('标准动画支持返回animationend', () => { const mockStyle = { animation: '' }; expect(animEndString('animation', mockStyle)).toBe('animationend'); }); });
这种方式不仅让测试更简单,还让函数的复用性更强——比如以后想在非浏览器环境(比如Node.js里做一些样式检测)用它,直接传个自定义对象就行。
3. 手动引入jsdom模拟环境(适合Mocha等框架)
如果你的项目用的是Mocha这类没有内置jsdom的测试框架,那就手动装个jsdom来模拟浏览器环境:
先安装依赖:
npm install jsdom --save-dev
然后在测试文件顶部配置:
const { JSDOM } = require('jsdom'); const dom = new JSDOM('<!DOCTYPE html><body></body>'); // 把模拟的document和window挂到全局 global.document = dom.window.document; global.window = dom.window; const animEndString = require('./你的函数文件路径.js'); // 后续测试逻辑就和第一种方案一样啦
总结一下:如果想快速搞定,用Jest自带的环境模拟最省心;如果想让代码更健壮灵活,抽离依赖是最优解;要是用的是旧框架,手动引jsdom也能解决问题。
内容的提问来源于stack exchange,提问作者magicspon
相关产品推荐
相关产品推荐

