diff --git a/package.json b/package.json
index c837fd2a54a357..0788a8e265b1ae 100644
--- a/package.json
+++ b/package.json
@@ -185,6 +185,7 @@
"karma-firefox-launcher": "^2.1.3",
"karma-mocha": "^2.0.1",
"karma-sourcemap-loader": "^0.4.0",
+ "karma-spec-reporter": "^0.0.36",
"karma-webpack": "^5.0.0",
"lerna": "^8.2.2",
"lodash": "^4.17.21",
diff --git a/packages-internal/test-utils/src/focusVisible.ts b/packages-internal/test-utils/src/focusVisible.ts
index 1c6e10b23d1c29..9ef8f4934b5737 100644
--- a/packages-internal/test-utils/src/focusVisible.ts
+++ b/packages-internal/test-utils/src/focusVisible.ts
@@ -1,7 +1,7 @@
import { act, fireEvent } from './createRenderer';
-export default function focusVisible(element: HTMLElement) {
- act(() => {
+export default async function focusVisible(element: HTMLElement) {
+ await act(async () => {
element.blur();
fireEvent.keyDown(document.body, { key: 'Tab' });
element.focus();
diff --git a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx
index b8ff2c801884f9..adb6f340d46e03 100644
--- a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx
+++ b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx
@@ -97,18 +97,18 @@ describe('Joy ', () => {
});
describe('combobox', () => {
- it('should clear the input when blur', () => {
+ it('should clear the input when blur', async () => {
const { getByRole } = render();
const input = getByRole('combobox') as HTMLInputElement;
- act(() => {
+ await act(async () => {
input.focus();
fireEvent.change(document.activeElement!, { target: { value: 'a' } });
});
expect(input.value).to.equal('a');
- act(() => {
+ await act(async () => {
(document.activeElement as HTMLElement).blur();
});
expect(input.value).to.equal('');
@@ -237,7 +237,7 @@ describe('Joy ', () => {
});
describe('prop: limitTags', () => {
- it('show all items on focus', () => {
+ it('show all items on focus', async () => {
const { container, getAllByRole, getByRole } = render(
', () => {
// include hidden clear button because JSDOM thinks it's visible
expect(getAllByRole('button', { hidden: true })).to.have.lengthOf(4);
- act(() => {
+ await act(async () => {
getByRole('combobox').focus();
});
expect(container.textContent).to.equal('onetwothree');
@@ -261,7 +261,7 @@ describe('Joy ', () => {
}
});
- it('show 0 item on close when set 0 to limitTags', () => {
+ it('show 0 item on close when set 0 to limitTags', async () => {
const { container, getAllByRole, getByRole } = render(
', () => {
// include hidden clear button because JSDOM thinks it's visible
expect(getAllByRole('button', { hidden: true })).to.have.lengthOf(2);
- act(() => {
+ await act(async () => {
getByRole('combobox').focus();
});
expect(container.textContent).to.equal('onetwothree');
@@ -287,7 +287,7 @@ describe('Joy ', () => {
});
describe('prop: filterSelectedOptions', () => {
- it('when the last item is selected, highlights the new last item', () => {
+ it('when the last item is selected, highlights the new last item', async () => {
const { getByRole } = render(
', () => {
fireEvent.keyDown(textbox, { key: 'ArrowUp' });
checkHighlightIs(getByRole('listbox'), 'three');
fireEvent.keyDown(textbox, { key: 'Enter' }); // selects the last option (three)
- act(() => {
+ await act(async () => {
textbox.blur();
textbox.focus(); // opens the listbox again
});
@@ -310,7 +310,7 @@ describe('Joy ', () => {
});
describe('prop: autoSelect', () => {
- it('should not clear on blur when value does not match any option', () => {
+ it('should not clear on blur when value does not match any option', async () => {
const handleChange = spy();
const options = ['one', 'two'];
render(
@@ -321,7 +321,7 @@ describe('Joy ', () => {
fireEvent.change(textbox, { target: { value: 'o' } });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
fireEvent.change(textbox, { target: { value: 'oo' } });
- act(() => {
+ await act(async () => {
textbox.blur();
});
@@ -329,7 +329,7 @@ describe('Joy ', () => {
expect(handleChange.args[0][1]).to.deep.equal('oo');
});
- it('should add new value when autoSelect & multiple on blur', () => {
+ it('should add new value when autoSelect & multiple on blur', async () => {
const handleChange = spy();
const options = ['one', 'two'];
render(
@@ -345,7 +345,7 @@ describe('Joy ', () => {
);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
fireEvent.change(textbox, { target: { value: 't' } });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
textbox.blur();
@@ -355,7 +355,7 @@ describe('Joy ', () => {
expect(handleChange.args[0][1]).to.deep.equal(options);
});
- it('should add new value when autoSelect & multiple & freeSolo on blur', () => {
+ it('should add new value when autoSelect & multiple & freeSolo on blur', async () => {
const handleChange = spy();
render(
', () => {
);
fireEvent.change(document.activeElement!, { target: { value: 'a' } });
- act(() => {
+ await act(async () => {
(document.activeElement as HTMLElement).blur();
});
@@ -379,11 +379,11 @@ describe('Joy ', () => {
});
describe('prop: multiple', () => {
- it('should not crash', () => {
+ it('should not crash', async () => {
const { getByRole } = render();
const input = getByRole('combobox');
- act(() => {
+ await act(async () => {
input.focus();
(document.activeElement as HTMLElement).blur();
input.focus();
@@ -831,29 +831,29 @@ describe('Joy ', () => {
});
describe('prop: clearOnBlur', () => {
- it('should clear on blur', () => {
+ it('should clear on blur', async () => {
render();
const textbox = screen.getByRole('combobox') as HTMLInputElement;
fireEvent.change(textbox, { target: { value: 'test' } });
expect((document.activeElement as HTMLInputElement).value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('');
});
- it('should not clear on blur', () => {
+ it('should not clear on blur', async () => {
render();
const textbox = screen.getByRole('combobox') as HTMLInputElement;
fireEvent.change(textbox, { target: { value: 'test' } });
expect((document.activeElement as HTMLInputElement).value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('test');
});
- it('should not clear on blur with `multiple` enabled', () => {
+ it('should not clear on blur with `multiple` enabled', async () => {
render(
', () => {
const textbox = screen.getByRole('combobox') as HTMLInputElement;
fireEvent.change(textbox, { target: { value: 'test' } });
expect((document.activeElement as HTMLInputElement).value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('test');
@@ -947,7 +947,7 @@ describe('Joy ', () => {
});
describe('prop: openOnFocus', () => {
- it('enables open on input focus', () => {
+ it('enables open on input focus', async () => {
const { getByRole } = render(
,
);
@@ -960,7 +960,7 @@ describe('Joy ', () => {
fireEvent.click(textbox);
expect(textbox).to.have.attribute('aria-expanded', 'false');
- act(() => {
+ await act(async () => {
(document.activeElement as HTMLElement).blur();
});
@@ -1104,10 +1104,10 @@ describe('Joy ', () => {
expect(container.querySelector(`.${classes.root}`)).to.have.class(classes.hasPopupIcon);
});
- it('should close the popup when disabled is true', () => {
+ it('should close the popup when disabled is true', async () => {
const { setProps } = render();
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
@@ -1116,12 +1116,12 @@ describe('Joy ', () => {
expect(screen.queryByRole('listbox')).to.equal(null);
});
- it('should not crash when autoSelect & freeSolo are set, text is focused & disabled gets truthy', () => {
+ it('should not crash when autoSelect & freeSolo are set, text is focused & disabled gets truthy', async () => {
const { setProps } = render(
,
);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
setProps({ disabled: true });
@@ -1180,6 +1180,7 @@ describe('Joy ', () => {
{ id: '10', text: 'One' },
{ id: '20', text: 'Two' },
];
+
const options = [
{ id: '10', text: 'One' },
{ id: '20', text: 'Two' },
@@ -1235,6 +1236,7 @@ describe('Joy ', () => {
{ group: 2, value: 'F' },
{ group: 1, value: 'C' },
];
+
expect(() => {
render(
', () => {
});
describe('prop: options', () => {
- it('should scroll selected option into view when multiple elements with role as listbox available', function test() {
+ it('should scroll selected option into view when multiple elements with role as listbox available', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}
@@ -1304,6 +1306,7 @@ describe('Joy ', () => {
}}
autoFocus
/>
+
,
);
const select = getByRole('combobox');
- act(() => {
+ await act(async () => {
select.focus();
});
- act(() => {
+ await act(async () => {
select.blur();
});
@@ -114,7 +114,7 @@ describe('Joy ', () => {
expect(handleBlur.firstCall.returnValue).to.equal('blur-testing');
});
- it('should call onClose when the same option is selected', () => {
+ it('should call onClose when the same option is selected', async () => {
const handleChange = spy();
const handleClose = spy();
render(
@@ -124,7 +124,7 @@ describe('Joy ', () => {
,
);
- act(() => {
+ await act(async () => {
screen.getByRole('option', { selected: true }).click();
});
@@ -141,7 +141,7 @@ describe('Joy ', () => {
});
describe('prop: onChange', () => {
- it('should get selected value from the 2nd argument', () => {
+ it('should get selected value from the 2nd argument', async () => {
const onChangeHandler = spy();
const { getAllByRole, getByRole } = render(
@@ -151,7 +151,7 @@ describe('Joy ', () => {
,
);
fireEvent.click(getByRole('combobox'));
- act(() => {
+ await act(async () => {
getAllByRole('option')[1].click();
});
@@ -159,7 +159,7 @@ describe('Joy ', () => {
expect(onChangeHandler.args[0][1]).to.equal('1');
});
- it('should not be called if selected element has the current value (value did not change)', () => {
+ it('should not be called if selected element has the current value (value did not change)', async () => {
const onChangeHandler = spy();
const { getAllByRole, getByRole } = render(
@@ -169,7 +169,7 @@ describe('Joy ', () => {
,
);
fireEvent.click(getByRole('combobox'));
- act(() => {
+ await act(async () => {
getAllByRole('option')[1].click();
});
@@ -443,7 +443,7 @@ describe('Joy ', () => {
expect(onClick.callCount).to.equal(1);
});
- it('should not override the event.target on mouse events', () => {
+ it('should not override the event.target on mouse events', async () => {
const handleChange = spy();
const handleClick = spy();
render(
@@ -456,7 +456,7 @@ describe('Joy ', () => {
);
const options = screen.getAllByRole('option');
- act(() => {
+ await act(async () => {
options[0].click();
});
@@ -465,7 +465,7 @@ describe('Joy ', () => {
expect(handleClick.firstCall.args[0]).to.have.property('target', options[0]);
});
- it('should only select options', () => {
+ it('should only select options', async () => {
const handleChange = spy();
render(
@@ -476,7 +476,7 @@ describe('Joy ', () => {
);
const divider = screen.getByRole('separator');
- act(() => {
+ await act(async () => {
divider.click();
});
expect(handleChange.callCount).to.equal(0);
@@ -496,7 +496,7 @@ describe('Joy ', () => {
});
describe('form submission', () => {
- it('includes the Select value in the submitted form data when the `name` attribute is provided', function test() {
+ it('includes the Select value in the submitted form data when the `name` attribute is provided', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// FormData is not available in JSDOM
this.skip();
@@ -522,14 +522,14 @@ describe('Joy ', () => {
);
const button = getByText('Submit');
- act(() => {
+ await act(async () => {
button.click();
});
expect(isEventHandled).to.equal(true);
});
- it('transforms the selected value before posting using the getSerializedValue prop, if provided', function test() {
+ it('transforms the selected value before posting using the getSerializedValue prop, if provided', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// FormData is not available in JSDOM
this.skip();
@@ -558,14 +558,14 @@ describe('Joy ', () => {
);
const button = getByText('Submit');
- act(() => {
+ await act(async () => {
button.click();
});
expect(isEventHandled).to.equal(true);
});
- it('formats the object values as JSON before posting', function test() {
+ it('formats the object values as JSON before posting', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// FormData is not available in JSDOM
this.skip();
@@ -599,7 +599,7 @@ describe('Joy ', () => {
);
const button = getByText('Submit');
- act(() => {
+ await act(async () => {
button.click();
});
@@ -607,7 +607,7 @@ describe('Joy ', () => {
});
});
- it('should show dropdown if the children of the select button is clicked', () => {
+ it('should show dropdown if the children of the select button is clicked', async () => {
const { getByTestId, getByRole } = render(
', () => {
,
);
// Fire Click of the avatar
- act(() => {
+ await act(async () => {
fireEvent.click(getByTestId('test-element'));
});
expect(getByRole('combobox', { hidden: true })).to.have.attribute('aria-expanded', 'true');
// click again should close
- act(() => {
+ await act(async () => {
fireEvent.click(getByTestId('test-element'));
});
expect(getByRole('combobox', { hidden: true })).to.have.attribute('aria-expanded', 'false');
diff --git a/packages/mui-joy/src/Snackbar/Snackbar.test.tsx b/packages/mui-joy/src/Snackbar/Snackbar.test.tsx
index af55c7aa4e5d98..94006819994117 100644
--- a/packages/mui-joy/src/Snackbar/Snackbar.test.tsx
+++ b/packages/mui-joy/src/Snackbar/Snackbar.test.tsx
@@ -1,13 +1,23 @@
import * as React from 'react';
import { expect } from 'chai';
-import { spy } from 'sinon';
+import { SinonFakeTimers, spy, useFakeTimers } from 'sinon';
import { createRenderer, fireEvent, act } from '@mui/internal-test-utils';
import Snackbar, { snackbarClasses as classes } from '@mui/joy/Snackbar';
import { ThemeProvider } from '@mui/joy/styles';
import describeConformance from '../../test/describeConformance';
describe('Joy ', () => {
- const { render: clientRender, clock } = createRenderer({ clock: 'fake' });
+ let timer: SinonFakeTimers | null = null;
+
+ beforeEach(() => {
+ timer = useFakeTimers({ toFake: ['setTimeout', 'clearTimeout', 'Date'] });
+ });
+
+ afterEach(() => {
+ timer?.restore();
+ });
+
+ const { render: clientRender } = createRenderer();
/**
* @type {typeof plainRender extends (...args: infer T) => any ? T : never} args
@@ -19,9 +29,11 @@ describe('Joy ', () => {
* We have to defer the effect manually like `useEffect` would so we have to flush the effect manually instead of relying on `act()`.
* React bug: https://github.com/facebook/react/issues/20074
*/
- function render(...args: [React.ReactElement]) {
+ async function render(...args: [React.ReactElement]) {
const result = clientRender(...args);
- clock.tick(0);
+ await act(async () => {
+ await timer?.tickAsync(0);
+ });
return result;
}
@@ -30,7 +42,7 @@ describe('Joy ', () => {
Hello World!
,
() => ({
- render,
+ render: clientRender,
classes,
ThemeProvider,
muiName: 'JoySnackbar',
@@ -46,24 +58,26 @@ describe('Joy ', () => {
);
describe('prop: onClose', () => {
- it('should be called when clicking away', () => {
+ it('should be called when clicking away', async () => {
const handleClose = spy();
- render(
+ await render(
Message
,
);
const event = new window.Event('click', { bubbles: true, cancelable: true });
- document.body.dispatchEvent(event);
+ await act(async () => {
+ document.body.dispatchEvent(event);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([event, 'clickaway']);
});
- it('should be called when pressing Escape', () => {
+ it('should be called when pressing Escape', async () => {
const handleClose = spy();
- render(
+ await render(
Message
,
@@ -74,10 +88,10 @@ describe('Joy ', () => {
expect(handleClose.args[0][1]).to.equal('escapeKeyDown');
});
- it('can limit which Snackbars are closed when pressing Escape', () => {
+ it('can limit which Snackbars are closed when pressing Escape', async () => {
const handleCloseA = spy((event) => event.preventDefault());
const handleCloseB = spy();
- render(
+ await render(
Message A
@@ -96,10 +110,10 @@ describe('Joy ', () => {
});
describe('prop: autoHideDuration', () => {
- it('should call onClose when the timer is done', () => {
+ it('should call onClose when the timer is done', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- const { setProps } = render(
+ const { setProps } = await render(
Message
,
@@ -109,35 +123,41 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
});
- it('calls onClose at timeout even if the prop changes', () => {
+ it('calls onClose at timeout even if the prop changes', async () => {
const handleClose1 = spy();
const handleClose2 = spy();
const autoHideDuration = 2e3;
- const { setProps } = render(
+ const { setProps } = await render(
Message
,
);
setProps({ open: true });
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
setProps({ open: true, onClose: handleClose2 });
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
expect(handleClose1.callCount).to.equal(0);
expect(handleClose2.callCount).to.equal(1);
});
- it('should not call onClose when the autoHideDuration is reset', () => {
+ it('should not call onClose when the autoHideDuration is reset', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- const { setProps } = render(
+ const { setProps } = await render(
Message
,
@@ -147,17 +167,21 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
setProps({ autoHideDuration: undefined });
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
expect(handleClose.callCount).to.equal(0);
});
- it('should not call onClose if autoHideDuration is undefined', () => {
+ it('should not call onClose if autoHideDuration is undefined', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- render(
+ await render(
Message
,
@@ -165,16 +189,18 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(0);
});
- it('should not call onClose if autoHideDuration is null', () => {
+ it('should not call onClose if autoHideDuration is null', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- render(
+ await render(
Message
,
@@ -182,16 +208,18 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(0);
});
- it('should not call onClose when closed', () => {
+ it('should not call onClose when closed', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- const { setProps } = render(
+ const { setProps } = await render(
Message
,
@@ -199,9 +227,13 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
setProps({ open: false });
- clock.tick(autoHideDuration / 2);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
expect(handleClose.callCount).to.equal(0);
});
@@ -215,12 +247,16 @@ describe('Joy ', () => {
},
{
type: 'keyboard',
- enter: (container: HTMLElement) => act(() => container.querySelector('button')!.focus()),
- leave: (container: HTMLElement) => act(() => container.querySelector('button')!.blur()),
+ enter: async (container: HTMLElement) => {
+ await act(async () => container.querySelector('button')!.focus());
+ },
+ leave: async (container: HTMLElement) => {
+ await act(async () => container.querySelector('button')!.blur());
+ },
},
].forEach((userInteraction) => {
describe(`interacting with ${userInteraction.type}`, () => {
- it('should be able to interrupt the timer', () => {
+ it('should be able to interrupt the timer', async () => {
const handleMouseEnter = spy();
const handleMouseLeave = spy();
const handleBlur = spy();
@@ -228,7 +264,7 @@ describe('Joy ', () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- const { container } = render(
+ const { container } = await render(
undo}
open
@@ -245,8 +281,10 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration / 2);
- userInteraction.enter(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await await userInteraction.enter(container.querySelector('div')!);
if (userInteraction.type === 'keyboard') {
expect(handleFocus.callCount).to.equal(1);
@@ -254,8 +292,10 @@ describe('Joy ', () => {
expect(handleMouseEnter.callCount).to.equal(1);
}
- clock.tick(autoHideDuration / 2);
- userInteraction.leave(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await await userInteraction.leave(container.querySelector('div')!);
if (userInteraction.type === 'keyboard') {
expect(handleBlur.callCount).to.equal(1);
@@ -264,18 +304,20 @@ describe('Joy ', () => {
}
expect(handleClose.callCount).to.equal(0);
- clock.tick(2e3);
+ await act(async () => {
+ await timer?.tickAsync(2e3);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
});
- it('should not call onClose with not timeout after user interaction', () => {
+ it('should not call onClose with not timeout after user interaction', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
const resumeHideDuration = 3e3;
- const { container } = render(
+ const { container } = await render(
undo}
open
@@ -289,24 +331,30 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration / 2);
- userInteraction.enter(container.querySelector('div')!);
- clock.tick(autoHideDuration / 2);
- userInteraction.leave(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await userInteraction.enter(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await userInteraction.leave(container.querySelector('div')!);
expect(handleClose.callCount).to.equal(0);
- clock.tick(2e3);
+ await act(async () => {
+ await timer?.tickAsync(2e3);
+ });
expect(handleClose.callCount).to.equal(0);
});
- it('should call onClose when timer done after user interaction', () => {
+ it('should call onClose when timer done after user interaction', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
const resumeHideDuration = 3e3;
- const { container } = render(
+ const { container } = await render(
undo}
open
@@ -320,24 +368,30 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration / 2);
- userInteraction.enter(container.querySelector('div')!);
- clock.tick(autoHideDuration / 2);
- userInteraction.leave(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await userInteraction.enter(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration / 2);
+ });
+ await userInteraction.leave(container.querySelector('div')!);
expect(handleClose.callCount).to.equal(0);
- clock.tick(resumeHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(resumeHideDuration);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
});
- it('should call onClose immediately after user interaction when 0', () => {
+ it('should call onClose immediately after user interaction when 0', async () => {
const handleClose = spy();
const autoHideDuration = 6e3;
const resumeHideDuration = 0;
- const { setProps, container } = render(
+ const { setProps, container } = await render(
undo}
open
@@ -353,10 +407,14 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- userInteraction.enter(container.querySelector('div')!);
- clock.tick(100);
- userInteraction.leave(container.querySelector('div')!);
- clock.tick(resumeHideDuration);
+ await userInteraction.enter(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(100);
+ });
+ await userInteraction.leave(container.querySelector('div')!);
+ await act(async () => {
+ await timer?.tickAsync(resumeHideDuration);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
@@ -365,10 +423,10 @@ describe('Joy ', () => {
});
describe('prop: disableWindowBlurListener', () => {
- it('should pause auto hide when not disabled and window lost focus', () => {
+ it('should pause auto hide when not disabled and window lost focus', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- render(
+ await render(
', () => {
,
);
- act(() => {
+ await act(async () => {
const bEvent = new window.Event('blur', {
bubbles: false,
cancelable: false,
@@ -389,11 +447,13 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(0);
- act(() => {
+ await act(async () => {
const fEvent = new window.Event('focus', {
bubbles: false,
cancelable: false,
@@ -403,16 +463,18 @@ describe('Joy ', () => {
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
});
- it('should not pause auto hide when disabled and window lost focus', () => {
+ it('should not pause auto hide when disabled and window lost focus', async () => {
const handleClose = spy();
const autoHideDuration = 2e3;
- render(
+ await render(
', () => {
,
);
- act(() => {
+ await act(async () => {
const event = new window.Event('blur', { bubbles: false, cancelable: false });
window.dispatchEvent(event);
});
expect(handleClose.callCount).to.equal(0);
- clock.tick(autoHideDuration);
+ await act(async () => {
+ await timer?.tickAsync(autoHideDuration);
+ });
expect(handleClose.callCount).to.equal(1);
expect(handleClose.args[0]).to.deep.equal([null, 'timeout']);
@@ -438,13 +502,13 @@ describe('Joy ', () => {
});
describe('prop: open', () => {
- it('should not render anything when closed', () => {
- const { container } = render(Hello World!);
+ it('should not render anything when closed', async () => {
+ const { container } = await render(Hello World!);
expect(container).to.have.text('');
});
- it('should be able show it after mounted', () => {
- const { container, setProps } = render(Hello World!);
+ it('should be able show it after mounted', async () => {
+ const { container, setProps } = await render(Hello World!);
expect(container).to.have.text('');
setProps({ open: true });
expect(container).to.have.text('Hello World!');
diff --git a/packages/mui-joy/src/Switch/Switch.test.tsx b/packages/mui-joy/src/Switch/Switch.test.tsx
index d14a52403e2db0..357a4a6dc7187a 100644
--- a/packages/mui-joy/src/Switch/Switch.test.tsx
+++ b/packages/mui-joy/src/Switch/Switch.test.tsx
@@ -19,6 +19,7 @@ describe('', () => {
{ slotName: 'input', slotClassName: classes.input },
{ slotName: 'thumb', slotClassName: classes.thumb },
],
+
testVariantProps: { variant: 'soft' },
testCustomVariant: true,
refInstanceof: window.HTMLDivElement,
@@ -91,11 +92,11 @@ describe('', () => {
expect(getByRole('switch')).to.have.property('readOnly', true);
});
- it('the Checked state changes after change events', () => {
+ it('the Checked state changes after change events', async () => {
const { getByRole } = render();
// how a user would trigger it
- act(() => {
+ await act(async () => {
getByRole('switch').click();
fireEvent.change(getByRole('switch'), { target: { checked: '' } });
});
@@ -116,7 +117,7 @@ describe('', () => {
expect(getByText('bar')).toBeVisible();
});
- it('can receive startDecorator as function', () => {
+ it('can receive startDecorator as function', async () => {
const { getByText, getByRole } = render(
(checked ? 'On' : 'Off')} />,
);
@@ -124,7 +125,7 @@ describe('', () => {
expect(getByText('Off')).toBeVisible();
// how a user would trigger it
- act(() => {
+ await act(async () => {
getByRole('switch').click();
fireEvent.change(getByRole('switch'), { target: { checked: '' } });
});
@@ -132,7 +133,7 @@ describe('', () => {
expect(getByText('On')).toBeVisible();
});
- it('can receive endDecorator as function', () => {
+ it('can receive endDecorator as function', async () => {
const { getByText, getByRole } = render(
(checked ? 'On' : 'Off')} />,
);
@@ -140,7 +141,7 @@ describe('', () => {
expect(getByText('Off')).toBeVisible();
// how a user would trigger it
- act(() => {
+ await act(async () => {
getByRole('switch').click();
fireEvent.change(getByRole('switch'), { target: { checked: '' } });
});
diff --git a/packages/mui-joy/src/Textarea/Textarea.test.tsx b/packages/mui-joy/src/Textarea/Textarea.test.tsx
index 25f272d8b7939e..cae79a54ae9ad1 100644
--- a/packages/mui-joy/src/Textarea/Textarea.test.tsx
+++ b/packages/mui-joy/src/Textarea/Textarea.test.tsx
@@ -68,14 +68,14 @@ describe('Joy ', () => {
expect(container.firstChild).to.have.class(classes.disabled);
});
- it('should reset the focused state if getting disabled', () => {
+ it('should reset the focused state if getting disabled', async () => {
const handleBlur = spy();
const handleFocus = spy();
const { container, setProps } = render(
,
);
- act(() => {
+ await act(async () => {
container.querySelector('textarea')?.focus();
});
expect(handleFocus.callCount).to.equal(1);
@@ -88,14 +88,14 @@ describe('Joy ', () => {
});
describe('slotProps: input', () => {
- it('`onKeyDown` and `onKeyUp` should work', () => {
+ it('`onKeyDown` and `onKeyUp` should work', async () => {
const handleKeyDown = spy();
const handleKeyUp = spy();
const { container } = render(
,
);
- act(() => {
+ await act(async () => {
container.querySelector('textarea')!.focus();
});
fireEvent.keyDown(container.querySelector('textarea')!);
@@ -105,31 +105,31 @@ describe('Joy ', () => {
expect(handleKeyUp.callCount).to.equal(1);
});
- it('should call focus and blur', () => {
+ it('should call focus and blur', async () => {
const handleBlur = spy();
const handleFocus = spy();
const { container } = render(
,
);
- act(() => {
+ await act(async () => {
container.querySelector('textarea')!.focus();
});
expect(handleFocus.callCount).to.equal(1);
- act(() => {
+ await act(async () => {
container.querySelector('textarea')!.blur();
});
expect(handleFocus.callCount).to.equal(1);
});
- it('should override outer handlers', () => {
+ it('should override outer handlers', async () => {
const handleFocus = spy();
const handleSlotFocus = spy();
const { container } = render(
,
);
- act(() => {
+ await act(async () => {
container.querySelector('textarea')!.focus();
});
expect(handleFocus.callCount).to.equal(0);
diff --git a/packages/mui-joy/src/ToggleButtonGroup/ToggleButtonGroup.test.tsx b/packages/mui-joy/src/ToggleButtonGroup/ToggleButtonGroup.test.tsx
index b2b1a3068cbe5d..be83963fc145ec 100644
--- a/packages/mui-joy/src/ToggleButtonGroup/ToggleButtonGroup.test.tsx
+++ b/packages/mui-joy/src/ToggleButtonGroup/ToggleButtonGroup.test.tsx
@@ -46,7 +46,7 @@ describe('', () => {
expect(secondButton).to.have.property('disabled', true);
});
- it('should toggle the state when immediate children is not button', () => {
+ it('should toggle the state when immediate children is not button', async () => {
function CustomButton() {
return ;
}
@@ -80,17 +80,17 @@ describe('', () => {
const { getAllByRole } = render();
const [firstButton, secondButton, thirdButton, fourthButton] = getAllByRole('button');
- act(() => {
+ await act(async () => {
firstButton.click();
});
expect(handleChange.args[0][1]).to.have.members(['tooltip-button']);
expect(firstButton).to.have.attribute('aria-pressed', 'true');
- act(() => {
+ await act(async () => {
secondButton.click();
});
expect(handleChange.args[1][1]).to.have.members(['tooltip-button', 'custom-button']);
expect(secondButton).to.have.attribute('aria-pressed', 'true');
- act(() => {
+ await act(async () => {
thirdButton.click();
});
expect(handleChange.args[2][1]).to.have.members([
@@ -99,7 +99,7 @@ describe('', () => {
'custom-iconbutton',
]);
expect(thirdButton).to.have.attribute('aria-pressed', 'true');
- act(() => {
+ await act(async () => {
fourthButton.click();
});
expect(handleChange.args[3][1]).to.have.members([
diff --git a/packages/mui-joy/src/Tooltip/Tooltip.test.tsx b/packages/mui-joy/src/Tooltip/Tooltip.test.tsx
index 6f2f6476fc30a4..3fe67ed328d2e7 100644
--- a/packages/mui-joy/src/Tooltip/Tooltip.test.tsx
+++ b/packages/mui-joy/src/Tooltip/Tooltip.test.tsx
@@ -138,7 +138,7 @@ describe('', () => {
describe('focus', () => {
// https://github.com/mui/mui-x/issues/12248
- it('should support event handlers with extra parameters', () => {
+ it('should support event handlers with extra parameters', async () => {
const handleFocus = spy((event, extra) => extra);
const handleBlur = spy((event, ...params) => params);
@@ -167,14 +167,14 @@ describe('', () => {
);
const input = getByRole('textbox');
- act(() => {
+ await act(async () => {
input.focus();
});
expect(handleFocus.callCount).to.equal(1);
expect(handleFocus.returnValues[0]).to.equal('focus');
- act(() => {
+ await act(async () => {
input.blur();
});
diff --git a/packages/mui-material/src/AccordionSummary/AccordionSummary.test.js b/packages/mui-material/src/AccordionSummary/AccordionSummary.test.js
index f0279b38dd8ee4..14137bf7fba154 100644
--- a/packages/mui-material/src/AccordionSummary/AccordionSummary.test.js
+++ b/packages/mui-material/src/AccordionSummary/AccordionSummary.test.js
@@ -77,11 +77,11 @@ describe('', () => {
);
});
- it('should fire onBlur when the button blurs', () => {
+ it('should fire onBlur when the button blurs', async () => {
const handleBlur = spy();
const { getByRole } = render();
- act(() => {
+ await act(async () => {
const button = getByRole('button');
button.focus();
button.blur();
@@ -99,7 +99,7 @@ describe('', () => {
expect(handleClick.callCount).to.equal(1);
});
- it('fires onChange of the Accordion if clicked', () => {
+ it('fires onChange of the Accordion if clicked', async () => {
const handleChange = spy();
const { getByRole } = render(
@@ -107,14 +107,14 @@ describe('', () => {
,
);
- act(() => {
+ await act(async () => {
getByRole('button').click();
});
expect(handleChange.callCount).to.equal(1);
});
- it('calls onFocusVisible if focused visibly', function test() {
+ it('calls onFocusVisible if focused visibly', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// JSDOM doesn't support :focus-visible
this.skip();
@@ -127,7 +127,7 @@ describe('', () => {
// this doesn't actually apply focus like in the browser. we need to move focus manually
fireEvent.keyDown(document.body, { key: 'Tab' });
- act(() => {
+ await act(async () => {
getByRole('button').focus();
});
diff --git a/packages/mui-material/src/Autocomplete/Autocomplete.test.js b/packages/mui-material/src/Autocomplete/Autocomplete.test.js
index 4184039129eb83..a8d7ecf26af1b8 100644
--- a/packages/mui-material/src/Autocomplete/Autocomplete.test.js
+++ b/packages/mui-material/src/Autocomplete/Autocomplete.test.js
@@ -49,6 +49,7 @@ describe('', () => {
open
renderInput={(params) => }
/>,
+
() => ({
classes,
inheritComponent: 'div',
@@ -75,6 +76,7 @@ describe('', () => {
open
renderInput={(params) => }
/>,
+
() => ({
classes,
render,
@@ -95,6 +97,7 @@ describe('', () => {
open
renderInput={(params) => }
/>,
+
() => ({
classes,
render,
@@ -158,20 +161,20 @@ describe('', () => {
});
describe('combobox', () => {
- it('should clear the input when blur', () => {
+ it('should clear the input when blur', async () => {
const { getByRole } = render(
} />,
);
const input = getByRole('combobox');
- act(() => {
+ await act(async () => {
input.focus();
fireEvent.change(document.activeElement, { target: { value: 'a' } });
});
expect(input.value).to.equal('a');
- act(() => {
+ await act(async () => {
document.activeElement.blur();
});
expect(input.value).to.equal('');
@@ -295,7 +298,7 @@ describe('', () => {
});
// https://github.com/mui/material-ui/issues/34998
- it('should scroll the listbox to the top when keyboard highlight wraps around after the last item is highlighted', function test() {
+ it('should scroll the listbox to the top when keyboard highlight wraps around after the last item is highlighted', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}
@@ -313,7 +316,7 @@ describe('', () => {
/>,
);
const textbox = getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
@@ -392,7 +395,7 @@ describe('', () => {
});
describe('prop: limitTags', () => {
- it('show all items on focus', () => {
+ it('show all items on focus', async () => {
const { container, getAllByRole, getByRole } = render(
', () => {
// include hidden clear button because JSDOM thinks it's visible
expect(getAllByRole('button', { hidden: true })).to.have.lengthOf(4);
- act(() => {
+ await act(async () => {
getByRole('combobox').focus();
});
expect(container.textContent).to.equal('onetwothree');
@@ -417,7 +420,7 @@ describe('', () => {
}
});
- it('show 0 item on close when set 0 to limitTags', () => {
+ it('show 0 item on close when set 0 to limitTags', async () => {
const { container, getAllByRole, getByRole } = render(
', () => {
// include hidden clear button because JSDOM thinks it's visible
expect(getAllByRole('button', { hidden: true })).to.have.lengthOf(2);
- act(() => {
+ await act(async () => {
getByRole('combobox').focus();
});
expect(container.textContent).to.equal('onetwothree');
@@ -444,7 +447,7 @@ describe('', () => {
});
describe('prop: filterSelectedOptions', () => {
- it('when the last item is selected, highlights the new last item', () => {
+ it('when the last item is selected, highlights the new last item', async () => {
const { getByRole } = render(
', () => {
checkHighlightIs(getByRole('listbox'), 'three');
fireEvent.keyDown(textbox, { key: 'Enter' }); // selects the last option (three)
- act(() => {
+ await act(async () => {
textbox.blur();
textbox.focus(); // opens the listbox again
});
@@ -468,7 +471,7 @@ describe('', () => {
});
describe('prop: autoSelect', () => {
- it('should not clear on blur when value does not match any option', () => {
+ it('should not clear on blur when value does not match any option', async () => {
const handleChange = spy();
const options = ['one', 'two'];
render(
@@ -485,7 +488,7 @@ describe('', () => {
fireEvent.change(textbox, { target: { value: 'o' } });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
fireEvent.change(textbox, { target: { value: 'oo' } });
- act(() => {
+ await act(async () => {
textbox.blur();
});
@@ -493,7 +496,7 @@ describe('', () => {
expect(handleChange.args[0][1]).to.deep.equal('oo');
});
- it('should add new value when autoSelect & multiple on blur', () => {
+ it('should add new value when autoSelect & multiple on blur', async () => {
const handleChange = spy();
const options = ['one', 'two'];
render(
@@ -509,7 +512,7 @@ describe('', () => {
);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
fireEvent.change(textbox, { target: { value: 't' } });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
textbox.blur();
@@ -519,7 +522,7 @@ describe('', () => {
expect(handleChange.args[0][1]).to.deep.equal(options);
});
- it('should add new value when autoSelect & multiple & freeSolo on blur', () => {
+ it('should add new value when autoSelect & multiple & freeSolo on blur', async () => {
const handleChange = spy();
render(
', () => {
);
fireEvent.change(document.activeElement, { target: { value: 'a' } });
- act(() => {
+ await act(async () => {
document.activeElement.blur();
});
@@ -543,7 +546,7 @@ describe('', () => {
});
describe('prop: multiple', () => {
- it('should not crash', () => {
+ it('should not crash', async () => {
const { getByRole } = render(
', () => {
);
const input = getByRole('combobox');
- act(() => {
+ await act(async () => {
input.focus();
document.activeElement.blur();
input.focus();
@@ -769,6 +772,7 @@ describe('', () => {
renderInput={(params) => }
value={[]}
/>
+
,
);
@@ -795,6 +799,7 @@ describe('', () => {
renderInput={(params) => }
value={['one']}
/>
+
,
);
@@ -1245,7 +1250,7 @@ describe('', () => {
});
describe('prop: clearOnBlur', () => {
- it('should clear on blur', () => {
+ it('should clear on blur', async () => {
render(
', () => {
const textbox = screen.getByRole('combobox');
fireEvent.change(textbox, { target: { value: 'test' } });
expect(document.activeElement.value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('');
});
- it('should not clear on blur', () => {
+ it('should not clear on blur', async () => {
render(
', () => {
const textbox = screen.getByRole('combobox');
fireEvent.change(textbox, { target: { value: 'test' } });
expect(document.activeElement.value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('test');
});
- it('should not clear on blur with `multiple` enabled', () => {
+ it('should not clear on blur with `multiple` enabled', async () => {
render(
', () => {
const textbox = screen.getByRole('combobox');
fireEvent.change(textbox, { target: { value: 'test' } });
expect(document.activeElement.value).to.equal('test');
- act(() => {
+ await act(async () => {
textbox.blur();
});
expect(textbox.value).to.equal('test');
@@ -1404,7 +1409,7 @@ describe('', () => {
});
describe('prop: openOnFocus', () => {
- it('enables open on input focus', () => {
+ it('enables open on input focus', async () => {
const { getByRole } = render(
', () => {
fireEvent.click(textbox);
expect(textbox).to.have.attribute('aria-expanded', 'false');
- act(() => {
+ await act(async () => {
document.activeElement.blur();
});
@@ -1694,7 +1699,7 @@ describe('', () => {
expect(container.querySelector(`.${classes.root}`)).to.have.class(classes.hasPopupIcon);
});
- it('should close the popup when disabled is true', () => {
+ it('should close the popup when disabled is true', async () => {
const { setProps } = render(
', () => {
/>,
);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
@@ -1711,7 +1716,7 @@ describe('', () => {
expect(screen.queryByRole('listbox')).to.equal(null);
});
- it('should not crash when autoSelect & freeSolo are set, text is focused & disabled gets truthy', () => {
+ it('should not crash when autoSelect & freeSolo are set, text is focused & disabled gets truthy', async () => {
const { setProps } = render(
', () => {
/>,
);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
setProps({ disabled: true });
@@ -1785,6 +1790,7 @@ describe('', () => {
{ id: '10', text: 'One' },
{ id: '20', text: 'Two' },
];
+
const options = [
{ id: '10', text: 'One' },
{ id: '20', text: 'Two' },
@@ -1821,6 +1827,7 @@ describe('', () => {
{ group: 2, value: 'F' },
{ group: 1, value: 'C' },
];
+
expect(() => {
render(
', () => {
label: 'one',
},
];
+
const handleChange = spy();
const { getByRole } = render(
', () => {
expect(textbox.selectionEnd).to.equal(3);
});
- it('should focus the input when clicking on the open action', () => {
+ it('should focus the input when clicking on the open action', async () => {
const { getByRole, queryByTitle } = render(
', () => {
fireEvent.click(textbox);
expect(textbox).toHaveFocus();
- act(() => {
+ await act(async () => {
textbox.blur();
});
fireEvent.click(queryByTitle('Open'));
@@ -2232,7 +2240,7 @@ describe('', () => {
expect(textbox).to.have.attribute('aria-expanded', 'true');
});
- it('should not focus when tooltip clicked', () => {
+ it('should not focus when tooltip clicked', async () => {
const { getByRole, getByText } = render(
', () => {
const textbox = getByRole('combobox');
const tooltip = getByText('tooltip');
- act(() => {
+ await act(async () => {
fireEvent.click(tooltip);
});
@@ -2528,7 +2536,7 @@ describe('', () => {
expect(handleChange.args[0][3]).to.deep.equal({ option: options[2] });
});
- it('provides a reason and details on blur', () => {
+ it('provides a reason and details on blur', async () => {
const handleChange = spy();
const options = ['one', 'two', 'three'];
render(
@@ -2543,7 +2551,7 @@ describe('', () => {
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
- act(() => {
+ await act(async () => {
textbox.blur();
});
@@ -2610,6 +2618,7 @@ describe('', () => {
renderInput={(params) => }
value={value}
/>
+
@@ -3229,7 +3238,7 @@ describe('', () => {
expect(container.querySelector(`.${classes.root}`)).to.have.class(classes.hasPopupIcon);
});
- it('should focus on input when clicked', () => {
+ it('should focus on input when clicked', async () => {
render(
', () => {
fireEvent.click(textbox);
expect(textbox).toHaveFocus();
- act(() => {
+ await act(async () => {
textbox.blur();
});
fireEvent.click(screen.queryByTitle('Open'));
@@ -3264,7 +3273,7 @@ describe('', () => {
expect(screen.queryByRole('listbox')).to.equal(null);
});
- it('should not be able to delete the tag when multiple=true', () => {
+ it('should not be able to delete the tag when multiple=true', async () => {
const { container } = render(
', () => {
expect(chip).not.to.have.class(chipClasses.deletable);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
expect(container.querySelectorAll(`.${chipClasses.root}`)).to.have.length(2);
@@ -3287,7 +3296,7 @@ describe('', () => {
expect(container.querySelectorAll(`.${chipClasses.root}`)).to.have.length(2);
});
- it('should not be able to delete the tag using Backspace when using renderValue', () => {
+ it('should not be able to delete the tag using Backspace when using renderValue', async () => {
const { container } = render(
', () => {
expect(chip).not.to.have.class(chipClasses.deletable);
const textbox = screen.getByRole('combobox');
- act(() => {
+ await act(async () => {
textbox.focus();
});
@@ -3443,7 +3452,7 @@ describe('', () => {
});
// https://github.com/mui/material-ui/issues/36212
- it('should preserve scrollTop position of the listbox when adding new options on mobile', function test() {
+ it('should preserve scrollTop position of the listbox when adding new options on mobile', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}
@@ -3466,7 +3475,7 @@ describe('', () => {
expect(listbox).to.have.property('scrollTop', 0);
const options = getAllByRole('option');
- act(() => {
+ await act(async () => {
fireEvent.touchStart(options[1]);
listbox.scrollBy(0, 60);
setProps({ options: getOptions(10) });
diff --git a/packages/mui-material/src/Breadcrumbs/Breadcrumbs.test.js b/packages/mui-material/src/Breadcrumbs/Breadcrumbs.test.js
index 3308455a9c7e24..942398ce772493 100644
--- a/packages/mui-material/src/Breadcrumbs/Breadcrumbs.test.js
+++ b/packages/mui-material/src/Breadcrumbs/Breadcrumbs.test.js
@@ -59,7 +59,7 @@ describe('', () => {
expect(getByRole('button').querySelector('[data-testid="MoreHorizIcon"]')).not.to.equal(null);
});
- it('should expand when `BreadcrumbCollapsed` is clicked', () => {
+ it('should expand when `BreadcrumbCollapsed` is clicked', async () => {
const { getAllByRole, getByRole, getByText } = render(
first
@@ -74,7 +74,7 @@ describe('', () => {
,
);
- act(() => {
+ await act(async () => {
getByRole('button').click();
});
diff --git a/packages/mui-material/src/ButtonBase/ButtonBase.test.js b/packages/mui-material/src/ButtonBase/ButtonBase.test.js
index 280c78a13e41c9..cf35e51b143dc8 100644
--- a/packages/mui-material/src/ButtonBase/ButtonBase.test.js
+++ b/packages/mui-material/src/ButtonBase/ButtonBase.test.js
@@ -256,7 +256,7 @@ describe('', () => {
});
describe('interactions', () => {
- it('should not have a focus ripple by default', () => {
+ it('should not have a focus ripple by default', async () => {
const { getByRole } = render(
', () => {
const button = getByRole('button');
simulatePointerDevice();
- focusVisible(button);
+ await focusVisible(button);
expect(button.querySelectorAll('.ripple-pulsate')).to.have.lengthOf(0);
});
@@ -744,7 +744,7 @@ describe('', () => {
expect(getByText('Hello')).to.have.property('disabled', true);
});
- it('should reset the focused state', function test() {
+ it('should reset the focused state', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// JSDOM doesn't support :focus-visible
this.skip();
@@ -754,7 +754,7 @@ describe('', () => {
const button = getByText('Hello');
simulatePointerDevice();
- focusVisible(button);
+ await focusVisible(button);
expect(button).to.have.class(classes.focusVisible);
@@ -839,12 +839,12 @@ describe('', () => {
expect(button).not.to.have.class(classes.focusVisible);
}
- focusVisible(button);
+ await focusVisible(button);
expect(button).to.have.class(classes.focusVisible);
});
- it('removes focus-visible if focus is re-targetted', function test() {
+ it('removes focus-visible if focus is re-targetted', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// JSDOM doesn't support :focus-visible
this.skip();
@@ -887,14 +887,14 @@ describe('', () => {
const focusRetarget = getByText('you cannot escape me');
simulatePointerDevice();
- focusVisible(buttonBase);
+ await focusVisible(buttonBase);
expect(focusRetarget).toHaveFocus();
expect(eventLog).to.deep.equal(['focus-visible', 'focus', 'blur']);
expect(buttonBase).not.to.have.class(classes.focusVisible);
});
- it('onFocusVisibleHandler() should propagate call to onFocusVisible prop', function test() {
+ it('onFocusVisibleHandler() should propagate call to onFocusVisible prop', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// JSDOM doesn't support :focus-visible
this.skip();
@@ -908,7 +908,7 @@ describe('', () => {
);
simulatePointerDevice();
- focusVisible(getByRole('button'));
+ await focusVisible(getByRole('button'));
expect(onFocusVisibleSpy.calledOnce).to.equal(true);
expect(onFocusVisibleSpy.firstCall.args).to.have.lengthOf(1);
diff --git a/packages/mui-material/src/ButtonBase/TouchRipple.test.js b/packages/mui-material/src/ButtonBase/TouchRipple.test.js
index c2948f1b3dd481..68a3c26ef052f8 100644
--- a/packages/mui-material/src/ButtonBase/TouchRipple.test.js
+++ b/packages/mui-material/src/ButtonBase/TouchRipple.test.js
@@ -58,10 +58,10 @@ describe('', () => {
}));
describe('prop: center', () => {
- it('should compute the right ripple dimensions', () => {
+ it('should compute the right ripple dimensions', async () => {
const { instance, queryRipple } = renderTouchRipple({ center: true });
- act(() => {
+ await act(async () => {
instance.start(
{},
{
@@ -76,48 +76,48 @@ describe('', () => {
});
});
- it('should create individual ripples', () => {
+ it('should create individual ripples', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples } = renderTouchRipple();
expect(queryAllActiveRipples()).to.have.lengthOf(0);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.start({ clientX: 0, clientY: 0 }, cb);
});
expect(queryAllActiveRipples()).to.have.lengthOf(1);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.start({ clientX: 0, clientY: 0 }, cb);
});
expect(queryAllActiveRipples()).to.have.lengthOf(2);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.start({ clientX: 0, clientY: 0 }, cb);
});
expect(queryAllActiveRipples()).to.have.lengthOf(3);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.stop({ type: 'mouseup' });
});
expect(queryAllActiveRipples()).to.have.lengthOf(2);
expect(queryAllStoppingRipples()).to.have.lengthOf(1);
- act(() => {
+ await act(async () => {
instance.stop({ type: 'mouseup' });
});
expect(queryAllActiveRipples()).to.have.lengthOf(1);
expect(queryAllStoppingRipples()).to.have.lengthOf(2);
- act(() => {
+ await act(async () => {
instance.stop({ type: 'mouseup' });
});
@@ -126,10 +126,10 @@ describe('', () => {
});
describe('creating unique ripples', () => {
- it('should create a ripple', () => {
+ it('should create a ripple', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples } = renderTouchRipple();
- act(() => {
+ await act(async () => {
instance.start(
{},
{
@@ -144,10 +144,10 @@ describe('', () => {
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
});
- it('should ignore a mousedown event after a touchstart event', () => {
+ it('should ignore a mousedown event after a touchstart event', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples } = renderTouchRipple();
- act(() => {
+ await act(async () => {
instance.start({ type: 'touchstart' }, cb);
instance.start({ type: 'mousedown' }, cb);
});
@@ -156,7 +156,7 @@ describe('', () => {
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
});
- it('should create a specific ripple', () => {
+ it('should create a specific ripple', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples, queryRipple } =
renderTouchRipple({
center: true,
@@ -164,7 +164,7 @@ describe('', () => {
const clientX = 1;
const clientY = 1;
- act(() => {
+ await act(async () => {
instance.start({ clientX, clientY }, { fakeElement: true }, cb);
});
@@ -178,13 +178,13 @@ describe('', () => {
describe('mobile', () => {
clock.withFakeTimers();
- it('should delay the display of the ripples', () => {
+ it('should delay the display of the ripples', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples } = renderTouchRipple();
expect(queryAllActiveRipples()).to.have.lengthOf(0);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.start({ touches: [], clientX: 0, clientY: 0 }, { fakeElement: true }, cb);
});
@@ -197,7 +197,7 @@ describe('', () => {
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
clock.tick(DELAY_RIPPLE);
- act(() => {
+ await act(async () => {
instance.stop({ type: 'touchend' }, cb);
});
@@ -205,13 +205,13 @@ describe('', () => {
expect(queryAllStoppingRipples()).to.have.lengthOf(1);
});
- it('should trigger the ripple for short touch interactions', () => {
+ it('should trigger the ripple for short touch interactions', async () => {
const { instance, queryAllActiveRipples, queryAllStoppingRipples } = renderTouchRipple();
expect(queryAllActiveRipples()).to.have.lengthOf(0);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.start({ touches: [], clientX: 0, clientY: 0 }, { fakeElement: true }, cb);
});
@@ -223,7 +223,7 @@ describe('', () => {
expect(queryAllActiveRipples()).to.have.lengthOf(0);
expect(queryAllStoppingRipples()).to.have.lengthOf(0);
- act(() => {
+ await act(async () => {
instance.stop({ type: 'touchend' }, cb);
});
diff --git a/packages/mui-material/src/Checkbox/Checkbox.test.js b/packages/mui-material/src/Checkbox/Checkbox.test.js
index 49599c9108aede..bab172f62c6c31 100644
--- a/packages/mui-material/src/Checkbox/Checkbox.test.js
+++ b/packages/mui-material/src/Checkbox/Checkbox.test.js
@@ -54,11 +54,11 @@ describe('', () => {
expect(getByRole('checkbox')).to.have.property('checked', true);
});
- it('flips the checked property when clicked and calls onchange with the checked state', () => {
+ it('flips the checked property when clicked and calls onchange with the checked state', async () => {
const handleChange = spy();
const { getByRole } = render();
- act(() => {
+ await act(async () => {
getByRole('checkbox').click();
});
@@ -66,7 +66,7 @@ describe('', () => {
expect(handleChange.callCount).to.equal(1);
expect(handleChange.getCall(0).args[0].target).to.have.property('checked', true);
- act(() => {
+ await act(async () => {
getByRole('checkbox').click();
});
diff --git a/packages/mui-material/src/Chip/Chip.test.js b/packages/mui-material/src/Chip/Chip.test.js
index aa695a6de9aabb..c609414eb00eb6 100644
--- a/packages/mui-material/src/Chip/Chip.test.js
+++ b/packages/mui-material/src/Chip/Chip.test.js
@@ -174,7 +174,7 @@ describe('', () => {
expect(chip).to.have.class(classes.filledPrimary);
});
- it('should not be focused when a deletable chip is disabled and skipFocusWhenDisabled is true', () => {
+ it('should not be focused when a deletable chip is disabled and skipFocusWhenDisabled is true', async () => {
const { getByTestId } = render(
', () => {
const chip = getByTestId('chip');
simulatePointerDevice();
- act(() => {
+ await act(async () => {
fireEvent.keyDown(document.body, { key: 'Tab' });
});
@@ -431,11 +431,11 @@ describe('', () => {
});
describe('reacts to keyboard chip', () => {
- it('should call onKeyDown when a key is pressed', () => {
+ it('should call onKeyDown when a key is pressed', async () => {
const handleKeydown = stub().callsFake((event) => event.key);
const { getByRole } = render( {}} onKeyDown={handleKeydown} />);
const chip = getByRole('button');
- act(() => {
+ await act(async () => {
chip.focus();
});
@@ -445,11 +445,11 @@ describe('', () => {
expect(handleKeydown.firstCall.returnValue).to.equal('p');
});
- it('should call onClick when `space` is released ', () => {
+ it('should call onClick when `space` is released ', async () => {
const handleClick = spy();
const { getByRole } = render();
const chip = getByRole('button');
- act(() => {
+ await act(async () => {
chip.focus();
});
@@ -458,11 +458,11 @@ describe('', () => {
expect(handleClick.callCount).to.equal(1);
});
- it('should call onClick when `enter` is pressed ', () => {
+ it('should call onClick when `enter` is pressed ', async () => {
const handleClick = spy();
const { getByRole } = render();
const chip = getByRole('button');
- act(() => {
+ await act(async () => {
chip.focus();
});
@@ -473,14 +473,14 @@ describe('', () => {
describe('prop: onDelete', () => {
['Backspace', 'Delete'].forEach((key) => {
- it(`should call onDelete '${key}' is released`, () => {
+ it(`should call onDelete '${key}' is released`, async () => {
const handleDelete = spy();
const handleKeyDown = spy();
const { getAllByRole } = render(
{}} onKeyDown={handleKeyDown} onDelete={handleDelete} />,
);
const chip = getAllByRole('button')[0];
- act(() => {
+ await act(async () => {
chip.focus();
});
@@ -497,12 +497,12 @@ describe('', () => {
});
});
- it('should not prevent default on input', () => {
+ it('should not prevent default on input', async () => {
const handleKeyDown = spy();
const { container } = render(} onKeyDown={handleKeyDown} />);
const input = container.querySelector('input');
- act(() => {
+ await act(async () => {
input.focus();
});
fireEvent.keyDown(input, { key: 'Backspace' });
@@ -671,14 +671,14 @@ describe('', () => {
}
});
- it('has a focus-visible polyfill', () => {
+ it('has a focus-visible polyfill', async () => {
const { container } = render( {}} />);
const chip = container.querySelector(`.${classes.root}`);
simulatePointerDevice();
expect(chip).not.to.have.class(classes.focusVisible);
- act(() => {
+ await act(async () => {
chip.focus();
});
@@ -688,17 +688,17 @@ describe('', () => {
expect(chip).not.to.have.class(classes.focusVisible);
}
- focusVisible(chip);
+ await focusVisible(chip);
expect(chip).to.have.class(classes.focusVisible);
});
- it('should reset the focused state', () => {
+ it('should reset the focused state', async () => {
const { container, setProps } = render( {}} />);
const chip = container.querySelector(`.${classes.root}`);
simulatePointerDevice();
- focusVisible(chip);
+ await focusVisible(chip);
expect(chip).to.have.class(classes.focusVisible);
diff --git a/packages/mui-material/src/ClickAwayListener/ClickAwayListener.test.js b/packages/mui-material/src/ClickAwayListener/ClickAwayListener.test.js
index e0c4c3730a4a82..238e411f395ce7 100644
--- a/packages/mui-material/src/ClickAwayListener/ClickAwayListener.test.js
+++ b/packages/mui-material/src/ClickAwayListener/ClickAwayListener.test.js
@@ -1,7 +1,7 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { expect } from 'chai';
-import { spy } from 'sinon';
+import { spy, useFakeTimers } from 'sinon';
import {
act,
createRenderer,
@@ -13,35 +13,48 @@ import Portal from '@mui/material/Portal';
import ClickAwayListener from '@mui/material/ClickAwayListener';
describe('', () => {
- const { render: clientRender, clock } = createRenderer({ clock: 'fake' });
+ /** @type {import('sinon').SinonFakeTimers | null} */
+ let timer = null;
+
+ beforeEach(() => {
+ timer = useFakeTimers({ toFake: ['setTimeout', 'clearTimeout', 'Date'] });
+ });
+
+ afterEach(() => {
+ timer?.restore();
+ });
+
+ const { render: clientRender } = createRenderer();
/**
- * @type {typeof plainRender extends (...args: infer T) => any ? T : never} args
+ * @type {typeof clientRender}
*
* @remarks
* This is for all intents and purposes the same as our client render method.
- * `plainRender` is already wrapped in act().
+ * `clientRender` is already wrapped in act().
* However, React has a bug that flushes effects in a portal synchronously.
* We have to defer the effect manually like `useEffect` would so we have to flush the effect manually instead of relying on `act()`.
* React bug: https://github.com/facebook/react/issues/20074
*/
- function render(...args) {
+ async function render(...args) {
const result = clientRender(...args);
- clock.tick(0);
+ await act(async () => {
+ await timer?.tickAsync(0);
+ });
return result;
}
- it('should render the children', () => {
+ it('should render the children', async () => {
const children = ;
- const { container } = render(
+ const { container } = await render(
{}}>{children},
);
expect(container.querySelectorAll('span').length).to.equal(1);
});
describe('prop: onClickAway', () => {
- it('should be called when clicking away', () => {
+ it('should be called when clicking away', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -52,9 +65,9 @@ describe('', () => {
expect(handleClickAway.args[0].length).to.equal(1);
});
- it('should not be called when clicking inside', () => {
+ it('should not be called when clicking inside', async () => {
const handleClickAway = spy();
- const { container } = render(
+ const { container } = await render(
,
@@ -64,9 +77,9 @@ describe('', () => {
expect(handleClickAway.callCount).to.equal(0);
});
- it('should be called when preventDefault is `true`', () => {
+ it('should be called when preventDefault is `true`', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -80,9 +93,9 @@ describe('', () => {
document.body.removeEventListener('click', preventDefault);
});
- it('should not be called when clicking inside a portaled element', () => {
+ it('should not be called when clicking inside a portaled element', async () => {
const handleClickAway = spy();
- const { getByText } = render(
+ const { getByText } = await render(
@@ -96,9 +109,9 @@ describe('', () => {
expect(handleClickAway.callCount).to.equal(0);
});
- it('should be called when clicking inside a portaled element and `disableReactTree` is `true`', () => {
+ it('should be called when clicking inside a portaled element and `disableReactTree` is `true`', async () => {
const handleClickAway = spy();
- const { getByText } = render(
+ const { getByText } = await render(
@@ -112,9 +125,9 @@ describe('', () => {
expect(handleClickAway.callCount).to.equal(1);
});
- it('should not be called even if the event propagation is stopped', () => {
+ it('should not be called even if the event propagation is stopped', async () => {
const handleClickAway = spy();
- const { getByText } = render(
+ const { getByText } = await render(
', () => {
});
['onClick', 'onClickCapture'].forEach((eventListenerName) => {
- it(`should not be called when ${eventListenerName} mounted the listener`, () => {
+ it(`should not be called when ${eventListenerName} mounted the listener`, async () => {
function Test() {
const [open, setOpen] = React.useState(false);
@@ -177,7 +190,7 @@ describe('', () => {
);
}
- render();
+ await render();
fireDiscreteEvent.click(screen.getByTestId('trigger'));
@@ -185,7 +198,7 @@ describe('', () => {
});
});
- it('should be called if an element is interleaved between mousedown and mouseup', () => {
+ it('should be called if an element is interleaved between mousedown and mouseup', async () => {
/**
* @param {Element} element
* @returns {Element[]}
@@ -240,7 +253,7 @@ describe('', () => {
);
}
- render();
+ await render();
const mouseDownTarget = screen.getByTestId('trigger');
fireDiscreteEvent.mouseDown(mouseDownTarget);
@@ -255,9 +268,9 @@ describe('', () => {
});
describe('prop: mouseEvent', () => {
- it('should not call `props.onClickAway` when `props.mouseEvent` is `false`', () => {
+ it('should not call `props.onClickAway` when `props.mouseEvent` is `false`', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -266,9 +279,9 @@ describe('', () => {
expect(handleClickAway.callCount).to.equal(0);
});
- it('should call `props.onClickAway` when mouse down is triggered', () => {
+ it('should call `props.onClickAway` when mouse down is triggered', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -280,9 +293,9 @@ describe('', () => {
expect(handleClickAway.args[0].length).to.equal(1);
});
- it('should call `props.onClickAway` when mouse up is triggered', () => {
+ it('should call `props.onClickAway` when mouse up is triggered', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -294,9 +307,9 @@ describe('', () => {
expect(handleClickAway.args[0].length).to.equal(1);
});
- it('should call `props.onClickAway` when pointer down is triggered', () => {
+ it('should call `props.onClickAway` when pointer down is triggered', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -308,9 +321,9 @@ describe('', () => {
expect(handleClickAway.args[0].length).to.equal(1);
});
- it('should call `props.onClickAway` when pointer up is triggered', () => {
+ it('should call `props.onClickAway` when pointer up is triggered', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -324,9 +337,9 @@ describe('', () => {
});
describe('prop: touchEvent', () => {
- it('should not call `props.onClickAway` when `props.touchEvent` is `false`', () => {
+ it('should not call `props.onClickAway` when `props.touchEvent` is `false`', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -335,9 +348,9 @@ describe('', () => {
expect(handleClickAway.callCount).to.equal(0);
});
- it('should call `props.onClickAway` when the appropriate touch event is triggered', () => {
+ it('should call `props.onClickAway` when the appropriate touch event is triggered', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -349,9 +362,9 @@ describe('', () => {
expect(handleClickAway.args[0].length).to.equal(1);
});
- it('should ignore `touchend` when preceded by `touchmove` event', () => {
+ it('should ignore `touchend` when preceded by `touchmove` event', async () => {
const handleClickAway = spy();
- render(
+ await render(
,
@@ -368,10 +381,10 @@ describe('', () => {
});
});
- it('should handle null child', () => {
+ it('should handle null child', async () => {
const Child = React.forwardRef(() => null);
const handleClickAway = spy();
- render(
+ await render(
,
@@ -386,7 +399,7 @@ describe('', () => {
['onClickCapture', false],
['onClickCapture', true],
].forEach(([eventName, disableReactTree]) => {
- it(`when 'disableRectTree=${disableReactTree}' ${eventName} triggers onClickAway if an outside target is removed`, function test() {
+ it(`when 'disableRectTree=${disableReactTree}' ${eventName} triggers onClickAway if an outside target is removed`, async function test() {
if (!new Event('click').composedPath) {
this.skip();
}
@@ -404,16 +417,16 @@ describe('', () => {
);
}
- render();
+ await render();
- act(() => {
+ await act(async () => {
screen.getByRole('button').click();
});
expect(handleClickAway.callCount).to.equal(1);
});
- it(`when 'disableRectTree=${disableReactTree}' ${eventName} does not trigger onClickAway if an inside target is removed`, function test() {
+ it(`when 'disableRectTree=${disableReactTree}' ${eventName} does not trigger onClickAway if an inside target is removed`, async function test() {
if (!new Event('click').composedPath) {
this.skip();
}
@@ -429,9 +442,9 @@ describe('', () => {
);
}
- render();
+ await render();
- act(() => {
+ await act(async () => {
screen.getByRole('button').click();
});
diff --git a/packages/mui-material/src/Collapse/Collapse.test.js b/packages/mui-material/src/Collapse/Collapse.test.js
index 77d92ca254b1d3..0b973f0e64489c 100644
--- a/packages/mui-material/src/Collapse/Collapse.test.js
+++ b/packages/mui-material/src/Collapse/Collapse.test.js
@@ -187,7 +187,7 @@ describe('', () => {
expect(next2.callCount).to.equal(1);
});
- it('should use timeout as delay when timeout is number', () => {
+ it('should use timeout as delay when timeout is number', async () => {
const timeout = 10;
const next = spy();
const { setProps } = render(
@@ -199,12 +199,12 @@ describe('', () => {
setProps({ in: true });
expect(next.callCount).to.equal(0);
- act(() => {
+ await act(async () => {
clock.tick(0);
});
expect(next.callCount).to.equal(0);
- act(() => {
+ await act(async () => {
clock.tick(timeout);
});
diff --git a/packages/mui-material/src/Dialog/Dialog.test.js b/packages/mui-material/src/Dialog/Dialog.test.js
index f04aee38ff943c..f427b9e19fcc97 100644
--- a/packages/mui-material/src/Dialog/Dialog.test.js
+++ b/packages/mui-material/src/Dialog/Dialog.test.js
@@ -1,6 +1,6 @@
import * as React from 'react';
import { expect } from 'chai';
-import { spy } from 'sinon';
+import { spy, useFakeTimers } from 'sinon';
import { act, createRenderer, fireEvent, screen } from '@mui/internal-test-utils';
import Modal from '@mui/material/Modal';
import Dialog, { dialogClasses as classes } from '@mui/material/Dialog';
@@ -12,8 +12,8 @@ import describeConformance from '../../test/describeConformance';
* more comprehensive simulation of a user click (mousedown + click)
* @param {HTMLElement} element
*/
-function userClick(element) {
- act(() => {
+async function userClick(element) {
+ await act(async () => {
fireEvent.mouseDown(element);
fireEvent.mouseUp(element);
element.click();
@@ -30,8 +30,8 @@ function findBackdrop(view) {
/**
* @param {typeof import('@mui/internal-test-utils').screen} view
*/
-function clickBackdrop(view) {
- userClick(findBackdrop(view));
+async function clickBackdrop(view) {
+ await userClick(findBackdrop(view));
}
const CustomFade = React.forwardRef(function CustomFade(props, ref) {
@@ -39,7 +39,18 @@ const CustomFade = React.forwardRef(function CustomFade(props, ref) {
});
describe('', () => {
- const { clock, render } = createRenderer({ clock: 'fake' });
+ /** @type {import('sinon').SinonFakeTimers | null} */
+ let timer = null;
+
+ beforeEach(() => {
+ timer = useFakeTimers({ toFake: ['setTimeout', 'clearTimeout', 'Date'] });
+ });
+
+ afterEach(() => {
+ timer?.restore();
+ });
+
+ const { render } = createRenderer();
describeConformance(