6

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.

5
  • Looks like no error like you mentioned above occurred apart from the tests getting failed? Commented Jan 12, 2021 at 9:14
  • Yeah, the test failure is what I'm struggling with. If you click into the test failure it says "Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`" - Ah, hold on, refreshing the page, now that error goes away - but the tests still fail. Commented Jan 12, 2021 at 9:28
  • No I couldn't see anything like that. Here is what I've seen loom.com/share/840989b580d7416c8265736e2c92e0fe Commented Jan 12, 2021 at 9:37
  • Thanks for the video @tmhao2005 - yeah, that could have been a strange problem with codesandbox instead. But mainly I'm looking for help in how to test this hook (I've updated the question above). Commented Jan 12, 2021 at 9:39
  • 1
    I dropped you a suggestion as answer. Check my inline comment to ensure you follow up properly Commented Jan 12, 2021 at 10:11

2 Answers 2

4

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @tmhao2005 - I had set up the async/await (with mockDelay) and was seeing if that was the root of the problem, but seems like it was down to: setViewportSize({ width: window.innerWidth, //document.documentElement.clientWidth - doesn't work height: window.innerHeight //document.documentElement.clientHeight - doesn't work }); The problem seems to be that document.documentElement.clientX wouldn't respond in the test (but was fine in the app itself)
Yep it looks like doesn’t work in case of simulation. But it would be best if you go for mock the timer since it makes more sense and be faster though :)
3

The solution that worked for me was the following (base on this 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 })
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.