使用酶,模拟 keydown 事件不适用于事件动态添加到元素的元素

Using enzyme, simulating keydown event is not working on element where event is dynamically added to element

我有一个运行良好的组件,我正在尝试使用 jest 和 enzyme 编写一些测试。

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 时模拟却工作正常吗?我试图在各种文章中搜索此术语,但一无所获。 提前致谢。

酶模拟的工作方式类似于 .simulate("click") 实际上会查找 onClick 函数并将参数传递给它,没有 'actual' 点击继续

所以 enzyme 不会模拟直接添加事件的触发...你可能需要自己去派发事件。

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 中的依赖数组。 当 dom 元素有时在反应重新渲染之间发生变化时,删除 useEffect 中的空数组依赖项以保证其安全。

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

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

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

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

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