1
votes

My component utilizes useLayoutEffect to execute a function for calculating two state variables for position. The same function is passed to the Element.scroll event of one the internal containers:

The code looks like this:

export const Component = ({children}) => {
    // .....

    const containerRef = useRef<HTMLDivElement>(null);
    const [canClickLeft, setCanClickLeft] = useState(false);
    const [canClickRight, setCanClickRight] = useState(false);

    const checkForPosition = () => {
      if (containerRef.current) {
        // logic here;

        const positionLeft = false;
        const positionRight = true;
  
        setCanClickLeft(positionLeft);
        setCanClickRight(positionRight);
      }
    };

    const doSomething = () = {....}
  
    useLayoutEffect(() => {
        checkForPosition();
    });


    return (
      <>
        <StyledContainer onScroll={() => checkForPosition()}>
          {children}
        </StyledContainer>
  
        <button disabled={!canClickLeft} onClick={doSomething}>Click Left</button>
        <button disabled={!canClickRight onClick={doSomething}}>Click Right</button>
      </>
    );
};

I have a simple test for the aforementioned lines of code:

test('flow', () => {
  const {asFragment, getByTestId} = render(<Component />)

  expect(asFragment()).toMatchSnapshot();
  expect(getByText('Click Left')).toBeDisabled();
  expect(getByText('Click Right')).toBeEnabled();
});

Unfortunately jest throws an error with the following error message:

expect(element).toBeEnabled()
Received element is not enabled: <button disabled=""/>

Can someone explain the essence of this error? And what is the correct way to test this component ?

Edit: The main issue seems to be the unknow ref at render time inside the test.

Looks like other people have struggled with this as well: https://spectrum.chat/testing-library/general/testing-useeffect-with-usestate-and-useref-inside~168a4df3-e2cd-486d-b908-e1f67c87b7be

Edit2: Another related thread How to test useRef with Jest and react-testing-library?

Edit3: Ok, the ref is actually there and accessible https://rafaelquintanilha.com/react-testing-library-common-scenarios/#scenario-3---focused-element

1

1 Answers

0
votes

After being stuck in this conundrum for a few days I think I found out why I got the failing tests.

The logic inside the checkForPosition functions deals heavily with element properties like clientHeight, clientWidth, scrollHeight, scrollWidth, offsetWidth, offsetHeight etc. accessed inside the referenced dom element.

React Testin Library realies on JSDOM to 'render' react web components but JSDOM doesn't support layout in its escennce. All these dimension mesaruments equal 0 everywhere in my tests.

https://github.com/testing-library/react-testing-library/issues/353#issuecomment-481248489

So I tried mocking the useRef function which didn't work for me at all:

Tried to use functions like act to better reprodice the react component cycle, tried async code with timers, but still couldn't make it work:

At the end decided to just mock the element's props and somehow intercept the referenced dom component:

Additionl resources: https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests

Make useEffect hook run synchronously to make testing nice: https://twitter.com/kentcdodds/status/1064023833189900288?lang=en