Tooltip: Testing Library hover event doesn't trigger tooltip
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 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 thefindByRolewhen it gets two elements instead of 1 - I think you should usually
awaitanyuserEventcalls - I think you should also wrap any
userEventcalls inactbefore 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();
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 🤔
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.