+
);
@@ -610,7 +610,7 @@ describe('
- Columns', () => {
await user.dblClick(separators[0]);
await waitFor(() => {
- expect(columns.map((_, i) => getColumnHeaderCell(i).offsetWidth)).to.deep.equal([50, 233]);
+ expect(columns.map((_, i) => getColumnHeaderCell(i).offsetWidth)).to.deep.equal([50, 248]);
});
await user.dblClick(separators[1]);
@@ -625,7 +625,9 @@ describe('
- Columns', () => {
await act(async () =>
apiRef.current?.autosizeColumns({ includeHeaders: false, ...options }),
);
- expect(getWidths()).to.deep.equal(widths);
+ await waitFor(() => {
+ expect(getWidths()).to.deep.equal(widths);
+ });
};
it('.columns works', async () => {
@@ -646,7 +648,7 @@ describe('
- Columns', () => {
it('.expand works', async () => {
// These values are tuned to Ubuntu/Chromium and might be flaky in other environments
- await autosize({ expand: true }, [135, 147]);
+ await autosize({ expand: true }, [142, 155]);
});
});
});
diff --git a/packages/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx
index dca905e2fc91a..0a636b5bb96b2 100644
--- a/packages/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx
@@ -501,9 +501,7 @@ describe('
- Filter', () => {
// The first combo is hidden and we include hidden elements to make the query faster
// https://github.com/testing-library/dom-testing-library/issues/820#issuecomment-726936225
const input = getSelectInput(
- screen.queryAllByRole('combobox', { name: 'Logic operator', hidden: true })[
- isJSDOM ? 1 : 0 // https://github.com/testing-library/dom-testing-library/issues/846
- ],
+ screen.queryAllByRole('combobox', { name: 'Logic operator', hidden: true })[0],
);
fireEvent.change(input!, { target: { value: 'or' } });
expect(onFilterModelChange.callCount).to.equal(1);
@@ -1362,8 +1360,7 @@ describe('
- Filter', () => {
},
};
render(
);
- // For JSDom, the first hidden combo is also found which we are not interested in
- const select = screen.getAllByRole('combobox', { name: 'Logic operator' })[isJSDOM ? 1 : 0];
+ const select = screen.getAllByRole('combobox', { name: 'Logic operator' })[0];
expect(select).not.to.have.class('Mui-disabled');
});
diff --git a/packages/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx
index 0195ccd1aa909..80f090f74e173 100644
--- a/packages/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/rowEditing.DataGridPro.test.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { expect } from 'chai';
-import { SinonFakeTimers, useFakeTimers, spy } from 'sinon';
+import { spy } from 'sinon';
import { RefObject } from '@mui/x-internals/types';
import {
GridApi,
@@ -17,6 +17,7 @@ import { getBasicGridData } from '@mui/x-data-grid-generator';
import { createRenderer, fireEvent, act, screen, waitFor } from '@mui/internal-test-utils';
import { getCell, getRow, spyApi } from 'test/utils/helperFn';
import { fireUserEvent } from 'test/utils/fireUserEvent';
+import { vi } from 'vitest';
describe('
- Row editing', () => {
const { render } = createRenderer();
@@ -409,15 +410,12 @@ describe('
- Row editing', () => {
});
describe('with debounceMs > 0', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers();
+ vi.useFakeTimers();
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should debounce multiple changes if debounceMs > 0', async () => {
@@ -447,7 +445,7 @@ describe('
- Row editing', () => {
expect(renderEditCell.callCount).to.equal(0);
await act(async () => {
- await timer?.tickAsync(100);
+ await vi.advanceTimersByTimeAsync(100);
});
expect(renderEditCell.callCount).not.to.equal(0);
expect(renderEditCell.lastCall.args[0].value).to.equal('USD GBP');
diff --git a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
index 31521fa6aed90..46e27758f3680 100644
--- a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
@@ -1,7 +1,8 @@
import * as React from 'react';
import { createRenderer, act, fireEvent, waitFor, reactMajor } from '@mui/internal-test-utils';
-import { SinonFakeTimers, useFakeTimers, spy } from 'sinon';
+import { spy } from 'sinon';
import { expect } from 'chai';
+import { vi } from 'vitest';
import { RefObject } from '@mui/x-internals/types';
import {
$,
@@ -176,15 +177,12 @@ describe('
- Rows', () => {
}
describe('throttling', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers();
+ vi.useFakeTimers();
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should not throttle by default', () => {
@@ -201,15 +199,15 @@ describe('
- Rows', () => {
await act(async () => apiRef.current?.updateRows([{ id: 1, brand: 'Fila' }]));
await act(async () => {
- await timer?.tickAsync(10);
+ await vi.advanceTimersByTimeAsync(10);
});
expect(getColumnValues(0)).to.deep.equal(['Nike', 'Adidas', 'Puma']);
await act(async () => {
- await timer?.tickAsync(100);
+ await vi.advanceTimersByTimeAsync(100);
});
-
- timer?.restore();
+ // It seems that the trigger is not dependant only on timeout.
+ vi.useRealTimers();
await waitFor(async () => {
expect(getColumnValues(0)).to.deep.equal(['Nike', 'Fila', 'Puma']);
});
@@ -376,15 +374,12 @@ describe('
- Rows', () => {
}
describe('throttling', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers();
+ vi.useFakeTimers();
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should not throttle by default', () => {
@@ -401,20 +396,20 @@ describe('
- Rows', () => {
await act(() => apiRef.current?.setRows([{ id: 3, brand: 'Asics' }]));
await act(async () => {
- await timer?.tickAsync(10);
+ await vi.advanceTimersByTimeAsync(10);
});
expect(getColumnValues(0)).to.deep.equal(['Nike', 'Adidas', 'Puma']);
// React 18 seems to render twice
const timerCount = reactMajor < 19 ? 2 : 1;
- expect(timer?.countTimers()).to.equal(timerCount);
+ expect(vi.getTimerCount()).to.equal(timerCount);
await act(async () => {
- await timer?.tickAsync(100);
+ await vi.advanceTimersByTimeAsync(100);
});
- expect(timer?.countTimers()).to.equal(0);
+ expect(vi.getTimerCount()).to.equal(0);
// It seems that the trigger is not dependant only on timeout.
- timer?.restore();
+ vi.useRealTimers();
await waitFor(async () => {
expect(getColumnValues(0)).to.deep.equal(['Asics']);
});
@@ -577,8 +572,8 @@ describe('
- Rows', () => {
let firstColumn = $$(firstRow, '[role="gridcell"]')[0];
expect(firstColumn).to.have.attr('data-colindex', '0');
await act(async () => virtualScroller.scrollTo({ left: columnThresholdPx }));
- firstColumn = $(renderingZone, '[role="row"] > [role="gridcell"]')!;
await waitFor(() => {
+ firstColumn = $(renderingZone, '[role="row"] > [role="gridcell"]')!;
expect(firstColumn).to.have.attr('data-colindex', '1');
});
});
diff --git a/packages/x-data-grid-pro/tsconfig.json b/packages/x-data-grid-pro/tsconfig.json
index a95beb1e8020a..08e4c0e2576ce 100644
--- a/packages/x-data-grid-pro/tsconfig.json
+++ b/packages/x-data-grid-pro/tsconfig.json
@@ -7,7 +7,8 @@
"chai-dom",
"mocha",
"node"
- ]
+ ],
+ "skipLibCheck": true
},
"include": ["src/**/*"]
}
diff --git a/packages/x-data-grid-pro/vitest.config.browser.mts b/packages/x-data-grid-pro/vitest.config.browser.mts
new file mode 100644
index 0000000000000..8362de2857660
--- /dev/null
+++ b/packages/x-data-grid-pro/vitest.config.browser.mts
@@ -0,0 +1,23 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ launch: {
+ // Required for tests which use scrollbars.
+ ignoreDefaultArgs: ['--hide-scrollbars'],
+ },
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-data-grid-pro/vitest.config.jsdom.mts b/packages/x-data-grid-pro/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-data-grid-pro/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
index 39d8927ad02d5..ed148d9e434e4 100644
--- a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
@@ -953,7 +953,7 @@ describe('
- Layout & warnings', () => {
'The Data Grid component requires all rows to have a unique `id` property',
reactMajor < 19 &&
'The Data Grid component requires all rows to have a unique `id` property',
- reactMajor < 19 && 'The above error occurred in the
component',
+ reactMajor < 19 && 'The above error occurred in the component',
]);
expect((errorRef.current as any).errors).to.have.length(1);
expect((errorRef.current as any).errors[0].toString()).to.include(
diff --git a/packages/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx b/packages/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx
index 6a171cf373681..bddd0f4c77ac6 100644
--- a/packages/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/quickFiltering.DataGrid.test.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { createRenderer, screen, fireEvent, reactMajor } from '@mui/internal-test-utils';
+import { createRenderer, screen, reactMajor, waitFor, act } from '@mui/internal-test-utils';
import { expect } from 'chai';
import { spy } from 'sinon';
import {
@@ -11,10 +11,10 @@ import {
getGridStringQuickFilterFn,
} from '@mui/x-data-grid';
import { getColumnValues, sleep } from 'test/utils/helperFn';
-import { testSkipIf, isJSDOM } from 'test/utils/skipIf';
+import { isJSDOM } from 'test/utils/skipIf';
describe(' - Quick filter', () => {
- const { render, clock } = createRenderer();
+ const { render } = createRenderer();
const baselineProps = {
autoHeight: isJSDOM,
@@ -59,24 +59,21 @@ describe(' - Quick filter', () => {
}
describe('component', () => {
- clock.withFakeTimers();
-
- it('should apply filter', () => {
- render();
+ it('should apply filter', async () => {
+ const { user } = render();
expect(getColumnValues(0)).to.deep.equal(['Nike', 'Adidas', 'Puma']);
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'a' },
- });
- clock.runToLast();
+ await user.type(screen.getByRole('searchbox'), 'a');
- expect(getColumnValues(0)).to.deep.equal(['Adidas', 'Puma']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Adidas', 'Puma']);
+ });
});
- it('should allow to customize input splitting', () => {
+ it('should allow to customize input splitting', async () => {
const onFilterModelChange = spy();
- render(
+ const { user } = render(
- Quick filter', () => {
expect(onFilterModelChange.callCount).to.equal(0);
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adid, nik' },
- });
- clock.runToLast();
- expect(onFilterModelChange.lastCall.firstArg).to.deep.equal({
- items: [],
- logicOperator: 'and',
- quickFilterValues: ['adid', 'nik'],
- quickFilterLogicOperator: 'and',
+ await user.click(screen.getByRole('button', { name: 'Search' }));
+ await user.type(screen.getByRole('searchbox'), 'adid, nik');
+
+ await waitFor(() => {
+ expect(onFilterModelChange.lastCall.firstArg).to.deep.equal({
+ items: [],
+ logicOperator: 'and',
+ quickFilterValues: ['adid', 'nik'],
+ quickFilterLogicOperator: 'and',
+ });
});
});
- it('should no prettify user input', () => {
- render();
+ it('should no prettify user input', async () => {
+ const { user } = render();
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adidas nike' },
- });
- clock.runToLast();
+ await user.click(screen.getByRole('button', { name: 'Search' }));
+ await user.type(screen.getByRole('searchbox'), 'adidas nike');
expect(screen.getByRole('searchbox').value).to.equal('adidas nike');
});
@@ -165,11 +161,9 @@ describe(' - Quick filter', () => {
expect(screen.getByRole('searchbox').value).to.equal('');
expect(screen.getByRole('searchbox').tabIndex).to.equal(-1);
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('false');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'false',
+ );
});
it('should be expanded by default if there is a value', () => {
@@ -177,154 +171,108 @@ describe(' - Quick filter', () => {
expect(screen.getByRole('searchbox').value).to.equal('adidas');
expect(screen.getByRole('searchbox').tabIndex).to.equal(0);
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('true');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'true',
+ );
});
- it('should expand when the trigger is clicked', () => {
- render();
+ it('should expand when the trigger is clicked', async () => {
+ const { user } = render();
- fireEvent.click(screen.getByRole('button', { name: 'Search' }));
+ await user.click(screen.getByRole('button', { name: 'Search' }));
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('true');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'true',
+ );
});
- it('should expand when the input changes value', () => {
- render();
-
- fireEvent.focus(screen.getByRole('searchbox'));
+ it('should expand when the input changes value', async () => {
+ const { user } = render();
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adidas' },
- });
+ await user.type(screen.getByRole('searchbox'), 'adidas');
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('true');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'true',
+ );
});
- it('should collapse when the input is blurred with no value', () => {
- render();
+ it('should collapse when the escape key is pressed with no value', async () => {
+ const { user } = render();
- fireEvent.click(screen.getByRole('button', { name: 'Search' }));
+ await user.click(screen.getByRole('button', { name: 'Search' }));
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('true');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'true',
+ );
- fireEvent.blur(screen.getByRole('searchbox'));
+ await user.keyboard('[Escape]');
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('false');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'false',
+ );
});
- it('should collapse when the escape key is pressed with no value', () => {
- render();
+ it('should clear the input when the escape key is pressed with a value and not collapse the input', async () => {
+ const { user } = render();
- fireEvent.click(screen.getByRole('button', { name: 'Search' }));
+ await user.click(screen.getByRole('button', { name: 'Search' }));
- // Wait for the input to be focused
- clock.runToLast();
+ await user.type(screen.getByRole('searchbox'), 'adidas');
- fireEvent.keyDown(screen.getByRole('searchbox'), {
- key: 'Escape',
- });
-
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('false');
- });
-
- it('should clear the input when the escape key is pressed with a value and not collapse the input', () => {
- render();
-
- fireEvent.click(screen.getByRole('button', { name: 'Search' }));
- clock.runToLast();
-
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adidas' },
- });
- clock.runToLast();
-
- fireEvent.keyDown(screen.getByRole('searchbox'), {
- key: 'Escape',
- });
+ await user.keyboard('[Escape]');
expect(screen.getByRole('searchbox').value).to.equal('');
- expect(
- screen
- .getByRole('button', { name: 'Search' })
- .getAttribute('aria-expanded'),
- ).to.equal('true');
+ expect(screen.getByRole('button', { name: 'Search' }).getAttribute('aria-expanded')).to.equal(
+ 'true',
+ );
});
- it('should clear the value when the clear button is clicked and focus to `the input', () => {
- render();
+ it('should clear the value when the clear button is clicked and focus to `the input', async () => {
+ const { user } = render(
+ ,
+ );
- fireEvent.click(screen.getByRole('button', { name: 'Clear' }));
- clock.runToLast();
+ await user.click(screen.getByRole('button', { name: 'Clear' }));
expect(screen.getByRole('searchbox').value).to.equal('');
expect(screen.getByRole('searchbox')).toHaveFocus();
});
- it('should focus the input when the trigger is clicked and return focus to the trigger when collapsed', () => {
- render();
-
- fireEvent.click(screen.getByRole('button', { name: 'Search' }));
+ it('should focus the input when the trigger is clicked and return focus to the trigger when collapsed', async () => {
+ const { user } = render();
- // Wait for the input to be focused
- clock.runToLast();
-
- expect(screen.getByRole('searchbox')).toHaveFocus();
+ await user.click(screen.getByRole('button', { name: 'Search' }));
- fireEvent.blur(screen.getByRole('searchbox'));
+ await waitFor(() => {
+ expect(screen.getByRole('searchbox')).toHaveFocus();
+ });
- // Wait for the trigger to be focused
- clock.runToLast();
+ await user.keyboard('[Escape]');
- expect(screen.getByRole('button', { name: 'Search' })).toHaveFocus();
+ expect(screen.getByRole('button', { name: 'Search' })).toHaveFocus();
});
});
describe('quick filter logic', () => {
- clock.withFakeTimers();
+ it('should return rows that match all values by default', async () => {
+ const { user } = render();
- it('should return rows that match all values by default', () => {
- render();
+ await user.click(screen.getByRole('button', { name: 'Search' }));
+ await user.type(screen.getByRole('searchbox'), 'adid');
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adid' },
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Adidas']);
});
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal(['Adidas']);
+ await user.type(screen.getByRole('searchbox'), ' nik');
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adid nik' },
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal([]);
});
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal([]);
});
- it('should return rows that match some values if quickFilterLogicOperator="or"', () => {
- render(
+ it('should return rows that match some values if quickFilterLogicOperator="or"', async () => {
+ const { user } = render(
- Quick filter', () => {
/>,
);
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adid' },
+ await user.click(screen.getByRole('button', { name: 'Search' }));
+ await user.type(screen.getByRole('searchbox'), 'adid');
+
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Adidas']);
});
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal(['Adidas']);
- fireEvent.change(screen.getByRole('searchbox'), {
- target: { value: 'adid nik' },
+ await user.type(screen.getByRole('searchbox'), ' nik');
+
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Nike', 'Adidas']);
});
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal(['Nike', 'Adidas']);
});
- it('should ignore hidden columns by default', () => {
- render(
+ it('should ignore hidden columns by default', async () => {
+ const { user } = render(
- Quick filter', () => {
/>,
);
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '1' } });
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal([]);
+ await user.type(screen.getByRole('searchbox'), '1');
+
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal([]);
+ });
+
+ await user.type(screen.getByRole('searchbox'), '[Backspace]2');
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '2' } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal([]);
});
- it('should search hidden columns when quickFilterExcludeHiddenColumns=false', () => {
- render(
+ it('should search hidden columns when quickFilterExcludeHiddenColumns=false', async () => {
+ const { user } = render(
- Quick filter', () => {
/>,
);
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '1' } });
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal(['Adidas']);
+ await user.type(screen.getByRole('searchbox'), '1');
+
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Adidas']);
+ });
+
+ await user.type(screen.getByRole('searchbox'), '[Backspace]2');
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '2' } });
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal(['Puma']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['Puma']);
+ });
});
- it('should ignore hidden columns when quickFilterExcludeHiddenColumns=true', () => {
- render(
+ it('should ignore hidden columns when quickFilterExcludeHiddenColumns=true', async () => {
+ const { user } = render(
- Quick filter', () => {
/>,
);
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '1' } });
- clock.runToLast();
- expect(getColumnValues(0)).to.deep.equal([]);
+ await user.type(screen.getByRole('searchbox'), '1');
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal([]);
+ });
- fireEvent.change(screen.getByRole('searchbox'), { target: { value: '2' } });
- clock.runToLast();
+ await user.type(screen.getByRole('searchbox'), '[Backspace]2');
expect(getColumnValues(0)).to.deep.equal([]);
});
@@ -427,7 +382,6 @@ describe(' - Quick filter', () => {
quickFilterExcludeHiddenColumns: true,
},
});
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal([]);
});
@@ -461,12 +415,10 @@ describe(' - Quick filter', () => {
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount);
setProps({ columnVisibilityModel: { brand: false } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal([]);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount + 1);
setProps({ columnVisibilityModel: { brand: true } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal(['1']);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount + 2);
});
@@ -494,12 +446,10 @@ describe(' - Quick filter', () => {
expect(getApplyQuickFilterFnSpy.callCount).to.equal(0);
setProps({ columnVisibilityModel: { brand: false } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(0);
setProps({ columnVisibilityModel: { brand: true } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(0);
});
@@ -531,20 +481,16 @@ describe(' - Quick filter', () => {
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount);
setProps({ columnVisibilityModel: { brand: false } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal(['1']);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount);
setProps({ columnVisibilityModel: { brand: true } });
- clock.runToLast();
expect(getColumnValues(0)).to.deep.equal(['1']);
expect(getApplyQuickFilterFnSpy.callCount).to.equal(initialCallCount);
});
});
describe('column type: string', () => {
- clock.withFakeTimers();
-
const getRows = ({ quickFilterValues }: Pick) => {
const { unmount } = render(
- Quick filter', () => {
});
describe('column type: number', () => {
- clock.withFakeTimers();
-
const getRows = ({ quickFilterValues }: Pick) => {
const { unmount } = render(
- Quick filter', () => {
});
describe('column type: singleSelect', () => {
- clock.withFakeTimers();
-
const getRows = ({ quickFilterValues }: Pick) => {
const { unmount } = render(
- Quick filter', () => {
});
// https://github.com/mui/mui-x/issues/6783
- testSkipIf(isJSDOM)('should not override user input when typing', async () => {
+ it('should not override user input when typing', async () => {
// Warning: this test doesn't fail consistently as it is timing-sensitive.
const debounceMs = 50;
- render(
+ const { user } = render(
- Quick filter', () => {
expect(searchBox.value).to.equal('');
- fireEvent.change(searchBox, { target: { value: 'a' } });
- await sleep(debounceMs - 2);
+ await user.type(searchBox, `a`);
+ await act(() => sleep(debounceMs - 2));
expect(searchBox.value).to.equal('a');
- fireEvent.change(searchBox, { target: { value: 'ab' } });
- await sleep(10);
+ await user.type(searchBox, `b`);
+ await act(() => sleep(10));
expect(searchBox.value).to.equal('ab');
- fireEvent.change(searchBox, { target: { value: 'abc' } });
- await sleep(debounceMs * 2);
+ await user.type(searchBox, `c`);
+ await act(() => sleep(debounceMs * 2));
expect(searchBox.value).to.equal('abc');
});
diff --git a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx
index daaa960b898b5..e51349df762c5 100644
--- a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { RefObject } from '@mui/x-internals/types';
-import { createRenderer, screen, act, waitFor, fireEvent } from '@mui/internal-test-utils';
+import { createRenderer, screen, act, waitFor } from '@mui/internal-test-utils';
import {
DataGrid,
DataGridProps,
@@ -11,7 +11,6 @@ import {
useGridApiRef,
GridApi,
GridRowSelectionModel,
- GridPreferencePanelsValue,
} from '@mui/x-data-grid';
import {
getCell,
@@ -417,26 +416,23 @@ describe(' - Row selection', () => {
expect(input2.checked).to.equal(true);
});
- testSkipIf(isJSDOM)('should remove the selection from rows that are filtered out', async () => {
- render(
- ,
- );
+ it('should remove the selection from rows that are filtered out', async () => {
+ const { user } = render();
const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' });
- fireEvent.click(selectAllCheckbox);
+ await user.click(selectAllCheckbox);
expect(getSelectedRowIds()).to.deep.equal([0, 1, 2, 3]);
expect(grid('selectedRowCount')?.textContent).to.equal('4 rows selected');
- fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), {
- target: { value: 1 },
- });
+ const idText = screen.getByRole('columnheader', { name: 'id' });
+ await user.hover(idText);
+ const idMenu = idText.querySelector('button[aria-label="id column menu"]')!;
+ await user.click(idMenu);
+
+ const filterButton = screen.getByText('Filter');
+ await user.click(filterButton);
+
+ await user.keyboard('1');
+
await waitFor(() => {
// Previous selection is cleaned with only the filtered rows
expect(getSelectedRowIds()).to.deep.equal([1]);
@@ -445,42 +441,38 @@ describe(' - Row selection', () => {
});
it('should only select filtered items when "select all" is toggled after applying a filter', async () => {
- render(
- ,
- );
+ const { user } = render();
const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' });
- fireEvent.click(selectAllCheckbox);
+ await user.click(selectAllCheckbox);
await waitFor(() => {
expect(getSelectedRowIds()).to.deep.equal([0, 1, 2, 3]);
});
expect(grid('selectedRowCount')?.textContent).to.equal('4 rows selected');
- // Click on Menu in id header column
- fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), {
- target: { value: 1 },
- });
+ const idText = screen.getByRole('columnheader', { name: 'id' });
+ await user.hover(idText);
+ const idMenu = idText.querySelector('button[aria-label="id column menu"]')!;
+ await user.click(idMenu);
+
+ const filterButton = screen.getByText('Filter');
+ await user.click(filterButton);
+
+ await user.keyboard('1');
+
await waitFor(() => {
// Previous selection is cleared and only the filtered row is selected
expect(getSelectedRowIds()).to.deep.equal([1]);
});
expect(grid('selectedRowCount')?.textContent).to.equal('1 row selected');
- fireEvent.click(selectAllCheckbox); // Unselect all
+ await user.click(selectAllCheckbox); // Unselect all
await waitFor(() => {
expect(getSelectedRowIds()).to.deep.equal([]);
});
expect(grid('selectedRowCount')).to.equal(null);
- fireEvent.click(selectAllCheckbox); // Select all filtered rows
+ await user.click(selectAllCheckbox); // Select all filtered rows
await waitFor(() => {
expect(getSelectedRowIds()).to.deep.equal([1]);
});
diff --git a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
index 3b9fa7e7d3c72..c2115475d1a9e 100644
--- a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
@@ -864,6 +864,11 @@ describe(' - Rows', () => {
// In Chrome non-headless and Edge this test is flaky
testSkipIf(!isJSDOM || !userAgent.includes('Headless') || /edg/i.test(userAgent))(
'should position correctly the render zone when changing pageSize to a lower value and moving to next page',
+ {
+ // Retry the test because it is flaky
+ retries: 3,
+ },
+ // @ts-expect-error mocha types are incorrect
async () => {
const data = getBasicGridData(120, 3);
const columnHeaderHeight = 50;
diff --git a/packages/x-data-grid/src/tests/slots.DataGrid.test.tsx b/packages/x-data-grid/src/tests/slots.DataGrid.test.tsx
index 13c120e71f5b5..c44573bca9149 100644
--- a/packages/x-data-grid/src/tests/slots.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/slots.DataGrid.test.tsx
@@ -167,7 +167,7 @@ describe(' - Slots', () => {
'MUI X: useGridRootProps should only be used inside the DataGrid, DataGridPro or DataGridPremium component.',
reactMajor < 19 &&
'MUI X: useGridRootProps should only be used inside the DataGrid, DataGridPro or DataGridPremium component.',
- reactMajor < 19 && 'The above error occurred in the component',
+ reactMajor < 19 && 'The above error occurred in the component',
]);
});
diff --git a/packages/x-data-grid/vitest.config.browser.mts b/packages/x-data-grid/vitest.config.browser.mts
new file mode 100644
index 0000000000000..8362de2857660
--- /dev/null
+++ b/packages/x-data-grid/vitest.config.browser.mts
@@ -0,0 +1,23 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ launch: {
+ // Required for tests which use scrollbars.
+ ignoreDefaultArgs: ['--hide-scrollbars'],
+ },
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-data-grid/vitest.config.jsdom.mts b/packages/x-data-grid/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-data-grid/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.test.tsx
index 251be3a43bde3..10b2048c56286 100644
--- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.test.tsx
+++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.test.tsx
@@ -20,15 +20,9 @@ describe('', () => {
Component: DateRangePicker,
});
- const originalMatchMedia = window.matchMedia;
-
- afterEach(() => {
- window.matchMedia = originalMatchMedia;
- });
-
it('should not use the mobile picker by default', () => {
+ stubMatchMedia(true);
// Test with accessible DOM structure
- window.matchMedia = stubMatchMedia(true);
const { unmount } = renderWithProps({ enableAccessibleFieldDOMStructure: true });
openPicker({ type: 'date-range', initialFocus: 'start', fieldType: 'single-input' });
expect(screen.queryByRole('dialog')).to.have.class(pickerPopperClasses.root);
@@ -36,15 +30,14 @@ describe('', () => {
unmount();
// Test with non-accessible DOM structure
- window.matchMedia = stubMatchMedia(true);
renderWithProps({ enableAccessibleFieldDOMStructure: false });
openPicker({ type: 'date-range', initialFocus: 'start', fieldType: 'single-input' });
expect(screen.queryByRole('dialog')).to.have.class(pickerPopperClasses.root);
});
it('should use the mobile picker when `useMediaQuery` returns `false`', () => {
+ stubMatchMedia(false);
// Test with accessible DOM structure
- window.matchMedia = stubMatchMedia(false);
const { unmount } = renderWithProps({ enableAccessibleFieldDOMStructure: true });
openPicker({ type: 'date-range', initialFocus: 'start', fieldType: 'single-input' });
expect(screen.queryByRole('dialog')).not.to.have.class(pickerPopperClasses.root);
@@ -52,7 +45,6 @@ describe('', () => {
unmount();
// Test with non-accessible DOM structure
- window.matchMedia = stubMatchMedia(false);
renderWithProps({ enableAccessibleFieldDOMStructure: false });
openPicker({ type: 'date-range', initialFocus: 'start', fieldType: 'single-input' });
expect(screen.queryByRole('dialog')).not.to.have.class(pickerPopperClasses.root);
diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
index 6fd9927fdaa11..b3032d3acc2fc 100644
--- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
+++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { expect } from 'chai';
-import { spy, useFakeTimers, SinonFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { fireEvent, screen, act, within, waitFor } from '@mui/internal-test-utils';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
@@ -17,6 +17,7 @@ import {
getTextbox,
} from 'test/utils/pickers';
import { testSkipIf, isJSDOM } from 'test/utils/skipIf';
+import { vi } from 'vitest';
const getPickerDay = (name: string, picker = 'January 2018') =>
within(screen.getByRole('grid', { name: picker })).getByRole('gridcell', { name });
@@ -696,15 +697,12 @@ describe('', () => {
});
describe('disabled dates', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 10), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 10));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should respect the disablePast prop', async () => {
diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx
index c5944e250add1..56eb20140dfe3 100644
--- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx
+++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/tests/DesktopDateTimeRangePicker.test.tsx
@@ -8,21 +8,18 @@ import {
getFieldSectionsContainer,
expectFieldValueV7,
} from 'test/utils/pickers';
-import { SinonFakeTimers, useFakeTimers } from 'sinon';
+import { vi } from 'vitest';
import { DesktopDateTimeRangePicker } from '../DesktopDateTimeRangePicker';
describe('', () => {
const { render } = createPickerRenderer();
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 10, 10, 16, 0), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 10, 10, 16, 0));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
describe('value selection', () => {
diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/MobileDateTimeRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/MobileDateTimeRangePicker.test.tsx
index 77943ca072f21..d04d45af40a20 100644
--- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/MobileDateTimeRangePicker.test.tsx
+++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/tests/MobileDateTimeRangePicker.test.tsx
@@ -8,21 +8,18 @@ import {
expectFieldValueV7,
} from 'test/utils/pickers';
import { MobileDateTimeRangePicker } from '@mui/x-date-pickers-pro/MobileDateTimeRangePicker';
-import { SinonFakeTimers, useFakeTimers } from 'sinon';
+import { vi } from 'vitest';
describe('', () => {
const { render } = createPickerRenderer();
describe('value selection', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 10, 10, 16, 0), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 10, 10, 16, 0));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should cycle focused views among the visible step after selection', async () => {
diff --git a/packages/x-date-pickers-pro/tsconfig.json b/packages/x-date-pickers-pro/tsconfig.json
index 82f2e7898632c..048fc82f52d59 100644
--- a/packages/x-date-pickers-pro/tsconfig.json
+++ b/packages/x-date-pickers-pro/tsconfig.json
@@ -10,7 +10,8 @@
"mocha",
"node"
],
- "noImplicitAny": false
+ "noImplicitAny": false,
+ "skipLibCheck": true
},
"include": ["src/**/*", "../../test/utils/addChaiAssertions.ts"]
}
diff --git a/packages/x-date-pickers-pro/vitest.config.browser.mts b/packages/x-date-pickers-pro/vitest.config.browser.mts
new file mode 100644
index 0000000000000..1b6f538191a3a
--- /dev/null
+++ b/packages/x-date-pickers-pro/vitest.config.browser.mts
@@ -0,0 +1,19 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-date-pickers-pro/vitest.config.jsdom.mts b/packages/x-date-pickers-pro/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-date-pickers-pro/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts b/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts
index 6004c385f7bac..758a8fd66b53f 100644
--- a/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts
+++ b/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts
@@ -82,7 +82,7 @@ export class AdapterDateFns
implements MuiPickersAdapter
{
constructor({ locale, formats }: AdapterOptions = {}) {
- /* istanbul ignore next */
+ /* v8 ignore start */
if (process.env.NODE_ENV !== 'production') {
if (typeof addDays !== 'function') {
throw new Error(
@@ -98,6 +98,7 @@ export class AdapterDateFns
);
}
}
+ /* v8 ignore stop */
super({ locale: locale ?? enUS, formats, longFormatters });
}
diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts
index 14375117a0131..60e794d08e1d5 100644
--- a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts
+++ b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts
@@ -121,7 +121,7 @@ export class AdapterDateFnsJalali
implements MuiPickersAdapter
{
constructor({ locale, formats }: AdapterOptions = {}) {
- /* istanbul ignore next */
+ /* v8 ignore start */
if (process.env.NODE_ENV !== 'production') {
if (typeof addDays !== 'function') {
throw new Error(
@@ -137,6 +137,7 @@ export class AdapterDateFnsJalali
);
}
}
+ /* v8 ignore stop */
super({
locale: locale ?? defaultLocale,
// some formats are different in jalali adapter,
diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts
index 1fdad7a49c363..6d21b8caf2c3d 100644
--- a/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts
+++ b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts
@@ -1,6 +1,7 @@
// date-fns-jalali@<3 has no exports field defined
// See https://github.com/date-fns/date-fns/issues/1781
/* eslint-disable import/extensions, class-methods-use-this */
+/* v8 ignore start */
// @ts-nocheck
import addSeconds from 'date-fns-jalali/addSeconds/index.js';
import addMinutes from 'date-fns-jalali/addMinutes/index.js';
@@ -47,6 +48,7 @@ import isWithinInterval from 'date-fns-jalali/isWithinInterval/index.js';
import defaultLocale from 'date-fns-jalali/locale/fa-IR/index.js';
import type { Locale as DateFnsLocale } from 'date-fns-jalali';
import longFormatters from 'date-fns-jalali/_lib/format/longFormatters/index.js';
+/* v8 ignore end */
import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models';
import { AdapterDateFnsBase } from '../AdapterDateFnsBase';
@@ -125,7 +127,7 @@ export class AdapterDateFnsJalali
implements MuiPickersAdapter
{
constructor({ locale, formats }: AdapterOptions = {}) {
- /* istanbul ignore next */
+ /* v8 ignore start */
if (process.env.NODE_ENV !== 'production') {
if (typeof addDays !== 'function') {
throw new Error(
@@ -136,6 +138,7 @@ export class AdapterDateFnsJalali
);
}
}
+ /* v8 ignore stop */
super({
locale: locale ?? defaultLocale,
// some formats are different in jalali adapter,
diff --git a/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts
index 1c0c2b2947f7c..0059fd9a1f49c 100644
--- a/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts
+++ b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts
@@ -1,6 +1,7 @@
// date-fns@<3 has no exports field defined
// See https://github.com/date-fns/date-fns/issues/1781
/* eslint-disable import/extensions, class-methods-use-this */
+/* v8 ignore start */
// @ts-nocheck
import addDays from 'date-fns/addDays/index.js';
import addSeconds from 'date-fns/addSeconds/index.js';
@@ -47,6 +48,7 @@ import isWithinInterval from 'date-fns/isWithinInterval/index.js';
import defaultLocale from 'date-fns/locale/en-US/index.js';
import type { Locale as DateFnsLocale } from 'date-fns';
import longFormatters from 'date-fns/_lib/format/longFormatters/index.js';
+/* v8 ignore end */
import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models';
import { AdapterDateFnsBase } from '../AdapterDateFnsBase';
@@ -86,7 +88,7 @@ export class AdapterDateFns
implements MuiPickersAdapter
{
constructor({ locale, formats }: AdapterOptions = {}) {
- /* istanbul ignore next */
+ /* v8 ignore start */
if (process.env.NODE_ENV !== 'production') {
if (typeof addDays !== 'function') {
throw new Error(
@@ -97,6 +99,7 @@ export class AdapterDateFns
);
}
}
+ /* v8 ignore stop */
super({ locale: locale ?? defaultLocale, formats, longFormatters });
}
diff --git a/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts b/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts
index cc26fbdcac6a2..e5162683884dd 100644
--- a/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts
+++ b/packages/x-date-pickers/src/AdapterDayjs/AdapterDayjs.ts
@@ -1,4 +1,5 @@
/* eslint-disable class-methods-use-this */
+/* v8 ignore start */
import defaultDayjs, { Dayjs } from 'dayjs';
// dayjs has no exports field defined
// See https://github.com/iamkun/dayjs/issues/2562
@@ -8,6 +9,7 @@ import customParseFormatPlugin from 'dayjs/plugin/customParseFormat.js';
import localizedFormatPlugin from 'dayjs/plugin/localizedFormat.js';
import isBetweenPlugin from 'dayjs/plugin/isBetween.js';
import advancedFormatPlugin from 'dayjs/plugin/advancedFormat.js';
+/* v8 ignore stop */
/* eslint-enable import/extensions */
import { warnOnce } from '@mui/x-internals/warning';
import {
@@ -208,7 +210,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
const timezone = defaultDayjs.tz.guess();
// We can't change the system timezone in the tests
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (timezone !== 'UTC') {
return defaultDayjs.tz(value, timezone);
}
@@ -220,7 +222,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
};
private createUTCDate = (value: string | undefined): Dayjs => {
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (!this.hasUTCPlugin()) {
throw new Error(MISSING_UTC_PLUGIN);
}
@@ -229,12 +231,12 @@ export class AdapterDayjs implements MuiPickersAdapter {
};
private createTZDate = (value: string | undefined, timezone: PickersTimezone): Dayjs => {
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (!this.hasUTCPlugin()) {
throw new Error(MISSING_UTC_PLUGIN);
}
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (!this.hasTimezonePlugin()) {
throw new Error(MISSING_TIMEZONE_PLUGIN);
}
@@ -250,7 +252,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
let localeObject = locales[locale];
if (localeObject === undefined) {
- /* istanbul ignore next */
+ /* v8 ignore start */
if (process.env.NODE_ENV !== 'production') {
warnOnce([
'MUI X: Your locale has not been found.',
@@ -259,6 +261,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
'fallback on English locale.',
]);
}
+ /* v8 ignore stop */
localeObject = locales.en;
}
@@ -280,7 +283,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
if (timezone !== 'UTC') {
const fixedValue = value.tz(this.cleanTimezone(timezone), true);
// TODO: Simplify the case when we raise the `dayjs` peer dep to 1.11.12 (https://github.com/iamkun/dayjs/releases/tag/v1.11.12)
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
// @ts-ignore
if (fixedValue.$offset === (value.$offset ?? 0)) {
return value;
@@ -345,7 +348,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
}
if (timezone === 'UTC') {
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (!this.hasUTCPlugin()) {
throw new Error(MISSING_UTC_PLUGIN);
}
@@ -365,7 +368,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
return value;
}
- /* istanbul ignore next */
+ /* v8 ignore next */
throw new Error(MISSING_TIMEZONE_PLUGIN);
}
@@ -389,7 +392,7 @@ export class AdapterDayjs implements MuiPickersAdapter {
};
public is12HourCycleInCurrentLocale = () => {
- /* istanbul ignore next */
+ /* v8 ignore next */
return /A|a/.test(this.getLocaleFormats().LT || '');
};
diff --git a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts
index faf174a2b1099..113e89a2a496a 100644
--- a/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts
+++ b/packages/x-date-pickers/src/AdapterLuxon/AdapterLuxon.ts
@@ -197,7 +197,7 @@ export class AdapterLuxon implements MuiPickersAdapter {
return this.locale;
};
- /* istanbul ignore next */
+ /* v8 ignore start */
public is12HourCycleInCurrentLocale = () => {
if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {
return true; // Luxon defaults to en-US if Intl not found
@@ -207,6 +207,7 @@ export class AdapterLuxon implements MuiPickersAdapter {
new Intl.DateTimeFormat(this.locale, { hour: 'numeric' })?.resolvedOptions()?.hour12,
);
};
+ /* v8 ignore stop */
public expandFormat = (format: string) => {
// Extract escaped section to avoid extending them
@@ -482,7 +483,7 @@ export class AdapterLuxon implements MuiPickersAdapter {
};
public getWeekNumber = (value: DateTime) => {
- /* istanbul ignore next */
+ /* v8 ignore next */
return value.localWeekNumber ?? value.weekNumber;
};
diff --git a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
index 2f5a9020cb078..a07b58c2024b7 100644
--- a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
+++ b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
@@ -174,7 +174,7 @@ export class AdapterMoment implements MuiPickersAdapter {
};
private createTZDate = (value: string | undefined, timezone: PickersTimezone): Moment => {
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (!this.hasTimezonePlugin()) {
throw new Error(MISSING_TIMEZONE_PLUGIN);
}
@@ -235,7 +235,7 @@ export class AdapterMoment implements MuiPickersAdapter {
}
if (!this.hasTimezonePlugin()) {
- /* istanbul ignore next */
+ /* v8 ignore next 3 */
if (timezone !== 'default') {
throw new Error(MISSING_TIMEZONE_PLUGIN);
}
diff --git a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.test.tsx b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.test.tsx
index 865999bc4294a..023bc85553ecf 100644
--- a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.test.tsx
+++ b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.test.tsx
@@ -1,4 +1,4 @@
-import moment, { Moment } from 'moment';
+import moment, { Moment } from 'moment-hijri';
import { expect } from 'chai';
import { DateTimeField } from '@mui/x-date-pickers/DateTimeField';
import { AdapterMomentHijri } from '@mui/x-date-pickers/AdapterMomentHijri';
@@ -9,12 +9,28 @@ import {
describeHijriAdapter,
buildFieldInteractions,
} from 'test/utils/pickers';
-import 'moment/locale/ar';
+import 'moment/locale/ar-sa';
+import { beforeAll } from 'vitest';
+import { isJSDOM } from 'test/utils/skipIf';
describe('', () => {
+ beforeAll(() => {
+ if (!isJSDOM) {
+ // Vitest browser mode does not correctly load the locale
+ // This is the minimal amount of locale data needed to run the tests
+ moment.updateLocale('ar-sa', {
+ weekdays: 'Ø§Ù„Ø£ØØ¯_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+ weekdaysShort: 'Ø£ØØ¯_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+ meridiem: (hour) => (hour < 12 ? 'ص' : 'م'),
+ postformat: (input) =>
+ input.replace(/\d/g, (match) => '٠١٢٣٤٥٦٧٨٩'[match]).replace(/,/g, '،'),
+ });
+ }
+ });
+
describeHijriAdapter(AdapterMomentHijri, {
before: () => {
- moment.locale('ar-SA');
+ moment.locale('ar-sa');
},
after: () => {
moment.locale('en');
diff --git a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts
index 9d640b095bb61..e200a847444fb 100644
--- a/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts
+++ b/packages/x-date-pickers/src/AdapterMomentHijri/AdapterMomentHijri.ts
@@ -1,4 +1,5 @@
/* eslint-disable class-methods-use-this */
+/* v8 ignore next */
import defaultHMoment, { Moment } from 'moment-hijri';
import { AdapterMoment } from '../AdapterMoment';
import {
@@ -144,10 +145,12 @@ export class AdapterMomentHijri extends AdapterMoment implements MuiPickersAdapt
return this.moment(value).locale('ar-SA') as unknown as R;
};
+ /* v8 ignore next 3 */
public getTimezone = (): string => {
return 'default';
};
+ /* v8 ignore next 3 */
public setTimezone = (value: Moment): Moment => {
return value;
};
diff --git a/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts b/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts
index 387cf89b5074f..4091419e588b4 100644
--- a/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts
+++ b/packages/x-date-pickers/src/AdapterMomentJalaali/AdapterMomentJalaali.ts
@@ -1,4 +1,5 @@
/* eslint-disable class-methods-use-this */
+/* v8 ignore next */
import defaultJMoment, { Moment } from 'moment-jalaali';
import { AdapterMoment } from '../AdapterMoment';
import {
diff --git a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
index 03cf55d43071f..fc07d0e5927e5 100644
--- a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
+++ b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
@@ -5,7 +5,8 @@ import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import { PickersDay } from '@mui/x-date-pickers/PickersDay';
import { createPickerRenderer, adapterToUse } from 'test/utils/pickers';
import { testSkipIf, isJSDOM } from 'test/utils/skipIf';
-import { SinonFakeTimers, useFakeTimers, spy } from 'sinon';
+import { spy } from 'sinon';
+import { vi } from 'vitest';
describe('', () => {
const { render } = createPickerRenderer();
@@ -127,15 +128,12 @@ describe('', () => {
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2019, 0, 2), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2019, 0, 2));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
// test: https://github.com/mui/mui-x/issues/12373
diff --git a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx
index ca9fa61f0d8bc..ec641adf481a5 100644
--- a/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx
+++ b/packages/x-date-pickers/src/DatePicker/tests/DatePicker.test.tsx
@@ -9,15 +9,12 @@ describe('', () => {
const { render } = createPickerRenderer();
it('should render in mobile mode when `useMediaQuery` returns `false`', async () => {
- const originalMatchMedia = window.matchMedia;
- window.matchMedia = stubMatchMedia(false);
+ stubMatchMedia(false);
const { user } = render();
await user.click(screen.getByLabelText(/Choose date/));
expect(screen.queryByRole('dialog')).to.not.equal(null);
-
- window.matchMedia = originalMatchMedia;
});
describe('form behavior', () => {
diff --git a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx
index adb5239e0e909..7b583b1c268ba 100644
--- a/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx
+++ b/packages/x-date-pickers/src/DateTimePicker/tests/DateTimePicker.test.tsx
@@ -8,14 +8,11 @@ describe('', () => {
const { render } = createPickerRenderer();
it('should render in mobile mode when `useMediaQuery` returns `false`', async () => {
- const originalMatchMedia = window.matchMedia;
- window.matchMedia = stubMatchMedia(false);
+ stubMatchMedia(false);
const { user } = render();
await user.click(screen.getByLabelText(/Choose date/));
expect(screen.queryByRole('dialog')).to.not.equal(null);
-
- window.matchMedia = originalMatchMedia;
});
});
diff --git a/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx b/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
index b36fd310860e0..6155f644dea3e 100644
--- a/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
+++ b/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
-import { spy, useFakeTimers, SinonFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { expect } from 'chai';
import { fireEvent, screen } from '@mui/internal-test-utils';
import { MonthCalendar } from '@mui/x-date-pickers/MonthCalendar';
import { createPickerRenderer, adapterToUse } from 'test/utils/pickers';
+import { vi } from 'vitest';
describe('', () => {
const { render } = createPickerRenderer();
@@ -27,15 +28,12 @@ describe('', () => {
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2019, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2019, 0, 1));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should select start of month without time when no initial value is present', () => {
@@ -161,15 +159,12 @@ describe('', () => {
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2019, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2019, 0, 1));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should disable months after initial render when "disableFuture" prop changes', async () => {
diff --git a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx
index db5f770ed0b2e..46a0c2bd969b9 100644
--- a/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx
+++ b/packages/x-date-pickers/src/TimePicker/tests/TimePicker.test.tsx
@@ -8,14 +8,11 @@ describe('', () => {
const { render } = createPickerRenderer();
it('should render in mobile mode when `useMediaQuery` returns `false`', async () => {
- const originalMatchMedia = window.matchMedia;
- window.matchMedia = stubMatchMedia(false);
+ stubMatchMedia(false);
const { user } = render();
await user.click(screen.getByLabelText(/Choose time/));
expect(screen.queryByRole('dialog')).to.not.equal(null);
-
- window.matchMedia = originalMatchMedia;
});
});
diff --git a/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx b/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
index dc65ccda80150..841ac200afc5f 100644
--- a/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
+++ b/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
-import { spy, useFakeTimers, SinonFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { expect } from 'chai';
import { act, fireEvent, screen } from '@mui/internal-test-utils';
import { YearCalendar } from '@mui/x-date-pickers/YearCalendar';
import { createPickerRenderer, adapterToUse } from 'test/utils/pickers';
+import { vi } from 'vitest';
describe('', () => {
const { render } = createPickerRenderer();
@@ -171,15 +172,12 @@ describe('', () => {
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2019, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2019, 0, 1));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should disable years after initial render when "disableFuture" prop changes', () => {
diff --git a/packages/x-date-pickers/src/internals/utils/date-utils.test.ts b/packages/x-date-pickers/src/internals/utils/date-utils.test.ts
index e27f519a28878..56c2a335252cd 100644
--- a/packages/x-date-pickers/src/internals/utils/date-utils.test.ts
+++ b/packages/x-date-pickers/src/internals/utils/date-utils.test.ts
@@ -1,6 +1,6 @@
import { expect } from 'chai';
import { adapterToUse } from 'test/utils/pickers';
-import { useFakeTimers, SinonFakeTimers } from 'sinon';
+import { vi } from 'vitest';
import { findClosestEnabledDate } from './date-utils';
describe('findClosestEnabledDate', () => {
@@ -101,15 +101,12 @@ describe('findClosestEnabledDate', () => {
});
describe('fake clock', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date('2000-01-02'), toFake: ['Date'] });
+ vi.setSystemTime(new Date('2000-01-02'));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should return now with given time part if disablePast and now is valid', () => {
@@ -176,15 +173,12 @@ describe('findClosestEnabledDate', () => {
});
describe('fake clock hours', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
-
beforeEach(() => {
- timer = useFakeTimers({ now: new Date('2000-01-02T11:12:13.123Z'), toFake: ['Date'] });
+ vi.setSystemTime(new Date('2000-01-02T11:12:13.123Z'));
});
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should keep the time of the `date` when `disablePast`', () => {
diff --git a/packages/x-date-pickers/tsconfig.json b/packages/x-date-pickers/tsconfig.json
index 5f862d31ec2ba..f63ee3ebfc2ad 100644
--- a/packages/x-date-pickers/tsconfig.json
+++ b/packages/x-date-pickers/tsconfig.json
@@ -8,7 +8,8 @@
"mocha",
"node"
],
- "noImplicitAny": false
+ "noImplicitAny": false,
+ "skipLibCheck": true
},
"include": ["src/**/*", "../../test/utils/addChaiAssertions.ts"]
}
diff --git a/packages/x-date-pickers/vitest.config.browser.mts b/packages/x-date-pickers/vitest.config.browser.mts
new file mode 100644
index 0000000000000..baded152ae863
--- /dev/null
+++ b/packages/x-date-pickers/vitest.config.browser.mts
@@ -0,0 +1,30 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+
+import { getTestName } from '../../scripts/getTestName.mts';
+import { filterReplace } from './vitest.config.jsdom.mts';
+
+export default mergeConfig(sharedConfig, {
+ plugins: [filterReplace],
+ resolve: {
+ alias: [
+ {
+ find: 'moment/locale',
+ replacement: 'moment/dist/locale',
+ },
+ ],
+ },
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-date-pickers/vitest.config.jsdom.mts b/packages/x-date-pickers/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..44cc271f3ef00
--- /dev/null
+++ b/packages/x-date-pickers/vitest.config.jsdom.mts
@@ -0,0 +1,28 @@
+import { mergeConfig } from 'vitest/config';
+// eslint-disable-next-line import/no-relative-packages
+import { redirectImports } from '../../test/vite-plugin-filter-replace.mts';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export const filterReplace = redirectImports([
+ {
+ test: /\/AdapterDateFnsV2\//,
+ from: 'date-fns',
+ to: 'date-fns-v2',
+ include: ['date-fns-v2/locale', 'date-fns-v2/**/*.js'],
+ },
+ {
+ test: /\/AdapterDateFnsJalaliV2\//,
+ from: 'date-fns-jalali',
+ to: 'date-fns-jalali-v2',
+ include: ['date-fns-jalali-v2/locale', 'date-fns-jalali-v2/**/*.js'],
+ },
+]);
+
+export default mergeConfig(sharedConfig, {
+ plugins: [filterReplace],
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-internals/vitest.config.jsdom.mts b/packages/x-internals/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-internals/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-license/vitest.config.browser.mts b/packages/x-license/vitest.config.browser.mts
new file mode 100644
index 0000000000000..1b6f538191a3a
--- /dev/null
+++ b/packages/x-license/vitest.config.browser.mts
@@ -0,0 +1,19 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-license/vitest.config.jsdom.mts b/packages/x-license/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-license/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-telemetry/src/runtime/config.test.ts b/packages/x-telemetry/src/runtime/config.test.ts
index cd492ff95a2bf..73376ad383c57 100644
--- a/packages/x-telemetry/src/runtime/config.test.ts
+++ b/packages/x-telemetry/src/runtime/config.test.ts
@@ -1,20 +1,18 @@
/* eslint-disable no-underscore-dangle */
-import sinon from 'sinon';
import { expect } from 'chai';
import { ponyfillGlobal } from '@mui/utils';
+import { vi } from 'vitest';
import { muiXTelemetrySettings } from '@mui/x-telemetry';
import { getTelemetryEnvConfig } from './config';
describe('Telemetry: getTelemetryConfig', () => {
beforeEach(() => {
- sinon.stub(process, 'env').value({
- NODE_ENV: 'development',
- });
+ vi.stubEnv('NODE_ENV', 'development');
});
afterEach(() => {
- sinon.restore();
+ vi.unstubAllEnvs();
// Reset env config cache
getTelemetryEnvConfig(true);
});
@@ -25,12 +23,12 @@ describe('Telemetry: getTelemetryConfig', () => {
function testConfigWithDisabledEnv(envKey: string) {
it(`should be disabled, if ${envKey} is set to '1'`, () => {
- sinon.stub(process, 'env').value({ [envKey]: '1' });
+ vi.stubEnv(envKey, '1');
expect(getTelemetryEnvConfig(true).IS_COLLECTING).equal(false);
});
it(`should be enabled, if ${envKey} is set to '0'`, () => {
- sinon.stub(process, 'env').value({ [envKey]: '0' });
+ vi.stubEnv(envKey, '0');
expect(getTelemetryEnvConfig(true).IS_COLLECTING).equal(true);
});
}
@@ -41,14 +39,14 @@ describe('Telemetry: getTelemetryConfig', () => {
it('should be disabled if global.__MUI_X_TELEMETRY_DISABLED__ is set to `1`', () => {
ponyfillGlobal.__MUI_X_TELEMETRY_DISABLED__ = undefined;
- sinon.stub(ponyfillGlobal, '__MUI_X_TELEMETRY_DISABLED__').value(true);
+ vi.stubGlobal('__MUI_X_TELEMETRY_DISABLED__', true);
expect(getTelemetryEnvConfig(true).IS_COLLECTING).equal(false);
});
it('should be enabled if global.__MUI_X_TELEMETRY_DISABLED__ is set to `0`', () => {
ponyfillGlobal.__MUI_X_TELEMETRY_DISABLED__ = undefined;
- sinon.stub(ponyfillGlobal, '__MUI_X_TELEMETRY_DISABLED__').value(false);
+ vi.stubGlobal('__MUI_X_TELEMETRY_DISABLED__', false);
expect(getTelemetryEnvConfig(true).IS_COLLECTING).equal(true);
});
@@ -72,12 +70,10 @@ describe('Telemetry: getTelemetryConfig', () => {
});
it('debug should be enabled if env MUI_X_TELEMETRY_DEBUG is set to `1`', () => {
- sinon.stub(process, 'env').value({ MUI_X_TELEMETRY_DEBUG: '1' });
- process.stdout.write(`${JSON.stringify(getTelemetryEnvConfig(true), null, 2)}\n`);
+ vi.stubEnv('MUI_X_TELEMETRY_DEBUG', '1');
expect(getTelemetryEnvConfig(true).DEBUG).equal(true);
- sinon.stub(process, 'env').value({ MUI_X_TELEMETRY_DEBUG: '0' });
- process.stdout.write(`${JSON.stringify(getTelemetryEnvConfig(true), null, 2)}\n`);
+ vi.stubEnv('MUI_X_TELEMETRY_DEBUG', '0');
expect(getTelemetryEnvConfig(true).DEBUG).equal(false);
});
});
diff --git a/packages/x-telemetry/tsconfig.json b/packages/x-telemetry/tsconfig.json
index 827e5bc9734ed..5130f461f7f4f 100644
--- a/packages/x-telemetry/tsconfig.json
+++ b/packages/x-telemetry/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
+ "skipLibCheck": true,
"types": ["@mui/internal-test-utils/initMatchers", "chai-dom", "mocha", "node", "vite/client"]
},
"include": ["src/**/*"]
diff --git a/packages/x-telemetry/vitest.config.browser.mts b/packages/x-telemetry/vitest.config.browser.mts
new file mode 100644
index 0000000000000..1b6f538191a3a
--- /dev/null
+++ b/packages/x-telemetry/vitest.config.browser.mts
@@ -0,0 +1,19 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-telemetry/vitest.config.jsdom.mts b/packages/x-telemetry/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-telemetry/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-tree-view-pro/vitest.config.browser.mts b/packages/x-tree-view-pro/vitest.config.browser.mts
new file mode 100644
index 0000000000000..1b6f538191a3a
--- /dev/null
+++ b/packages/x-tree-view-pro/vitest.config.browser.mts
@@ -0,0 +1,19 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-tree-view-pro/vitest.config.jsdom.mts b/packages/x-tree-view-pro/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-tree-view-pro/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx
index a5e54a8063fef..0105373eb4bbc 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx
@@ -7,6 +7,7 @@ import { act, fireEvent } from '@mui/internal-test-utils';
import { TreeItem, TreeItemProps } from '@mui/x-tree-view/TreeItem';
import { UseTreeItemContentSlotOwnProps } from '@mui/x-tree-view/useTreeItem';
import { useTreeItemUtils } from '@mui/x-tree-view/hooks';
+import { clearWarningsCache } from '@mui/x-internals/warning';
/**
* All tests related to keyboard navigation (e.g.: expanding using "Enter" and "ArrowRight")
@@ -14,6 +15,10 @@ import { useTreeItemUtils } from '@mui/x-tree-view/hooks';
*/
describeTreeView<[UseTreeViewExpansionSignature]>('useTreeViewExpansion plugin', ({ render }) => {
describe('model props (expandedItems, defaultExpandedItems, onExpandedItemsChange)', () => {
+ beforeEach(() => {
+ clearWarningsCache();
+ });
+
it('should not expand items when no default state and no control state are defined', () => {
const view = render({
items: [{ id: '1', children: [{ id: '1.1' }] }, { id: '2' }],
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewItems/useTreeViewItems.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewItems/useTreeViewItems.test.tsx
index 2e0ceafdefdf1..f4babee7a6bd6 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewItems/useTreeViewItems.test.tsx
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewItems/useTreeViewItems.test.tsx
@@ -29,8 +29,8 @@ describeTreeView<
'MUI X: The Tree View component requires all items to have a unique `id` property.',
reactMajor < 19 &&
'MUI X: The Tree View component requires all items to have a unique `id` property.',
- reactMajor < 19 && `The above error occurred in the component`,
- reactMajor < 19 && `The above error occurred in the component`,
+ reactMajor < 19 && `The above error occurred in the component`,
+ reactMajor < 19 && `The above error occurred in the component`,
]);
} else {
expect(() =>
@@ -40,7 +40,7 @@ describeTreeView<
reactMajor < 19 &&
'MUI X: The Tree View component requires all items to have a unique `id` property.',
reactMajor < 19 &&
- `The above error occurred in the component`,
+ `The above error occurred in the component`,
]);
}
});
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx
index 9bf2012fb2bf5..1c79ef97b0176 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx
@@ -6,6 +6,7 @@ import {
UseTreeViewExpansionSignature,
UseTreeViewSelectionSignature,
} from '@mui/x-tree-view/internals';
+import { clearWarningsCache } from '@mui/x-internals/warning';
/**
* All tests related to keyboard navigation (e.g.: selection using "Space")
@@ -15,6 +16,10 @@ describeTreeView<[UseTreeViewSelectionSignature, UseTreeViewExpansionSignature]>
'useTreeViewSelection plugin',
({ render }) => {
describe('model props (selectedItems, defaultSelectedItems, onSelectedItemsChange)', () => {
+ beforeEach(() => {
+ clearWarningsCache();
+ });
+
it('should not select items when no default state and no control state are defined', () => {
const view = render({
items: [{ id: '1' }, { id: '2' }],
diff --git a/packages/x-tree-view/vitest.config.browser.mts b/packages/x-tree-view/vitest.config.browser.mts
new file mode 100644
index 0000000000000..1b6f538191a3a
--- /dev/null
+++ b/packages/x-tree-view/vitest.config.browser.mts
@@ -0,0 +1,19 @@
+///
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'browser',
+ browser: {
+ enabled: true,
+ instances: [
+ {
+ browser: 'chromium',
+ },
+ ],
+ },
+ },
+});
diff --git a/packages/x-tree-view/vitest.config.jsdom.mts b/packages/x-tree-view/vitest.config.jsdom.mts
new file mode 100644
index 0000000000000..50dd48e254699
--- /dev/null
+++ b/packages/x-tree-view/vitest.config.jsdom.mts
@@ -0,0 +1,10 @@
+import { mergeConfig } from 'vitest/config';
+import sharedConfig from '../../vitest.shared.mts';
+import { getTestName } from '../../scripts/getTestName.mts';
+
+export default mergeConfig(sharedConfig, {
+ test: {
+ name: getTestName(import.meta.url),
+ environment: 'jsdom',
+ },
+});
diff --git a/patches/babel-plugin-replace-imports@1.0.2.patch b/patches/babel-plugin-replace-imports@1.0.2.patch
deleted file mode 100644
index be94600572cda..0000000000000
--- a/patches/babel-plugin-replace-imports@1.0.2.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/lib/index.js b/lib/index.js
-index 8da63adc141b73774c50363b31ee00001ccd9156..db49ed11479699f329f6b0bfb70fa73d6ad960e2 100644
---- a/lib/index.js
-+++ b/lib/index.js
-@@ -1 +1 @@
--'use strict';Object.defineProperty(exports,'__esModule',{value:!0}),exports.optionLabels=void 0,exports.getErrorMessage=getErrorMessage;var _lodash=require('lodash.isempty'),_lodash2=_interopRequireDefault(_lodash),_lodash3=require('lodash.isstring'),_lodash4=_interopRequireDefault(_lodash3),_lodash5=require('lodash.isregexp'),_lodash6=_interopRequireDefault(_lodash5),_lodash7=require('lodash.isobject'),_lodash8=_interopRequireDefault(_lodash7),_lodash9=require('lodash.isfunction'),_lodash10=_interopRequireDefault(_lodash9);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}var PLUGIN='babel-plugin-replace-imports',ERRORS={0:'options are required.',1:'option is required.',2:'option must be a RegExp.',3:'option must be a String or a Function',4:'options item must be an Object.'},optionLabels=exports.optionLabels={test:'test',replacer:'replacer'};function getErrorMessage(code,text){var msg=((text?'\xAB'+text+'\xBB':'')+' '+ERRORS[code]).trim();return'\n'+PLUGIN+': '+msg}function init(_ref){function throwError(code,text){var msg=getErrorMessage(code,text);throw new Error(msg)}function getOption(option){return(!(0,_lodash8.default)(option)||(0,_lodash6.default)(option)||Array.isArray(option))&&throwError(4),option}function getTestOption(option){return!(0,_lodash6.default)(option)&&(0,_lodash2.default)(option)&&throwError(1,optionLabels.test),(0,_lodash6.default)(option)||throwError(2,optionLabels.test),option}function getReplacerListOption(option){return(0,_lodash10.default)(option)?[option]:((0,_lodash2.default)(option)&&throwError(1,optionLabels.replacer),Array.isArray(option)?option:[option])}function getReplacerOption(option){return(0,_lodash4.default)(option)||(0,_lodash10.default)(option)||throwError(3,optionLabels.replacer),option}var types=_ref.types;return{visitor:{ImportDeclaration:function ImportDeclaration(path,_ref2){var opts=_ref2.opts;if(!path.node.__processed){(0,_lodash2.default)(opts)&&throwError(0);var source=path.node.source.value,transforms=[],options=opts;Array.isArray(options)||(options=[opts]);for(var _ret,_loop=function(i){var opt=getOption(options[i]),regex=getTestOption(opt[optionLabels.test]);if(regex.test(source)){var replacerList=getReplacerListOption(opt[optionLabels.replacer]);return replacerList.forEach(function(replacer){var repl=getReplacerOption(replacer),importDeclaration=types.importDeclaration(path.node.specifiers,types.stringLiteral(source.replace(regex,repl)));importDeclaration.__processed=!0,transforms.push(importDeclaration)}),'break'}},i=0;i=18'}
+
'@bundled-es-modules/cookie@2.0.1':
resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==}
@@ -2815,152 +2831,152 @@ packages:
resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==}
engines: {node: '>=16'}
- '@esbuild/aix-ppc64@0.25.2':
- resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
+ '@esbuild/aix-ppc64@0.25.3':
+ resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.25.2':
- resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
+ '@esbuild/android-arm64@0.25.3':
+ resolution: {integrity: sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.25.2':
- resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
+ '@esbuild/android-arm@0.25.3':
+ resolution: {integrity: sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.25.2':
- resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
+ '@esbuild/android-x64@0.25.3':
+ resolution: {integrity: sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.25.2':
- resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
+ '@esbuild/darwin-arm64@0.25.3':
+ resolution: {integrity: sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.25.2':
- resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
+ '@esbuild/darwin-x64@0.25.3':
+ resolution: {integrity: sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.25.2':
- resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
+ '@esbuild/freebsd-arm64@0.25.3':
+ resolution: {integrity: sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.25.2':
- resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
+ '@esbuild/freebsd-x64@0.25.3':
+ resolution: {integrity: sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.25.2':
- resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
+ '@esbuild/linux-arm64@0.25.3':
+ resolution: {integrity: sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.25.2':
- resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
+ '@esbuild/linux-arm@0.25.3':
+ resolution: {integrity: sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.25.2':
- resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
+ '@esbuild/linux-ia32@0.25.3':
+ resolution: {integrity: sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.25.2':
- resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
+ '@esbuild/linux-loong64@0.25.3':
+ resolution: {integrity: sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.25.2':
- resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
+ '@esbuild/linux-mips64el@0.25.3':
+ resolution: {integrity: sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.25.2':
- resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
+ '@esbuild/linux-ppc64@0.25.3':
+ resolution: {integrity: sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.25.2':
- resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
+ '@esbuild/linux-riscv64@0.25.3':
+ resolution: {integrity: sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.25.2':
- resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
+ '@esbuild/linux-s390x@0.25.3':
+ resolution: {integrity: sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.25.2':
- resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
+ '@esbuild/linux-x64@0.25.3':
+ resolution: {integrity: sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.25.2':
- resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
+ '@esbuild/netbsd-arm64@0.25.3':
+ resolution: {integrity: sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.25.2':
- resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
+ '@esbuild/netbsd-x64@0.25.3':
+ resolution: {integrity: sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.25.2':
- resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
+ '@esbuild/openbsd-arm64@0.25.3':
+ resolution: {integrity: sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.25.2':
- resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
+ '@esbuild/openbsd-x64@0.25.3':
+ resolution: {integrity: sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/sunos-x64@0.25.2':
- resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
+ '@esbuild/sunos-x64@0.25.3':
+ resolution: {integrity: sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.25.2':
- resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
+ '@esbuild/win32-arm64@0.25.3':
+ resolution: {integrity: sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.25.2':
- resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
+ '@esbuild/win32-ia32@0.25.3':
+ resolution: {integrity: sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.25.2':
- resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
+ '@esbuild/win32-x64@0.25.3':
+ resolution: {integrity: sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -4659,6 +4675,15 @@ packages:
webdriverio:
optional: true
+ '@vitest/coverage-v8@3.1.2':
+ resolution: {integrity: sha512-XDdaDOeaTMAMYW7N63AqoK32sYUWbXnTkC6tEbVcu3RlU1bB9of32T+PGf8KZvxqLNqeXhafDFqCkwpf2+dyaQ==}
+ peerDependencies:
+ '@vitest/browser': 3.1.2
+ vitest: 3.1.2
+ peerDependenciesMeta:
+ '@vitest/browser':
+ optional: true
+
'@vitest/expect@3.1.2':
resolution: {integrity: sha512-O8hJgr+zREopCAqWl3uCVaOdqJwZ9qaDwUP7vy3Xigad0phZe9APxKhPcDNqYYi0rX5oMvwJMSCAXY2afqeTSA==}
@@ -5124,9 +5149,6 @@ packages:
babel-plugin-react-remove-properties@0.3.0:
resolution: {integrity: sha512-vbxegtXGyVcUkCvayLzftU95vuvpYFV85pRpeMpohMHeEY46Qe0VNWfkVVcCbaZ12CXHzDFOj0esumATcW83ng==}
- babel-plugin-replace-imports@1.0.2:
- resolution: {integrity: sha512-v+9S4FBg9wYit3c+bDxhRHv/pnhBhhneZOPvqT1c293SSjUuUy1MPK76TsJ9038fp/SD2/TNcqG5PUBoG9/ByQ==}
-
babel-plugin-search-and-replace@1.1.1:
resolution: {integrity: sha512-fjP2VTF3mxxOUnc96mdK22llH92A6gu7A5AFapJmgnqsQi3bqLduIRP0FpA2r5vRZOYPpnX4rE5izQlpsMBjSA==}
@@ -5325,8 +5347,8 @@ packages:
camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- caniuse-lite@1.0.30001707:
- resolution: {integrity: sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==}
+ caniuse-lite@1.0.30001703:
+ resolution: {integrity: sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==}
chai-dom@1.12.1:
resolution: {integrity: sha512-tvz+D0PJue2VHXRec3udgP/OeeXBiePU3VH6JhEnHQJYzvNzR2nUvEykA9dXVS76JvaUENSOYH8Ufr0kZSnlCQ==}
@@ -5369,6 +5391,10 @@ packages:
resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ chalk@5.3.0:
+ resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
chance@1.1.12:
resolution: {integrity: sha512-vVBIGQVnwtUG+SYe0ge+3MvF78cvSpuCOEUJr7sVEk2vSBuMW6OXNJjSzdtzrlxNUEaoqH2GBd5Y/+18BEB01Q==}
@@ -6239,8 +6265,8 @@ packages:
es6-error@4.1.1:
resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
- esbuild@0.25.2:
- resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
+ esbuild@0.25.3:
+ resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==}
engines: {node: '>=18'}
hasBin: true
@@ -7478,6 +7504,10 @@ packages:
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
engines: {node: '>=10'}
+ istanbul-lib-source-maps@5.0.6:
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
+ engines: {node: '>=10'}
+
istanbul-reports@3.1.7:
resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
engines: {node: '>=8'}
@@ -7903,9 +7933,6 @@ packages:
lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
- lodash.isempty@4.4.0:
- resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==}
-
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
@@ -7931,9 +7958,6 @@ packages:
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
- lodash.isregexp@4.0.1:
- resolution: {integrity: sha512-rw9+95tYcUa9nQ1FgdtKvO+hReLGNqnNMHfLq8SwK5Mo6D0R0tIsnRHGHaTHSKeYBaLCJ1JvXWdz4UmpPZ2bag==}
-
lodash.isstring@4.0.1:
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
@@ -8022,6 +8046,9 @@ packages:
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+ magicast@0.3.5:
+ resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+
make-array@1.0.5:
resolution: {integrity: sha512-sgK2SAzxT19rWU+qxKUcn6PAh/swiIiz2F8C2cZjLc1z4iwYIfdoihqFIDQ8BDzAGtWPYJ6Sr13K1j/DXynDLA==}
engines: {node: '>=0.10.0'}
@@ -8418,8 +8445,8 @@ packages:
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- nanoid@3.3.11:
- resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ nanoid@3.3.9:
+ resolution: {integrity: sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -10031,6 +10058,10 @@ packages:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
+ test-exclude@7.0.1:
+ resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
+ engines: {node: '>=18'}
+
text-extensions@1.9.0:
resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==}
engines: {node: '>=0.10'}
@@ -10492,6 +10523,12 @@ packages:
yaml:
optional: true
+ vitest-fail-on-console@0.7.1:
+ resolution: {integrity: sha512-/PjuonFu7CwUVrKaiQPIGXOtiEv2/Gz3o8MbLmovX9TGDxoRCctRC8CA9zJMRUd6AvwGu/V5a3znObTmlPNTgw==}
+ peerDependencies:
+ vite: '>=4.5.2'
+ vitest: '>=0.26.2'
+
vitest@3.1.2:
resolution: {integrity: sha512-WaxpJe092ID1C0mr+LH9MmNrhfzi8I65EX/NRU/Ld016KqQNRgxSOlGNP1hHN+a/F8L15Mh8klwaF77zR3GeDQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@@ -11796,6 +11833,8 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
+ '@bcoe/v8-coverage@1.0.2': {}
+
'@bundled-es-modules/cookie@2.0.1':
dependencies:
cookie: 0.7.2
@@ -11988,79 +12027,79 @@ snapshots:
esquery: 1.6.0
jsdoc-type-pratt-parser: 4.1.0
- '@esbuild/aix-ppc64@0.25.2':
+ '@esbuild/aix-ppc64@0.25.3':
optional: true
- '@esbuild/android-arm64@0.25.2':
+ '@esbuild/android-arm64@0.25.3':
optional: true
- '@esbuild/android-arm@0.25.2':
+ '@esbuild/android-arm@0.25.3':
optional: true
- '@esbuild/android-x64@0.25.2':
+ '@esbuild/android-x64@0.25.3':
optional: true
- '@esbuild/darwin-arm64@0.25.2':
+ '@esbuild/darwin-arm64@0.25.3':
optional: true
- '@esbuild/darwin-x64@0.25.2':
+ '@esbuild/darwin-x64@0.25.3':
optional: true
- '@esbuild/freebsd-arm64@0.25.2':
+ '@esbuild/freebsd-arm64@0.25.3':
optional: true
- '@esbuild/freebsd-x64@0.25.2':
+ '@esbuild/freebsd-x64@0.25.3':
optional: true
- '@esbuild/linux-arm64@0.25.2':
+ '@esbuild/linux-arm64@0.25.3':
optional: true
- '@esbuild/linux-arm@0.25.2':
+ '@esbuild/linux-arm@0.25.3':
optional: true
- '@esbuild/linux-ia32@0.25.2':
+ '@esbuild/linux-ia32@0.25.3':
optional: true
- '@esbuild/linux-loong64@0.25.2':
+ '@esbuild/linux-loong64@0.25.3':
optional: true
- '@esbuild/linux-mips64el@0.25.2':
+ '@esbuild/linux-mips64el@0.25.3':
optional: true
- '@esbuild/linux-ppc64@0.25.2':
+ '@esbuild/linux-ppc64@0.25.3':
optional: true
- '@esbuild/linux-riscv64@0.25.2':
+ '@esbuild/linux-riscv64@0.25.3':
optional: true
- '@esbuild/linux-s390x@0.25.2':
+ '@esbuild/linux-s390x@0.25.3':
optional: true
- '@esbuild/linux-x64@0.25.2':
+ '@esbuild/linux-x64@0.25.3':
optional: true
- '@esbuild/netbsd-arm64@0.25.2':
+ '@esbuild/netbsd-arm64@0.25.3':
optional: true
- '@esbuild/netbsd-x64@0.25.2':
+ '@esbuild/netbsd-x64@0.25.3':
optional: true
- '@esbuild/openbsd-arm64@0.25.2':
+ '@esbuild/openbsd-arm64@0.25.3':
optional: true
- '@esbuild/openbsd-x64@0.25.2':
+ '@esbuild/openbsd-x64@0.25.3':
optional: true
- '@esbuild/sunos-x64@0.25.2':
+ '@esbuild/sunos-x64@0.25.3':
optional: true
- '@esbuild/win32-arm64@0.25.2':
+ '@esbuild/win32-arm64@0.25.3':
optional: true
- '@esbuild/win32-ia32@0.25.2':
+ '@esbuild/win32-ia32@0.25.3':
optional: true
- '@esbuild/win32-x64@0.25.2':
+ '@esbuild/win32-x64@0.25.3':
optional: true
'@eslint-community/eslint-utils@4.5.0(eslint@8.57.1)':
@@ -13791,11 +13830,11 @@ snapshots:
'@types/use-sync-external-store@1.5.0': {}
- '@types/webpack-bundle-analyzer@4.7.0(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))':
+ '@types/webpack-bundle-analyzer@4.7.0(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))':
dependencies:
'@types/node': 22.15.3
tapable: 2.2.1
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
transitivePeerDependencies:
- '@swc/core'
- esbuild
@@ -13942,6 +13981,26 @@ snapshots:
- utf-8-validate
- vite
+ '@vitest/coverage-v8@3.1.2(@vitest/browser@3.1.2)(vitest@3.1.2)':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@bcoe/v8-coverage': 1.0.2
+ debug: 4.4.0(supports-color@8.1.1)
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 5.0.6
+ istanbul-reports: 3.1.7
+ magic-string: 0.30.17
+ magicast: 0.3.5
+ std-env: 3.9.0
+ test-exclude: 7.0.1
+ tinyrainbow: 2.0.0
+ vitest: 3.1.2(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/browser@3.1.2)(@vitest/ui@3.1.2)(jsdom@26.1.0)(lightningcss@1.29.3)(msw@2.7.3(@types/node@22.15.3)(typescript@5.8.3))(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0)
+ optionalDependencies:
+ '@vitest/browser': 3.1.2(msw@2.7.3(@types/node@22.15.3)(typescript@5.8.3))(playwright@1.52.0)(vite@6.3.4(@types/node@22.15.3)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0))(vitest@3.1.2)
+ transitivePeerDependencies:
+ - supports-color
+
'@vitest/expect@3.1.2':
dependencies:
'@vitest/spy': 3.1.2
@@ -14081,17 +14140,17 @@ snapshots:
'@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))(webpack@5.99.7)':
dependencies:
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7)
'@webpack-cli/info@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))(webpack@5.99.7)':
dependencies:
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7)
'@webpack-cli/serve@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))(webpack@5.99.7)':
dependencies:
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7)
'@xtuc/ieee754@1.2.0': {}
@@ -14422,7 +14481,7 @@ snapshots:
autoprefixer@10.4.21(postcss@8.5.3):
dependencies:
browserslist: 4.24.4
- caniuse-lite: 1.0.30001707
+ caniuse-lite: 1.0.30001703
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
@@ -14449,7 +14508,7 @@ snapshots:
dependencies:
'@babel/core': 7.27.1
find-up: 5.0.0
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
babel-plugin-istanbul@7.0.0:
dependencies:
@@ -14517,14 +14576,6 @@ snapshots:
babel-plugin-react-remove-properties@0.3.0: {}
- babel-plugin-replace-imports@1.0.2(patch_hash=779d8690d607924781aaf4f896bfbd209a78755ddd5b9ebbea5ebce3b2919ba0):
- dependencies:
- lodash.isempty: 4.4.0
- lodash.isfunction: 3.0.9
- lodash.isobject: 3.0.2
- lodash.isregexp: 4.0.1
- lodash.isstring: 4.0.1
-
babel-plugin-search-and-replace@1.1.1: {}
babel-plugin-transform-import-meta@2.3.2(@babel/core@7.27.1):
@@ -14623,7 +14674,7 @@ snapshots:
dependencies:
ansi-align: 3.0.1
camelcase: 7.0.1
- chalk: 5.0.1
+ chalk: 5.3.0
cli-boxes: 3.0.0
string-width: 5.1.2
type-fest: 2.19.0
@@ -14647,7 +14698,7 @@ snapshots:
browserslist@4.24.4:
dependencies:
- caniuse-lite: 1.0.30001707
+ caniuse-lite: 1.0.30001703
electron-to-chromium: 1.5.114
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4)
@@ -14756,7 +14807,7 @@ snapshots:
camelize@1.0.1: {}
- caniuse-lite@1.0.30001707: {}
+ caniuse-lite@1.0.30001703: {}
chai-dom@1.12.1(chai@4.5.0):
dependencies:
@@ -14811,6 +14862,8 @@ snapshots:
chalk@5.0.1: {}
+ chalk@5.3.0: {}
+
chance@1.1.12: {}
character-entities-legacy@3.0.0: {}
@@ -14991,7 +15044,7 @@ snapshots:
dependencies:
schema-utils: 4.3.2
serialize-javascript: 6.0.2
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
compression@1.7.4:
dependencies:
@@ -15750,33 +15803,33 @@ snapshots:
es6-error@4.1.1: {}
- esbuild@0.25.2:
+ esbuild@0.25.3:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.25.2
- '@esbuild/android-arm': 0.25.2
- '@esbuild/android-arm64': 0.25.2
- '@esbuild/android-x64': 0.25.2
- '@esbuild/darwin-arm64': 0.25.2
- '@esbuild/darwin-x64': 0.25.2
- '@esbuild/freebsd-arm64': 0.25.2
- '@esbuild/freebsd-x64': 0.25.2
- '@esbuild/linux-arm': 0.25.2
- '@esbuild/linux-arm64': 0.25.2
- '@esbuild/linux-ia32': 0.25.2
- '@esbuild/linux-loong64': 0.25.2
- '@esbuild/linux-mips64el': 0.25.2
- '@esbuild/linux-ppc64': 0.25.2
- '@esbuild/linux-riscv64': 0.25.2
- '@esbuild/linux-s390x': 0.25.2
- '@esbuild/linux-x64': 0.25.2
- '@esbuild/netbsd-arm64': 0.25.2
- '@esbuild/netbsd-x64': 0.25.2
- '@esbuild/openbsd-arm64': 0.25.2
- '@esbuild/openbsd-x64': 0.25.2
- '@esbuild/sunos-x64': 0.25.2
- '@esbuild/win32-arm64': 0.25.2
- '@esbuild/win32-ia32': 0.25.2
- '@esbuild/win32-x64': 0.25.2
+ '@esbuild/aix-ppc64': 0.25.3
+ '@esbuild/android-arm': 0.25.3
+ '@esbuild/android-arm64': 0.25.3
+ '@esbuild/android-x64': 0.25.3
+ '@esbuild/darwin-arm64': 0.25.3
+ '@esbuild/darwin-x64': 0.25.3
+ '@esbuild/freebsd-arm64': 0.25.3
+ '@esbuild/freebsd-x64': 0.25.3
+ '@esbuild/linux-arm': 0.25.3
+ '@esbuild/linux-arm64': 0.25.3
+ '@esbuild/linux-ia32': 0.25.3
+ '@esbuild/linux-loong64': 0.25.3
+ '@esbuild/linux-mips64el': 0.25.3
+ '@esbuild/linux-ppc64': 0.25.3
+ '@esbuild/linux-riscv64': 0.25.3
+ '@esbuild/linux-s390x': 0.25.3
+ '@esbuild/linux-x64': 0.25.3
+ '@esbuild/netbsd-arm64': 0.25.3
+ '@esbuild/netbsd-x64': 0.25.3
+ '@esbuild/openbsd-arm64': 0.25.3
+ '@esbuild/openbsd-x64': 0.25.3
+ '@esbuild/sunos-x64': 0.25.3
+ '@esbuild/win32-arm64': 0.25.3
+ '@esbuild/win32-ia32': 0.25.3
+ '@esbuild/win32-x64': 0.25.3
escalade@3.2.0: {}
@@ -15842,7 +15895,7 @@ snapshots:
lodash: 4.17.21
resolve: 2.0.0-next.5
semver: 5.7.2
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
transitivePeerDependencies:
- supports-color
@@ -16817,7 +16870,7 @@ snapshots:
pretty-error: 4.0.0
tapable: 2.2.1
optionalDependencies:
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
htmlparser2@6.1.0:
dependencies:
@@ -17241,6 +17294,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ istanbul-lib-source-maps@5.0.6:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ debug: 4.4.0(supports-color@8.1.1)
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+
istanbul-reports@3.1.7:
dependencies:
html-escaper: 2.0.2
@@ -17522,7 +17583,7 @@ snapshots:
dependencies:
glob: 7.2.3
minimatch: 9.0.5
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
webpack-merge: 4.2.2
karma@6.4.4:
@@ -17828,8 +17889,6 @@ snapshots:
lodash.isboolean@3.0.3: {}
- lodash.isempty@4.4.0: {}
-
lodash.isequal@4.5.0: {}
lodash.isfunction@3.0.9: {}
@@ -17846,8 +17905,6 @@ snapshots:
lodash.isplainobject@4.0.6: {}
- lodash.isregexp@4.0.1: {}
-
lodash.isstring@4.0.1: {}
lodash.isundefined@3.0.1: {}
@@ -17925,6 +17982,12 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
+ magicast@0.3.5:
+ dependencies:
+ '@babel/parser': 7.27.1
+ '@babel/types': 7.27.1
+ source-map-js: 1.2.1
+
make-array@1.0.5: {}
make-dir@2.1.0:
@@ -18518,7 +18581,7 @@ snapshots:
object-assign: 4.1.1
thenify-all: 1.6.0
- nanoid@3.3.11: {}
+ nanoid@3.3.9: {}
natural-compare@1.4.0: {}
@@ -18538,7 +18601,7 @@ snapshots:
'@swc/counter': 0.1.3
'@swc/helpers': 0.5.15
busboy: 1.6.0
- caniuse-lite: 1.0.30001707
+ caniuse-lite: 1.0.30001703
postcss: 8.4.31
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
@@ -18706,7 +18769,7 @@ snapshots:
dependencies:
loader-utils: 2.0.4
schema-utils: 3.3.0
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
nwsapi@2.2.18: {}
@@ -19219,19 +19282,19 @@ snapshots:
postcss@8.4.31:
dependencies:
- nanoid: 3.3.11
+ nanoid: 3.3.9
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.4.49:
dependencies:
- nanoid: 3.3.11
+ nanoid: 3.3.9
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.5.3:
dependencies:
- nanoid: 3.3.11
+ nanoid: 3.3.9
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -20206,7 +20269,7 @@ snapshots:
dependencies:
loader-utils: 2.0.4
schema-utils: 3.3.0
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
string-width@4.2.3:
dependencies:
@@ -20408,16 +20471,17 @@ snapshots:
temp-dir@1.0.0: {}
- terser-webpack-plugin@5.3.14(@swc/core@1.11.21)(webpack@5.99.7):
+ terser-webpack-plugin@5.3.14(@swc/core@1.11.21)(esbuild@0.25.3)(webpack@5.99.7):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 4.3.2
serialize-javascript: 6.0.2
terser: 5.39.0
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
optionalDependencies:
'@swc/core': 1.11.21
+ esbuild: 0.25.3
terser@5.39.0:
dependencies:
@@ -20432,6 +20496,12 @@ snapshots:
glob: 7.2.3
minimatch: 3.1.2
+ test-exclude@7.0.1:
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 10.4.5
+ minimatch: 9.0.5
+
text-extensions@1.9.0: {}
text-table@0.2.0: {}
@@ -20550,7 +20620,7 @@ snapshots:
tsx@4.19.4:
dependencies:
- esbuild: 0.25.2
+ esbuild: 0.25.3
get-tsconfig: 4.10.0
optionalDependencies:
fsevents: 2.3.3
@@ -20853,7 +20923,7 @@ snapshots:
vite@6.3.4(@types/node@22.15.3)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0):
dependencies:
- esbuild: 0.25.2
+ esbuild: 0.25.3
fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
postcss: 8.5.3
@@ -20867,6 +20937,12 @@ snapshots:
tsx: 4.19.4
yaml: 2.7.0
+ vitest-fail-on-console@0.7.1(vite@6.3.4(@types/node@22.15.3)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0))(vitest@3.1.2):
+ dependencies:
+ chalk: 5.3.0
+ vite: 6.3.4(@types/node@22.15.3)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0)
+ vitest: 3.1.2(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/browser@3.1.2)(@vitest/ui@3.1.2)(jsdom@26.1.0)(lightningcss@1.29.3)(msw@2.7.3(@types/node@22.15.3)(typescript@5.8.3))(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0)
+
vitest@3.1.2(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/browser@3.1.2)(@vitest/ui@3.1.2)(jsdom@26.1.0)(lightningcss@1.29.3)(msw@2.7.3(@types/node@22.15.3)(typescript@5.8.3))(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.0):
dependencies:
'@vitest/expect': 3.1.2
@@ -20963,7 +21039,7 @@ snapshots:
import-local: 3.2.0
interpret: 3.1.1
rechoir: 0.8.0
- webpack: 5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
+ webpack: 5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7))
webpack-merge: 6.0.1
optionalDependencies:
webpack-bundle-analyzer: 4.10.2
@@ -20980,7 +21056,7 @@ snapshots:
webpack-sources@3.2.3: {}
- webpack@5.99.7(@swc/core@1.11.21)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7)):
+ webpack@5.99.7(@swc/core@1.11.21)(esbuild@0.25.3)(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.99.7)):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.7
@@ -21003,7 +21079,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.2
tapable: 2.2.1
- terser-webpack-plugin: 5.3.14(@swc/core@1.11.21)(webpack@5.99.7)
+ terser-webpack-plugin: 5.3.14(@swc/core@1.11.21)(esbuild@0.25.3)(webpack@5.99.7)
watchpack: 2.4.2
webpack-sources: 3.2.3
optionalDependencies:
diff --git a/renovate.json b/renovate.json
index 931624193417f..d74896da36c44 100644
--- a/renovate.json
+++ b/renovate.json
@@ -104,7 +104,7 @@
},
{
"groupName": "Vite & Vitest",
- "matchPackageNames": ["@vitejs/**", "/vitest/"]
+ "matchPackageNames": ["@vitejs/**", "/vitest/", "esbuild"]
},
{
"groupName": "date-fns-v2",
diff --git a/scripts/getTestName.mts b/scripts/getTestName.mts
new file mode 100644
index 0000000000000..63cab306773b0
--- /dev/null
+++ b/scripts/getTestName.mts
@@ -0,0 +1,10 @@
+import { readFileSync } from 'node:fs';
+
+export const getTestName = (url: string): string => {
+ const packageJson = readFileSync(new URL('./package.json', url), 'utf-8');
+
+ const packageJsonParsed = JSON.parse(packageJson);
+ const packageName = packageJsonParsed.name.split('/')[1] ?? packageJsonParsed.name;
+
+ return packageName;
+};
diff --git a/scripts/test.mjs b/scripts/test.mjs
deleted file mode 100644
index d2a4b5485de60..0000000000000
--- a/scripts/test.mjs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* eslint-disable no-console */
-import { spawn } from 'node:child_process';
-
-/*
-This script ensures that we can use the same commands to run tests
-when using pnpm as when using Yarn.
-It enables to run `pnpm test` (or `pnpm t`) without any arguments, to run all tests,
-or `pnpm test ` (or `pnpm t `) to run a subset of tests in watch mode.
-
-See https://github.com/mui/mui-x/pull/12948 for more context.
-*/
-
-if (process.argv.length < 3) {
- console.log('Running unit tests...');
- spawn('pnpm', ['test:unit'], {
- shell: true,
- stdio: ['inherit', 'inherit', 'inherit'],
- env: {
- ...process.env,
- TZ: 'UTC',
- },
- });
-} else {
- console.log('Running selected tests in watch mode...');
- console.warn(
- 'Note: run `pnpm tc` to have a better experience (and be able to pass in additional parameters).',
- );
-
- console.log('cmd', ['tc', ...process.argv.slice(2)]);
-
- spawn('pnpm', ['tc', ...process.argv.slice(2)], {
- shell: true,
- stdio: ['inherit', 'inherit', 'inherit'],
- env: {
- ...process.env,
- TZ: 'UTC',
- },
- });
-}
diff --git a/test/cli.js b/test/cli.js
deleted file mode 100644
index 509892a5809c7..0000000000000
--- a/test/cli.js
+++ /dev/null
@@ -1,126 +0,0 @@
-const childProcess = require('child_process');
-const fs = require('fs');
-const glob = require('fast-glob');
-const path = require('path');
-const yargs = require('yargs');
-
-async function run(argv) {
- const workspaceRoot = path.resolve(__dirname, '../');
-
- const gitignore = fs.readFileSync(path.join(workspaceRoot, '.gitignore'), { encoding: 'utf-8' });
- const ignore = gitignore
- .split(/\r?\n/)
- .filter((pattern) => {
- return pattern.length > 0 && !pattern.startsWith('#');
- })
- .map((line) => {
- if (line.startsWith('/')) {
- // "/" marks the cwd of the ignore file.
- // Since we declare the dirname of the gitignore the cwd we can prepend "." as a shortcut.
- return `.${line}`;
- }
- return line;
- });
- const globPattern = `**/*${argv.testFilePattern.replace(/\\/g, '/')}*`;
- const spec = glob
- .sync(globPattern, {
- cwd: workspaceRoot,
- ignore,
- followSymbolicLinks: false,
- })
- .filter((relativeFile) => {
- return /\.test\.(js|ts|tsx)$/.test(relativeFile);
- });
-
- if (spec.length === 0) {
- throw new Error(`Could not find any file test files matching '${globPattern}'`);
- }
-
- const args = ['mocha'].concat(spec);
- if (argv.bail) {
- args.push('--bail');
- }
- if (argv.debug || argv.inspecting) {
- args.push('--timeout 0');
- }
- if (argv.debug) {
- args.push('--inspect-brk');
- }
- if (!argv.single) {
- args.push('--watch');
- }
- if (argv.testNamePattern !== undefined) {
- args.push(`--grep '${argv.testNamePattern}'`);
- }
-
- const mochaProcess = childProcess.spawn('pnpm', args, {
- env: {
- ...process.env,
- BABEL_ENV: 'test',
- NODE_ENV: argv.production ? 'production' : 'test',
- TZ: 'UTC',
- },
- shell: true,
- stdio: ['inherit', 'inherit', 'inherit'],
- });
-
- mochaProcess.once('exit', (signal) => {
- process.exit(signal !== null ? signal : undefined);
- });
-
- process.on('SIGINT', () => {
- // Forward interrupt.
- // Otherwise cli.js exits and the you get dangling console output from mocha.
- // "dangling" meaning that you get mocha output in the new terminal input.
- mochaProcess.kill('SIGINT');
- });
-}
-
-yargs
- .command({
- command: '$0 ',
- description: 'Test cli for developing',
- builder: (command) => {
- return command
- .positional('testFilePattern', {
- description: 'Only test files match "**/*{testFilePattern}*.test.{js,ts,tsx}"',
- type: 'string',
- })
- .option('bail', {
- alias: 'b',
- description: 'Stop on first error.',
- type: 'boolean',
- })
- .option('debug', {
- alias: 'd',
- description:
- 'Allows attaching a debugger and waits for the debugger to start code execution.',
- type: 'boolean',
- })
- .option('inspecting', {
- description: 'In case you expect to hit breakpoints that may interrupt a test.',
- type: 'boolean',
- })
- .option('production', {
- alias: 'p',
- description:
- 'Run tests in production environment. WARNING: Will not work with most tests.',
- type: 'boolean',
- })
- .option('single', {
- alias: 's',
- description: 'Run only once i.e. not in watch mode.',
- type: 'boolean',
- })
- .option('testNamePattern', {
- alias: 't',
- description: 'Limit tests by their name given a pattern.',
- type: 'string',
- });
- },
- handler: run,
- })
- .help()
- .strict(true)
- .version(false)
- .parse();
diff --git a/test/setupVitest.ts b/test/setupVitest.ts
new file mode 100644
index 0000000000000..f76a851fb71c1
--- /dev/null
+++ b/test/setupVitest.ts
@@ -0,0 +1,96 @@
+import { beforeAll, afterAll } from 'vitest';
+import 'test/utils/addChaiAssertions';
+import 'test/utils/setupPickers';
+import 'test/utils/licenseRelease';
+import { generateTestLicenseKey, setupTestLicenseKey } from 'test/utils/testLicense';
+import { configure } from '@mui/internal-test-utils';
+import { config } from 'react-transition-group';
+
+import sinon from 'sinon';
+import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingDataGrid } from '@mui/x-data-grid';
+import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingDataGridPro } from '@mui/x-data-grid-pro';
+import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingTreeView } from '@mui/x-tree-view';
+import { unstable_cleanupDOM as unstable_cleanupDOMCharts } from '@mui/x-charts/internals';
+import failOnConsole from 'vitest-fail-on-console';
+import { clearWarningsCache } from '@mui/x-internals/warning';
+import { isJSDOM } from './utils/skipIf';
+
+// Core's setupVitest is causing issues with the test setup
+// import '@mui/internal-test-utils/setupVitest';
+
+// Enable missing act warnings: https://github.com/reactwg/react-18/discussions/102
+(globalThis as any).jest = null;
+(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
+
+let licenseKey: string = '';
+
+beforeAll(() => {
+ licenseKey = generateTestLicenseKey();
+});
+
+beforeEach(() => {
+ clearWarningsCache();
+ setupTestLicenseKey(licenseKey);
+ config.disabled = true;
+});
+
+afterEach(() => {
+ unstable_resetCleanupTrackingDataGrid();
+ unstable_resetCleanupTrackingDataGridPro();
+ unstable_resetCleanupTrackingTreeView();
+ unstable_cleanupDOMCharts();
+
+ // Restore Sinon default sandbox to avoid memory leak
+ // See https://github.com/sinonjs/sinon/issues/1866
+ sinon.restore();
+ config.disabled = false;
+});
+
+configure({
+ // JSDOM logs errors otherwise on `getComputedStyle(element, pseudoElement)` calls.
+ computedStyleSupportsPseudoElements: !isJSDOM,
+});
+
+failOnConsole();
+
+if (!globalThis.before) {
+ (globalThis as any).before = beforeAll;
+}
+if (!globalThis.after) {
+ (globalThis as any).after = afterAll;
+}
+
+const isJsdom = typeof window !== 'undefined' && window.navigator.userAgent.includes('jsdom');
+
+// Only necessary when not in browser mode.
+if (isJsdom) {
+ class Touch {
+ instance: any;
+
+ constructor(instance: any) {
+ this.instance = instance;
+ }
+
+ get identifier() {
+ return this.instance.identifier;
+ }
+
+ get pageX() {
+ return this.instance.pageX;
+ }
+
+ get pageY() {
+ return this.instance.pageY;
+ }
+
+ get clientX() {
+ return this.instance.clientX;
+ }
+
+ get clientY() {
+ return this.instance.clientY;
+ }
+ }
+ // @ts-expect-error
+ globalThis.window.Touch = Touch;
+}
diff --git a/test/utils/pickers/createPickerRenderer.tsx b/test/utils/pickers/createPickerRenderer.tsx
index 4486c900675de..0630c430ac523 100644
--- a/test/utils/pickers/createPickerRenderer.tsx
+++ b/test/utils/pickers/createPickerRenderer.tsx
@@ -1,10 +1,11 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { createRenderer, CreateRendererOptions, RenderOptions } from '@mui/internal-test-utils';
-import sinon from 'sinon';
+import { vi } from 'vitest';
import { AdapterClassToUse, AdapterName, adapterToUse, availableAdapters } from './adapters';
-interface CreatePickerRendererOptions extends CreateRendererOptions {
+interface CreatePickerRendererOptions
+ extends Omit {
// Set-up locale with date-fns object. Other are deduced from `locale.code`
locale?: { code: string } | any;
adapterName?: AdapterName;
@@ -15,29 +16,21 @@ export function createPickerRenderer({
locale,
adapterName,
instance,
- clock: inClock,
clockConfig,
...createRendererOptions
}: CreatePickerRendererOptions = {}) {
- // TODO: Temporary until vitest is enabled
- // If only clockConfig='2020/02/20' is provided, we just fake the Date, not the timers
- // Most of the time we are using the clock we just want to fake the Date
- // If timers are faked it can create inconsistencies with the tests.
- // In some cases it also prevents us from really testing the real behavior of the component.
- if (!inClock && clockConfig) {
- let timer: sinon.SinonFakeTimers | null = null;
- beforeEach(() => {
- timer = sinon.useFakeTimers({ now: clockConfig, toFake: ['Date'] });
- });
- afterEach(() => {
- timer?.restore();
- });
- }
-
- const { clock, render: clientRender } = createRenderer({
+ const { render: clientRender } = createRenderer({
...createRendererOptions,
- // TODO: Temporary until vitest is enabled
- ...(inClock ? { clock: inClock, clockConfig } : {}),
+ });
+ beforeEach(() => {
+ if (clockConfig) {
+ vi.setSystemTime(clockConfig);
+ }
+ });
+ afterEach(() => {
+ if (clockConfig) {
+ vi.useRealTimers();
+ }
});
let adapterLocale = [
@@ -67,7 +60,6 @@ export function createPickerRenderer({
}
return {
- clock,
render(node: React.ReactElement, options?: Omit) {
return clientRender(node, { ...options, wrapper: Wrapper });
},
diff --git a/test/utils/pickers/describeRangeValidation/testDayViewRangeValidation.tsx b/test/utils/pickers/describeRangeValidation/testDayViewRangeValidation.tsx
index 5a86fa33339f5..8d219cde1a523 100644
--- a/test/utils/pickers/describeRangeValidation/testDayViewRangeValidation.tsx
+++ b/test/utils/pickers/describeRangeValidation/testDayViewRangeValidation.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import { expect } from 'chai';
-import { SinonFakeTimers, useFakeTimers } from 'sinon';
import { screen } from '@mui/internal-test-utils';
import { adapterToUse } from 'test/utils/pickers';
import { describeSkipIf } from 'test/utils/skipIf';
+import { vi } from 'vitest';
import { DescribeRangeValidationTestSuite } from './describeRangeValidation.types';
const isDisabled = (el: HTMLElement) => el.getAttribute('disabled') !== null;
@@ -68,14 +68,14 @@ export const testDayViewRangeValidation: DescribeRangeValidationTestSuite = (
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 5));
});
+
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
+
it('should apply disablePast', () => {
const { render } = getOptions();
diff --git a/test/utils/pickers/describeRangeValidation/testTextFieldKeyboardRangeValidation.tsx b/test/utils/pickers/describeRangeValidation/testTextFieldKeyboardRangeValidation.tsx
index 3236b438cdaf4..bc8d308f46161 100644
--- a/test/utils/pickers/describeRangeValidation/testTextFieldKeyboardRangeValidation.tsx
+++ b/test/utils/pickers/describeRangeValidation/testTextFieldKeyboardRangeValidation.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
import { expect } from 'chai';
-import { SinonFakeTimers, spy, useFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { adapterToUse, getAllFieldInputRoot } from 'test/utils/pickers';
import { act } from '@mui/internal-test-utils/createRenderer';
import { describeSkipIf, testSkipIf } from 'test/utils/skipIf';
+import { vi } from 'vitest';
import { DescribeRangeValidationTestSuite } from './describeRangeValidation.types';
const testInvalidStatus = (
@@ -99,14 +100,14 @@ export const testTextFieldKeyboardRangeValidation: DescribeRangeValidationTestSu
testInvalidStatus([true, false], fieldType);
});
describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 1));
});
+
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
+
it('should apply disablePast', () => {
const onErrorMock = spy();
const now = adapterToUse.date();
diff --git a/test/utils/pickers/describeRangeValidation/testTextFieldRangeValidation.tsx b/test/utils/pickers/describeRangeValidation/testTextFieldRangeValidation.tsx
index 6da9c85a50b06..3fd78a254ebb2 100644
--- a/test/utils/pickers/describeRangeValidation/testTextFieldRangeValidation.tsx
+++ b/test/utils/pickers/describeRangeValidation/testTextFieldRangeValidation.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import { expect } from 'chai';
-import { SinonFakeTimers, spy, useFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { adapterToUse, getAllFieldInputRoot } from 'test/utils/pickers';
import { describeSkipIf, testSkipIf } from 'test/utils/skipIf';
+import { vi } from 'vitest';
import { DescribeRangeValidationTestSuite } from './describeRangeValidation.types';
const testInvalidStatus = (
@@ -188,17 +189,16 @@ export const testTextFieldRangeValidation: DescribeRangeValidationTestSuite = (
testInvalidStatus([true, false], fieldType);
});
- describe('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
+ describe('with fake timer', () => {
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 1));
});
+
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
- it('should apply disablePast', async () => {
+ it('should apply disablePast', () => {
const onErrorMock = spy();
let now;
function WithFakeTimer(props: any) {
diff --git a/test/utils/pickers/describeValidation/testTextFieldValidation.tsx b/test/utils/pickers/describeValidation/testTextFieldValidation.tsx
index da24ced2703cc..f73a3f6be42de 100644
--- a/test/utils/pickers/describeValidation/testTextFieldValidation.tsx
+++ b/test/utils/pickers/describeValidation/testTextFieldValidation.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
import { expect } from 'chai';
-import { spy, useFakeTimers, SinonFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { TimeView } from '@mui/x-date-pickers/models';
import { adapterToUse, getFieldInputRoot } from 'test/utils/pickers';
import { describeSkipIf, testSkipIf } from 'test/utils/skipIf';
+import { vi } from 'vitest';
import { DescribeValidationTestSuite } from './describeValidation.types';
export const testTextFieldValidation: DescribeValidationTestSuite = (ElementToTest, getOptions) => {
@@ -138,13 +139,12 @@ export const testTextFieldValidation: DescribeValidationTestSuite = (ElementToTe
});
describeSkipIf(!withDate)('with fake timers', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 1));
});
+
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it('should apply disablePast', () => {
diff --git a/test/utils/pickers/describeValue/testPickerActionBar.tsx b/test/utils/pickers/describeValue/testPickerActionBar.tsx
index 04d7dc4c4f52a..5815cfbe1bc06 100644
--- a/test/utils/pickers/describeValue/testPickerActionBar.tsx
+++ b/test/utils/pickers/describeValue/testPickerActionBar.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { expect } from 'chai';
-import { SinonFakeTimers, spy, useFakeTimers } from 'sinon';
+import { spy } from 'sinon';
import { fireEvent, screen } from '@mui/internal-test-utils';
import { PickerRangeValue } from '@mui/x-date-pickers/internals';
import {
@@ -9,6 +9,7 @@ import {
expectPickerChangeHandlerValue,
isPickerRangeType,
} from 'test/utils/pickers';
+import { vi } from 'vitest';
import { DescribeValueTestSuite } from './describeValue.types';
export const testPickerActionBar: DescribeValueTestSuite = (
@@ -222,13 +223,12 @@ export const testPickerActionBar: DescribeValueTestSuite = (
});
describe('today action', () => {
- // TODO: temporary for vitest. Can move to `vi.useFakeTimers`
- let timer: SinonFakeTimers | null = null;
beforeEach(() => {
- timer = useFakeTimers({ now: new Date(2018, 0, 1), toFake: ['Date'] });
+ vi.setSystemTime(new Date(2018, 0, 1));
});
+
afterEach(() => {
- timer?.restore();
+ vi.useRealTimers();
});
it("should call onClose, onChange with today's value and onAccept with today's value", () => {
diff --git a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx
index d565d0c22c5ce..87d15f9f377f8 100644
--- a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx
+++ b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx
@@ -192,9 +192,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite {
const onChange = spy();
const onAccept = spy();
const onClose = spy();
diff --git a/test/utils/pickers/misc.ts b/test/utils/pickers/misc.ts
index 05892985870ed..040e263f82111 100644
--- a/test/utils/pickers/misc.ts
+++ b/test/utils/pickers/misc.ts
@@ -1,16 +1,22 @@
import sinon from 'sinon';
import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models';
+import { onTestFinished } from 'vitest';
import { PickerComponentFamily } from './describe.types';
import { OpenPickerParams } from './openPicker';
-export const stubMatchMedia = (matches = true) =>
- sinon.stub().returns({
+export const stubMatchMedia = (matches = true) => {
+ const original = window.matchMedia;
+ window.matchMedia = sinon.stub().returns({
matches,
addListener: () => {},
addEventListener: () => {},
removeListener: () => {},
removeEventListener: () => {},
});
+ onTestFinished(() => {
+ window.matchMedia = original;
+ });
+};
const getChangeCountForComponentFamily = (componentFamily: PickerComponentFamily) => {
switch (componentFamily) {
diff --git a/test/utils/skipIf.ts b/test/utils/skipIf.ts
index a189e7a99d8ba..36d64a4b61270 100644
--- a/test/utils/skipIf.ts
+++ b/test/utils/skipIf.ts
@@ -23,4 +23,3 @@ export const isJSDOM = /jsdom/.test(window.navigator.userAgent);
export const isOSX = /macintosh/i.test(window.navigator.userAgent);
export const hasTouchSupport =
typeof window.Touch !== 'undefined' && typeof window.TouchEvent !== 'undefined';
-export const isVitest = process.env.VITEST === 'true';
diff --git a/test/vite-plugin-filter-replace.mts b/test/vite-plugin-filter-replace.mts
new file mode 100644
index 0000000000000..f4679ae0b2bb8
--- /dev/null
+++ b/test/vite-plugin-filter-replace.mts
@@ -0,0 +1,89 @@
+import { Plugin } from 'vite';
+import path from 'path';
+
+interface RedirectRule {
+ /**
+ * A regex to test importer path against.
+ *
+ * Eg: /\\/AdapterDateFnsV2\\// will match `/src/AdapterDateFnsV2/index.js`
+ */
+ test: RegExp;
+ /**
+ * The import path to match. Any import path that starts with this will be redirected.
+ *
+ * Eg: 'date-fns' will match `import { format } from 'date-fns'` and `import { format } from 'date-fns/addDays'`
+ */
+ from: string;
+ /**
+ * The import path to redirect to. This will be replaced in place of `from`.
+ *
+ * Eg: 'date-fns-v2' will redirect `import { format } from 'date-fns'` to `import { format } from 'date-fns-v2'`
+ */
+ to: string;
+ /**
+ * An array of import paths to include. Use this to force the inclusion of certain dependencies.
+ * This is useful when you want to include a dependency that is not included by default.
+ *
+ * Eg: ['date-fns-v2/**\/*.js']
+ */
+ include?: string[];
+}
+
+const cleanDepName = (name: string) => {
+ // If the name starts with '@', we need to split it into scope and lib
+ // e.g. `@mui/material/Button` -> `@mui/material`
+ if (name.startsWith('@')) {
+ const [scope, lib] = name.split('/');
+ return `${scope}/${lib}`;
+ }
+ // If the name does not start with '@', we only care about the first part
+ // e.g. `material/Button` -> `material`
+ return name.split('/')[0];
+};
+
+export function redirectImports(rules: RedirectRule[]): Plugin {
+ return {
+ name: 'vite-plugin-redirect-imports',
+ enforce: 'pre',
+
+ config(config) {
+ config.optimizeDeps ??= {};
+ config.optimizeDeps.include ??= [];
+
+ const depsToInclude = new Set([
+ ...rules.flatMap((rule) => rule.include ?? []),
+ ...rules.flatMap((rule) => cleanDepName(rule.to)),
+ ]);
+
+ // Ignore already-included deps
+ config.optimizeDeps.include.forEach((dep) => depsToInclude.delete(dep));
+ config.optimizeDeps.include.push(...depsToInclude);
+ },
+
+ async resolveId(source, importer) {
+ if (!importer) {
+ return null;
+ }
+
+ const normalizedImporter = importer.split(path.sep).join('/');
+
+ for (const rule of rules) {
+ if (!rule.test.test(normalizedImporter)) {
+ continue;
+ }
+
+ // Match `from` or `from/...`
+ const match = source === rule.from || source.startsWith(`${rule.from}/`);
+ if (!match) {
+ continue;
+ }
+
+ const newSource = rule.to + source.slice(rule.from.length);
+
+ return this.resolve(newSource, importer, { skipSelf: true });
+ }
+
+ return null;
+ },
+ };
+}
diff --git a/tsconfig.json b/tsconfig.json
index ed9328c304d56..c6238bc0289ea 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,6 +8,7 @@
"strict": true,
"baseUrl": "./",
"allowJs": true,
+ "allowImportingTsExtensions": true,
"paths": {
"@mui/x-data-grid": ["./packages/x-data-grid/src"],
"@mui/x-data-grid/*": ["./packages/x-data-grid/src/*"],
@@ -49,7 +50,8 @@
"test/*": ["./test/*"],
"docs/*": ["./node_modules/@mui/monorepo/docs/*"],
"docsx/*": ["./docs/*"]
- }
+ },
+ "types": ["@vitest/browser/providers/playwright"]
},
"exclude": ["**/node_modules/!(@mui)/**", "**/build/**/*", "docs/export/**/*"]
}
diff --git a/vitest.config.mts b/vitest.config.mts
new file mode 100644
index 0000000000000..e350ef7758af9
--- /dev/null
+++ b/vitest.config.mts
@@ -0,0 +1,49 @@
+import { resolve, dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { defineConfig } from 'vitest/config';
+
+const CURRENT_DIR = dirname(fileURLToPath(import.meta.url));
+const WORKSPACE_ROOT = resolve(CURRENT_DIR, './');
+
+declare global {
+ interface MUIEnv {
+ JSDOM?: string;
+ BROWSER?: string;
+ CI?: string;
+ }
+}
+
+// Checking the environment variables simplifies the scripts in the package.json
+// We use `cross-env BROWSER=true vitest` instead of `vitest --project "browser/*"`
+// Which allows us to run `pnpm test:browser --project "x-charts"` for example.
+const getWorkspaces = () => {
+ const getFill = () => {
+ const isBrowser = process.env.BROWSER === 'true';
+ // We delete the env to prevent it from being used in the tests
+ delete process.env.BROWSER;
+ if (isBrowser) {
+ return 'browser';
+ }
+ return 'jsdom';
+ };
+
+ const fill = getFill();
+
+ return [
+ `packages/*/vitest.config.${fill}.mts`,
+ ...(fill.includes('jsdom') ? [`docs/vitest.config.${fill}.mts`] : []),
+ ];
+};
+
+export default defineConfig({
+ test: {
+ workspace: getWorkspaces(),
+ coverage: {
+ provider: 'v8',
+ reporter: process.env.CI ? ['lcovonly'] : ['text'],
+ reportsDirectory: resolve(WORKSPACE_ROOT, 'coverage'),
+ include: ['packages/*/src/**/*.{ts,tsx}'],
+ exclude: ['**/*.{test,spec}.{js,ts,tsx}'],
+ },
+ },
+});
diff --git a/vitest.shared.mts b/vitest.shared.mts
new file mode 100644
index 0000000000000..7182870457568
--- /dev/null
+++ b/vitest.shared.mts
@@ -0,0 +1,84 @@
+import { resolve, dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { defineConfig } from 'vitest/config';
+
+const CURRENT_DIR = dirname(fileURLToPath(import.meta.url));
+const WORKSPACE_ROOT = resolve(CURRENT_DIR, './');
+
+export default defineConfig({
+ // We seem to need both this and the `env` property below to make it work.
+ define: {
+ 'process.env.NODE_ENV': '"test"',
+ LICENSE_DISABLE_CHECK: 'false',
+ },
+ esbuild: {
+ minifyIdentifiers: false,
+ keepNames: true,
+ },
+ resolve: {
+ alias: [
+ // Generates resolver aliases for all packages and their plans.
+ ...[
+ { lib: 'x-charts', plans: ['pro'] },
+ { lib: 'x-date-pickers', plans: ['pro'] },
+ { lib: 'x-tree-view', plans: ['pro'] },
+ { lib: 'x-data-grid', plans: ['pro', 'premium', 'generator'] },
+ { lib: 'x-internals' },
+ { lib: 'x-license' },
+ { lib: 'x-telemetry' },
+ ].flatMap((v) => {
+ return [
+ {
+ find: `@mui/${v.lib}`,
+ replacement: resolve(WORKSPACE_ROOT, `./packages/${v.lib}/src`),
+ },
+ ...(v.plans ?? []).map((plan) => ({
+ find: `@mui/${v.lib}-${plan}`,
+ replacement: resolve(WORKSPACE_ROOT, `./packages/${v.lib}-${plan}/src`),
+ })),
+ ];
+ }),
+ {
+ find: 'test/utils',
+ replacement: new URL('./test/utils', import.meta.url).pathname,
+ },
+ ],
+ },
+ test: {
+ globals: true,
+ setupFiles: [new URL('test/setupVitest.ts', import.meta.url).pathname],
+ // Required for some tests that contain early returns or conditional tests.
+ passWithNoTests: true,
+ env: {
+ NODE_ENV: 'test',
+ },
+ browser: {
+ isolate: false,
+ provider: 'playwright',
+ headless: true,
+ screenshotFailures: false,
+ },
+ // Disable isolation to speed up the tests.
+ isolate: false,
+ // Performance improvements for the tests.
+ // https://vitest.dev/guide/improving-performance.html#improving-performance
+ ...(process.env.CI && {
+ // Important to avoid timeouts on CI.
+ fileParallelism: false,
+ // Increase the timeout for the tests due to slow CI machines.
+ testTimeout: 30000,
+ // Retry failed tests up to 3 times. This is useful for flaky tests.
+ retry: 3,
+ // Reduce the number of workers to avoid CI timeouts.
+ poolOptions: {
+ forks: {
+ singleFork: true,
+ },
+ threads: {
+ singleThread: true,
+ },
+ },
+ }),
+ exclude: ['**/*.spec.{js,ts,tsx}', '**/node_modules/**', '**/dist/**'],
+ },
+});