React testing library element title undefined

Viewed 1090

I am trying to test that when I hover over an icon, a tooltip appears with certain text.

Using Jest, react testing library, and the tooltip is a MUI 4 component.

The icon and tooltip

<div
   data-testid="tooltip-icon"
   className={classes.infoTooltipIcon}
>
   <Tooltip
      data-testid="tooltip-text"
      title="Tooltip text"
   >
      <InfoIcon/>
   </Tooltip>
</div>

Slimmed down test

it('has a tooltip on the info icon', () => {
    render(<Component />);

    const infoIcon = screen.getByTestId('tooltip-icon');
    userEvent.hover(infoIcon); // works
    
    const infoTooltip = screen.getByTestId('tooltip-text')
    expect(infoTooltip.title).toEqual('Tooltip text);
  });

Currently, this results in

actual: undefined
expected: 'Tooltip text'

If I screen.debug(infoTooltip) the title is there and has the correct text, but its an <svg/> could this cause an issue?

Output of screen.debug(infoTooltip)

<svg
      aria-hidden="true"
      class="MuiSvgIcon-root makeStyles-center-52"
      data-testid="tooltip-text"
      focusable="false"
      title="Tooltip text"
      viewBox="0 0 24 24"
    >
      <path
        d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"
      />
    </svg>

Additionally, I have also tried screen.getByTitle('Tooltip text') and it does not work.

3 Answers

It seems like MUI applies the tooltip to whatever the child of the <Tooltip/> is, in my case it was the <svg/> generated by <InfoIcon/>. If you wrap the <InfoIcon/> in a <span> tag the tooltip title will then be applied to the <span/>, making it possible to explicitly look for the tooltip text.

My UI

<div
   data-testid="tooltip-icon"
   className={classes.infoTooltipIcon}
>
   <Tooltip
      data-testid="tooltip-text"
      title="Tooltip text"
   >
      <span>
         <InfoIcon/>
     </span>
   </Tooltip>
</div>

My test

it('has a tooltip on the info icon', () => {
    render(<Component />);

    const infoIcon = screen.getByTestId('tooltip-icon');
    userEvent.hover(infoIcon);
    
    const infoTooltip = screen.getByTestId('tooltip-text')
    expect(infoTooltip.title).toEqual('Tooltip text);
  });

This way if I have multiple tooltips I can ensure I'm grabbing the exact one I want via test id.

The better solution is that you should just use the InfoIcon with titleAccess props. https://material-ui.com/api/svg-icon

<InfoIcon titleAccess="Tooltip Text" />

After that, you could test the component like this as an example.

expect(
      getByRole('tooltip', { hidden: true, name: 'Tooltip Text' }),
    ).toBeInTheDocument();

Your suggestion with the span is good! If you don't want to add a span, then I think you just need to adjust the query to look for aria-hidden elements.(Since the svg has aria-hidden=true it gets excluded from the accessibility tree). The query would look like: const tooltip = screen.getByTitle("Tooltip text", { hidden: true } )

Related