首页 > 解决方案 > 使用酶,模拟 keydown 事件不适用于将事件动态添加到元素的元素

问题描述

我有一个完全可以正常工作的组件,我正在尝试使用 jest 和酶编写一些测试。

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>
    )
}

这是我试图模拟逃生事件的测试

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

这不会触发逃生事件。但是,当我将事件处理程序直接附加到 dom 上的组件时,相同的测试正在模拟转义事件并且似乎工作正常。

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 时工作正常?我试图在各种文章中搜索这个术语,但什么也得不到。提前致谢。

标签: reactjsjestjsenzyme

解决方案


像 .simulate("click") 一样的酶模拟工作实际上寻找 onClick 函数并将参数传递给它,没有“实际”点击正在进行

所以酶不会模拟直接添加的事件的触发器......你可能不得不自己去调度事件。

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 中的 Empty 数组依赖项,以在 dom 元素有时在 react 重新渲染之间发生变化时确保其安全。

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

您仅在安装组件时附加 eventHandler。

但是 DOM 元素可能会在 react 渲染之间发生变化,因此您实际上应该在所有 useEffects 中附加 eventListener,这些在 react 渲染和反应生命周期中的 DOM 更新后触发。

你也可以依赖callBackRefs,如果你认为 DOM 元素会有一些昂贵的东西并且不希望它在每个 useEffects 上运行。

对于仅附加事件侦听器,这个没有依赖数组的 useEffect 应该没问题。


推荐阅读