Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hooks ref.current is undefined during test

TLDR - I have a responsive component using ref.current.offsetWidth but it doesn't work when I test it with Jest

The navbar component works and renders fine in localhost. But when I'm trying to stimulate different screen widths using Jest for unit testing, the ref hook is unable to pick up div length for some reason. Any suggestion on how to fix this?

Error: TypeError: Cannot read property 'offsetWidth' of undefined

Code: Navbar.js

// custom hook to get live div width 
const useContainerDimensions = myRef => {
  const getDimensions = () => ({
    width: myRef.current.offsetWidth,            //location of error
  });

  const [dimensions, setDimensions] = useState({ width: 0 });

  useEffect(() => {
    const handleResize = () => {
      setDimensions(getDimensions());
    };
    if (myRef.current) {
      setDimensions(getDimensions());
    }

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, [myRef]);

  return dimensions;
};

const Navbar = () => {
  const inputRef = useRef();
  const { width } = useContainerDimensions(inputRef);

  useEffect(() => {
    if (width >= 890) {
      setCurrTabPerRow(5);
      setTabStyle('5 tabs');
    }
    if (width < 890) {
      setCurrTabPerRow(4);
      setTabStyle('4 tabs');
    }
  }, [width]);

  return (
    ... 
    <div ref={inputRef}>
      //...stuff
    </div>
    ...
  )
}

export default Navbar;

navbar.test.js

const resizeWindow = (x, y) => {
  window.innerWidth = x;
  window.innerHeight = y;
  window.dispatchEvent(new Event('resize'));
}

describe('Navbar component', () => {
  it('should render', () => {
    const component = mount(
      <Navbar filter>
        <Navbar.Tab id="stuff1" />
        <Navbar.Tab id="stuff2" />
        <Navbar.Tab id="stuff3" />
      </Navbar>
    );
    act(() => {
      resizeWindow(500, 300);
    });
    expect(component).toMatchSnapshot();
  });
});
like image 258
Jpark9061 Avatar asked Nov 03 '25 20:11

Jpark9061


2 Answers

The initial value of the ref is undefined. You can simply check that the myRef.current exists before accessing further properties. and provide a fallback value.

const getDimensions = () => ({
  width: (myRef.current && myRef.current.offsetWidth) || 0,
});

or with optional chaining

const getDimensions = () => ({
  width: myRef?.current?.offsetWidth || 0,
});
like image 135
Drew Reese Avatar answered Nov 05 '25 12:11

Drew Reese


The useRef hook initially has no value. You're passing the inputRef right after declaring it.

Try to do something like this:

const [containerWidth, setContainerWidth] = useState(0);

useEffect(() => {
  if(inputRef.current) {
    const { width } = useContainerDimensions(inputRef);

    setContainerWidth(width);
  }
}, [inputRef])

Then you make sure that the inputRef has some value before passing to your custom hook.

like image 37
FerreiraCode Avatar answered Nov 05 '25 10:11

FerreiraCode