Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jestjs 我如何测试开玩笑地使用'requestAnimationFrame'的代码?_Jestjs_Settimeout_Requestanimationframe_Jsdom - Fatal编程技术网

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)