mantine icon indicating copy to clipboard operation
mantine copied to clipboard

Tooltip: Testing Library hover event doesn't trigger tooltip

Open DanielGibbsNZ opened this issue 3 years ago • 2 comments

What package has an issue

@mantine/core

Describe the bug

When trying to test the Tooltip component using Jest and React Testing Library, I am unable to get the tooltip to appear in the DOM when hovering over the trigger. Previously this worked fine on Mantine 4.2.11.

Packages:

  • @mantine/core: 5.0.2
  • @mantine/hooks: 5.0.2
  • @testing-library/dom: 8.14.0
  • @testing-library/jest-dom: 5.16.4
  • @testing-library/react: 13.3.0
  • @testing-library/user-event: 12.2.2

Note that while some of the testing library packages are not the latest versions, the issue still occurs with the latest versions in the CodeSandbox link provided.

Component:

import { MantineProvider, Tooltip } from "@mantine/core";

export default function App() {
  return (
    <MantineProvider withGlobalStyles withNormalizeCSS>
      <Tooltip
        label={<div role="tooltip">Tooltip contents</div>}
        position="top"
        withArrow
      >
        <span>Tooltip trigger</span>
      </Tooltip>
    </MantineProvider>
  );
}

Test:

import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom/extend-expect";

import App from "./App";

it("renders a tooltip with the given contents", async () => {
  render(<App />);

  expect(screen.queryByRole("tooltip")).not.toBeInTheDocument();

  const trigger = screen.getByText("Tooltip trigger");

  userEvent.hover(trigger);

  const tooltip = await screen.findByRole("tooltip");
  expect(tooltip).toHaveTextContent("Tooltip contents");

  userEvent.unhover(trigger);

  expect(screen.queryByRole("tooltip")).not.toBeInTheDocument();
});

I've tried using various over things to trigger the tooltip (such as fireEvent.mouseEnter) but can't seem to get it to appear no matter what I do. I don't mind mocking some @floating-ui packages if needed, but at the moment I don't know what to mock to get basic tooltip functionality to work in tests.

What version of @mantine/hooks page do you have in package.json?

5.0.2

If possible, please include a link to a codesandbox with the reproduced problem

https://codesandbox.io/s/falling-leaf-glfq9q

Do you know how to fix the issue

No

Are you willing to participate in fixing this issue and create a pull request with the fix

Yes

Possible fix

No response

DanielGibbsNZ avatar Aug 02 '22 00:08 DanielGibbsNZ

@DanielGibbsNZ I was able to run your test just fine with a few tweaks:

  • You are passing a div with role="tooltip" into the Tooltip, but Mantine already sets this role on a component inside Tooltip, so your tests fails on the findByRole when it gets two elements instead of 1
  • I think you should usually await any userEvent calls
  • I think you should also wrap any userEvent calls in act before assertions

Here's a fixed version of the test, assuming you also get rid of the role="tooltip" bit in the component:

render(<App />);

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();

const trigger = screen.getByText('Tooltip trigger');

await userEvent.hover(trigger);

const tooltip = await screen.findByRole('tooltip');
 expect(tooltip).toHaveTextContent('Tooltip contents');

await act(async () => {
  await userEvent.unhover(trigger);
});

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();

ercgrat avatar Aug 06 '22 17:08 ercgrat

Hi @ercgrat, thanks for your reply. I've removed role="tooltip" (I think it was needed using Mantine v4) but this wasn't the issue as findByRole didn't return any elements at all.

It looks like this does indeed work using user-event version 14. Unfortunately due to the breaking change in version 14 (adding await to every single call) the codebase I'm working on is still using version 12.

Not sure exactly why the test fails on version 12 as it worked fine using Mantine version 4 🤔

DanielGibbsNZ avatar Aug 07 '22 21:08 DanielGibbsNZ

I can confirm that the above method works well, thanks @ercgrat! You can find tooltip test here – https://github.com/mantinedev/mantine/blob/master/src/mantine-core/src/Tooltip/Tooltip.test.tsx#L63:L75

  it('shows tooltip when target element is hovered', async () => {
    render(
      <Tooltip label="test-tooltip" transitionDuration={0}>
        <button type="button">target</button>
      </Tooltip>
    );

    await userEvent.hover(screen.getByRole('button'));
    expect(screen.getByText('test-tooltip')).toBeInTheDocument();

    await userEvent.unhover(screen.getByRole('button'));
    expect(screen.queryAllByText('test-tooltip')).toHaveLength(0);
  });

@DanielGibbsNZ I'm not sure how that would translate to older RTL versions, you can try using some sleep() timers. Also make sure that the issue is not caused by tooltip transition (try setting it to 0 like in the example).

I'm closing this issue as it seems to be resolved, but feel free to ask any questions here.

rtivital avatar Aug 12 '22 16:08 rtivital