При использовании фермента имитация события нажатия клавиш не работает на элементе, где событие динамически добавляется к элементу. - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть компонент, который работает абсолютно нормально, и я пытаюсь написать несколько тестов, используя шутки и энзимы.

const handleEvent = (e: KeyboardEvent) => {
    if(e.keyCode === 27)
      console.log('Escape event');
}
const Component = () => {    
    const ref = useRef(null);
    useEffect(() => {
        ref.current?.addEventListener('keydown', handleEvent);
        return () => {
            ref.current?.removeEventListener('keydown', handleEvent);
        }
    }, []);
    return (
         <div ref={ref}> Some inner elements </div>
    )
}

Это тест, в котором я пытаюсь смоделировать escape-событие

it('simulate escape event', () => {
    const component = mount(<Component />);
    component.simulate('keydown', { keyCode: 27 });
    // assertion of things that are handled on escape
});

Это не вызывает escape-событие. Но когда я присоединяю обработчик событий к компоненту непосредственно в DOM, тот же тест имитирует escape-событие и, кажется, работает нормально.

const handleEvent = (e: KeyboardEvent) => {
   if(e.keyCode === 27)
     console.log('Escape event');
}
const Component = () => {    
   const ref = useRef(null);
   return (
        <div ref={ref} onKeyDown={handleEvent}> Some inner elements </div>
   )
}

Может кто-нибудь сказать, почему имитация не работает, когда событие динамически присоединяется к компоненту, но работает нормально при добавлении его непосредственно в dom? Я пытался искать по этим терминам в различных статьях и ничего не мог получить. Заранее спасибо.

1 Ответ

1 голос
/ 19 апреля 2020

Имитация фермента работает подобно .simulate («click») фактически ищет функцию onClick и передает ей параметры, при этом «фактический» щелчок не происходит

Таким образом, фермент не будет имитировать триггер при события, добавленные непосредственно… вам, возможно, придется go отправить событие Event самим.

component.getDOMNode (), чтобы получить узел DOM, на котором должен работать dispatchEvent. Что-то вроде ниже

 it('simulate escape event', () => {
    const component = mount(<Component />);

    const event = new Event('keydown');
    event.keyCode = 27;

    component.getDOMNode().dispatchEvent(event);
    // assertion of things that are handled on escape
  });

Также еще одна проблема, которую я вижу, состоит в том, что массив зависимостей в useEffect. Удалите зависимость пустого массива в useEffect, чтобы сохранить его в безопасности, когда элемент dom иногда изменяется между реактивными повторными рендерингами.

  useEffect(() => {
        ref.current?.addEventListener('keydown', handleEvent);
        return () => {
            ref.current?.removeEventListener('keydown', handleEvent);
        }
    });

Вы присоединяете eventHandler только при монтировании компонента.

Но элемент DOM может меняться между реагирующими рендерингами, поэтому вы должны фактически прикрепить eventListener во все useEffects, которые запускаются после рендеринга реагирования и обновлений DOM в жизненном цикле реакции.

U также может полагаться на callBackRefs , если вы думаете, что в элементе DOM будет что-то дорогое, и не хотите, чтобы оно выполнялось при каждом использовании useEffects.

Для простого подключения прослушивателей событий этот useEffect без массива зависимостей должен подойти.

...