user901916
user901916

Reputation: 63

React Testing Library - mock offsetWidth, offsetLeft

I need your help on fixing the test case. I am trying to mock the document body offsetwidth, offsetLeft objects.

In the resize method, I am trying to mock the newWidth which is calculating the mouse position and accordingly getting the actual width and resizing the material UI modal.

index.tsx Following is the section from where I am triggering the enableResize on mousedown event.

 <div onMouseDown={enableResize} className={classes.dragger} />
    

useResize.tsx

  import {
  Dispatch,
  SetStateAction,
  useCallback,
  useEffect,
  useState,
} from 'react';

type UseResizeProps = {
  minWidth: number;
  maxWidth: number;
};

type UseResizeReturn = {
  width: number;
  enableResize: () => void;
  disableResize: () => void;
  isResizing: boolean;
  resize: (e: MouseEvent) => void;
  setWidth: Dispatch<SetStateAction<number>>;
};

const useResize = ({ minWidth, maxWidth }: UseResizeProps): UseResizeReturn => {
  const [isResizing, setIsResizing] = useState(false);
  const [width, setWidth] = useState(minWidth);

  const enableResize = useCallback(() => {
    setIsResizing(true);
  }, [setIsResizing]);

  const disableResize = useCallback(() => {
    setIsResizing(false);
  }, [setIsResizing]);

  const resize = useCallback(
    (e: MouseEvent) => {
      if (isResizing) {
        const newWidth =
          document.body.offsetWidth - (e.clientX - document.body.offsetLeft);
        if (newWidth > minWidth && newWidth < maxWidth) {
          setWidth(newWidth);
        }
      }
    },
    [minWidth, maxWidth, isResizing, setWidth],
  );

  useEffect(() => {
    document.addEventListener('mousemove', resize);
    document.addEventListener('mouseup', disableResize);

    return () => {
      document.removeEventListener('mousemove', resize);
      document.removeEventListener('mouseup', disableResize);
    };
  }, [disableResize, resize]);

  return {
    width,
    enableResize,
    isResizing,
    disableResize,
    resize,
    setWidth,
  };
};

export default useResize;
       

useResize.test.tsx

    const { result } = renderHook(() => useResize(defaultProps));
    const event = new MouseEvent('mousedown', {
      bubbles: true,
      clientX: 1000,
    });

    act(() => {
      result.current.resize(event);
      result.current.enableResize();
    });
    expect(result.current.isResizing).toBeTruthy();

    Object.defineProperty(document.body, 'offsetWidth', {
      value: 1536,
    });

    Object.defineProperty(document.body, 'offsetLeft', {
      value: 0,
    });

    const width: any =
      document.body.offsetWidth - (event.clientX - document.body.offsetLeft);

    window.dispatchEvent(new Event('resize'));

    expect(defaultProps.minWidth).toBeLessThan(width);

    act(() => {
      result.current.setWidth(width);
    });

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

Upvotes: 0

Views: 1266

Answers (1)

Lin Du
Lin Du

Reputation: 102607

If we only focus on the unit testing for the useResize hook, a simulated mousedown event to enable the resizing is unnecessary. We can call the enableResize function directly to change the isResizing state.

Instead of Event, we can create and dispatch a MouseEvent with mousemove type and clientX value.

E.g:

useResize.test.tsx:

import { renderHook, act } from '@testing-library/react-hooks';
import useResize from './useResize';

describe('72926548', () => {
  test('should set new width', async () => {
    const { result } = renderHook(() => useResize({ minWidth: 100, maxWidth: 200 }));
    act(() => {
      result.current.enableResize();
    })
    expect(result.current.isResizing).toBeTrue();
    Object.defineProperty(document.body, 'offsetWidth', {
      value: 1150,
    });
    Object.defineProperty(document.body, 'offsetLeft', {
      value: 0,
    });
    act(() => {
      document.dispatchEvent(new MouseEvent('mousemove', { clientX: 1000 }));
    })
    expect(result.current.width).toBe(150);
  });
});

Test result:

 PASS  stackoverflow/72926548/useResize.test.tsx (6.32 s)
  72926548
    ✓ should set new width (14 ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   95.24 |    66.67 |   83.33 |   95.24 |                   
 useResize.tsx |   95.24 |    66.67 |   83.33 |   95.24 | 32                
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        6.615 s, estimated 7 s

package versions:

"@testing-library/react-hooks": "^8.0.1",
"jest": "^26.6.3",
"react": "^16.14.0",
"react-dom": "^16.14.0"

Upvotes: 0

Related Questions