React测试库 - 无法测试窗口调整大小React Hook

4
我已经创建了一个自定义的React Hook,用于在窗口调整大小时获取视口宽度和高度(事件被防抖处理)。这个Hook运行良好,但我一直无法找到一种使用React Testing Library进行测试的方法(我一直遇到错误)。
我已经在CodeSandbox中重新创建了应用程序(包括测试),以尝试调试,但是在测试过程中遇到了不同的错误。
有时我会得到:
Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`

但通常失败的原因是挂钩返回的数据似乎没有被返回。

expect(received).toBe(expected) // Object.is equality

Expected: 500
Received: undefined

这可能是我在使用React测试库时遗漏的东西。非常感谢任何帮助解决问题的支持!
演示应用程序/测试在这里:

https://codesandbox.io/s/useviewportsize-4l7gb?file=/src/use-viewport-size.test.tsx

===========

解决方案

感谢 @tmhao2005,问题似乎是由于挂钩从 document 而不是 window 获取调整大小的值导致的:

  setViewportSize({
    width: window.innerWidth, //document.documentElement.clientWidth - doesn't work
    height: window.innerHeight //document.documentElement.clientHeight - doesn't work
  });

似乎在应用程序中获取clientWidth/Height是可以的,但在React测试库测试中失败了。
我选择client大小,因为我相信它不包括滚动条宽度。

除了测试未通过之外,好像没有发生您上面提到的错误? - tmhao2005
是的,我正在努力解决测试失败的问题。如果您点击测试失败,它会显示“在'EventTarget'上执行'dispatchEvent'失败:参数1不是'Event'类型。”
  • 啊,等一下,刷新页面,现在那个错误消失了 - 但测试仍然失败。
- thathurtabit
不,我没有看到类似的东西。这是我看到的 https://www.loom.com/share/840989b580d7416c8265736e2c92e0fe - tmhao2005
感谢@tmhao2005的视频 - 是的,这可能是codesandbox的奇怪问题。但主要我正在寻求如何测试这个hook的帮助(我已经更新了上面的问题)。 - thathurtabit
1
我在答案中给了你一个建议。请查看我的内联注释,以确保您正确跟进。 - tmhao2005
2个回答

3

我认为有几个需要改变的事情,才能使你的测试再次正常运行:

  • 你没有等待防抖函数生效,这是主要问题。因此,你可以使用模拟定时器或者等待防抖函数被调用。
// Make your test as `async` in case of wanting to wait
test("should return new values on window resize", async () => {
  // If you go for mocking timer, uncomment this & below advance the timer 
  // jest.useFakeTimers();
  const { result } = renderHook(() => useViewportSize());

  act(() => {
    window.resizeTo(500, 500);
    //fireEvent(window, new Event("resize"));
  });

  // jest.advanceTimersByTime(251) // you can also use this way
  await mockDelay(debounceDelay); // `await` 300ms to make sure the function callback run

  expect(result.current.width).toBe(500);
  expect(result.current.height).toBe(500);
});


您可以通过使用模拟值来优化您的实现代码:
const debouncedHandleResize = debounce(() => {
  setViewportSize({
    // using your mock values
    width: window.innerWidth,
    height: window.innerHeight
  });
}, debounceTime);

PS: 我还根据异步方式编辑了您的codesandbox:https://codesandbox.io/s/useviewportsize-forked-pvnc1?file=/src/use-viewport-size.test.tsx


感谢@tmhao2005 - 我已经设置了async/await(带有mockDelay),并且正在查看是否这是问题的根源,但似乎问题出在: setViewportSize({ width: window.innerWidth, //document.documentElement.clientWidth - doesn't work height: window.innerHeight //document.documentElement.clientHeight - doesn't work });问题似乎是document.documentElement.clientX在测试中无法响应(但在应用程序本身中很好)。 - thathurtabit
1
是的,看起来在模拟情况下不起作用。但是最好还是去模拟计时器,因为这样更有意义,而且速度更快 :) - tmhao2005

2
我的解决方案是基于这个RTL bug comment,以下是具体步骤:
it('should check that the useMediaQuery returns the proper value', () => {
  const size = renderHook(() => useMediaQuery())

  act(() => {
    window.innerHeight = 500
    window.innerWidth = 500
  })

  fireEvent(window, new Event('resize'))

  expect(size.result.current).toEqual({ height: 500, width: 500 })
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接