I want to write a jest unit test for a module that uses requestAnimationFrame
and cancelAnimationFrame
.
I tried overriding window.requestAnimationFrame with my own mock (as suggested in this answer ), but the module keeps on using the implementation provided by jsdom.
My current approach is to use the (somehow) builtin requestAnimationFrame
implementation from jsdom, which seems to use setTimeout
under the hood, which should be mockable by using jest.useFakeTimers()
.
jest.useFakeTimers();
describe("fakeTimers", () => {
test.only("setTimeout and trigger", () => {
const order: number[] = [];
expect(order).toEqual([]);
setTimeout(t => order.push(1));
expect(order).toEqual([]);
jest.runAllTimers();
expect(order).toEqual([1]);
});
test.only("requestAnimationFrame and runAllTimers", () => {
const order: number[] = [];
expect(order).toEqual([]);
requestAnimationFrame(t => order.push(1));
expect(order).toEqual([]);
jest.runAllTimers();
expect(order).toEqual([1]);
});
});
The first test is successful, while the second fails, because order
is empty.
What is the correct way to test code that relies on requestAnimationFrame()
. Especially if I need to test conditions where a frame was cancelled?
6条答案
按热度按时间h4cxqtbf1#
这里的解决方案来自玩笑问题:
q1qsirdb2#
I'm not sure this solution is perfect but this works for my case.
There are two key principles working here.
1) Create a delay that is based on requestAnimationFrame:
2) Make the animation I am testing run very fast:
In my case the animation I was waiting on has a configurable duration which is set to 1 in my props data.
Another solution to this could potentially be running the waitRaf method multiple times but this will slow down tests.
My example test file (Vue app with Jest):
wbrvyc0a3#
所以,我自己找到了解决办法。
我确实需要覆盖
window.requestAnimationFrame
和window.cancelAnimationFrame
。问题是,我没有正确地包含mock模块。
mock必须在导入任何可能调用
requestAnimationFrame
的模块 * 之前 * 导入。yws3nbqq4#
Here is my solution inspired by the first answer.
Then in test mock the timer:
Directly call
cb
inmockImplementation
will produce infinite call loop. So I make use of the Jest Timer Mocks to get it under control.qxgroojn5#
我的 typescript 解决方案。我认为通过让每一帧的时间过得非常快,它会使动画非常(基本上是即时的)快。在某些情况下可能不是正确的解决方案,但我会说这将有助于许多。
jum4pzuy6#
以前版本的问题是直接调用回调,这不反映requestAnimationFrame的异步性质。
下面是一个使用
jest.useFakeTimers()
来实现这一点的模拟,同时在代码执行时提供控制权:在测试中,您可以使用:
这有助于包含Zalgo。