Skip to content

Component is not re-rendered upon custom hook state change #1093

@danguilherme

Description

@danguilherme
  • @testing-library/react version: 12.1.5
  • Testing Framework and version: jest @ 26.6.3
  • DOM Environment: jsdom @ 16.5.3, jest-environment-jsdom @ 26.6.2

Relevant code or config:

A simplified version of our code:

useInnerText.ts

export function useInnerText(): [RefObject<HTMLDivElement>, string] {
    const [innerText, setInnerText] = useState('');
    const ref = useRef<HTMLDivElement>(null);
    useEffect(() => {
        setInnerText(ref.current?.innerText ?? '');
    }, [ref]);

    return [ref, innerText];
}

MultiLineHeader.tsx

export const MultiLineHeader: React.FC<{ message: string }> = React.memo(
    ({ message }) => {
        const [ref, innerText] = useInnerText();
        const muiColumnHeader = ref.current?.closest(
            '.MuiDataGrid-columnHeader'
        );
        if (muiColumnHeader instanceof HTMLElement) {
            muiColumnHeader.tabIndex = 0;
        }

        return (
            <div
                ref={ref}
                style={{
                    overflowWrap: 'anywhere',
                    lineClamp: innerText.includes(' ') ? 2 : 1,
                }}
            >
                {message}
            </div>
        );
    }
);

MultiLineHeader.test.tsx

it('makes column tabbable', () => {
    render(
        <div
            data-test-id="column-header"
            className="MuiDataGrid-columnHeader"
        >
            <MultiLineHeader message="Long message" />
        </div>
    );
    screen.debug();

    expect(screen.getByTestId('column-header')).toHaveAttribute(
        'tabindex',
        '0'
    );
});

What you did:

We are using Material UI's DataGrid in our app, and we want to make the column header accessible through tab for our tables. As we don't have the option to customise the component itself, we are using refs to do the job. So we get the ref of the column header label element and go up to the DataGrid's column header itself and add tabindex="0" to it.

It works as expected in the app, but it does not work in the test. ref is never updated with the element, nor the MultiLineHeader component is re-rendered upon innerText being set.

What happened:

In the app:
image

In the test (output of screen.debug()):

    <body>
      <div>
        <div
          class="MuiDataGrid-columnHeader"
          data-test-id="column-header"
        >
          <div
            style="overflow-wrap: anywhere; line-clamp: 1;"
          >
            Long message
          </div>
        </div>
      </div>
    </body>

Reproduction:

Test reproduction in Codesandbox: https://codesandbox.io/s/react-testing-library-demo-forked-yuqgxp?file=/src/__tests__/MultiLineHeader.js.

Problem description:

The problem here in my opinion is that the exact same piece of code works in the app, but not with the testing library. They should behave the same.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions