diff --git a/packages/mui-material/src/Tooltip/Tooltip.test.js b/packages/mui-material/src/Tooltip/Tooltip.test.js
index 12dfd41c811274..7b72441b10a175 100644
--- a/packages/mui-material/src/Tooltip/Tooltip.test.js
+++ b/packages/mui-material/src/Tooltip/Tooltip.test.js
@@ -13,6 +13,8 @@ import {
} from '@mui/internal-test-utils';
import { camelCase } from 'es-toolkit/string';
import Tooltip, { tooltipClasses as classes } from '@mui/material/Tooltip';
+import IconButton from '@mui/material/IconButton';
+import SaveIcon from '@mui/icons-material/Save';
import { testReset } from './Tooltip';
import describeConformance from '../../test/describeConformance';
@@ -1492,4 +1494,75 @@ describe('', () => {
expect(screen.getByTestId('popper')).to.have.class('my-class');
});
});
+
+ describe('IconButton trigger', () => {
+ it('uncontrolled mode', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ expect(screen.queryByRole('tooltip')).to.equal(null);
+
+ fireEvent.mouseOver(screen.getByRole('button'));
+ clock.tick(0);
+
+ expect(screen.getByRole('tooltip')).toBeVisible();
+
+ fireEvent.mouseLeave(screen.getByRole('button'));
+ // Tooltip schedules timeout even with no delay
+ clock.tick(0);
+ clock.tick(0);
+
+ expect(screen.queryByRole('tooltip')).to.equal(null);
+ });
+
+ it('controlled mode', async () => {
+ function App() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+
+
+
+
+ );
+ }
+
+ await render();
+
+ const trigger = screen.getByRole('button');
+
+ expect(screen.queryByRole('tooltip')).to.equal(null);
+
+ fireEvent.mouseOver(trigger);
+
+ expect(screen.getByRole('tooltip')).toBeVisible();
+
+ fireEvent.mouseLeave(screen.getByRole('button'));
+
+ clock.tick(0); // enterDelay
+ clock.tick(0); // TransitionProps.timeout
+
+ expect(screen.queryByRole('tooltip')).to.equal(null);
+ });
+ });
});
diff --git a/test/e2e/fixtures/Tooltip/ControlledTooltip.tsx b/test/e2e/fixtures/Tooltip/ControlledTooltip.tsx
new file mode 100644
index 00000000000000..57a39ae041ce39
--- /dev/null
+++ b/test/e2e/fixtures/Tooltip/ControlledTooltip.tsx
@@ -0,0 +1,24 @@
+import * as React from 'react';
+import IconButton from '@mui/material/IconButton';
+import Tooltip from '@mui/material/Tooltip';
+import SaveIcon from '@mui/icons-material/Save';
+
+export default function ControlledTooltips() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts
index bb1c355506ff02..046e995a539431 100644
--- a/test/e2e/index.test.ts
+++ b/test/e2e/index.test.ts
@@ -264,4 +264,19 @@ describe('e2e', () => {
await errorSelector.waitFor();
});
});
+
+ describe('', () => {
+ it('icon button trigger', async () => {
+ await renderFixture('Tooltip/ControlledTooltip');
+
+ const tooltip = page.getByRole('tooltip');
+ await expect(tooltip).toBeHidden();
+
+ await page.mouse.move(20, 20);
+ await expect(tooltip).toBeVisible();
+
+ await page.mouse.move(99, 99);
+ await expect(tooltip).toBeHidden();
+ });
+ });
});