我想为使用requestAnimationFrame
和cancelAnimationFrame
的模块编写一个有趣的单元测试。
我尝试使用自己的模拟方法覆盖window.requestAnimationFrame(如this answer中的建议,但是该模块继续使用jsdom提供的实现。
[我目前的方法是使用jsdom中的(某种程度上)内置的requestAnimationFrame
实现,似乎似乎在后台使用了setTimeout
,应该可以通过使用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]);
});
});
第一次测试成功,而第二次失败,因为order
为空。
依靠requestAnimationFrame()
来测试代码的正确方法是什么?特别是如果我需要测试取消帧的条件吗?
我不确定此解决方案是否完美,但这是否适合我的情况。
这里有两个主要原则。
1)创建一个基于requestAnimationFrame的延迟:
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
2)使我正在测试的动画运行得非常快:
就我而言,我正在等待的动画具有可配置的持续时间,在我的道具数据中将其设置为1。
您可能还需要模拟requestAnimationFrame,但这取决于您的设置,测试框架和实现
我的示例测试文件(带有Jest的Vue应用程序:] >>
import { mount } from '@vue/test-utils';
import AnimatedCount from '@/components/AnimatedCount.vue';
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
let wrapper;
describe('AnimatedCount.vue', () => {
beforeEach(() => {
wrapper = mount(AnimatedCount, {
propsData: {
value: 9,
duration: 1,
formatDisplayFn: (val) => "£" + val
}
});
});
it('renders a vue instance', () => {
expect(wrapper.isVueInstance()).toBe(true);
});
describe('When a value is passed in', () => {
it('should render the correct amount', async () => {
const valueOutputElement = wrapper.get("span");
wrapper.setProps({ value: 10 });
await wrapper.vm.$nextTick();
await waitRAF();
expect(valueOutputElement.text()).toBe("£10");
})
})
});