mock requestanimationframe 是为了防止真实动画干扰测试、避免无限等待并提升确定性,常用方法是替换全局 raf 为可手动触发的模拟函数,或使用 jest faketimers(需显式推进),同时需妥善处理 cancelanimationframe 以准确模拟取消逻辑。

在 JavaScript 单元测试中,Mock requestAnimationFrame(简称 rAF)主要是为了**避免真实动画循环干扰测试执行、防止无限等待、提升测试速度和确定性**。核心思路是:用可控的模拟函数替代原生 rAF,并能主动触发回调(如“立即执行下一次”或“执行 n 次”)。
替换全局 rAF 并提供手动触发能力
最常用做法是在测试前临时覆盖 window.requestAnimationFrame,返回一个可管理的 ID(比如计数器),并维护一个回调队列:
- 用
jest.mock或直接赋值方式劫持window.requestAnimationFrame - 每次调用时把回调存入数组,返回一个假的 ID(不需真实清除逻辑)
- 提供一个
advanceRAF()工具函数:取出队首回调并执行,模拟一次帧触发 - 可选支持
advanceRAF(3)执行多次,或flushRAF()清空全部待执行回调
使用 Jest 自带的 fake timers(推荐)
Jest v27+ 支持更简洁的方式:启用 fakeTimers 并配置 enableRequestAnimationFrame: true:
beforeEach(() => {
jest.useFakeTimers({ enableRequestAnimationFrame: true });
});
afterEach(() => {
jest.useRealTimers();
});
test('动画逻辑在下一帧执行', () => {
const callback = jest.fn();
requestAnimationFrame(callback);
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(16); // 模拟约 1 帧(60fps)
expect(callback).toHaveBeenCalledTimes(1);
});
注意:Jest 的 fake rAF 默认不会自动推进,需显式调用 jest.advanceTimersByTime(ms) 或 jest.runOnlyPendingTimers() 触发已注册的回调。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
处理嵌套 rAF 和 cancelAnimationFrame 场景
如果被测代码中用了 cancelAnimationFrame,Mock 时也应同步处理:
- 维护一个
activeIds = new Set()记录当前有效的 rAF ID -
requestAnimationFrame返回新 ID 并加入 set -
cancelAnimationFrame(id)从 set 中删除该 ID -
advanceRAF()只执行那些 ID 仍存在于 set 中的回调
这样能准确模拟“注册后又被取消”的行为,避免误触发已取消的动画帧。
实际测试中的关键提醒
Mock rAF 不是为了完全复刻浏览器行为,而是让测试可预测:
- 不要依赖 rAF 的精确时间间隔(16.6ms),只关注“是否调用”“调用顺序”“是否被取消”
- 若组件依赖 rAF 实现渲染节流(如防抖式重绘),测试重点应是“状态变更后,是否在下一帧更新 DOM”
- 真实环境里 rAF 可能被浏览器暂停(如页面非激活),但单元测试中通常忽略这类边界,除非专门测可见性逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










