Как протестировать код, который использует `requestAnimationFrame` в jest? - PullRequest
0 голосов
/ 04 мая 2020

Я хочу написать юнит-тест для модуля, который использует requestAnimationFrame и cancelAnimationFrame.

Я попытался переопределить window.requestAnimationFrame с моей собственной имитацией (как предложено в этого ответа ), но модуль продолжает использовать реализацию, предоставляемую jsdom.

Мой текущий подход - использовать (как-то) встроенную requestAnimationFrame реализацию из jsdom, которая, похоже, использует 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 Ответ

0 голосов
/ 11 мая 2020

Я не уверен, что это решение идеально, но это работает для моего случая.

Здесь работают два ключевых принципа.

1) Создайте задержку на основе по запросуAnimationFrame:

const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve));

2) Сделать анимацию, которую я тестирую, очень быстрой:

В моем случае анимация, на которой я ждал, имеет настраиваемая длительность, которая установлена ​​в 1 в моих данных props.

Другим решением этой проблемы может быть запуск метода waitRaf несколько раз, но это замедлит тестирование.

Вы также можете нужно смоделировать requestAnimationFrame, но это зависит от вашей настройки, среды тестирования и реализации

Мой пример тестового файла (Vue приложение с Jest):

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");
    })
  })
});
...