javascriptreactjsjestjsreact-testing-librarytesting-library

How to test addEventListener with jest and testing library?


I created a custom hook in reactJS that listens to changes in elements dimensions and then calculates the width and height of the element.

export function useDynamicDimensions(element) {
  const [ width, setWidth ] = useState(element?.innerWidth);
  const [ height, setHeight ] = useState(element?.innerHeight);

  useEffect(() => {
    const handleWindowResize = () => {
      setWidth(element?.innerWidth);
      setHeight(element?.innerHeight);
    };

    element?.addEventListener('resize', handleWindowResize);

    return () => element?.removeEventListener('resize', handleWindowResize);
  }, []);

  return { width, height };
}

I wrote the following test case using Jest and the testing library.

  it('updates dimensions on window resize', () => {
    const initialWidth = 100;
    const initialHeight = 200;
    const newWidth = 250;
    const newHeight = 300;

    const element = {
      innerWidth: initialWidth,
      innerHeight: initialHeight,
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
    };

    const { result } = renderHook(() => useDynamicDimensions(element));

    expect(result.current.width).toBe(initialWidth);
    expect(result.current.height).toBe(initialHeight);

    act(() => {
      element.innerWidth = newWidth;
      element.innerHeight = newHeight;
      global.dispatchEvent(new Event('resize'));
    });

    expect(result.current.width).toBe(250);
  });

But this test case doesn't work. It gives an error

expect(received).toBe(expected)

    Expected: 250
    Received: 100

Can someone tell me where I am going wrong?


Solution

  • Hey I found the answer to my own question :)

    import React from 'react';
    import { renderHook, act } from '@testing-library/react';
    
    describe('useDynamicDimensions', () => {
      it('should return dimensions as is if there is no change in dimensions', () => {
        const initialWidth = 800;
        const initialHeight = 600;
    
        const map = {};
    
        const element = {
          innerWidth: initialWidth,
          innerHeight: initialHeight,
          addEventListener: jest.fn((event, cb) => {
            map[event] = cb;
          }),
          removeEventListener: jest.fn()
        };
    
        const { result } = renderHook(() => useDynamicDimensions(element));
    
        expect(result.current.width).toBe(initialWidth);
        expect(result.current.height).toBe(initialHeight);
      });
    
      it('should update dimensions on element resize', () => {
        const initialWidth = 800;
        const initialHeight = 600;
    
        const map = {};
    
        const element = {
          innerWidth: initialWidth,
          innerHeight: initialHeight,
          addEventListener: jest.fn((event, cb) => {
            map[event] = cb;
          }),
          removeEventListener: jest.fn()
        };
    
        const { result } = renderHook(() => useDynamicDimensions(element));
    
        act(() => {
          element.innerWidth = 500;
          element.innerHeight = 300;
          map.resize?.();
        });
    
        expect(result.current.width).toBe(500);
        expect(result.current.height).toBe(300);
      });
    });