如何使用Jest测试Nuxt应用的自定义横向滚动功能
Nuxt 自定义横向滚动功能的 Jest 测试方案
整体逻辑拆成两个独立模块测试,完全覆盖功能链路,不需要复杂的DOM模拟:
- 工具函数层:对
~/helpers中三个滚动相关函数做独立单元测试,验证单个函数的行为正确性 - 组件绑定层:对首页组件做挂载/卸载测试,验证滚动事件的绑定、解绑逻辑和生命周期钩子匹配
前置准备
- Nuxt项目默认集成jsdom测试环境,自带window、document全局对象,无需额外安装DOM模拟库
- 提前mock
~/constants中的SCROLL_SPEED为固定值(比如50),方便计算滚动偏移量 - 每个用例执行前调用
jest.clearAllMocks()清空所有mock调用记录,避免跨用例的状态污染
工具函数单测(helpers.test.js)
先做基础的模块mock:
// mock常量,固定滚动速度方便断言 jest.mock('~/constants', () => ({ SCROLL_SPEED: 50 })) import { scrollHorizontally, enableCustomScrolling, disableCustomScrolling } from '~/helpers'
测试 enableCustomScrolling
- 核心验证点:调用函数时,会给window实例绑定两个跨浏览器兼容的滚轮事件(
mousewheel、DOMMouseScroll),绑定的回调和传入参数完全一致 - 测试步骤:
- 把
window.addEventListenermock为jest.fn() - 构造假的滚动回调
fakeHandler = jest.fn() - 调用
enableCustomScrolling(fakeHandler) - 断言:
window.addEventListener共调用2次,第一次参数为('mousewheel', fakeHandler),第二次为('DOMMouseScroll', fakeHandler)
可选补充:如果项目需要兼容IE6-8,可模拟window不支持addEventListener的场景,验证
attachEvent分支的逻辑 - 把
测试 disableCustomScrolling
- 核心验证点:调用函数时,会移除之前绑定的两个滚轮事件,移除的回调和传入参数完全一致
- 测试步骤:
- 把
window.removeEventListenermock为jest.fn() - 复用上面的
fakeHandler - 调用
disableCustomScrolling(fakeHandler) - 断言:
window.removeEventListener共调用2次,分别对应mousewheel、DOMMouseScroll两个事件,回调匹配
- 把
测试核心逻辑 scrollHorizontally
每个用例执行前重置两个DOM的scrollLeft初始值为0,保证初始状态一致,覆盖以下场景:
- 场景1:Chrome/Edge/Safari 正向滚轮(wheelDelta=1)
- 构造模拟事件:
{ wheelDelta: 1, preventDefault: jest.fn() } - 调用
scrollHorizontally(mockEvent) - 断言:
document.documentElement.scrollLeft= -50document.body.scrollLeft= -50- 事件的
preventDefault被调用,阻止默认纵向滚动
- 构造模拟事件:
- 场景2:Chrome/Edge/Safari 反向滚轮(wheelDelta=-1)
- 构造模拟事件:
{ wheelDelta: -1, preventDefault: jest.fn() } - 调用函数后断言两个scrollLeft值均为50
- 构造模拟事件:
- 场景3:Firefox 兼容场景(用detail传递滚轮值)
- 构造模拟事件:
{ detail: 1, preventDefault: jest.fn() } - 调用函数后断言两个scrollLeft值均为-50
- 构造模拟事件:
- 场景4:IE 兼容兜底(window.event全局事件)
- 给全局
window.event赋值上述正向滚轮的模拟事件,调用函数时不传参数,验证滚动逻辑正常执行
- 给全局
首页组件测试(index.test.js)
这部分不需要跑真实的滚动逻辑,只需要验证生命周期的绑定关系,因此提前把~/helpers整个模块mock掉,避免真实事件绑定污染全局测试环境:
// 完整mock helpers模块 jest.mock('~/helpers', () => ({ scrollHorizontally: jest.fn(), enableCustomScrolling: jest.fn(), disableCustomScrolling: jest.fn() })) import { mount } from '@vue/test-utils' import HomePage from '~/pages/index.vue' import { enableCustomScrolling, disableCustomScrolling, scrollHorizontally } from '~/helpers'
测试用例:
- 验证beforeMount阶段:挂载组件后,断言
enableCustomScrolling被调用,传入的参数就是导出的scrollHorizontally(组件模板是占位文本,和滚动逻辑无关,不需要校验DOM渲染结果) - 验证beforeDestroy阶段:组件挂载完成后调用
wrapper.destroy(),断言disableCustomScrolling被调用,传入的参数同样是scrollHorizontally
常见坑点
- jsdom环境下的scrollLeft属性是可写的,不需要额外做DOM模拟,直接赋值初始值即可
- 不要在测试中触发真实的浏览器滚动行为,所有DOM状态变化都要显式重置
- 如果遇到事件对象的兼容问题,可以根据项目实际支持的浏览器范围,裁剪不需要的兼容分支测试,减少冗余用例
内容的提问来源于stack exchange,提问作者Josue0117
相关产品推荐
相关产品推荐

