React Testing Library - Failing to test Window Resize React Hook

Viewed 7093

I've created a custom React Hook for getting the viewport width & height on window resize (the event is debounced). The hook works fine, but I've been unable to find a way to test with React Testing Library (I keep running into errors).

I've recreated the app in CodeSandbox (along with the tests) to try to debug, but I'm running into different errors while testing.

Sometimes I get:

Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`

But the general failures are that the data from the hook does not seem to be returned.

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

Expected: 500
Received: undefined

This could be something I'm missing with React Testing Library.

Any help getting to the bottom of the problem would be super appreciated!

Demo app/tests here:

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

===========

Solution

Thanks to @tmhao2005 it seemed that the problem was down to the hook getting the resize values from document rather than window:

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

It seems that getting the clientWidth/Height is fine in the app, but fails in the React Testing Library tests.

I was opting for client sizing as I believe that does not include scollbar widths.

1 Answers

I think there are a few things you have to change to make your test working again:

  • You haven't waited to your debounce function work which is the main problem. So you can use either mock the timer or wait until your debounce function getting called.
// 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);
});

  • You might refine your implementation code by changing to use your mock value instead:
const debouncedHandleResize = debounce(() => {
  setViewportSize({
    // using your mock values
    width: window.innerWidth,
    height: window.innerHeight
  });
}, debounceTime);

PS: I also edited your codesandbox based on the async way: https://codesandbox.io/s/useviewportsize-forked-pvnc1?file=/src/use-viewport-size.test.tsx

Related