Jestjs 我如何测试开玩笑地使用'requestAnimationFrame'的代码?
我想为使用Jestjs 我如何测试开玩笑地使用'requestAnimationFrame'的代码?,jestjs,settimeout,requestanimationframe,jsdom,Jestjs,Settimeout,Requestanimationframe,Jsdom,我想为使用requestAnimationFrame和cancelAnimationFrame的模块编写一个jest单元测试 我尝试用我自己的mock覆盖window.requestAnimationFrame(如中所建议),但该模块继续使用jsdom提供的实现 我目前的方法是使用jsdom中内置的requestAnimationFrame实现,它似乎在幕后使用了setTimeout,可以通过使用jest.useFakeTimers()来模拟 jest.useFakeTimers(); 描述(“
requestAnimationFrame
和cancelAnimationFrame
的模块编写一个jest单元测试
我尝试用我自己的mock覆盖window.requestAnimationFrame(如中所建议),但该模块继续使用jsdom提供的实现
我目前的方法是使用jsdom中内置的requestAnimationFrame
实现,它似乎在幕后使用了setTimeout
,可以通过使用jest.useFakeTimers()
来模拟
jest.useFakeTimers();
描述(“fakeTimers”,()=>{
仅测试(“设置超时和触发器”,()=>{
常量顺序:编号[]=[];
期望(订单)。toEqual([]);
setTimeout(t=>order.push(1));
期望(订单)。toEqual([]);
jest.runAllTimers();
期望(订单)。toEqual([1]);
});
test.only(“requestAnimationFrame和runAllTimers”,()=>{
常量顺序:编号[]=[];
期望(订单)。toEqual([]);
requestAnimationFrame(t=>order.push(1));
期望(订单)。toEqual([]);
jest.runAllTimers();
期望(订单)。toEqual([1]);
});
});
第一个测试成功,而第二个测试失败,因为order
为空
测试依赖于
requestAnimationFrame()
的代码的正确方法是什么。特别是如果我需要测试取消帧的条件时?我不确定这个解决方案是否完美,但这适用于我的情况
这里有两个关键原则
1)创建基于requestAnimationFrame的延迟:
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
2)使我正在测试的动画运行得非常快:
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
在我的例子中,我等待的动画有一个可配置的持续时间,在我的道具数据中设置为1
另一个解决方案可能是多次运行waitRaf方法,但这会降低测试速度
您可能还需要模拟requestAnimationFrame,但这取决于您的设置、测试框架和实现
我的示例测试文件(带笑话的Vue应用):
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
我不确定这个解决方案是否完美,但这对我的情况有效 这里有两个关键原则 1)创建基于requestAnimationFrame的延迟:
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
2)使我正在测试的动画运行得非常快:
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
在我的例子中,我等待的动画有一个可配置的持续时间,在我的道具数据中设置为1
另一个解决方案可能是多次运行waitRaf方法,但这会降低测试速度
您可能还需要模拟requestAnimationFrame,但这取决于您的设置、测试框架和实现
我的示例测试文件(带笑话的Vue应用):
const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));
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");
})
})
});
所以,我自己找到了解决办法 我确实需要覆盖
窗口.requestAnimationFrame
和窗口.cancelAnimationFrame
问题是,我没有正确地包含模拟模块
//mock_requestAnimationFrame.js
类RequestAnimationFrameMockSession{
handleCounter=0;
队列=新映射();
requestAnimationFrame(回调){
const handle=this.handleCounter++;
this.queue.set(句柄、回调);
返回手柄;
}
取消动画帧(控制柄){
this.queue.delete(句柄);
}
triggerNextAnimationFrame(time=performance.now()){
const nextEntry=this.queue.entries().next().value;
if(nextEntry==未定义)返回;
const[nextHandle,nextCallback]=nextEntry;
下一次回调(时间);
this.queue.delete(nextHandle);
}
triggerAllAnimationFrames(time=performance.now()){
而(this.queue.size>0)this.triggerNextAnimationFrame(time);
}
重置(){
this.queue.clear();
此.handleCounter=0;
}
};
export const requestAnimationFrameMock=新建RequestAnimationFrameMockSession();
window.requestAnimationFrame=requestAnimationFrameMock.requestAnimationFrame.bind(requestAnimationFrameMock);
window.cancelAnimationFrame=requestAnimationFrameMock.cancelAnimationFrame.bind(requestAnimationFrameMock);
在导入任何可能调用requestAnimationFrame
的模块之前,必须导入mock
//mock_requestAnimationFrame.test.js
从“/mock_requestAnimationFrame”导入{requestAnimationFrameMock}”;
描述(“mock_requestAnimationFrame”,()=>{
在每个之前(()=>{
requestAnimationFrameMock.reset();
})
测试(“重新测试->触发器”,()=>{
常量顺序=[];
expect(requestAnimationFrameMock.queue.size).toBe(0);
期望(订单)。toEqual([]);
requestAnimationFrame(t=>order.push(1));
expect(requestAnimationFrameMock.queue.size).toBe(1);
期望(订单)。toEqual([]);
requestAnimationFrameMock.triggerNextAnimationFrame();
expect(requestAnimationFrameMock.queue.size).toBe(0);
期望(订单)。toEqual([1]);
});
测试(“请求->请求->触发->触发”,()=>{
常量顺序=[];
expect(requestAnimationFrameMock.queue.size).toBe(0);
期望(订单)。toEqual([]);
requestAnimationFrame(t=>order.push(1));
requestAnimationFrame(t=>order.push(2));
expect(requestAnimationFrameMock.queue.size).toBe(2);
期望(订单)。toEqual([]);
requestAnimationFrameMock.triggerNextAnimationFrame();
expect(requestAnimationFrameMock.queue.size).toBe(1);
期望(订单)。toEqual([1]);
requestAnimationFrameMock.triggerNextAnimationFrame();
expect(requestAnimationFrameMock.queue.size).toBe(0);
期望(订单).toEqual([1,2]);
});
测试(“重新测试->取消”,()=>{
常量顺序=[];
expect(requestAnimationFram)