From d69264c4af8f669cc383ef6e63ca9f5dbcf9ae16 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 4 Sep 2024 15:06:56 +0200 Subject: [PATCH 01/44] Make createRenderer compliant with vitest --- .../test-utils/src/createRenderer.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 85889bc3d911a8..c0fb2a42343069 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -1,23 +1,23 @@ /* eslint-env mocha */ -import * as React from 'react'; -import * as ReactDOMServer from 'react-dom/server'; import createEmotionCache from '@emotion/cache'; import { CacheProvider as EmotionCacheProvider } from '@emotion/react'; import { - act as rtlAct, buildQueries, cleanup, - fireEvent as rtlFireEvent, + prettyDOM, queries, queryHelpers, - render as testingLibraryRender, - prettyDOM, - within, RenderResult, + act as rtlAct, + fireEvent as rtlFireEvent, screen as rtlScreen, Screen, + render as testingLibraryRender, + within, } from '@testing-library/react/pure'; import { userEvent } from '@testing-library/user-event'; +import * as React from 'react'; +import * as ReactDOMServer from 'react-dom/server'; import { useFakeTimers } from 'sinon'; import reactMajor from './reactMajor'; @@ -114,8 +114,8 @@ class DispatchingProfiler implements Profiler { private renders: RenderMark[] = []; - constructor(test: import('mocha').Test) { - this.id = test.fullTitle(); + constructor(test: any) { + this.id = test?.fullTitle?.() || test?.task?.name || test?.task?.id; } onRender: Profiler['onRender'] = ( @@ -511,7 +511,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende */ let prepared = false; let profiler: Profiler = null!; - beforeEach(function beforeEachHook() { + beforeEach(function beforeEachHook(t) { if (!wasCalledInSuite) { const error = new Error( 'Unable to run `before` hook for `createRenderer`. This usually indicates that `createRenderer` was called in a `before` hook instead of in a `describe()` block.', @@ -520,7 +520,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende throw error; } - const test = this.currentTest; + const test = this?.currentTest || t; if (test === undefined) { throw new Error( 'Unable to find the currently running test. This is a bug with the client-renderer. Please report this issue to a maintainer.', From 31326f975d0059858748a263407d5b25ee3d8b7b Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 4 Sep 2024 15:07:11 +0200 Subject: [PATCH 02/44] Make describeConformance compliant with vitest --- .../test-utils/src/describeConformance.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 3c2177b299de8a..27e21f89fb5172 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -1,6 +1,6 @@ /* eslint-env mocha */ -import * as React from 'react'; import { expect } from 'chai'; +import * as React from 'react'; import createDescribe from './createDescribe'; import { MuiRenderResult } from './createRenderer'; @@ -622,9 +622,9 @@ function testThemeStyleOverrides( getOptions: () => ConformanceOptions, ) { describe('theme style overrides:', () => { - it("respect theme's styleOverrides custom state", async function test() { + it("respect theme's styleOverrides custom state", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); + this?.skip?.() ?? t?.skip(); } const { muiName, testStateOverrides, render, ThemeProvider, createTheme } = getOptions(); @@ -677,9 +677,9 @@ function testThemeStyleOverrides( expect(container.firstChild).to.toHaveComputedStyle(testStyle); }); - it("respect theme's styleOverrides slots", async function test() { + it("respect theme's styleOverrides slots", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); + this?.skip?.() ?? t?.skip(); } const { @@ -788,9 +788,9 @@ function testThemeStyleOverrides( } }); - it('overrideStyles does not replace each other in slots', async function test() { + it('overrideStyles does not replace each other in slots', async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); + this?.skip?.() ?? t?.skip(); } const { muiName, classes, testStateOverrides, render, ThemeProvider, createTheme } = @@ -866,9 +866,9 @@ function testThemeStyleOverrides( */ function testThemeVariants(element: React.ReactElement, getOptions: () => ConformanceOptions) { describe('theme variants:', () => { - it("respect theme's variants", async function test() { + it("respect theme's variants", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); + this?.skip?.() ?? t?.skip(); } const { muiName, testVariantProps, render, ThemeProvider, createTheme } = getOptions(); @@ -921,9 +921,9 @@ function testThemeVariants(element: React.ReactElement, getOptions: () => C expect(getByTestId('without-props')).not.to.toHaveComputedStyle(testStyle); }); - it('supports custom variant', async function test() { + it('supports custom variant', async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); + this?.skip?.() ?? t?.skip(); } const { muiName, testCustomVariant, render, ThemeProvider, createTheme } = getOptions(); From 4db459cf3f56022ca327133e941028ad9e160f94 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 4 Sep 2024 17:17:37 +0200 Subject: [PATCH 03/44] Warning becomes too verbose --- packages-internal/test-utils/src/init.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages-internal/test-utils/src/init.js b/packages-internal/test-utils/src/init.js index 85e2fe80a5eb6c..b835bf58b88afe 100644 --- a/packages-internal/test-utils/src/init.js +++ b/packages-internal/test-utils/src/init.js @@ -6,6 +6,4 @@ import './initMatchers'; // in the test files which helps documenting what is part of the DOM but hidden // from assistive technology const defaultHidden = !process.env.CI; -// adds verbosity for something that might be confusing -console.warn(`${defaultHidden ? 'including' : 'excluding'} inaccessible elements by default`); testingLibrary.configure({ defaultHidden }); From 456df29605aee6337493f7b5a70747c51e019310 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 5 Sep 2024 19:45:33 +0200 Subject: [PATCH 04/44] global this --- packages-internal/test-utils/src/createDOM.js | 8 +++---- .../test-utils/src/createRenderer.tsx | 4 ++-- .../test-utils/src/describeConformance.tsx | 22 ++++++++++++++----- .../test-utils/src/initMatchers.ts | 6 ++--- .../test-utils/src/setupJSDOM.js | 4 ++-- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages-internal/test-utils/src/createDOM.js b/packages-internal/test-utils/src/createDOM.js index c08017b408cf81..53d3b7407204bc 100644 --- a/packages-internal/test-utils/src/createDOM.js +++ b/packages-internal/test-utils/src/createDOM.js @@ -25,7 +25,7 @@ function createDOM() { pretendToBeVisual: true, url: 'http://localhost', }); - global.window = dom.window; + globalThis.window = dom.window; // Not yet supported: https://github.com/jsdom/jsdom/issues/2152 class Touch { constructor(instance) { @@ -52,14 +52,14 @@ function createDOM() { return this.instance.clientY; } } - global.window.Touch = Touch; + globalThis.window.Touch = Touch; Object.keys(dom.window) .filter((key) => !blacklist.includes(key)) .concat(whitelist) .forEach((key) => { - if (typeof global[key] === 'undefined') { - global[key] = dom.window[key]; + if (typeof globalThis[key] === 'undefined') { + globalThis[key] = dom.window[key]; } }); } diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index c0fb2a42343069..85fbe5c4160a5a 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -554,11 +554,11 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende profiler = null!; emotionCache.sheet.tags.forEach((styleTag) => { - styleTag.remove(); + styleTag?.remove(); }); emotionCache = null!; - serverContainer.remove(); + serverContainer?.remove(); serverContainer = null!; }); diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 27e21f89fb5172..8ddb6216db490b 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -624,6 +624,8 @@ function testThemeStyleOverrides( describe('theme style overrides:', () => { it("respect theme's styleOverrides custom state", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); } const { muiName, testStateOverrides, render, ThemeProvider, createTheme } = getOptions(); @@ -679,6 +681,8 @@ function testThemeStyleOverrides( it("respect theme's styleOverrides slots", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); } @@ -790,6 +794,8 @@ function testThemeStyleOverrides( it('overrideStyles does not replace each other in slots', async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); } @@ -868,6 +874,8 @@ function testThemeVariants(element: React.ReactElement, getOptions: () => C describe('theme variants:', () => { it("respect theme's variants", async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); } @@ -923,6 +931,8 @@ function testThemeVariants(element: React.ReactElement, getOptions: () => C it('supports custom variant', async function test(t) { if (/jsdom/.test(window.navigator.userAgent)) { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); } @@ -974,12 +984,14 @@ function testThemeCustomPalette( getOptions: () => ConformanceOptions, ) { describe('theme extended palette:', () => { - it('should render without errors', function test() { + it('should render without errors', function test(t) { const { render, ThemeProvider, createTheme } = getOptions(); if (!/jsdom/.test(window.navigator.userAgent) || !render || !ThemeProvider || !createTheme) { - this.skip(); + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + this?.skip?.() ?? t?.skip(); } - + // @ts-ignore const theme = createTheme({ palette: { custom: { @@ -988,7 +1000,7 @@ function testThemeCustomPalette( unknown: null, }, }); - + // @ts-ignore expect(() => render({element})).not.to.throw(); }); }); @@ -1023,7 +1035,7 @@ function describeConformance( beforeEach(() => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key: string) => storage[key], setItem: (key: string, value: string) => { diff --git a/packages-internal/test-utils/src/initMatchers.ts b/packages-internal/test-utils/src/initMatchers.ts index e0f23f9070426b..d7251804918ebd 100644 --- a/packages-internal/test-utils/src/initMatchers.ts +++ b/packages-internal/test-utils/src/initMatchers.ts @@ -1,10 +1,10 @@ -import chai, { AssertionError } from 'chai'; -import chaiDom from 'chai-dom'; -import _ from 'lodash'; import { isInaccessible } from '@testing-library/dom'; import { prettyDOM } from '@testing-library/react/pure'; +import chai, { AssertionError } from 'chai'; +import chaiDom from 'chai-dom'; import { computeAccessibleDescription, computeAccessibleName } from 'dom-accessibility-api'; import formatUtil from 'format-util'; +import _ from 'lodash'; chai.use(chaiDom); diff --git a/packages-internal/test-utils/src/setupJSDOM.js b/packages-internal/test-utils/src/setupJSDOM.js index 49523ac38da135..916f5837685427 100644 --- a/packages-internal/test-utils/src/setupJSDOM.js +++ b/packages-internal/test-utils/src/setupJSDOM.js @@ -4,8 +4,8 @@ const createDOM = require('./createDOM'); const { createMochaHooks } = require('./mochaHooks'); // Enable missing act warnings: https://github.com/reactwg/react-18/discussions/102 -global.jest = null; -global.IS_REACT_ACT_ENVIRONMENT = true; +globalThis.jest = null; +globalThis.IS_REACT_ACT_ENVIRONMENT = true; createDOM(); require('./init'); From 76edd75cb6a7bb02fd820e65e9a020103ca908c0 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 5 Sep 2024 20:44:21 +0200 Subject: [PATCH 05/44] Fix chai matchers --- .../test-utils/src/describeConformance.tsx | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 8ddb6216db490b..6653a642a3171a 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -108,7 +108,7 @@ export function testClassName( React.cloneElement(element, { className, 'data-testid': testId }), ); - expect(getByTestId(testId)).to.have.class(className); + expect(getByTestId(testId).getAttribute('class')).to.include(className); }); } @@ -172,7 +172,7 @@ export function testPropsSpread( React.cloneElement(element, { [testProp]: value, 'data-testid': testId }), ); - expect(getByTestId(testId)).to.have.attribute(testProp, value); + expect(getByTestId(testId).getAttribute(testProp)).to.equal(value); }); } @@ -230,14 +230,14 @@ export function testRootClass( // jump to the host component because some components pass the `root` class // to the `classes` prop of the root component. // https://github.com/mui/material-ui/blob/f9896bcd129a1209153106296b3d2487547ba205/packages/material-ui/src/OutlinedInput/OutlinedInput.js#L101 - expect(container.firstChild).to.have.class(className); - expect(container.firstChild).to.have.class(classes.root); + expect(container.firstElementChild?.getAttribute('class')).to.include(className); + expect(container.firstElementChild?.getAttribute('class')).to.include(classes.root); expect(document.querySelectorAll(`.${classes.root}`).length).to.equal(1); // classes test only for @mui/material if (!skip || !skip.includes('classesRoot')) { // Test that classes prop works - expect(container.firstChild).to.have.class(classesRootClassname); + expect(container.firstElementChild?.getAttribute('class')).to.include(classesRootClassname); // Test that `classes` does not spread to DOM expect(document.querySelectorAll('[classes]').length).to.equal(0); @@ -288,7 +288,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo const renderedElement = queryByTestId('custom'); expect(renderedElement).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(renderedElement).to.have.class(slotOptions.expectedClassName); + expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); } }); @@ -319,7 +319,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo expect(renderedElement!.nodeName.toLowerCase()).to.equal(slotElement); if (slotOptions.expectedClassName) { - expect(renderedElement).to.have.class(slotOptions.expectedClassName); + expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); } }); } @@ -343,7 +343,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo const renderedElement = queryByTestId('custom'); expect(renderedElement).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(renderedElement).to.have.class(slotOptions.expectedClassName); + expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); } }); @@ -423,7 +423,9 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo expect(renderedElement!.nodeName.toLowerCase()).to.equal(slotElement); if (slotOptions.expectedClassName) { - expect(renderedElement).to.have.class(slotOptions.expectedClassName); + expect(renderedElement?.getAttribute('class')).to.include( + slotOptions.expectedClassName, + ); } }); } @@ -451,7 +453,7 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C expect(slotComponent).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(slotComponent).to.have.class(slotOptions.expectedClassName); + expect(slotComponent?.getAttribute('class')).to.include(slotOptions.expectedClassName); } }); @@ -466,8 +468,12 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C const { getByTestId } = await render(React.cloneElement(element, { slotProps })); - expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName); - expect(getByTestId('custom')).to.have.class(slotProps[slotName].className); + expect(getByTestId('custom').getAttribute('class')).to.include( + slotOptions.expectedClassName, + ); + expect(getByTestId('custom').getAttribute('class')).to.include( + slotProps[slotName].className, + ); }); } @@ -484,7 +490,7 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C expect(slotComponent).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(slotComponent).to.have.class(slotOptions.expectedClassName); + expect(slotComponent?.getAttribute('class')).to.include(slotOptions.expectedClassName); } }); @@ -507,8 +513,9 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C React.cloneElement(element, { componentsProps, slotProps }), ); const slotComponent = queryByTestId('custom'); - expect(slotComponent).to.have.attribute('data-from-slot-props', 'true'); - expect(slotComponent).not.to.have.attribute('data-from-components-props'); + expect(slotComponent?.getAttribute('data-from-slot-props')).to.equal('true'); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + expect(slotComponent?.getAttribute('data-from-components-props')).to.be.undefined; }); } }); @@ -608,7 +615,7 @@ function testThemeDefaultProps( const { container } = await render({element}); - expect(container.firstChild).to.have.attribute(testProp, 'testProp'); + expect(container.firstElementChild?.getAttribute(testProp)).to.equal('testProp'); }); }); } From 2a7343c0d8b596db7670f875741b0736f1633e08 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 5 Sep 2024 20:57:04 +0200 Subject: [PATCH 06/44] fix lint --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8c828c846ffa23..e88181eb4bbd6e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,7 +42,7 @@ const NO_RESTRICTED_IMPORTS_PATTERNS_DEEPLY_NESTED = [ module.exports = { root: true, // So parent files don't get applied env: { - es6: true, + es2020: true, browser: true, node: true, }, From c60515e39a430659f8233650d6f3a56fc7b952ff Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 6 Sep 2024 01:11:19 +0200 Subject: [PATCH 07/44] Fix mocha done --- packages-internal/test-utils/src/createRenderer.tsx | 2 +- .../test-utils/src/describeConformance.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 85fbe5c4160a5a..975ad3bf39964b 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -511,7 +511,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende */ let prepared = false; let profiler: Profiler = null!; - beforeEach(function beforeEachHook(t) { + beforeEach(function beforeEachHook(t = {}) { if (!wasCalledInSuite) { const error = new Error( 'Unable to run `before` hook for `createRenderer`. This usually indicates that `createRenderer` was called in a `before` hook instead of in a `describe()` block.', diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 6653a642a3171a..472562ca88eac8 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -629,7 +629,7 @@ function testThemeStyleOverrides( getOptions: () => ConformanceOptions, ) { describe('theme style overrides:', () => { - it("respect theme's styleOverrides custom state", async function test(t) { + it("respect theme's styleOverrides custom state", async function test(t = {}) { if (/jsdom/.test(window.navigator.userAgent)) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -686,7 +686,7 @@ function testThemeStyleOverrides( expect(container.firstChild).to.toHaveComputedStyle(testStyle); }); - it("respect theme's styleOverrides slots", async function test(t) { + it("respect theme's styleOverrides slots", async function test(t = {}) { if (/jsdom/.test(window.navigator.userAgent)) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -799,7 +799,7 @@ function testThemeStyleOverrides( } }); - it('overrideStyles does not replace each other in slots', async function test(t) { + it('overrideStyles does not replace each other in slots', async function test(t = {}) { if (/jsdom/.test(window.navigator.userAgent)) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -879,7 +879,7 @@ function testThemeStyleOverrides( */ function testThemeVariants(element: React.ReactElement, getOptions: () => ConformanceOptions) { describe('theme variants:', () => { - it("respect theme's variants", async function test(t) { + it("respect theme's variants", async function test(t = {}) { if (/jsdom/.test(window.navigator.userAgent)) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -936,7 +936,7 @@ function testThemeVariants(element: React.ReactElement, getOptions: () => C expect(getByTestId('without-props')).not.to.toHaveComputedStyle(testStyle); }); - it('supports custom variant', async function test(t) { + it('supports custom variant', async function test(t = {}) { if (/jsdom/.test(window.navigator.userAgent)) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -991,7 +991,7 @@ function testThemeCustomPalette( getOptions: () => ConformanceOptions, ) { describe('theme extended palette:', () => { - it('should render without errors', function test(t) { + it('should render without errors', function test(t = {}) { const { render, ThemeProvider, createTheme } = getOptions(); if (!/jsdom/.test(window.navigator.userAgent) || !render || !ThemeProvider || !createTheme) { // @ts-ignore From 63115f534a41058e7e4bf0b44fdabe914caa9862 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 6 Sep 2024 01:12:23 +0200 Subject: [PATCH 08/44] add mocha types --- packages-internal/test-utils/src/createRenderer.tsx | 2 +- packages-internal/test-utils/tsconfig.json | 2 +- tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 975ad3bf39964b..faf3370c2167b1 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -550,7 +550,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende } cleanup(); - profiler.report(); + profiler?.report(); profiler = null!; emotionCache.sheet.tags.forEach((styleTag) => { diff --git a/packages-internal/test-utils/tsconfig.json b/packages-internal/test-utils/tsconfig.json index 6ba9f9bb572db7..fbee0a28b0b198 100644 --- a/packages-internal/test-utils/tsconfig.json +++ b/packages-internal/test-utils/tsconfig.json @@ -3,7 +3,7 @@ "lib": ["es2020", "dom"], "noEmit": true, "moduleResolution": "node", - "types": ["node"], + "types": ["node", "mocha"], "strict": true, "esModuleInterop": true, "isolatedModules": true, diff --git a/tsconfig.json b/tsconfig.json index 7a6f730e4ae2c8..77600e5acb52b5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -52,7 +52,7 @@ "@mui/internal-test-utils/*": ["./packages-internal/test-utils/src/*"] }, // Otherwise we get react-native typings which conflict with dom.lib. - "types": ["node", "react"] + "types": ["node", "react", "mocha"] }, "exclude": ["**/.*/", "**/build", "**/node_modules", "docs/export"] } From e7e755b2eb61fc813bc0abc15b8321549bdf4fda Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 6 Sep 2024 01:30:55 +0200 Subject: [PATCH 09/44] Replace tobeundefined with tobenull --- packages-internal/test-utils/src/describeConformance.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 472562ca88eac8..20095374d6de82 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -515,7 +515,7 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C const slotComponent = queryByTestId('custom'); expect(slotComponent?.getAttribute('data-from-slot-props')).to.equal('true'); // eslint-disable-next-line @typescript-eslint/no-unused-expressions - expect(slotComponent?.getAttribute('data-from-components-props')).to.be.undefined; + expect(slotComponent?.getAttribute('data-from-components-props')).to.be.null; }); } }); From 917dd258312633d30ce99aa26e0923b6c94e4d4e Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 10 Sep 2024 14:59:05 +0200 Subject: [PATCH 10/44] separately export chai plugins --- packages-internal/test-utils/package.json | 3 +- .../test-utils/src/chai.types.ts | 112 +++ .../test-utils/src/chaiPlugin.ts | 546 +++++++++++++++ .../test-utils/src/initMatchers.ts | 659 +----------------- 4 files changed, 664 insertions(+), 656 deletions(-) create mode 100644 packages-internal/test-utils/src/chai.types.ts create mode 100644 packages-internal/test-utils/src/chaiPlugin.ts diff --git a/packages-internal/test-utils/package.json b/packages-internal/test-utils/package.json index 9bb2b23a0802f1..4098e41097c818 100644 --- a/packages-internal/test-utils/package.json +++ b/packages-internal/test-utils/package.json @@ -21,7 +21,8 @@ "./setupBabel": "./build/setupBabel.js", "./setupBabelPlaywright": "./build/setupBabelPlaywright.js", "./setupJSDOM": "./build/setupJSDOM.js", - "./setupKarma": "./build/setupKarma.js" + "./setupKarma": "./build/setupKarma.js", + "./chaiPlugin": "./build/chaiPlugin.js" }, "scripts": { "prebuild": "rimraf ./build", diff --git a/packages-internal/test-utils/src/chai.types.ts b/packages-internal/test-utils/src/chai.types.ts new file mode 100644 index 00000000000000..8c24b06f71d539 --- /dev/null +++ b/packages-internal/test-utils/src/chai.types.ts @@ -0,0 +1,112 @@ +export {}; + +// https://stackoverflow.com/a/46755166/3406963 +declare global { + namespace Chai { + interface Assertion { + /** + * Checks if the element in question is considered `aria-hidden`. + * Does not replace accessibility check as that requires display/visibility/layout + * @deprecated Use `inaccessible` + `visible` instead + */ + toBeAriaHidden(): void; + /** + * Checks `expectedStyle` is a subset of the elements inline style i.e. `element.style`. + * @example expect(element).toHaveInlineStyle({ width: '200px' }) + */ + toHaveInlineStyle( + expectedStyle: Partial< + Record< + Exclude< + keyof CSSStyleDeclaration, + | 'getPropertyPriority' + | 'getPropertyValue' + | 'item' + | 'removeProperty' + | 'setProperty' + | number + >, + string + > + >, + ): void; + /** + * Checks `expectedStyle` is a subset of the elements computed style i.e. `window.getComputedStyle(element)`. + * @example expect(element).toHaveComputedStyle({ width: '200px' }) + */ + toHaveComputedStyle( + expectedStyle: Partial< + Record< + Exclude< + keyof CSSStyleDeclaration, + | 'getPropertyPriority' + | 'getPropertyValue' + | 'item' + | 'removeProperty' + | 'setProperty' + | number + >, + string + > + >, + ): void; + /** + * Check if an element's [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) is not `hidden` or `collapsed`. + */ + toBeVisible(): void; + /** + * Check if an element's [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) is `hidden` or `collapsed`. + */ + toBeHidden(): void; + /** + * Checks if the element is inaccessible. + * + * Elements are considered inaccessible if they either: + * - have [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) `hidden` + * - have [`display`](https://developer.mozilla.org/en-US/docs/Web/CSS/display) `none` + * - have `aria-hidden` `true` or any of their parents + * + * @see [Excluding Elements from the Accessibility Tree](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion) + */ + toBeInaccessible(): void; + toHaveAccessibleDescription(description: string): void; + /** + * Checks if the accessible name computation (according to `accname` spec) + * matches the expectation. + * + * @see https://www.w3.org/TR/accname-1.2/ + * @param name + */ + toHaveAccessibleName(name: string): void; + /** + * Checks if the element is actually focused i.e. `document.activeElement` is equal to the actual element. + */ + toHaveFocus(): void; + /** + * Checks if the element is the active-descendant of the active element. + */ + toHaveVirtualFocus(): void; + /** + * Matches calls to `console.warn` in the asserted callback. + * + * @example expect(() => render()).not.toWarnDev() + * @example expect(() => render()).toWarnDev('single message') + * @example expect(() => render()).toWarnDev(['first warning', 'then the second']) + */ + toWarnDev(messages?: string | readonly (string | boolean)[]): void; + /** + * Matches calls to `console.error` in the asserted callback. + * + * @example expect(() => render()).not.toErrorDev() + * @example expect(() => render()).toErrorDev('single message') + * @example expect(() => render()).toErrorDev(['first warning', 'then the second']) + */ + toErrorDev(messages?: string | readonly (string | boolean)[]): void; + /** + * Asserts that the given callback throws an error matching the given message in development (process.env.NODE_ENV !== 'production'). + * In production it expects a minified error. + */ + toThrowMinified(message: string): void; + } + } +} diff --git a/packages-internal/test-utils/src/chaiPlugin.ts b/packages-internal/test-utils/src/chaiPlugin.ts new file mode 100644 index 00000000000000..0b0b4322c893c4 --- /dev/null +++ b/packages-internal/test-utils/src/chaiPlugin.ts @@ -0,0 +1,546 @@ +import { isInaccessible } from '@testing-library/dom'; +import { prettyDOM } from '@testing-library/react/pure'; +import chai, { AssertionError } from 'chai'; +import { computeAccessibleDescription, computeAccessibleName } from 'dom-accessibility-api'; +import formatUtil from 'format-util'; +import _ from 'lodash'; +import './chai.types'; + +const isKarma = Boolean(process.env.KARMA); + +function isInJSDOM() { + return /jsdom/.test(window.navigator.userAgent); +} + +// chai#utils.elToString that looks like stringified elements in testing-library +function elementToString(element: Element | null | undefined) { + if (typeof element?.nodeType === 'number') { + return prettyDOM(element, undefined, { highlight: !isKarma, maxDepth: 1 }); + } + return String(element); +} + +const chaiPlugin: Parameters<(typeof chai)['use']>[0] = (chaiAPI, utils) => { + const blockElements = new Set([ + 'html', + 'address', + 'blockquote', + 'body', + 'dd', + 'div', + 'dl', + 'dt', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'noframes', + 'ol', + 'p', + 'ul', + 'center', + 'dir', + 'hr', + 'menu', + 'pre', + ]); + + function pretendVisibleGetComputedStyle(element: Element): CSSStyleDeclaration { + // `CSSStyleDeclaration` is not constructable + // https://stackoverflow.com/a/52732909/3406963 + // this is not equivalent to the declaration from `getComputedStyle` + // for example `getComputedStyle` would return a readonly declaration + // let's hope this doesn't get passed around until it's no longer clear where it comes from + const declaration = document.createElement('span').style; + + // initial values + declaration.content = ''; + // technically it's `inline`. We partially apply the default user agent sheet (chrome) here + // we're only interested in elements that use block + declaration.display = blockElements.has(element.tagName) ? 'block' : 'inline'; + declaration.visibility = 'visible'; + + return declaration; + } + + // better diff view for expect(element).to.equal(document.activeElement) + chaiAPI.Assertion.addMethod('toHaveFocus', function elementIsFocused() { + const element = utils.flag(this, 'object'); + + this.assert( + element === document.activeElement, + // karma does not show the diff like mocha does + `expected element to have focus${isKarma ? '\nexpected #{exp}\nactual: #{act}' : ''}`, + `expected element to NOT have focus \n${elementToString(element)}`, + elementToString(element), + elementToString(document.activeElement), + ); + }); + + chaiAPI.Assertion.addMethod('toHaveVirtualFocus', function elementIsVirtuallyFocused() { + const element = utils.flag(this, 'object'); + const id = element.getAttribute('id'); + + const virtuallyFocusedElementId = document.activeElement!.getAttribute('aria-activedescendant'); + + this.assert( + virtuallyFocusedElementId === id, + `expected element to be virtually focused\nexpected id #{exp}\n${ + virtuallyFocusedElementId === null + ? `activeElement: ${elementToString(document.activeElement)}` + : 'actual id: #{act}' + }`, + 'expected element to NOT to be virtually focused', + id, + virtuallyFocusedElementId, + virtuallyFocusedElementId !== null, + ); + }); + + chaiAPI.Assertion.addMethod('toBeAriaHidden', function elementIsAccessible() { + const element = utils.flag(this, 'object'); + + // used for debugging failed assertions, will either point to the top most node + // or the node that had aria-hidden="true" + let previousNode = element; + let currentNode = element; + let ariaHidden = false; + // "An element is considered hidden if it, or any of its ancestors are not + // rendered or have their aria-hidden attribute value set to true." + // -- https://www.w3.org/TR/wai-aria-1.1/#aria-hidden + while ( + currentNode !== null && + // stopping at so that failed assertion message only prints + // or below. use cases for aria-hidden on are unknown + currentNode !== document.documentElement && + ariaHidden === false + ) { + ariaHidden = currentNode.getAttribute('aria-hidden') === 'true'; + previousNode = currentNode; + currentNode = currentNode.parentElement; + } + + this.assert( + ariaHidden === true, + `expected \n${elementToString(element)} to be aria-hidden`, + `expected \n${elementToString(element)} to not be aria-hidden, but \n${elementToString( + previousNode, + )} had aria-hidden="true" instead`, + // Not interested in a diff but the typings require the 4th parameter. + undefined, + ); + }); + + chaiAPI.Assertion.addMethod('toBeInaccessible', function elementIsAccessible() { + const element = utils.flag(this, 'object'); + + const inaccessible = isInaccessible(element); + + this.assert( + inaccessible === true, + `expected \n${elementToString(element)} to be inaccessible but it was accessible`, + `expected \n${elementToString(element)} to be accessible but it was inaccessible`, + // Not interested in a diff but the typings require the 4th parameter. + undefined, + ); + }); + + chaiAPI.Assertion.addMethod('toHaveAccessibleName', function hasAccessibleName(expectedName) { + const root = utils.flag(this, 'object'); + // make sure it's an Element + new chai.Assertion(root.nodeType, `Expected an Element but got '${String(root)}'`).to.equal(1); + + const actualName = computeAccessibleName(root, { + computedStyleSupportsPseudoElements: !isInJSDOM(), + // in local development we pretend to be visible. full getComputedStyle is + // expensive and reserved for CI + getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle, + }); + + this.assert( + actualName === expectedName, + `expected \n${elementToString(root)} to have accessible name #{exp} but got #{act} instead.`, + `expected \n${elementToString(root)} not to have accessible name #{exp}.`, + expectedName, + actualName, + ); + }); + + chaiAPI.Assertion.addMethod( + 'toHaveAccessibleDescription', + function hasAccessibleDescription(expectedDescription) { + const root = utils.flag(this, 'object'); + // make sure it's an Element + new chai.Assertion(root.nodeType, `Expected an Element but got '${String(root)}'`).to.equal( + 1, + ); + + const actualDescription = computeAccessibleDescription(root, { + // in local development we pretend to be visible. full getComputedStyle is + // expensive and reserved for CI + getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle, + }); + + const possibleDescriptionComputationMessage = root.hasAttribute('title') + ? ' computeAccessibleDescription can be misleading when a `title` attribute is used. This might be a bug in `dom-accessibility-api`.' + : ''; + this.assert( + actualDescription === expectedDescription, + `expected \n${elementToString( + root, + )} to have accessible description #{exp} but got #{act} instead.${possibleDescriptionComputationMessage}`, + `expected \n${elementToString( + root, + )} not to have accessible description #{exp}.${possibleDescriptionComputationMessage}`, + expectedDescription, + actualDescription, + ); + }, + ); + + /** + * Correct name for `to.be.visible` + */ + chaiAPI.Assertion.addMethod('toBeVisible', function toBeVisible() { + // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions + new chaiAPI.Assertion(this._obj).to.be.visible; + }); + + /** + * Correct name for `not.to.be.visible` + */ + chaiAPI.Assertion.addMethod('toBeHidden', function toBeHidden() { + // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions + new chaiAPI.Assertion(this._obj).not.to.be.visible; + }); + + function assertMatchingStyles( + this: Chai.AssertionStatic, + actualStyleDeclaration: CSSStyleDeclaration, + expectedStyleUnnormalized: Record, + options: { styleTypeHint: string }, + ): void { + const { styleTypeHint } = options; + + // Compare objects using hyphen case. + // This is closer to actual CSS and required for getPropertyValue anyway. + const expectedStyle: Record = {}; + Object.keys(expectedStyleUnnormalized).forEach((cssProperty) => { + const hyphenCasedPropertyName = _.kebabCase(cssProperty); + const isVendorPrefixed = /^(moz|ms|o|webkit)-/.test(hyphenCasedPropertyName); + const propertyName = isVendorPrefixed + ? `-${hyphenCasedPropertyName}` + : hyphenCasedPropertyName; + expectedStyle[propertyName] = expectedStyleUnnormalized[cssProperty]; + }); + + const shorthandProperties = new Set([ + 'all', + 'animation', + 'background', + 'border', + 'border-block-end', + 'border-block-start', + 'border-bottom', + 'border-color', + 'border-image', + 'border-inline-end', + 'border-inline-start', + 'border-left', + 'border-radius', + 'border-right', + 'border-style', + 'border-top', + 'border-width', + 'column-rule', + 'columns', + 'flex', + 'flex-flow', + 'font', + 'gap', + 'grid', + 'grid-area', + 'grid-column', + 'grid-row', + 'grid-template', + 'list-style', + 'margin', + 'mask', + 'offset', + 'outline', + 'overflow', + 'padding', + 'place-content', + 'place-items', + 'place-self', + 'scroll-margin', + 'scroll-padding', + 'text-decoration', + 'text-emphasis', + 'transition', + ]); + const usedShorthandProperties = Object.keys(expectedStyle).filter((cssProperty) => { + return shorthandProperties.has(cssProperty); + }); + if (usedShorthandProperties.length > 0) { + throw new Error( + [ + `Shorthand properties are not supported in ${styleTypeHint} styles matchers since browsers can compute them differently. `, + 'Use longhand properties instead for the follow shorthand properties:\n', + usedShorthandProperties + .map((cssProperty) => { + return `- https://developer.mozilla.org/en-US/docs/Web/CSS/${cssProperty}#constituent_properties`; + }) + .join('\n'), + ].join(''), + ); + } + + const actualStyle: Record = {}; + Object.keys(expectedStyle).forEach((cssProperty) => { + actualStyle[cssProperty] = actualStyleDeclaration.getPropertyValue(cssProperty); + }); + + const jsdomHint = + 'Styles in JSDOM e.g. from `test:unit` are often misleading since JSDOM does not implement the Cascade nor actual CSS property value computation. ' + + 'If results differ between real browsers and JSDOM, skip the test in JSDOM e.g. `if (/jsdom/.test(window.navigator.userAgent)) this.skip();`'; + const shorthandHint = + 'Browsers can compute shorthand properties differently. Prefer longhand properties e.g. `borderTopColor`, `borderRightColor` etc. instead of `border` or `border-color`.'; + const messageHint = `${jsdomHint}\n${shorthandHint}`; + + if (isKarma) { + // `#{exp}` and `#{act}` placeholders escape the newlines + const expected = JSON.stringify(expectedStyle, null, 2); + const actual = JSON.stringify(actualStyle, null, 2); + // karma's `dots` reporter does not support diffs + this.assert( + // TODO Fix upstream docs/types + (utils as any).eql(actualStyle, expectedStyle), + `expected ${styleTypeHint} style of #{this} did not match\nExpected:\n${expected}\nActual:\n${actual}\n\n\n${messageHint}`, + `expected #{this} to not have ${styleTypeHint} style\n${expected}\n\n\n${messageHint}`, + expectedStyle, + actualStyle, + ); + } else { + this.assert( + // TODO Fix upstream docs/types + (utils as any).eql(actualStyle, expectedStyle), + `expected #{this} to have ${styleTypeHint} style #{exp} \n\n${messageHint}`, + `expected #{this} not to have ${styleTypeHint} style #{exp}${messageHint}`, + expectedStyle, + actualStyle, + true, + ); + } + } + + chaiAPI.Assertion.addMethod( + 'toHaveInlineStyle', + function toHaveInlineStyle(expectedStyleUnnormalized: Record) { + const element = utils.flag(this, 'object') as HTMLElement; + if (element?.nodeType !== 1) { + // Same pre-condition for negated and unnegated assertion + throw new AssertionError(`Expected an Element but got ${String(element)}`); + } + + assertMatchingStyles.call(this, element.style, expectedStyleUnnormalized, { + styleTypeHint: 'inline', + }); + }, + ); + + chaiAPI.Assertion.addMethod( + 'toHaveComputedStyle', + function toHaveComputedStyle(expectedStyleUnnormalized: Record) { + const element = utils.flag(this, 'object') as HTMLElement; + if (element?.nodeType !== 1) { + // Same pre-condition for negated and unnegated assertion + throw new AssertionError(`Expected an Element but got ${String(element)}`); + } + const computedStyle = element.ownerDocument.defaultView!.getComputedStyle(element); + + assertMatchingStyles.call(this, computedStyle, expectedStyleUnnormalized, { + styleTypeHint: 'computed', + }); + }, + ); + + chaiAPI.Assertion.addMethod('toThrowMinified', function toThrowMinified(expectedDevMessage) { + // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved. + if (process.env.NODE_ENV !== 'production') { + (this as any).to.throw(expectedDevMessage); + } else { + utils.flag( + this, + 'message', + "Looks like the error was not minified. This can happen if the error code hasn't been generated yet. Run `pnpm extract-error-codes` and try again.", + ); + // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved. + (this as any).to.throw('Minified MUI error', 'helper'); + } + }); + + function addConsoleMatcher(matcherName: string, methodName: 'error' | 'warn') { + /** + * @param {string[]} expectedMessages + */ + function matcher(this: Chai.AssertionStatic, expectedMessagesInput = []) { + // documented pattern to get the actual value of the assertion + // eslint-disable-next-line no-underscore-dangle + const callback = this._obj; + + if (process.env.NODE_ENV !== 'production') { + const expectedMessages = + typeof expectedMessagesInput === 'string' + ? [expectedMessagesInput] + : expectedMessagesInput.slice(); + const unexpectedMessages: Error[] = []; + // TODO Remove type once MUI X enables noImplicitAny + let caughtError: unknown | null = null; + + this.assert( + expectedMessages.length > 0, + `Expected to call console.${methodName} but didn't provide messages. ` + + `If you don't expect any messages prefer \`expect().not.${matcherName}();\`.`, + `Expected no call to console.${methodName} while also expecting messages.` + + 'Expected no call to console.error but provided messages. ' + + "If you want to make sure a certain message isn't logged prefer the positive. " + + 'By expecting certain messages you automatically expect that no other messages are logged', + // Not interested in a diff but the typings require the 4th parameter. + undefined, + ); + + // Ignore skipped messages in e.g. `[condition && 'foo']` + const remainingMessages = expectedMessages.filter((messageOrFalse) => { + return messageOrFalse !== false; + }); + + // eslint-disable-next-line no-console + const originalMethod = console[methodName]; + + let messagesMatched = 0; + const consoleMatcher = (format: string, ...args: readonly unknown[]) => { + // Ignore legacy root deprecation warnings + // TODO: Remove once we no longer use legacy roots. + if ( + format.indexOf('Use createRoot instead.') !== -1 || + format.indexOf('Use hydrateRoot instead.') !== -1 + ) { + return; + } + const actualMessage = formatUtil(format, ...args); + const expectedMessage = remainingMessages.shift(); + messagesMatched += 1; + + // TODO Remove type once MUI X enables noImplicitAny + let message: string | null = null; + if (expectedMessage === undefined) { + message = `Expected no more error messages but got:\n"${actualMessage}"`; + } else if (!actualMessage.includes(expectedMessage)) { + message = `Expected #${messagesMatched} "${expectedMessage}" to be included in \n"${actualMessage}"`; + } + + if (message !== null) { + const error = new Error(message); + + const { stack: fullStack } = error; + const fullStacktrace = fullStack!.replace(`Error: ${message}\n`, '').split('\n'); + + const usefulStacktrace = fullStacktrace + // + // first line points to this frame which is irrelevant for the tester + .slice(1); + const usefulStack = `${message}\n${usefulStacktrace.join('\n')}`; + + error.stack = usefulStack; + unexpectedMessages.push(error); + } + }; + // eslint-disable-next-line no-console + console[methodName] = consoleMatcher; + + try { + callback(); + } catch (error) { + caughtError = error; + } finally { + // eslint-disable-next-line no-console + console[methodName] = originalMethod; + + // unexpected thrown error takes precedence over unexpected console call + if (caughtError !== null) { + // not the same pattern as described in the block because we don't rethrow in the catch + // eslint-disable-next-line no-unsafe-finally + throw caughtError; + } + + const formatMessages = (messages: ReadonlyArray) => { + const formattedMessages = messages.map((message) => { + if (typeof message === 'string') { + return `"${message}"`; + } + // full Error + return `${message.stack}`; + }); + return `\n\n - ${formattedMessages.join('\n\n- ')}`; + }; + + const shouldHaveWarned = utils.flag(this, 'negate') !== true; + + // unreachable from expect().not.toWarnDev(messages) + if (unexpectedMessages.length > 0) { + const unexpectedMessageRecordedMessage = `Recorded unexpected console.${methodName} calls: ${formatMessages( + unexpectedMessages, + )}`; + // chai will duplicate the stack frames from the unexpected calls in their assertion error + // it's not ideal but the test failure is located the second to last stack frame + // and the origin of the call is the second stackframe in the stack + this.assert( + // force chai to always trigger an assertion error + !shouldHaveWarned, + unexpectedMessageRecordedMessage, + unexpectedMessageRecordedMessage, + // Not interested in a diff but the typings require the 4th parameter. + undefined, + ); + } + + if (shouldHaveWarned) { + this.assert( + remainingMessages.length === 0, + `Could not match the following console.${methodName} calls. ` + + `Make sure previous actions didn't call console.${methodName} by wrapping them in expect(() => {}).not.${matcherName}(): ${formatMessages( + remainingMessages, + )}`, + `Impossible state reached in \`expect().${matcherName}()\`. ` + + `This is a bug in the matcher.`, + // Not interested in a diff but the typings require the 4th parameter. + undefined, + ); + } + } + } else { + // nothing to do in prod + // If there are still console calls than our test setup throws. + callback(); + } + } + + chaiAPI.Assertion.addMethod(matcherName, matcher); + } + + /** + * @example expect(() => render()).toWarnDev('single message') + * @example expect(() => render()).toWarnDev(['first warning', 'then the second']) + */ + addConsoleMatcher('toWarnDev', 'warn'); + addConsoleMatcher('toErrorDev', 'error'); +}; + +export default chaiPlugin; diff --git a/packages-internal/test-utils/src/initMatchers.ts b/packages-internal/test-utils/src/initMatchers.ts index d7251804918ebd..8ab13d2b5fd6e4 100644 --- a/packages-internal/test-utils/src/initMatchers.ts +++ b/packages-internal/test-utils/src/initMatchers.ts @@ -1,658 +1,7 @@ -import { isInaccessible } from '@testing-library/dom'; -import { prettyDOM } from '@testing-library/react/pure'; -import chai, { AssertionError } from 'chai'; +import chai from 'chai'; import chaiDom from 'chai-dom'; -import { computeAccessibleDescription, computeAccessibleName } from 'dom-accessibility-api'; -import formatUtil from 'format-util'; -import _ from 'lodash'; +import './chai.types'; +import chaiPlugin from './chaiPlugin'; chai.use(chaiDom); - -const isKarma = Boolean(process.env.KARMA); - -// https://stackoverflow.com/a/46755166/3406963 -declare global { - namespace Chai { - interface Assertion { - /** - * Checks if the element in question is considered `aria-hidden`. - * Does not replace accessibility check as that requires display/visibility/layout - * @deprecated Use `inaccessible` + `visible` instead - */ - toBeAriaHidden(): void; - /** - * Checks `expectedStyle` is a subset of the elements inline style i.e. `element.style`. - * @example expect(element).toHaveInlineStyle({ width: '200px' }) - */ - toHaveInlineStyle( - expectedStyle: Partial< - Record< - Exclude< - keyof CSSStyleDeclaration, - | 'getPropertyPriority' - | 'getPropertyValue' - | 'item' - | 'removeProperty' - | 'setProperty' - | number - >, - string - > - >, - ): void; - /** - * Checks `expectedStyle` is a subset of the elements computed style i.e. `window.getComputedStyle(element)`. - * @example expect(element).toHaveComputedStyle({ width: '200px' }) - */ - toHaveComputedStyle( - expectedStyle: Partial< - Record< - Exclude< - keyof CSSStyleDeclaration, - | 'getPropertyPriority' - | 'getPropertyValue' - | 'item' - | 'removeProperty' - | 'setProperty' - | number - >, - string - > - >, - ): void; - /** - * Check if an element's [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) is not `hidden` or `collapsed`. - */ - toBeVisible(): void; - /** - * Check if an element's [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) is `hidden` or `collapsed`. - */ - toBeHidden(): void; - /** - * Checks if the element is inaccessible. - * - * Elements are considered inaccessible if they either: - * - have [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) `hidden` - * - have [`display`](https://developer.mozilla.org/en-US/docs/Web/CSS/display) `none` - * - have `aria-hidden` `true` or any of their parents - * - * @see [Excluding Elements from the Accessibility Tree](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion) - */ - toBeInaccessible(): void; - toHaveAccessibleDescription(description: string): void; - /** - * Checks if the accessible name computation (according to `accname` spec) - * matches the expectation. - * - * @see https://www.w3.org/TR/accname-1.2/ - * @param name - */ - toHaveAccessibleName(name: string): void; - /** - * Checks if the element is actually focused i.e. `document.activeElement` is equal to the actual element. - */ - toHaveFocus(): void; - /** - * Checks if the element is the active-descendant of the active element. - */ - toHaveVirtualFocus(): void; - /** - * Matches calls to `console.warn` in the asserted callback. - * - * @example expect(() => render()).not.toWarnDev() - * @example expect(() => render()).toWarnDev('single message') - * @example expect(() => render()).toWarnDev(['first warning', 'then the second']) - */ - toWarnDev(messages?: string | readonly (string | boolean)[]): void; - /** - * Matches calls to `console.error` in the asserted callback. - * - * @example expect(() => render()).not.toErrorDev() - * @example expect(() => render()).toErrorDev('single message') - * @example expect(() => render()).toErrorDev(['first warning', 'then the second']) - */ - toErrorDev(messages?: string | readonly (string | boolean)[]): void; - /** - * Asserts that the given callback throws an error matching the given message in development (process.env.NODE_ENV !== 'production'). - * In production it expects a minified error. - */ - toThrowMinified(message: string): void; - } - } -} - -function isInJSDOM() { - return /jsdom/.test(window.navigator.userAgent); -} - -// chai#utils.elToString that looks like stringified elements in testing-library -function elementToString(element: Element | null | undefined) { - if (typeof element?.nodeType === 'number') { - return prettyDOM(element, undefined, { highlight: !isKarma, maxDepth: 1 }); - } - return String(element); -} -chai.use((chaiAPI, utils) => { - const blockElements = new Set([ - 'html', - 'address', - 'blockquote', - 'body', - 'dd', - 'div', - 'dl', - 'dt', - 'fieldset', - 'form', - 'frame', - 'frameset', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'noframes', - 'ol', - 'p', - 'ul', - 'center', - 'dir', - 'hr', - 'menu', - 'pre', - ]); - - function pretendVisibleGetComputedStyle(element: Element): CSSStyleDeclaration { - // `CSSStyleDeclaration` is not constructable - // https://stackoverflow.com/a/52732909/3406963 - // this is not equivalent to the declaration from `getComputedStyle` - // for example `getComputedStyle` would return a readonly declaration - // let's hope this doesn't get passed around until it's no longer clear where it comes from - const declaration = document.createElement('span').style; - - // initial values - declaration.content = ''; - // technically it's `inline`. We partially apply the default user agent sheet (chrome) here - // we're only interested in elements that use block - declaration.display = blockElements.has(element.tagName) ? 'block' : 'inline'; - declaration.visibility = 'visible'; - - return declaration; - } - - // better diff view for expect(element).to.equal(document.activeElement) - chai.Assertion.addMethod('toHaveFocus', function elementIsFocused() { - const element = utils.flag(this, 'object'); - - this.assert( - element === document.activeElement, - // karma does not show the diff like mocha does - `expected element to have focus${isKarma ? '\nexpected #{exp}\nactual: #{act}' : ''}`, - `expected element to NOT have focus \n${elementToString(element)}`, - elementToString(element), - elementToString(document.activeElement), - ); - }); - - chai.Assertion.addMethod('toHaveVirtualFocus', function elementIsVirtuallyFocused() { - const element = utils.flag(this, 'object'); - const id = element.getAttribute('id'); - - const virtuallyFocusedElementId = document.activeElement!.getAttribute('aria-activedescendant'); - - this.assert( - virtuallyFocusedElementId === id, - `expected element to be virtually focused\nexpected id #{exp}\n${ - virtuallyFocusedElementId === null - ? `activeElement: ${elementToString(document.activeElement)}` - : 'actual id: #{act}' - }`, - 'expected element to NOT to be virtually focused', - id, - virtuallyFocusedElementId, - virtuallyFocusedElementId !== null, - ); - }); - - chai.Assertion.addMethod('toBeAriaHidden', function elementIsAccessible() { - const element = utils.flag(this, 'object'); - - // used for debugging failed assertions, will either point to the top most node - // or the node that had aria-hidden="true" - let previousNode = element; - let currentNode = element; - let ariaHidden = false; - // "An element is considered hidden if it, or any of its ancestors are not - // rendered or have their aria-hidden attribute value set to true." - // -- https://www.w3.org/TR/wai-aria-1.1/#aria-hidden - while ( - currentNode !== null && - // stopping at so that failed assertion message only prints - // or below. use cases for aria-hidden on are unknown - currentNode !== document.documentElement && - ariaHidden === false - ) { - ariaHidden = currentNode.getAttribute('aria-hidden') === 'true'; - previousNode = currentNode; - currentNode = currentNode.parentElement; - } - - this.assert( - ariaHidden === true, - `expected \n${elementToString(element)} to be aria-hidden`, - `expected \n${elementToString(element)} to not be aria-hidden, but \n${elementToString( - previousNode, - )} had aria-hidden="true" instead`, - // Not interested in a diff but the typings require the 4th parameter. - undefined, - ); - }); - - chai.Assertion.addMethod('toBeInaccessible', function elementIsAccessible() { - const element = utils.flag(this, 'object'); - - const inaccessible = isInaccessible(element); - - this.assert( - inaccessible === true, - `expected \n${elementToString(element)} to be inaccessible but it was accessible`, - `expected \n${elementToString(element)} to be accessible but it was inaccessible`, - // Not interested in a diff but the typings require the 4th parameter. - undefined, - ); - }); - - chai.Assertion.addMethod('toHaveAccessibleName', function hasAccessibleName(expectedName) { - const root = utils.flag(this, 'object'); - // make sure it's an Element - new chai.Assertion(root.nodeType, `Expected an Element but got '${String(root)}'`).to.equal(1); - - const actualName = computeAccessibleName(root, { - computedStyleSupportsPseudoElements: !isInJSDOM(), - // in local development we pretend to be visible. full getComputedStyle is - // expensive and reserved for CI - getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle, - }); - - this.assert( - actualName === expectedName, - `expected \n${elementToString(root)} to have accessible name #{exp} but got #{act} instead.`, - `expected \n${elementToString(root)} not to have accessible name #{exp}.`, - expectedName, - actualName, - ); - }); - - chai.Assertion.addMethod( - 'toHaveAccessibleDescription', - function hasAccessibleDescription(expectedDescription) { - const root = utils.flag(this, 'object'); - // make sure it's an Element - new chai.Assertion(root.nodeType, `Expected an Element but got '${String(root)}'`).to.equal( - 1, - ); - - const actualDescription = computeAccessibleDescription(root, { - // in local development we pretend to be visible. full getComputedStyle is - // expensive and reserved for CI - getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle, - }); - - const possibleDescriptionComputationMessage = root.hasAttribute('title') - ? ' computeAccessibleDescription can be misleading when a `title` attribute is used. This might be a bug in `dom-accessibility-api`.' - : ''; - this.assert( - actualDescription === expectedDescription, - `expected \n${elementToString( - root, - )} to have accessible description #{exp} but got #{act} instead.${possibleDescriptionComputationMessage}`, - `expected \n${elementToString( - root, - )} not to have accessible description #{exp}.${possibleDescriptionComputationMessage}`, - expectedDescription, - actualDescription, - ); - }, - ); - - /** - * Correct name for `to.be.visible` - */ - chai.Assertion.addMethod('toBeVisible', function toBeVisible() { - // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions - new chai.Assertion(this._obj).to.be.visible; - }); - - /** - * Correct name for `not.to.be.visible` - */ - chai.Assertion.addMethod('toBeHidden', function toBeHidden() { - // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions - new chai.Assertion(this._obj).not.to.be.visible; - }); - - function assertMatchingStyles( - this: Chai.AssertionStatic, - actualStyleDeclaration: CSSStyleDeclaration, - expectedStyleUnnormalized: Record, - options: { styleTypeHint: string }, - ): void { - const { styleTypeHint } = options; - - // Compare objects using hyphen case. - // This is closer to actual CSS and required for getPropertyValue anyway. - const expectedStyle: Record = {}; - Object.keys(expectedStyleUnnormalized).forEach((cssProperty) => { - const hyphenCasedPropertyName = _.kebabCase(cssProperty); - const isVendorPrefixed = /^(moz|ms|o|webkit)-/.test(hyphenCasedPropertyName); - const propertyName = isVendorPrefixed - ? `-${hyphenCasedPropertyName}` - : hyphenCasedPropertyName; - expectedStyle[propertyName] = expectedStyleUnnormalized[cssProperty]; - }); - - const shorthandProperties = new Set([ - 'all', - 'animation', - 'background', - 'border', - 'border-block-end', - 'border-block-start', - 'border-bottom', - 'border-color', - 'border-image', - 'border-inline-end', - 'border-inline-start', - 'border-left', - 'border-radius', - 'border-right', - 'border-style', - 'border-top', - 'border-width', - 'column-rule', - 'columns', - 'flex', - 'flex-flow', - 'font', - 'gap', - 'grid', - 'grid-area', - 'grid-column', - 'grid-row', - 'grid-template', - 'list-style', - 'margin', - 'mask', - 'offset', - 'outline', - 'overflow', - 'padding', - 'place-content', - 'place-items', - 'place-self', - 'scroll-margin', - 'scroll-padding', - 'text-decoration', - 'text-emphasis', - 'transition', - ]); - const usedShorthandProperties = Object.keys(expectedStyle).filter((cssProperty) => { - return shorthandProperties.has(cssProperty); - }); - if (usedShorthandProperties.length > 0) { - throw new Error( - [ - `Shorthand properties are not supported in ${styleTypeHint} styles matchers since browsers can compute them differently. `, - 'Use longhand properties instead for the follow shorthand properties:\n', - usedShorthandProperties - .map((cssProperty) => { - return `- https://developer.mozilla.org/en-US/docs/Web/CSS/${cssProperty}#constituent_properties`; - }) - .join('\n'), - ].join(''), - ); - } - - const actualStyle: Record = {}; - Object.keys(expectedStyle).forEach((cssProperty) => { - actualStyle[cssProperty] = actualStyleDeclaration.getPropertyValue(cssProperty); - }); - - const jsdomHint = - 'Styles in JSDOM e.g. from `test:unit` are often misleading since JSDOM does not implement the Cascade nor actual CSS property value computation. ' + - 'If results differ between real browsers and JSDOM, skip the test in JSDOM e.g. `if (/jsdom/.test(window.navigator.userAgent)) this.skip();`'; - const shorthandHint = - 'Browsers can compute shorthand properties differently. Prefer longhand properties e.g. `borderTopColor`, `borderRightColor` etc. instead of `border` or `border-color`.'; - const messageHint = `${jsdomHint}\n${shorthandHint}`; - - if (isKarma) { - // `#{exp}` and `#{act}` placeholders escape the newlines - const expected = JSON.stringify(expectedStyle, null, 2); - const actual = JSON.stringify(actualStyle, null, 2); - // karma's `dots` reporter does not support diffs - this.assert( - // TODO Fix upstream docs/types - (utils as any).eql(actualStyle, expectedStyle), - `expected ${styleTypeHint} style of #{this} did not match\nExpected:\n${expected}\nActual:\n${actual}\n\n\n${messageHint}`, - `expected #{this} to not have ${styleTypeHint} style\n${expected}\n\n\n${messageHint}`, - expectedStyle, - actualStyle, - ); - } else { - this.assert( - // TODO Fix upstream docs/types - (utils as any).eql(actualStyle, expectedStyle), - `expected #{this} to have ${styleTypeHint} style #{exp} \n\n${messageHint}`, - `expected #{this} not to have ${styleTypeHint} style #{exp}${messageHint}`, - expectedStyle, - actualStyle, - true, - ); - } - } - - chai.Assertion.addMethod( - 'toHaveInlineStyle', - function toHaveInlineStyle(expectedStyleUnnormalized: Record) { - const element = utils.flag(this, 'object') as HTMLElement; - if (element?.nodeType !== 1) { - // Same pre-condition for negated and unnegated assertion - throw new AssertionError(`Expected an Element but got ${String(element)}`); - } - - assertMatchingStyles.call(this, element.style, expectedStyleUnnormalized, { - styleTypeHint: 'inline', - }); - }, - ); - - chai.Assertion.addMethod( - 'toHaveComputedStyle', - function toHaveComputedStyle(expectedStyleUnnormalized: Record) { - const element = utils.flag(this, 'object') as HTMLElement; - if (element?.nodeType !== 1) { - // Same pre-condition for negated and unnegated assertion - throw new AssertionError(`Expected an Element but got ${String(element)}`); - } - const computedStyle = element.ownerDocument.defaultView!.getComputedStyle(element); - - assertMatchingStyles.call(this, computedStyle, expectedStyleUnnormalized, { - styleTypeHint: 'computed', - }); - }, - ); - - chai.Assertion.addMethod('toThrowMinified', function toThrowMinified(expectedDevMessage) { - // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved. - if (process.env.NODE_ENV !== 'production') { - (this as any).to.throw(expectedDevMessage); - } else { - utils.flag( - this, - 'message', - "Looks like the error was not minified. This can happen if the error code hasn't been generated yet. Run `pnpm extract-error-codes` and try again.", - ); - // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved. - (this as any).to.throw('Minified MUI error', 'helper'); - } - }); -}); - -chai.use((chaiAPI, utils) => { - function addConsoleMatcher(matcherName: string, methodName: 'error' | 'warn') { - /** - * @param {string[]} expectedMessages - */ - function matcher(this: Chai.AssertionStatic, expectedMessagesInput = []) { - // documented pattern to get the actual value of the assertion - // eslint-disable-next-line no-underscore-dangle - const callback = this._obj; - - if (process.env.NODE_ENV !== 'production') { - const expectedMessages = - typeof expectedMessagesInput === 'string' - ? [expectedMessagesInput] - : expectedMessagesInput.slice(); - const unexpectedMessages: Error[] = []; - // TODO Remove type once MUI X enables noImplicitAny - let caughtError: unknown | null = null; - - this.assert( - expectedMessages.length > 0, - `Expected to call console.${methodName} but didn't provide messages. ` + - `If you don't expect any messages prefer \`expect().not.${matcherName}();\`.`, - `Expected no call to console.${methodName} while also expecting messages.` + - 'Expected no call to console.error but provided messages. ' + - "If you want to make sure a certain message isn't logged prefer the positive. " + - 'By expecting certain messages you automatically expect that no other messages are logged', - // Not interested in a diff but the typings require the 4th parameter. - undefined, - ); - - // Ignore skipped messages in e.g. `[condition && 'foo']` - const remainingMessages = expectedMessages.filter((messageOrFalse) => { - return messageOrFalse !== false; - }); - - // eslint-disable-next-line no-console - const originalMethod = console[methodName]; - - let messagesMatched = 0; - const consoleMatcher = (format: string, ...args: readonly unknown[]) => { - // Ignore legacy root deprecation warnings - // TODO: Remove once we no longer use legacy roots. - if ( - format.indexOf('Use createRoot instead.') !== -1 || - format.indexOf('Use hydrateRoot instead.') !== -1 - ) { - return; - } - const actualMessage = formatUtil(format, ...args); - const expectedMessage = remainingMessages.shift(); - messagesMatched += 1; - - // TODO Remove type once MUI X enables noImplicitAny - let message: string | null = null; - if (expectedMessage === undefined) { - message = `Expected no more error messages but got:\n"${actualMessage}"`; - } else if (!actualMessage.includes(expectedMessage)) { - message = `Expected #${messagesMatched} "${expectedMessage}" to be included in \n"${actualMessage}"`; - } - - if (message !== null) { - const error = new Error(message); - - const { stack: fullStack } = error; - const fullStacktrace = fullStack!.replace(`Error: ${message}\n`, '').split('\n'); - - const usefulStacktrace = fullStacktrace - // - // first line points to this frame which is irrelevant for the tester - .slice(1); - const usefulStack = `${message}\n${usefulStacktrace.join('\n')}`; - - error.stack = usefulStack; - unexpectedMessages.push(error); - } - }; - // eslint-disable-next-line no-console - console[methodName] = consoleMatcher; - - try { - callback(); - } catch (error) { - caughtError = error; - } finally { - // eslint-disable-next-line no-console - console[methodName] = originalMethod; - - // unexpected thrown error takes precedence over unexpected console call - if (caughtError !== null) { - // not the same pattern as described in the block because we don't rethrow in the catch - // eslint-disable-next-line no-unsafe-finally - throw caughtError; - } - - const formatMessages = (messages: ReadonlyArray) => { - const formattedMessages = messages.map((message) => { - if (typeof message === 'string') { - return `"${message}"`; - } - // full Error - return `${message.stack}`; - }); - return `\n\n - ${formattedMessages.join('\n\n- ')}`; - }; - - const shouldHaveWarned = utils.flag(this, 'negate') !== true; - - // unreachable from expect().not.toWarnDev(messages) - if (unexpectedMessages.length > 0) { - const unexpectedMessageRecordedMessage = `Recorded unexpected console.${methodName} calls: ${formatMessages( - unexpectedMessages, - )}`; - // chai will duplicate the stack frames from the unexpected calls in their assertion error - // it's not ideal but the test failure is located the second to last stack frame - // and the origin of the call is the second stackframe in the stack - this.assert( - // force chai to always trigger an assertion error - !shouldHaveWarned, - unexpectedMessageRecordedMessage, - unexpectedMessageRecordedMessage, - // Not interested in a diff but the typings require the 4th parameter. - undefined, - ); - } - - if (shouldHaveWarned) { - this.assert( - remainingMessages.length === 0, - `Could not match the following console.${methodName} calls. ` + - `Make sure previous actions didn't call console.${methodName} by wrapping them in expect(() => {}).not.${matcherName}(): ${formatMessages( - remainingMessages, - )}`, - `Impossible state reached in \`expect().${matcherName}()\`. ` + - `This is a bug in the matcher.`, - // Not interested in a diff but the typings require the 4th parameter. - undefined, - ); - } - } - } else { - // nothing to do in prod - // If there are still console calls than our test setup throws. - callback(); - } - } - - chai.Assertion.addMethod(matcherName, matcher); - } - - /** - * @example expect(() => render()).toWarnDev('single message') - * @example expect(() => render()).toWarnDev(['first warning', 'then the second']) - */ - addConsoleMatcher('toWarnDev', 'warn'); - addConsoleMatcher('toErrorDev', 'error'); -}); +chai.use(chaiPlugin); From 41cbeeafb53d0207aa1ea38ff6e0c911d4ef8885 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 10 Sep 2024 15:00:53 +0200 Subject: [PATCH 11/44] Revert "Fix chai matchers" This reverts commit 76edd75cb6a7bb02fd820e65e9a020103ca908c0. --- .../test-utils/src/describeConformance.tsx | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 20095374d6de82..9d3a102832b646 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -108,7 +108,7 @@ export function testClassName( React.cloneElement(element, { className, 'data-testid': testId }), ); - expect(getByTestId(testId).getAttribute('class')).to.include(className); + expect(getByTestId(testId)).to.have.class(className); }); } @@ -172,7 +172,7 @@ export function testPropsSpread( React.cloneElement(element, { [testProp]: value, 'data-testid': testId }), ); - expect(getByTestId(testId).getAttribute(testProp)).to.equal(value); + expect(getByTestId(testId)).to.have.attribute(testProp, value); }); } @@ -230,14 +230,14 @@ export function testRootClass( // jump to the host component because some components pass the `root` class // to the `classes` prop of the root component. // https://github.com/mui/material-ui/blob/f9896bcd129a1209153106296b3d2487547ba205/packages/material-ui/src/OutlinedInput/OutlinedInput.js#L101 - expect(container.firstElementChild?.getAttribute('class')).to.include(className); - expect(container.firstElementChild?.getAttribute('class')).to.include(classes.root); + expect(container.firstChild).to.have.class(className); + expect(container.firstChild).to.have.class(classes.root); expect(document.querySelectorAll(`.${classes.root}`).length).to.equal(1); // classes test only for @mui/material if (!skip || !skip.includes('classesRoot')) { // Test that classes prop works - expect(container.firstElementChild?.getAttribute('class')).to.include(classesRootClassname); + expect(container.firstChild).to.have.class(classesRootClassname); // Test that `classes` does not spread to DOM expect(document.querySelectorAll('[classes]').length).to.equal(0); @@ -288,7 +288,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo const renderedElement = queryByTestId('custom'); expect(renderedElement).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); + expect(renderedElement).to.have.class(slotOptions.expectedClassName); } }); @@ -319,7 +319,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo expect(renderedElement!.nodeName.toLowerCase()).to.equal(slotElement); if (slotOptions.expectedClassName) { - expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); + expect(renderedElement).to.have.class(slotOptions.expectedClassName); } }); } @@ -343,7 +343,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo const renderedElement = queryByTestId('custom'); expect(renderedElement).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(renderedElement?.getAttribute('class')).to.include(slotOptions.expectedClassName); + expect(renderedElement).to.have.class(slotOptions.expectedClassName); } }); @@ -423,9 +423,7 @@ function testSlotsProp(element: React.ReactElement, getOptions: () => Confo expect(renderedElement!.nodeName.toLowerCase()).to.equal(slotElement); if (slotOptions.expectedClassName) { - expect(renderedElement?.getAttribute('class')).to.include( - slotOptions.expectedClassName, - ); + expect(renderedElement).to.have.class(slotOptions.expectedClassName); } }); } @@ -453,7 +451,7 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C expect(slotComponent).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(slotComponent?.getAttribute('class')).to.include(slotOptions.expectedClassName); + expect(slotComponent).to.have.class(slotOptions.expectedClassName); } }); @@ -468,12 +466,8 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C const { getByTestId } = await render(React.cloneElement(element, { slotProps })); - expect(getByTestId('custom').getAttribute('class')).to.include( - slotOptions.expectedClassName, - ); - expect(getByTestId('custom').getAttribute('class')).to.include( - slotProps[slotName].className, - ); + expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName); + expect(getByTestId('custom')).to.have.class(slotProps[slotName].className); }); } @@ -490,7 +484,7 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C expect(slotComponent).not.to.equal(null); if (slotOptions.expectedClassName) { - expect(slotComponent?.getAttribute('class')).to.include(slotOptions.expectedClassName); + expect(slotComponent).to.have.class(slotOptions.expectedClassName); } }); @@ -513,9 +507,8 @@ function testSlotPropsProp(element: React.ReactElement, getOptions: () => C React.cloneElement(element, { componentsProps, slotProps }), ); const slotComponent = queryByTestId('custom'); - expect(slotComponent?.getAttribute('data-from-slot-props')).to.equal('true'); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - expect(slotComponent?.getAttribute('data-from-components-props')).to.be.null; + expect(slotComponent).to.have.attribute('data-from-slot-props', 'true'); + expect(slotComponent).not.to.have.attribute('data-from-components-props'); }); } }); @@ -615,7 +608,7 @@ function testThemeDefaultProps( const { container } = await render({element}); - expect(container.firstElementChild?.getAttribute(testProp)).to.equal('testProp'); + expect(container.firstChild).to.have.attribute(testProp, 'testProp'); }); }); } From 815740438070dfa59b2934955082654943ce2f02 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 11 Sep 2024 16:20:28 +0200 Subject: [PATCH 12/44] Use vitest internal fake timers --- .../test-utils/src/createRenderer.tsx | 85 ++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index faf3370c2167b1..054b91d534a60a 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -371,7 +371,80 @@ export interface Clock { export type ClockConfig = undefined | number | Date; -function createClock(defaultMode: 'fake' | 'real', config: ClockConfig): Clock { +const isVitest = + // VITEST is present on the environment when not in browser mode. + process.env.VITEST === 'true' || + // VITEST_BROWSER_DEBUG is present on vitest in browser mode. + typeof process.env.VITEST_BROWSER_DEBUG !== 'undefined'; + +function createVitestClock(defaultMode: 'fake' | 'real', config: ClockConfig, vi: any): Clock { + if (defaultMode === 'fake') { + beforeEach(() => { + vi.useFakeTimers(); + if (config) { + vi.setSystemTime(config); + } + }); + afterEach(() => { + vi.useRealTimers(); + }); + } else { + beforeEach(() => { + if (config) { + vi.setSystemTime(config); + } + }); + afterEach(() => { + vi.useRealTimers(); + }); + } + + return { + withFakeTimers: () => { + // @ts-ignore + beforeAll(() => { + vi.useFakeTimers(); + }); + // @ts-ignore + afterAll(() => { + vi.useRealTimers(); + }); + }, + runToLast: () => { + traceSync('runToLast', () => { + rtlAct(() => { + vi.runAllTimers(); + }); + }); + }, + isReal() { + return !vi.isFakeTimers(); + }, + restore() { + vi.useRealTimers(); + }, + tick(timeoutMS: number) { + traceSync('tick', () => { + rtlAct(() => { + vi.advanceTimersByTime(timeoutMS); + }); + }); + }, + runAll() { + traceSync('runAll', () => { + rtlAct(() => { + vi.runOnlyPendingTimers(); + }); + }); + }, + }; +} + +function createClock(defaultMode: 'fake' | 'real', config: ClockConfig, vi: any): Clock { + if (isVitest) { + return createVitestClock(defaultMode, config, vi); + } + let clock: ReturnType | null = null; let mode = defaultMode; @@ -457,6 +530,11 @@ export interface CreateRendererOptions extends Pick { - if (!clock.isReal()) { + if (!isVitest && !clock.isReal()) { const error = Error( "Can't cleanup before fake timers are restored.\n" + 'Be sure to:\n' + From 0e74f56d25aef375680bb1751d67968a122e5067 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 11 Sep 2024 16:30:38 +0200 Subject: [PATCH 13/44] only run useRealTimers if config --- packages-internal/test-utils/src/createRenderer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 054b91d534a60a..c2685eb65d351a 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -395,7 +395,9 @@ function createVitestClock(defaultMode: 'fake' | 'real', config: ClockConfig, vi } }); afterEach(() => { - vi.useRealTimers(); + if (config) { + vi.useRealTimers(); + } }); } From ae23bac4300da97b8c1971a49bbf3d46bce38821 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 11 Sep 2024 16:46:24 +0200 Subject: [PATCH 14/44] Invert running timers --- packages-internal/test-utils/src/createRenderer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index c2685eb65d351a..f475c6f585ae54 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -415,7 +415,7 @@ function createVitestClock(defaultMode: 'fake' | 'real', config: ClockConfig, vi runToLast: () => { traceSync('runToLast', () => { rtlAct(() => { - vi.runAllTimers(); + vi.runOnlyPendingTimers(); }); }); }, @@ -435,7 +435,7 @@ function createVitestClock(defaultMode: 'fake' | 'real', config: ClockConfig, vi runAll() { traceSync('runAll', () => { rtlAct(() => { - vi.runOnlyPendingTimers(); + vi.runAllTimers(); }); }); }, From ed66a3e44ec90a8e46cad4b24e478b8cb3aad8de Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 11 Sep 2024 18:38:11 +0200 Subject: [PATCH 15/44] From e9f9582f77a1f6857a96df4b5fd36fa4e09c03dd Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:41:19 +0200 Subject: [PATCH 16/44] Some updates --- package.json | 2 + .../test-utils/src/createRenderer.tsx | 23 ++- .../test-utils/src/setupVitest.ts | 95 ++++++++++ packages-internal/test-utils/tsconfig.json | 5 +- packages/mui-material/package.json | 1 + packages/mui-material/vitest.config.ts | 24 +++ pnpm-lock.yaml | 173 +++++++++++++++++- 7 files changed, 314 insertions(+), 9 deletions(-) create mode 100644 packages-internal/test-utils/src/setupVitest.ts create mode 100644 packages/mui-material/vitest.config.ts diff --git a/package.json b/package.json index 8cad6c232362f2..39fa496652433c 100644 --- a/package.json +++ b/package.json @@ -194,6 +194,8 @@ "terser-webpack-plugin": "^5.3.10", "tsx": "^4.19.1", "typescript": "^5.6.2", + "vitest": "^2.1.2", + "vitest-fail-on-console": "^0.7.1", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 24daf8b3941660..168843bc133cb4 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -114,8 +114,8 @@ class DispatchingProfiler implements Profiler { private renders: RenderMark[] = []; - constructor(test: any) { - this.id = test?.fullTitle?.() || test?.task?.name || test?.task?.id; + constructor(id: string) { + this.id = id; } onRender: Profiler['onRender'] = ( @@ -561,7 +561,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende clockConfig, strict: globalStrict = true, strictEffects: globalStrictEffects = globalStrict, - vi = {}, + vi = (globalThis as any).vi || {}, clockOptions, } = globalOptions; // save stack to re-use in test-hooks @@ -609,7 +609,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende */ let prepared = false; let profiler: Profiler = null!; - beforeEach(function beforeEachHook(t = {}) { + beforeEach(function beforeEachHook() { if (!wasCalledInSuite) { const error = new Error( 'Unable to run `before` hook for `createRenderer`. This usually indicates that `createRenderer` was called in a `before` hook instead of in a `describe()` block.', @@ -618,13 +618,22 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende throw error; } - const test = this?.currentTest || t; - if (test === undefined) { + let id: string | null = null; + + if (isVitest) { + // @ts-expect-error + id = expect.getState().currentTestName; + } else { + id = this.currentTest?.fullTitle() ?? null; + } + + if (!id) { throw new Error( 'Unable to find the currently running test. This is a bug with the client-renderer. Please report this issue to a maintainer.', ); } - profiler = new UsedProfiler(test); + + profiler = new UsedProfiler(id); emotionCache = createEmotionCache({ key: 'emotion-client-render' }); diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts new file mode 100644 index 00000000000000..fbd0b18a3a477c --- /dev/null +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -0,0 +1,95 @@ +import { beforeAll, afterAll, it } from 'vitest'; +import failOnConsole from 'vitest-fail-on-console'; +import './initMatchers'; + +failOnConsole({ + silenceMessage: (message) => { + if (process.env.NODE_ENV === 'production') { + // TODO: mock scheduler + if (message.includes('act(...) is not supported in production builds of React')) { + return true; + } + } + + // Ignore legacy root deprecation warnings + // TODO: Remove once we no longer use legacy roots. + if ( + message.includes('Use createRoot instead.') || + message.includes('Use hydrateRoot instead.') + ) { + return true; + } + + if (message.includes('Warning: useLayoutEffect does nothing on the server')) { + // Controversial warning that is commonly ignored by switching to `useEffect` on the server. + // https://github.com/facebook/react/issues/14927 + // However, this switch doesn't work since it relies on environment sniffing and we test SSR in a browser environment. + return true; + } + + // Unclear why this is an issue for the current occurrences of this warning. + // TODO: Revisit once https://github.com/facebook/react/issues/22796 is resolved + if ( + message.includes( + 'Detected multiple renderers concurrently rendering the same context provider.', + ) + ) { + return true; + } + + return false; + }, +}); + +function wrappedIt(name: string, fn: Function) { + return it(name, (context) => { + return fn?.call(context); + }); +} + +(globalThis as any).it = wrappedIt; + +if (!globalThis.before) { + (globalThis as any).before = beforeAll; +} +if (!globalThis.after) { + (globalThis as any).after = afterAll; +} +if (!globalThis.specify) { + (globalThis as any).specify = wrappedIt; +} + +const isVitestJsdom = process.env.MUI_JSDOM === 'true'; + +// Only necessary when not in browser mode. +if (isVitestJsdom) { + 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/packages-internal/test-utils/tsconfig.json b/packages-internal/test-utils/tsconfig.json index fbee0a28b0b198..2b79bf3292d517 100644 --- a/packages-internal/test-utils/tsconfig.json +++ b/packages-internal/test-utils/tsconfig.json @@ -7,7 +7,10 @@ "strict": true, "esModuleInterop": true, "isolatedModules": true, - "jsx": "react" + "jsx": "react", + // https://github.com/vitest-dev/vitest/issues/4688 + // TODO: Remove after fully migrated chai to vitest + "skipLibCheck": true }, "include": ["./src/**/*"] } diff --git a/packages/mui-material/package.json b/packages/mui-material/package.json index b277c097237c9f..b0b2df14059de0 100644 --- a/packages/mui-material/package.json +++ b/packages/mui-material/package.json @@ -36,6 +36,7 @@ "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/mui-material/**/*.test.{js,ts,tsx}'", + "test:v": "vitest", "typescript": "tsc -p tsconfig.json", "typescript:module-augmentation": "node scripts/testModuleAugmentation.js" }, diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts new file mode 100644 index 00000000000000..56b10260905766 --- /dev/null +++ b/packages/mui-material/vitest.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from 'vitest/config'; +import * as path from 'path'; + +export default defineConfig({ + test: { + exclude: ['**/*.spec.*'], + globals: true, + setupFiles: [path.resolve(__dirname, '../../packages-internal/test-utils/src/setupVitest')], + environment: 'jsdom', + }, + resolve: { + alias: { + '@mui/internal-test-utils': path.resolve(__dirname, '../../packages-internal/test-utils/src'), + '@mui/icons-material': path.resolve(__dirname, '../../packages/mui-icons-material/lib'), + }, + }, + esbuild: { + loader: 'tsx', + include: /.*\.[jt]sx?$/, + // loader: "tsx", + // include: /src\/.*\.[tj]sx?$/, + exclude: [], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 054ab5aaaddf8f..a617393dcf1a7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,6 +309,12 @@ importers: typescript: specifier: ^5.6.2 version: 5.6.2 + vitest: + specifier: ^2.1.2 + version: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + vitest-fail-on-console: + specifier: ^0.7.1 + version: 0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)) webpack: specifier: ^5.95.0 version: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) @@ -5847,6 +5853,9 @@ packages: '@vitest/expect@2.1.1': resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==} + '@vitest/expect@2.1.2': + resolution: {integrity: sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==} + '@vitest/mocker@2.1.1': resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==} peerDependencies: @@ -5859,21 +5868,48 @@ packages: vite: optional: true + '@vitest/mocker@2.1.2': + resolution: {integrity: sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==} + peerDependencies: + '@vitest/spy': 2.1.2 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@2.1.1': resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} + '@vitest/pretty-format@2.1.2': + resolution: {integrity: sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==} + '@vitest/runner@2.1.1': resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==} + '@vitest/runner@2.1.2': + resolution: {integrity: sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==} + '@vitest/snapshot@2.1.1': resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==} + '@vitest/snapshot@2.1.2': + resolution: {integrity: sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==} + '@vitest/spy@2.1.1': resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==} + '@vitest/spy@2.1.2': + resolution: {integrity: sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==} + '@vitest/utils@2.1.1': resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} + '@vitest/utils@2.1.2': + resolution: {integrity: sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==} + '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -12663,6 +12699,11 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-node@2.1.2: + resolution: {integrity: sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-plugin-node-polyfills@0.22.0: resolution: {integrity: sha512-F+G3LjiGbG8QpbH9bZ//GSBr9i1InSTkaulfUHFa9jkLqVGORFBoqc2A/Yu5Mmh1kNAbiAeKeK+6aaQUf3x0JA==} peerDependencies: @@ -12717,6 +12758,12 @@ packages: terser: 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@2.1.1: resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -12742,6 +12789,31 @@ packages: jsdom: optional: true + vitest@2.1.2: + resolution: {integrity: sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^20.16.10 + '@vitest/browser': 2.1.2 + '@vitest/ui': 2.1.2 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} @@ -17274,6 +17346,13 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 + '@vitest/expect@2.1.2': + dependencies: + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + tinyrainbow: 1.2.0 + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': dependencies: '@vitest/spy': 2.1.1 @@ -17282,31 +17361,64 @@ snapshots: optionalDependencies: vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': + dependencies: + '@vitest/spy': 2.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) + '@vitest/pretty-format@2.1.1': dependencies: tinyrainbow: 1.2.0 + '@vitest/pretty-format@2.1.2': + dependencies: + tinyrainbow: 1.2.0 + '@vitest/runner@2.1.1': dependencies: '@vitest/utils': 2.1.1 pathe: 1.1.2 + '@vitest/runner@2.1.2': + dependencies: + '@vitest/utils': 2.1.2 + pathe: 1.1.2 + '@vitest/snapshot@2.1.1': dependencies: '@vitest/pretty-format': 2.1.1 magic-string: 0.30.11 pathe: 1.1.2 + '@vitest/snapshot@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + magic-string: 0.30.11 + pathe: 1.1.2 + '@vitest/spy@2.1.1': dependencies: tinyspy: 3.0.0 + '@vitest/spy@2.1.2': + dependencies: + tinyspy: 3.0.0 + '@vitest/utils@2.1.1': dependencies: '@vitest/pretty-format': 2.1.1 loupe: 3.1.1 tinyrainbow: 1.2.0 + '@vitest/utils@2.1.2': + dependencies: + '@vitest/pretty-format': 2.1.2 + loupe: 3.1.1 + tinyrainbow: 1.2.0 + '@webassemblyjs/ast@1.12.1': dependencies: '@webassemblyjs/helper-numbers': 1.11.6 @@ -25672,6 +25784,23 @@ snapshots: - supports-color - terser + vite-node@2.1.2(@types/node@20.16.10)(terser@5.29.2): + dependencies: + cac: 6.7.14 + debug: 4.3.6(supports-color@8.1.1) + pathe: 1.1.2 + vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-plugin-node-polyfills@0.22.0(rollup@4.21.1)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.21.1) @@ -25705,11 +25834,17 @@ snapshots: fsevents: 2.3.3 terser: 5.29.2 + vitest-fail-on-console@0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)): + dependencies: + chalk: 5.3.0 + vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) + vitest: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + vitest@2.1.1(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2): dependencies: '@vitest/expect': 2.1.1 '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) - '@vitest/pretty-format': 2.1.1 + '@vitest/pretty-format': 2.1.2 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 '@vitest/spy': 2.1.1 @@ -25741,6 +25876,42 @@ snapshots: - supports-color - terser + vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2): + dependencies: + '@vitest/expect': 2.1.2 + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) + '@vitest/pretty-format': 2.1.2 + '@vitest/runner': 2.1.2 + '@vitest/snapshot': 2.1.2 + '@vitest/spy': 2.1.2 + '@vitest/utils': 2.1.2 + chai: 5.1.1 + debug: 4.3.6(supports-color@8.1.1) + magic-string: 0.30.11 + pathe: 1.1.2 + std-env: 3.7.0 + tinybench: 2.9.0 + tinyexec: 0.3.0 + tinypool: 1.0.0 + tinyrainbow: 1.2.0 + vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) + vite-node: 2.1.2(@types/node@20.16.10)(terser@5.29.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.16.10 + happy-dom: 12.10.3 + jsdom: 24.0.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vlq@1.0.1: {} vm-browserify@1.1.2: {} From 442770a36674fe17d1fb33a446eec4e9b2c2fdb5 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Sat, 5 Oct 2024 09:24:40 +0200 Subject: [PATCH 17/44] updates --- .../test-utils/src/setupVitest.ts | 24 ++++++++++++++----- packages/mui-material/vitest.config.ts | 18 ++++++++++++-- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index fbd0b18a3a477c..d114f2fda44091 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -1,7 +1,13 @@ import { beforeAll, afterAll, it } from 'vitest'; +import * as testingLibrary from '@testing-library/dom'; import failOnConsole from 'vitest-fail-on-console'; import './initMatchers'; +testingLibrary.configure({ + // JSDOM logs errors otherwise on `getComputedStyle(element, pseudoElement)` calls. + computedStyleSupportsPseudoElements: false, +}); + failOnConsole({ silenceMessage: (message) => { if (process.env.NODE_ENV === 'production') { @@ -41,12 +47,18 @@ failOnConsole({ }, }); -function wrappedIt(name: string, fn: Function) { - return it(name, (context) => { - return fn?.call(context); - }); +function wrapIt(itFn: typeof it.only) { + return function wrapper(name: string, fn: Function) { + return itFn(name, (context) => { + return fn?.call(context); + }); + }; } +const wrappedIt: any = wrapIt(it); +wrappedIt.skip = wrapIt(it.skip); +wrappedIt.only = wrapIt(it.only); + (globalThis as any).it = wrappedIt; if (!globalThis.before) { @@ -59,10 +71,10 @@ if (!globalThis.specify) { (globalThis as any).specify = wrappedIt; } -const isVitestJsdom = process.env.MUI_JSDOM === 'true'; +const isJsdom = typeof window !== 'undefined' && window.navigator.userAgent.includes('jsdom'); // Only necessary when not in browser mode. -if (isVitestJsdom) { +if (isJsdom) { class Touch { instance: any; diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts index 56b10260905766..9fd62ee1dadfca 100644 --- a/packages/mui-material/vitest.config.ts +++ b/packages/mui-material/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vitest/config'; +import { defineConfig, configDefaults } from 'vitest/config'; import * as path from 'path'; export default defineConfig({ @@ -7,13 +7,27 @@ export default defineConfig({ globals: true, setupFiles: [path.resolve(__dirname, '../../packages-internal/test-utils/src/setupVitest')], environment: 'jsdom', + environmentOptions: { + jsdom: { + pretendToBeVisual: true, + url: 'http://localhost', + }, + }, + fakeTimers: { + // We use performance.now in the codebase + toFake: [...configDefaults.fakeTimers.toFake, 'performance'], + }, }, resolve: { alias: { '@mui/internal-test-utils': path.resolve(__dirname, '../../packages-internal/test-utils/src'), - '@mui/icons-material': path.resolve(__dirname, '../../packages/mui-icons-material/lib'), + '@mui/material': path.resolve(__dirname, './src'), + '@mui/system': path.resolve(__dirname, '../mui-system/src'), + '@mui/utils': path.resolve(__dirname, '../mui-utils/src'), + '@mui/icons-material': path.resolve(__dirname, '../mui-icons-material/lib'), }, }, + // @mui/material writes JSX in js esbuild: { loader: 'tsx', include: /.*\.[jt]sx?$/, From 4e4cf7893195c27295c257c4de714b5c627b9144 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:27:20 +0200 Subject: [PATCH 18/44] tweaks --- .../test-utils/src/createRenderer.tsx | 6 +- packages-internal/test-utils/src/init.js | 7 ++ .../test-utils/src/setupVitest.ts | 4 +- .../src/ButtonBase/ButtonBase.test.js | 36 ++-------- packages/mui-material/src/Chip/Chip.test.js | 9 +-- .../mui-material/src/Divider/Divider.test.js | 65 ++++++++++--------- .../src/ListItemButton/ListItemButton.test.js | 9 +-- .../mui-material/src/Rating/Rating.test.js | 10 +-- .../mui-material/src/Tooltip/Tooltip.test.js | 18 +---- .../mui-material/src/internal/animate.test.js | 17 ++--- .../integration/PopperChildrenLayout.test.js | 14 +--- packages/mui-material/vitest.config.ts | 2 - .../src/usePreviousProps/usePreviousProps.ts | 4 +- 13 files changed, 63 insertions(+), 138 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 168843bc133cb4..1767ad6ecad1fb 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -412,12 +412,10 @@ function createVitestClock( return { withFakeTimers: () => { - // @ts-ignore - beforeAll(() => { + beforeEach(() => { vi.useFakeTimers(options); }); - // @ts-ignore - afterAll(() => { + afterEach(() => { vi.useRealTimers(); }); }, diff --git a/packages-internal/test-utils/src/init.js b/packages-internal/test-utils/src/init.js index 85e2fe80a5eb6c..e664eb393c2964 100644 --- a/packages-internal/test-utils/src/init.js +++ b/packages-internal/test-utils/src/init.js @@ -9,3 +9,10 @@ const defaultHidden = !process.env.CI; // adds verbosity for something that might be confusing console.warn(`${defaultHidden ? 'including' : 'excluding'} inaccessible elements by default`); testingLibrary.configure({ defaultHidden }); + +globalThis.describeSkipIf = + (condition) => + (...args) => { + // eslint-disable-next-line no-undef + return (condition ? describe.skip : describe)(...args); + }; diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index d114f2fda44091..15987d02ab899b 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -1,4 +1,4 @@ -import { beforeAll, afterAll, it } from 'vitest'; +import { beforeAll, afterAll, it, describe } from 'vitest'; import * as testingLibrary from '@testing-library/dom'; import failOnConsole from 'vitest-fail-on-console'; import './initMatchers'; @@ -105,3 +105,5 @@ if (isJsdom) { // @ts-expect-error globalThis.window.Touch = Touch; } + +(globalThis as any).describeSkipIf = describe.skipIf; diff --git a/packages/mui-material/src/ButtonBase/ButtonBase.test.js b/packages/mui-material/src/ButtonBase/ButtonBase.test.js index 569b3d9b4c488e..3a333d508a1be6 100644 --- a/packages/mui-material/src/ButtonBase/ButtonBase.test.js +++ b/packages/mui-material/src/ButtonBase/ButtonBase.test.js @@ -247,14 +247,7 @@ describe('', () => { }); }); - describe('ripple', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('ripple', () => { describe('interactions', () => { it('should not have a focus ripple by default', () => { const { getByRole } = render( @@ -611,14 +604,7 @@ describe('', () => { }); }); - describe('focusRipple', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focusRipple', () => { it('should pulsate the ripple when focusVisible', async () => { const { getByRole } = render( ', () => { }); }); - describe('event: keydown', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: keydown', () => { it('ripples on repeated keydowns', async () => { const { container, getByText } = render( @@ -1177,14 +1156,7 @@ describe('', () => { }); }); - describe('prop: action', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: action', () => { it('should be able to focus visible the button', async () => { /** * @type {React.RefObject} diff --git a/packages/mui-material/src/Chip/Chip.test.js b/packages/mui-material/src/Chip/Chip.test.js index aa695a6de9aabb..55952a13b4f637 100644 --- a/packages/mui-material/src/Chip/Chip.test.js +++ b/packages/mui-material/src/Chip/Chip.test.js @@ -663,14 +663,7 @@ describe('', () => { }); }); - describe('event: focus', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: focus', () => { it('has a focus-visible polyfill', () => { const { container } = render( {}} />); const chip = container.querySelector(`.${classes.root}`); diff --git a/packages/mui-material/src/Divider/Divider.test.js b/packages/mui-material/src/Divider/Divider.test.js index c498df2c6c4417..77c84fa1d25046 100644 --- a/packages/mui-material/src/Divider/Divider.test.js +++ b/packages/mui-material/src/Divider/Divider.test.js @@ -85,39 +85,40 @@ describe('', () => { }); }); - describe('custom border style', function test() { - before(function beforeHook() { - if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - - const StyledDivider = styled(Divider)(() => ({ - borderStyle: 'dashed', - })); - - it('should set the dashed border-left-style in before and after pseudo-elements when orientation is vertical', () => { - const { container } = render(content); - expect( - getComputedStyle(container.firstChild, '::before').getPropertyValue('border-left-style'), - ).to.equal('dashed'); - expect( - getComputedStyle(container.firstChild, '::after').getPropertyValue('border-left-style'), - ).to.equal('dashed'); - }); + describeSkipIf(/jsdom/.test(window.navigator.userAgent))( + 'custom border style', + function test() { + const StyledDivider = styled(Divider)(() => ({ + borderStyle: 'dashed', + })); + + it('should set the dashed border-left-style in before and after pseudo-elements when orientation is vertical', () => { + const { container } = render( + content, + ); + expect( + getComputedStyle(container.firstChild, '::before').getPropertyValue( + 'border-left-style', + ), + ).to.equal('dashed'); + expect( + getComputedStyle(container.firstChild, '::after').getPropertyValue('border-left-style'), + ).to.equal('dashed'); + }); - it('should set the dashed border-top-style in before and after pseudo-elements when orientation is horizontal', () => { - const { container } = render( - content, - ); - expect( - getComputedStyle(container.firstChild, '::before').getPropertyValue('border-top-style'), - ).to.equal('dashed'); - expect( - getComputedStyle(container.firstChild, '::after').getPropertyValue('border-top-style'), - ).to.equal('dashed'); - }); - }); + it('should set the dashed border-top-style in before and after pseudo-elements when orientation is horizontal', () => { + const { container } = render( + content, + ); + expect( + getComputedStyle(container.firstChild, '::before').getPropertyValue('border-top-style'), + ).to.equal('dashed'); + expect( + getComputedStyle(container.firstChild, '::after').getPropertyValue('border-top-style'), + ).to.equal('dashed'); + }); + }, + ); }); describe('prop: variant', () => { diff --git a/packages/mui-material/src/ListItemButton/ListItemButton.test.js b/packages/mui-material/src/ListItemButton/ListItemButton.test.js index d1ddb64aa6bc21..9ba74b92a6a929 100644 --- a/packages/mui-material/src/ListItemButton/ListItemButton.test.js +++ b/packages/mui-material/src/ListItemButton/ListItemButton.test.js @@ -54,14 +54,7 @@ describe('', () => { }); }); - describe('prop: focusVisibleClassName', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: focusVisibleClassName', () => { it('should merge the class names', async () => { const { getByRole } = render( , diff --git a/packages/mui-material/src/Rating/Rating.test.js b/packages/mui-material/src/Rating/Rating.test.js index 5e8f8e948f7216..cfd50442f93626 100644 --- a/packages/mui-material/src/Rating/Rating.test.js +++ b/packages/mui-material/src/Rating/Rating.test.js @@ -248,15 +248,7 @@ describe('', () => { }); }); - describe('
integration', () => { - before(function beforeHook() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM has issues with form validation for certain elements. - // We could address them individually but that doesn't add much value if we already have a working environment. - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))(' integration', () => { [ { ratingProps: { name: 'rating', defaultValue: 2 }, diff --git a/packages/mui-material/src/Tooltip/Tooltip.test.js b/packages/mui-material/src/Tooltip/Tooltip.test.js index 0a4d51d7a2fa39..df9c0f0fb99e56 100644 --- a/packages/mui-material/src/Tooltip/Tooltip.test.js +++ b/packages/mui-material/src/Tooltip/Tooltip.test.js @@ -505,14 +505,7 @@ describe('', () => { }); }); - describe('prop: delay', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: delay', () => { it('should take the enterDelay into account', async () => { const { queryByRole } = render( @@ -883,14 +876,7 @@ describe('', () => { }); }); - describe('focus', () => { - before(function beforeCallback() { - if (/jsdom/.test(window.navigator.userAgent)) { - // JSDOM doesn't support :focus-visible - this.skip(); - } - }); - + describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focus', () => { it('ignores base focus', async () => { render( diff --git a/packages/mui-material/src/internal/animate.test.js b/packages/mui-material/src/internal/animate.test.js index 239c2c48dddfcd..a5c0d6db2c4326 100644 --- a/packages/mui-material/src/internal/animate.test.js +++ b/packages/mui-material/src/internal/animate.test.js @@ -1,22 +1,13 @@ import { expect } from 'chai'; import animate from './animate'; -describe('animate', () => { +const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + +describeSkipIf(isJSDOM || isSafari)('animate', () => { let container; before(function beforeHook() { - const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - const isJSDOM = /jsdom/.test(window.navigator.userAgent); - if (isJSDOM || isSafari) { - // The test fails on Safari with just: - // - // container.scrollLeft = 200; - // expect(container.scrollLeft).to.equal(200); 💥 - - // in JSDOM the test prevents mocha from exiting - this.skip(); - } - container = document.createElement('div'); container.style.cssText = [ 'height: 100px', diff --git a/packages/mui-material/test/integration/PopperChildrenLayout.test.js b/packages/mui-material/test/integration/PopperChildrenLayout.test.js index 507ad32719ea8e..cc3e9f1773a32a 100644 --- a/packages/mui-material/test/integration/PopperChildrenLayout.test.js +++ b/packages/mui-material/test/integration/PopperChildrenLayout.test.js @@ -9,18 +9,10 @@ import Slide from '@mui/material/Slide'; import Zoom from '@mui/material/Zoom'; import Popper from '@mui/material/Popper'; -describe('', () => { - let isSafari; - const { render } = createRenderer(); - - before(function beforeHook() { - // JSDOM has neither layout nor window.scrollTo - if (/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } +const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - }); +describeSkipIf(/jsdom/.test(window.navigator.userAgent))('', () => { + const { render } = createRenderer(); let originalScrollX; let originalScrollY; diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts index 9fd62ee1dadfca..442061f2d37afb 100644 --- a/packages/mui-material/vitest.config.ts +++ b/packages/mui-material/vitest.config.ts @@ -31,8 +31,6 @@ export default defineConfig({ esbuild: { loader: 'tsx', include: /.*\.[jt]sx?$/, - // loader: "tsx", - // include: /src\/.*\.[tj]sx?$/, exclude: [], }, }); diff --git a/packages/mui-utils/src/usePreviousProps/usePreviousProps.ts b/packages/mui-utils/src/usePreviousProps/usePreviousProps.ts index 500b24bf87d98c..5b0e786b05c4eb 100644 --- a/packages/mui-utils/src/usePreviousProps/usePreviousProps.ts +++ b/packages/mui-utils/src/usePreviousProps/usePreviousProps.ts @@ -1,12 +1,12 @@ 'use client'; import * as React from 'react'; -const usePreviousProps = (value: T) => { +function usePreviousProps(value: T) { const ref = React.useRef({}); React.useEffect(() => { ref.current = value; }); return ref.current as Partial; -}; +} export default usePreviousProps; From ba7fd91bb311e33d462269a6ede471c86de14557 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Sat, 5 Oct 2024 19:52:28 +0200 Subject: [PATCH 19/44] Update ButtonBase.test.js --- packages/mui-material/src/ButtonBase/ButtonBase.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/mui-material/src/ButtonBase/ButtonBase.test.js b/packages/mui-material/src/ButtonBase/ButtonBase.test.js index 3a333d508a1be6..755cb20a2aabda 100644 --- a/packages/mui-material/src/ButtonBase/ButtonBase.test.js +++ b/packages/mui-material/src/ButtonBase/ButtonBase.test.js @@ -247,6 +247,8 @@ describe('', () => { }); }); + // @ts-expect-error Temporary shim while migrating to vitest + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('ripple', () => { describe('interactions', () => { it('should not have a focus ripple by default', () => { @@ -604,6 +606,8 @@ describe('', () => { }); }); + // @ts-expect-error Temporary shim while migrating to vitest + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focusRipple', () => { it('should pulsate the ripple when focusVisible', async () => { const { getByRole } = render( @@ -909,6 +913,8 @@ describe('', () => { }); }); + // @ts-expect-error Temporary shim while migrating to vitest + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: keydown', () => { it('ripples on repeated keydowns', async () => { const { container, getByText } = render( @@ -1156,6 +1162,8 @@ describe('', () => { }); }); + // @ts-expect-error Temporary shim while migrating to vitest + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: action', () => { it('should be able to focus visible the button', async () => { /** From 9e8711c821d7492fa3393bfddb9c9bb0e4e269b9 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Sat, 5 Oct 2024 19:58:40 +0200 Subject: [PATCH 20/44] fwfwr --- packages/mui-material/src/Chip/Chip.test.js | 1 + packages/mui-material/src/Divider/Divider.test.js | 1 + .../mui-material/src/ListItemButton/ListItemButton.test.js | 1 + packages/mui-material/src/Rating/Rating.test.js | 1 + packages/mui-material/src/Tooltip/Tooltip.test.js | 2 ++ packages/mui-material/src/internal/animate.test.js | 3 +++ .../mui-material/test/integration/PopperChildrenLayout.test.js | 3 +++ 7 files changed, 12 insertions(+) diff --git a/packages/mui-material/src/Chip/Chip.test.js b/packages/mui-material/src/Chip/Chip.test.js index 55952a13b4f637..538c5a3315eb40 100644 --- a/packages/mui-material/src/Chip/Chip.test.js +++ b/packages/mui-material/src/Chip/Chip.test.js @@ -663,6 +663,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: focus', () => { it('has a focus-visible polyfill', () => { const { container } = render( {}} />); diff --git a/packages/mui-material/src/Divider/Divider.test.js b/packages/mui-material/src/Divider/Divider.test.js index 77c84fa1d25046..d447e8f2c0b40d 100644 --- a/packages/mui-material/src/Divider/Divider.test.js +++ b/packages/mui-material/src/Divider/Divider.test.js @@ -85,6 +85,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))( 'custom border style', function test() { diff --git a/packages/mui-material/src/ListItemButton/ListItemButton.test.js b/packages/mui-material/src/ListItemButton/ListItemButton.test.js index 9ba74b92a6a929..187cdf42837a1e 100644 --- a/packages/mui-material/src/ListItemButton/ListItemButton.test.js +++ b/packages/mui-material/src/ListItemButton/ListItemButton.test.js @@ -54,6 +54,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: focusVisibleClassName', () => { it('should merge the class names', async () => { const { getByRole } = render( diff --git a/packages/mui-material/src/Rating/Rating.test.js b/packages/mui-material/src/Rating/Rating.test.js index cfd50442f93626..db687d69ada1ad 100644 --- a/packages/mui-material/src/Rating/Rating.test.js +++ b/packages/mui-material/src/Rating/Rating.test.js @@ -248,6 +248,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))(' integration', () => { [ { diff --git a/packages/mui-material/src/Tooltip/Tooltip.test.js b/packages/mui-material/src/Tooltip/Tooltip.test.js index df9c0f0fb99e56..4bc33e41fa466d 100644 --- a/packages/mui-material/src/Tooltip/Tooltip.test.js +++ b/packages/mui-material/src/Tooltip/Tooltip.test.js @@ -505,6 +505,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: delay', () => { it('should take the enterDelay into account', async () => { const { queryByRole } = render( @@ -876,6 +877,7 @@ describe('', () => { }); }); + // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focus', () => { it('ignores base focus', async () => { render( diff --git a/packages/mui-material/src/internal/animate.test.js b/packages/mui-material/src/internal/animate.test.js index a5c0d6db2c4326..296ea769ec52b0 100644 --- a/packages/mui-material/src/internal/animate.test.js +++ b/packages/mui-material/src/internal/animate.test.js @@ -4,9 +4,11 @@ import animate from './animate'; const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isJSDOM = /jsdom/.test(window.navigator.userAgent); +// eslint-disable-next-line no-undef describeSkipIf(isJSDOM || isSafari)('animate', () => { let container; + // eslint-disable-next-line mocha/no-top-level-hooks before(function beforeHook() { container = document.createElement('div'); container.style.cssText = [ @@ -21,6 +23,7 @@ describeSkipIf(isJSDOM || isSafari)('animate', () => { document.body.appendChild(container); }); + // eslint-disable-next-line mocha/no-top-level-hooks after(() => { if (container !== undefined) { document.body.removeChild(container); diff --git a/packages/mui-material/test/integration/PopperChildrenLayout.test.js b/packages/mui-material/test/integration/PopperChildrenLayout.test.js index cc3e9f1773a32a..cdce7b73ad1591 100644 --- a/packages/mui-material/test/integration/PopperChildrenLayout.test.js +++ b/packages/mui-material/test/integration/PopperChildrenLayout.test.js @@ -11,17 +11,20 @@ import Popper from '@mui/material/Popper'; const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); +// eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('', () => { const { render } = createRenderer(); let originalScrollX; let originalScrollY; + // eslint-disable-next-line mocha/no-top-level-hooks beforeEach(() => { originalScrollX = window.screenX; originalScrollY = window.scrollY; }); + // eslint-disable-next-line mocha/no-top-level-hooks afterEach(() => { window.scrollTo(originalScrollX, originalScrollY); }); From d2b3f7f6e336a4776935d9bb0541544b55df8c41 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:59:17 +0200 Subject: [PATCH 21/44] tweaks --- babel.config.js | 1 + package.json | 1 + .../test-utils/src/setupVitest.ts | 4 + .../src/Autocomplete/Autocomplete.test.js | 2 +- packages/mui-material/vitest.config.ts | 21 ++- pnpm-lock.yaml | 167 +++++++++++++++--- 6 files changed, 165 insertions(+), 31 deletions(-) diff --git a/babel.config.js b/babel.config.js index de9a6cdea126ae..0b0e796d325601 100644 --- a/babel.config.js +++ b/babel.config.js @@ -43,6 +43,7 @@ module.exports = function getBabelConfig(api) { '@mui/utils': resolveAliasPath('./packages/mui-utils/src'), '@mui/joy': resolveAliasPath('./packages/mui-joy/src'), '@mui/internal-docs-utils': resolveAliasPath('./packages-internal/docs-utils/src'), + '@mui/internal-test-utils': resolveAliasPath('./packages-internal/test-utils/src'), docs: resolveAliasPath('./docs'), test: resolveAliasPath('./test'), }; diff --git a/package.json b/package.json index 5f37c29382769f..30a7b6f023ddcc 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "@types/yargs": "^17.0.33", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "@vitest/coverage-v8": "^2.1.2", "babel-loader": "^9.2.1", "babel-plugin-istanbul": "^7.0.0", "babel-plugin-module-resolver": "^5.0.2", diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index 15987d02ab899b..c01c99804e0a4e 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -8,6 +8,10 @@ testingLibrary.configure({ computedStyleSupportsPseudoElements: false, }); +// 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; + failOnConsole({ silenceMessage: (message) => { if (process.env.NODE_ENV === 'production') { diff --git a/packages/mui-material/src/Autocomplete/Autocomplete.test.js b/packages/mui-material/src/Autocomplete/Autocomplete.test.js index 11f1bda5ab9220..cf669ffc0ca765 100644 --- a/packages/mui-material/src/Autocomplete/Autocomplete.test.js +++ b/packages/mui-material/src/Autocomplete/Autocomplete.test.js @@ -1324,7 +1324,7 @@ describe('', () => { it('should ignore keydown event until the IME is confirmed', function test() { // TODO: Often times out in Firefox 78. // Is this slow because of testing-library or because of the implementation? - this.timeout(4000); + this?.timeout?.(4000); const { getByRole } = render( =16 || 14 >=14.17'} hasBin: true + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + glob@11.0.0: resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} engines: {node: 20 || >=22} @@ -8947,6 +8963,10 @@ packages: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + istanbul-lib-hook@3.0.0: resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} engines: {node: '>=8'} @@ -8963,6 +8983,10 @@ packages: resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} engines: {node: '>=8'} + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + istanbul-lib-source-maps@3.0.6: resolution: {integrity: sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==} engines: {node: '>=6'} @@ -8971,10 +8995,18 @@ 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.5: resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} engines: {node: '>=8'} + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + iterate-iterator@1.0.2: resolution: {integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==} @@ -8993,6 +9025,9 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.0.1: resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} engines: {node: 20 || >=22} @@ -9554,6 +9589,9 @@ packages: magic-string@0.30.11: resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -10560,6 +10598,10 @@ packages: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} @@ -12141,6 +12183,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'} @@ -17227,6 +17273,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/coverage-v8@2.1.2(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.3.6(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.11 + magicast: 0.3.5 + std-env: 3.7.0 + test-exclude: 7.0.1 + tinyrainbow: 1.2.0 + vitest: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + transitivePeerDependencies: + - supports-color + '@vitest/expect@2.1.1': dependencies: '@vitest/spy': 2.1.1 @@ -17383,19 +17447,19 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) '@wyw-in-js/processor-utils@0.5.4': @@ -17857,7 +17921,7 @@ snapshots: '@babel/core': 7.25.2 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) babel-merge@3.0.0(@babel/core@7.25.2): dependencies: @@ -18553,7 +18617,7 @@ snapshots: dependencies: schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) compression@1.7.4: dependencies: @@ -19586,7 +19650,7 @@ snapshots: lodash: 4.17.21 resolve: 2.0.0-next.5 semver: 5.7.2 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color @@ -20351,6 +20415,15 @@ snapshots: minipass: 7.1.2 path-scurry: 1.10.1 + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + glob@11.0.0: dependencies: foreground-child: 3.3.0 @@ -20646,7 +20719,7 @@ snapshots: readable-stream: 1.0.34 through2: 0.4.2 - html-webpack-plugin@5.6.0(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))): + html-webpack-plugin@5.6.0(webpack@5.95.0(webpack-cli@5.1.4)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -20654,7 +20727,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -21047,6 +21120,8 @@ snapshots: istanbul-lib-coverage@3.2.0: {} + istanbul-lib-coverage@3.2.2: {} + istanbul-lib-hook@3.0.0: dependencies: append-transform: 2.0.0 @@ -21076,6 +21151,12 @@ snapshots: make-dir: 3.1.0 supports-color: 7.2.0 + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + istanbul-lib-source-maps@3.0.6: dependencies: debug: 4.3.6(supports-color@8.1.1) @@ -21094,11 +21175,24 @@ snapshots: transitivePeerDependencies: - supports-color + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.3.6(supports-color@8.1.1) + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + istanbul-reports@3.1.5: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.0 + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + iterate-iterator@1.0.2: {} iterate-value@1.0.2: @@ -21125,6 +21219,12 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jackspeak@4.0.1: dependencies: '@isaacs/cliui': 8.0.2 @@ -21563,7 +21663,7 @@ snapshots: dependencies: glob: 7.2.3 minimatch: 3.1.2 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) webpack-merge: 4.2.2 karma@6.4.4: @@ -21939,6 +22039,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + source-map-js: 1.2.1 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -23304,6 +23410,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + path-scurry@2.0.0: dependencies: lru-cache: 11.0.1 @@ -25168,14 +25279,14 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.6.3 - terser-webpack-plugin@5.3.10(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))): + terser-webpack-plugin@5.3.10(webpack@5.95.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) terser@5.29.2: dependencies: @@ -25190,6 +25301,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: {} @@ -25829,9 +25946,9 @@ snapshots: webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.95.0) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.95.0) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.95.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -25840,7 +25957,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) + webpack: 5.95.0(webpack-cli@5.1.4) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.10.2 @@ -25858,7 +25975,7 @@ snapshots: webpack-virtual-modules@0.6.1: {} - webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)): + webpack@5.95.0(webpack-cli@5.1.4): dependencies: '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 @@ -25880,7 +25997,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))) + terser-webpack-plugin: 5.3.10(webpack@5.95.0) watchpack: 2.4.1 webpack-sources: 3.2.3 optionalDependencies: From ccb3dd51f325a120eefd21c84bcdb4d2c00ba1b0 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:59:35 +0200 Subject: [PATCH 22/44] Update pnpm-lock.yaml --- pnpm-lock.yaml | 120 ++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 77 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ed1df9d23ef9b..a33bcdbdccf1e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -302,7 +302,7 @@ importers: version: 34.0.0(stylelint@15.11.0) terser-webpack-plugin: specifier: ^5.3.10 - version: 5.3.10(webpack@5.95.0) + version: 5.3.10(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))) tsx: specifier: ^4.19.1 version: 4.19.1 @@ -317,7 +317,7 @@ importers: version: 0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)) webpack: specifier: ^5.95.0 - version: 5.95.0(webpack-cli@5.1.4) + version: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-bundle-analyzer: specifier: ^4.10.2 version: 4.10.2 @@ -550,7 +550,7 @@ importers: version: 0.16.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(react@18.3.1) webpack: specifier: ^5.95.0 - version: 5.95.0(webpack-cli@5.1.4) + version: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) docs: dependencies: @@ -2328,7 +2328,7 @@ importers: version: 11.2.0 html-webpack-plugin: specifier: ^5.6.0 - version: 5.6.0(webpack@5.95.0(webpack-cli@5.1.4)) + version: 5.6.0(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -2370,7 +2370,7 @@ importers: version: 1.6.28 webpack: specifier: ^5.95.0 - version: 5.95.0(webpack-cli@5.1.4) + version: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) yargs: specifier: ^17.7.2 version: 17.7.2 @@ -8959,10 +8959,6 @@ packages: resolution: {integrity: sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==} engines: {node: '>=6'} - istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -8979,10 +8975,6 @@ packages: resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} engines: {node: '>=8'} - istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} - istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} @@ -8999,10 +8991,6 @@ packages: resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} - istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} - istanbul-reports@3.1.7: resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} @@ -10594,10 +10582,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} - path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -15673,7 +15657,7 @@ snapshots: '@npmcli/map-workspaces@3.0.6': dependencies: '@npmcli/name-from-folder': 2.0.0 - glob: 10.3.10 + glob: 10.4.5 minimatch: 9.0.5 read-package-json-fast: 3.0.2 @@ -15695,7 +15679,7 @@ snapshots: '@npmcli/package-json@5.2.0': dependencies: '@npmcli/git': 5.0.3 - glob: 10.3.10 + glob: 10.4.5 hosted-git-info: 7.0.2 json-parse-even-better-errors: 3.0.2 normalize-package-data: 6.0.2 @@ -17447,19 +17431,19 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.95.0)': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.95.0)': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.95.0)': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0)': dependencies: - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0) '@wyw-in-js/processor-utils@0.5.4': @@ -17921,7 +17905,7 @@ snapshots: '@babel/core': 7.25.2 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) babel-merge@3.0.0(@babel/core@7.25.2): dependencies: @@ -18234,9 +18218,9 @@ snapshots: '@istanbuljs/schema': 0.1.3 find-up: 5.0.0 foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-reports: 3.1.5 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.1.7 rimraf: 3.0.2 test-exclude: 6.0.0 v8-to-istanbul: 9.0.1 @@ -18249,7 +18233,7 @@ snapshots: dependencies: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.2 - glob: 10.3.10 + glob: 10.4.5 lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 @@ -18617,7 +18601,7 @@ snapshots: dependencies: schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) compression@1.7.4: dependencies: @@ -19650,7 +19634,7 @@ snapshots: lodash: 4.17.21 resolve: 2.0.0-next.5 semver: 5.7.2 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) transitivePeerDependencies: - supports-color @@ -20413,7 +20397,7 @@ snapshots: jackspeak: 2.3.6 minimatch: 9.0.5 minipass: 7.1.2 - path-scurry: 1.10.1 + path-scurry: 1.11.1 glob@10.4.5: dependencies: @@ -20464,7 +20448,7 @@ snapshots: fs.realpath: 1.0.0 minimatch: 8.0.4 minipass: 4.2.8 - path-scurry: 1.10.1 + path-scurry: 1.11.1 global-modules@2.0.0: dependencies: @@ -20719,7 +20703,7 @@ snapshots: readable-stream: 1.0.34 through2: 0.4.2 - html-webpack-plugin@5.6.0(webpack@5.95.0(webpack-cli@5.1.4)): + html-webpack-plugin@5.6.0(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -20727,7 +20711,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) htmlparser2@6.1.0: dependencies: @@ -21118,8 +21102,6 @@ snapshots: istanbul-lib-coverage@2.0.5: {} - istanbul-lib-coverage@3.2.0: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-hook@3.0.0: @@ -21131,7 +21113,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/parser': 7.25.6 '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -21140,17 +21122,11 @@ snapshots: dependencies: archy: 1.0.0 cross-spawn: 7.0.3 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 p-map: 3.0.0 rimraf: 3.0.2 uuid: 8.3.2 - istanbul-lib-report@3.0.0: - dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 - supports-color: 7.2.0 - istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 @@ -21170,7 +21146,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: debug: 4.3.6(supports-color@8.1.1) - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color @@ -21183,11 +21159,6 @@ snapshots: transitivePeerDependencies: - supports-color - istanbul-reports@3.1.5: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 - istanbul-reports@3.1.7: dependencies: html-escaper: 2.0.2 @@ -21638,10 +21609,10 @@ snapshots: karma-coverage-istanbul-reporter@3.0.3: dependencies: - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 3.0.6 - istanbul-reports: 3.1.5 + istanbul-reports: 3.1.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -21663,7 +21634,7 @@ snapshots: dependencies: glob: 7.2.3 minimatch: 3.1.2 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-merge: 4.2.2 karma@6.4.4: @@ -22801,7 +22772,7 @@ snapshots: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.1 - glob: 10.3.10 + glob: 10.4.5 graceful-fs: 4.2.11 make-fetch-happen: 13.0.1 nopt: 7.2.1 @@ -23017,13 +22988,13 @@ snapshots: foreground-child: 3.3.0 get-package-type: 0.1.0 glob: 7.2.3 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 istanbul-lib-instrument: 6.0.2 istanbul-lib-processinfo: 2.0.3 - istanbul-lib-report: 3.0.0 + istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 + istanbul-reports: 3.1.7 make-dir: 3.1.0 node-preload: 0.2.1 p-map: 3.0.0 @@ -23405,11 +23376,6 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.10.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -25279,14 +25245,14 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.6.3 - terser-webpack-plugin@5.3.10(webpack@5.95.0): + terser-webpack-plugin@5.3.10(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) terser@5.29.2: dependencies: @@ -25946,9 +25912,9 @@ snapshots: webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.95.0) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.95.0) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.95.0) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))(webpack@5.95.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -25957,7 +25923,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.95.0(webpack-cli@5.1.4) + webpack: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.10.2 @@ -25975,7 +25941,7 @@ snapshots: webpack-virtual-modules@0.6.1: {} - webpack@5.95.0(webpack-cli@5.1.4): + webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)): dependencies: '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 @@ -25997,7 +25963,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.95.0) + terser-webpack-plugin: 5.3.10(webpack@5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0))) watchpack: 2.4.1 webpack-sources: 3.2.3 optionalDependencies: From 9e3c284720eb8aadbd45d37a991c5b6f408bcd17 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 8 Oct 2024 21:12:49 +0200 Subject: [PATCH 23/44] remove troublesome deprecated queries --- .../test-utils/src/createRenderer.tsx | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 1767ad6ecad1fb..b3d74fdff42b7b 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -6,7 +6,6 @@ import { cleanup, prettyDOM, queries, - queryHelpers, RenderResult, act as rtlAct, fireEvent as rtlFireEvent, @@ -193,18 +192,6 @@ const [ }, ); -const queryAllByMuiTest = queryHelpers.queryAllByAttribute.bind(null, 'data-mui-test'); -const [queryByMuiTest, getAllByMuiTest, getByMuiTest, findAllByMuiTest, findByMuiTest] = - buildQueries( - queryAllByMuiTest, - function getMultipleError(container, dataMuiTest) { - return `Found multiple elements with the data-mui-test attribute of: ${dataMuiTest}`; - }, - function getMissingError(container, dataMuiTest) { - return `Found no element with the data-mui-test attribute of: ${dataMuiTest}`; - }, - ); - const customQueries = { queryDescriptionOf, queryAllDescriptionsOf, @@ -212,30 +199,6 @@ const customQueries = { getAllDescriptionsOf, findDescriptionOf, findAllDescriptionsOf, - /** - * @deprecated Use `queryAllByTestId` instead - */ - queryAllByMuiTest, - /** - * @deprecated Use `queryByTestId` instead - */ - queryByMuiTest, - /** - * @deprecated Use `getAllByTestId` instead - */ - getAllByMuiTest, - /** - * @deprecated Use `getByTestId` instead - */ - getByMuiTest, - /** - * @deprecated Use `findAllByTestId` instead - */ - findAllByMuiTest, - /** - * @deprecated Use `findByTestId` instead - */ - findByMuiTest, }; interface RenderConfiguration { From a105b2a68eb92d604de42e683d56aae75a45ed10 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:54:22 +0200 Subject: [PATCH 24/44] Browser tests --- package.json | 1 + .../src/styles/CssVarsProvider.test.tsx | 2 +- .../mui-joy/src/styles/extendTheme.test.js | 2 +- .../mui-material/src/Button/Button.test.js | 10 +- packages/mui-material/src/Fab/Fab.test.js | 10 +- .../mui-material/src/Portal/Portal.test.tsx | 11 +- packages/mui-material/src/Tabs/Tabs.test.js | 8 +- .../TextareaAutosize.test.tsx | 9 +- .../src/ToggleButton/ToggleButton.test.js | 10 +- .../src/internal/SwitchBase.test.js | 4 +- .../src/styles/ThemeProvider.test.tsx | 2 +- .../src/styles/ThemeProviderWithVars.test.js | 2 +- .../src/styles/extendTheme.test.js | 2 +- .../useScrollTrigger/useScrollTrigger.test.js | 10 +- .../test/integration/Menu.test.js | 10 +- packages/mui-material/vitest.config.ts | 11 + .../InitColorSchemeScript.test.js | 2 +- .../src/cssVars/createCssVarsProvider.test.js | 2 +- .../src/cssVars/useCurrentColorScheme.test.js | 2 +- pnpm-lock.yaml | 483 ++++++++++++++++-- .../mui-system/theme-scoping.test.tsx | 2 +- 21 files changed, 480 insertions(+), 115 deletions(-) diff --git a/package.json b/package.json index 30a7b6f023ddcc..2e98af6656e424 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "@types/yargs": "^17.0.33", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "@vitest/browser": "^2.1.2", "@vitest/coverage-v8": "^2.1.2", "babel-loader": "^9.2.1", "babel-plugin-istanbul": "^7.0.0", diff --git a/packages/mui-joy/src/styles/CssVarsProvider.test.tsx b/packages/mui-joy/src/styles/CssVarsProvider.test.tsx index 9bb17ff8964bce..9964ec20949eeb 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.test.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.test.tsx @@ -11,7 +11,7 @@ describe('[Joy] CssVarsProvider', () => { beforeEach(() => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key: string) => storage[key], setItem: (key: string, value: string) => { diff --git a/packages/mui-joy/src/styles/extendTheme.test.js b/packages/mui-joy/src/styles/extendTheme.test.js index 9bf3097075bac3..aa2b1b96e00397 100644 --- a/packages/mui-joy/src/styles/extendTheme.test.js +++ b/packages/mui-joy/src/styles/extendTheme.test.js @@ -205,7 +205,7 @@ describe('extendTheme', () => { beforeEach(() => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key) => storage[key], setItem: (key, value) => { diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index 5d57fa23d002a0..144992131bc6ca 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -624,14 +624,8 @@ describe('); expect(container.firstChild).to.have.text('Hello World'); diff --git a/packages/mui-material/src/Fab/Fab.test.js b/packages/mui-material/src/Fab/Fab.test.js index 4a55e6619cda40..a96a008b6f5606 100644 --- a/packages/mui-material/src/Fab/Fab.test.js +++ b/packages/mui-material/src/Fab/Fab.test.js @@ -160,14 +160,8 @@ describe('', () => { expect(renderedIconChild).to.have.class(childClassName); }); - describe('server-side', () => { - before(function beforeHook() { - // Only run the test on node. - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('should server-side render', () => { const { container } = renderToString(Fab); expect(container.firstChild).to.have.text('Fab'); diff --git a/packages/mui-material/src/Portal/Portal.test.tsx b/packages/mui-material/src/Portal/Portal.test.tsx index 3fe0b934c78bf5..c1ad892542e3ac 100644 --- a/packages/mui-material/src/Portal/Portal.test.tsx +++ b/packages/mui-material/src/Portal/Portal.test.tsx @@ -7,14 +7,9 @@ import Portal, { PortalProps } from '@mui/material/Portal'; describe('', () => { const { render, renderToString } = createRenderer(); - describe('server-side', () => { - before(function beforeHook() { - // Only run the test on node. - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - + // @ts-expect-error + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('render nothing on the server', () => { const { container } = renderToString( diff --git a/packages/mui-material/src/Tabs/Tabs.test.js b/packages/mui-material/src/Tabs/Tabs.test.js index 8b9f426c35e1ee..03910b2b4ee466 100644 --- a/packages/mui-material/src/Tabs/Tabs.test.js +++ b/packages/mui-material/src/Tabs/Tabs.test.js @@ -368,15 +368,11 @@ describe('', () => { ]); }); - describe('hidden tab / tabs', () => { + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('hidden tab / tabs', () => { let nodeEnv; before(function test() { - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - return; - } - nodeEnv = process.env.NODE_ENV; // We can't use a regular assignment, because it causes a syntax error in Karma Object.defineProperty(process.env, 'NODE_ENV', { diff --git a/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx b/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx index 114699b8ef1121..7d96b420c812bd 100644 --- a/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx +++ b/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx @@ -137,7 +137,9 @@ describe('', () => { expect(parseInt(input.style.height, 10)).to.be.within(15, 17); }); - describe('layout', () => { + // @ts-expect-error + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('layout', () => { const getComputedStyleStub = new Map>(); function setLayout( input: HTMLTextAreaElement, @@ -166,11 +168,6 @@ describe('', () => { } before(function beforeHook() { - // Only run the test on node. - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - stub(window, 'getComputedStyle').value( (node: Element) => getComputedStyleStub.get(node) || {}, ); diff --git a/packages/mui-material/src/ToggleButton/ToggleButton.test.js b/packages/mui-material/src/ToggleButton/ToggleButton.test.js index 3e2abc61028ab5..1cbd7c82314d4e 100644 --- a/packages/mui-material/src/ToggleButton/ToggleButton.test.js +++ b/packages/mui-material/src/ToggleButton/ToggleButton.test.js @@ -125,14 +125,8 @@ describe('', () => { }); }); - describe('server-side', () => { - before(function beforeHook() { - // Only run the test on node. - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('should server-side render', () => { const { container } = renderToString(Hello World); expect(container.firstChild).to.have.text('Hello World'); diff --git a/packages/mui-material/src/internal/SwitchBase.test.js b/packages/mui-material/src/internal/SwitchBase.test.js index 7e177979efa1ba..cfa1d2cd7563c2 100644 --- a/packages/mui-material/src/internal/SwitchBase.test.js +++ b/packages/mui-material/src/internal/SwitchBase.test.js @@ -395,7 +395,7 @@ describe('', () => { describe('check transitioning between controlled states throws errors', () => { it('should error when uncontrolled and changed to controlled', function test() { - if (global.didWarnControlledToUncontrolled) { + if (globalThis.didWarnControlledToUncontrolled) { this.skip(); } @@ -421,7 +421,7 @@ describe('', () => { }); it('should error when controlled and changed to uncontrolled', function test() { - if (global.didWarnControlledToUncontrolled) { + if (globalThis.didWarnControlledToUncontrolled) { this.skip(); } diff --git a/packages/mui-material/src/styles/ThemeProvider.test.tsx b/packages/mui-material/src/styles/ThemeProvider.test.tsx index b5828595030b49..46f8f198baab55 100644 --- a/packages/mui-material/src/styles/ThemeProvider.test.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.test.tsx @@ -12,7 +12,7 @@ describe('ThemeProvider', () => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions storage = {}; - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key: string) => storage[key], setItem: (key: string, value: string) => { diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.test.js b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js index 6311728b415ca3..e98a4cb95d72d5 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.test.js +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js @@ -12,7 +12,7 @@ describe('[Material UI] ThemeProviderWithVars', () => { beforeEach(() => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key) => storage[key], setItem: (key, value) => { diff --git a/packages/mui-material/src/styles/extendTheme.test.js b/packages/mui-material/src/styles/extendTheme.test.js index 6bffb73787a98f..1c03a9771ea160 100644 --- a/packages/mui-material/src/styles/extendTheme.test.js +++ b/packages/mui-material/src/styles/extendTheme.test.js @@ -14,7 +14,7 @@ describe('extendTheme', () => { beforeEach(() => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key) => storage[key], setItem: (key, value) => { diff --git a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js index 95b1aaa3f28151..13270aa1d08fb8 100644 --- a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js +++ b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js @@ -48,7 +48,8 @@ describe('useScrollTrigger', () => { }); }); - describe('scroll', () => { + // eslint-disable-next-line no-undef + describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('scroll', () => { const triggerRef = React.createRef(); const containerRef = React.createRef(); // Get the scroll container's parent const getContainer = () => containerRef.current.children[0]; // Get the scroll container @@ -75,13 +76,6 @@ describe('useScrollTrigger', () => { customContainer: PropTypes.bool, }; - before(function beforeHook() { - // Only run the test on node. - if (!/jsdom/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - function dispatchScroll(offset, element = window) { act(() => { element.pageYOffset = offset; diff --git a/packages/mui-material/test/integration/Menu.test.js b/packages/mui-material/test/integration/Menu.test.js index e27eff1e2fd37b..80130cd7a1e53e 100644 --- a/packages/mui-material/test/integration/Menu.test.js +++ b/packages/mui-material/test/integration/Menu.test.js @@ -308,18 +308,22 @@ describe(' integration', () => { ); }); - it('closes the menu when Tabbing while the list is active', async () => { - render(); + it.only('closes the menu when Tabbing while the list is active', async () => { + const { user } = render(); const trigger = screen.getByRole('button'); await act(async () => { trigger.focus(); + }); + + await act(async () => { trigger.click(); }); // react-transition-group uses one commit per state transition so we need to wait a bit fireEvent.keyDown(screen.getAllByRole('menuitem')[0], { key: 'Tab' }); - clock.tick(0); + + // await user.keyboard('[Tab]'); expect(screen.getByRole('menu', { hidden: true })).toBeInaccessible(); }); diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts index b2d1c0ffcce487..3bf479e5d5c38c 100644 --- a/packages/mui-material/vitest.config.ts +++ b/packages/mui-material/vitest.config.ts @@ -25,7 +25,18 @@ export default defineConfig({ // We use performance.now in the codebase toFake: [...configDefaults.fakeTimers.toFake, 'performance'], }, + browser: { + enabled: false, // enabled through CLI + name: 'chromium', + provider: 'playwright', + headless: !!process.env.CI, + viewport: { + width: 1024, + height: 896, + }, + }, }, + resolve: { alias: { '@mui/internal-test-utils': path.resolve(MONOREPO_ROOT, './packages-internal/test-utils/src'), diff --git a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js index 2b29e22c83a2fe..1ab5b4bc5bf69f 100644 --- a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js +++ b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js @@ -20,7 +20,7 @@ describe('InitColorSchemeScript', () => { beforeEach(() => { // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: (key) => storage[key], }, diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js index 4accde568ba8ca..d9c9436e977005 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js @@ -28,7 +28,7 @@ describe('createCssVarsProvider', () => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: spy((key) => storage[key]), setItem: spy((key, value) => { diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js index a0d75139ea55e6..870d494e44e4d8 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js @@ -45,7 +45,7 @@ describe('useCurrentColorScheme', () => { // clear the localstorage storage = {}; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: spy((key) => storage[key]), setItem: spy((key, value) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a33bcdbdccf1e1..7597a1f99dd161 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,9 +138,12 @@ importers: '@typescript-eslint/parser': specifier: ^7.18.0 version: 7.18.0(eslint@8.57.1)(typescript@5.6.2) + '@vitest/browser': + specifier: ^2.1.2 + version: 2.1.2(@vitest/spy@2.1.2)(playwright@1.47.2)(typescript@5.6.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2) '@vitest/coverage-v8': specifier: ^2.1.2 - version: 2.1.2(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)) + version: 2.1.2(@vitest/browser@2.1.2)(vitest@2.1.2) babel-loader: specifier: ^9.2.1 version: 9.2.1(@babel/core@7.25.2)(webpack@5.95.0) @@ -311,10 +314,10 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.2 - version: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + version: 2.1.2(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2) vitest-fail-on-console: specifier: ^0.7.1 - version: 0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)) + version: 0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2) webpack: specifier: ^5.95.0 version: 5.95.0(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.95.0)) @@ -359,7 +362,7 @@ importers: version: link:../../packages/mui-utils/build next: specifier: latest - version: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -369,7 +372,7 @@ importers: devDependencies: '@pigment-css/nextjs-plugin': specifier: 0.0.24 - version: 0.0.24(@types/react@18.3.10)(next@14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 0.0.24(@types/react@18.3.10)(next@14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@types/node': specifier: ^20.16.10 version: 20.16.10 @@ -661,7 +664,7 @@ importers: version: 9.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@toolpad/core': specifier: ^0.7.0 - version: 0.7.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/icons-material@packages+mui-icons-material+build)(@mui/material-pigment-css@6.1.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material@packages+mui-material+build)(@types/node@20.16.10)(@types/react@18.3.10)(happy-dom@12.10.3)(jsdom@24.0.0)(next@14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.29.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) + version: 0.7.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/icons-material@packages+mui-icons-material+build)(@mui/material-pigment-css@6.1.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material@packages+mui-material+build)(@types/node@20.16.10)(@types/react@18.3.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(next@14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.29.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) @@ -745,7 +748,7 @@ importers: version: 5.3.1(@mui/material@packages+mui-material+build)(react@18.3.1) next: specifier: ^14.2.14 - version: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) notistack: specifier: 3.0.1 version: 3.0.1(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1457,7 +1460,7 @@ importers: version: 18.3.10 next: specifier: ^14.2.14 - version: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -1631,7 +1634,7 @@ importers: version: 4.17.21 next: specifier: ^14.2.14 - version: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -1951,9 +1954,6 @@ importers: '@mui/internal-test-utils': specifier: workspace:^ version: link:../../packages-internal/test-utils - '@mui/styled-engine-sc': - specifier: workspace:* - version: link:build '@types/chai': specifier: ^4.3.20 version: 4.3.20 @@ -3252,6 +3252,15 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bundled-es-modules/cookie@2.0.0': + resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} + + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + + '@bundled-es-modules/tough-cookie@0.1.6': + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + '@chakra-ui/anatomy@2.2.2': resolution: {integrity: sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg==} @@ -3934,6 +3943,26 @@ packages: cpu: [x64] os: [win32] + '@inquirer/confirm@3.2.0': + resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==} + engines: {node: '>=18'} + + '@inquirer/core@9.2.1': + resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} + engines: {node: '>=18'} + + '@inquirer/figures@1.0.7': + resolution: {integrity: sha512-m+Trk77mp54Zma6xLkLuY+mvanPxlE4A7yNKs2HBiyZ4UkVs28Mv5c/pgWrHeInx+USHeX/WEPzjrWrcJiQgjw==} + engines: {node: '>=18'} + + '@inquirer/type@1.5.5': + resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==} + engines: {node: '>=18'} + + '@inquirer/type@2.0.0': + resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==} + engines: {node: '>=18'} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -4002,6 +4031,10 @@ packages: resolution: {integrity: sha512-wi72R01tgjBjzG2kjRyTHl4yCTKDfDMIXRyKz9E/FBa9SkFvUOAE4bdyY9MhEsRZmSWL7+CYE8Flv/HScRpBbA==} engines: {node: '>=18.0.0'} + '@mswjs/interceptors@0.35.9': + resolution: {integrity: sha512-SSnyl/4ni/2ViHKkiZb8eajA/eN1DNFaHjhGiLUdZvDz6PKF4COSf/17xqSz64nOo2Ia29SA6B2KNCsyCbVmaQ==} + engines: {node: '>=18'} + '@mui/base@5.0.0-beta.30': resolution: {integrity: sha512-dc38W4W3K42atE9nSaOeoJ7/x9wGIfawdwC/UmMxMLlZ1iSsITQ8dQJaTATCbn98YvYPINK/EH541YA5enQIPQ==} engines: {node: '>=12.0.0'} @@ -4525,6 +4558,9 @@ packages: '@next/env@14.2.14': resolution: {integrity: sha512-/0hWQfiaD5//LvGNgc8PjvyqV50vGK0cADYzaoOOGN8fxzBn3iAiaq3S0tCRnFBldq0LVveLcxCTi41ZoYgAgg==} + '@next/env@14.2.15': + resolution: {integrity: sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==} + '@next/eslint-plugin-next@14.2.14': resolution: {integrity: sha512-kV+OsZ56xhj0rnTn6HegyTGkoa16Mxjrpk7pjWumyB2P8JVQb8S9qtkjy/ye0GnTr4JWtWG4x/2qN40lKZ3iVQ==} @@ -4534,54 +4570,108 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@14.2.15': + resolution: {integrity: sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-x64@14.2.14': resolution: {integrity: sha512-cC9/I+0+SK5L1k9J8CInahduTVWGMXhQoXFeNvF0uNs3Bt1Ub0Azb8JzTU9vNCr0hnaMqiWu/Z0S1hfKc3+dww==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@14.2.15': + resolution: {integrity: sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-linux-arm64-gnu@14.2.14': resolution: {integrity: sha512-RMLOdA2NU4O7w1PQ3Z9ft3PxD6Htl4uB2TJpocm+4jcllHySPkFaUIFacQ3Jekcg6w+LBaFvjSPthZHiPmiAUg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-gnu@14.2.15': + resolution: {integrity: sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-musl@14.2.14': resolution: {integrity: sha512-WgLOA4hT9EIP7jhlkPnvz49iSOMdZgDJVvbpb8WWzJv5wBD07M2wdJXLkDYIpZmCFfo/wPqFsFR4JS4V9KkQ2A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-musl@14.2.15': + resolution: {integrity: sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-x64-gnu@14.2.14': resolution: {integrity: sha512-lbn7svjUps1kmCettV/R9oAvEW+eUI0lo0LJNFOXoQM5NGNxloAyFRNByYeZKL3+1bF5YE0h0irIJfzXBq9Y6w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + '@next/swc-linux-x64-gnu@14.2.15': + resolution: {integrity: sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-musl@14.2.14': resolution: {integrity: sha512-7TcQCvLQ/hKfQRgjxMN4TZ2BRB0P7HwrGAYL+p+m3u3XcKTraUFerVbV3jkNZNwDeQDa8zdxkKkw2els/S5onQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + '@next/swc-linux-x64-musl@14.2.15': + resolution: {integrity: sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-win32-arm64-msvc@14.2.14': resolution: {integrity: sha512-8i0Ou5XjTLEje0oj0JiI0Xo9L/93ghFtAUYZ24jARSeTMXLUx8yFIdhS55mTExq5Tj4/dC2fJuaT4e3ySvXU1A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@14.2.15': + resolution: {integrity: sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-ia32-msvc@14.2.14': resolution: {integrity: sha512-2u2XcSaDEOj+96eXpyjHjtVPLhkAFw2nlaz83EPeuK4obF+HmtDJHqgR1dZB7Gb6V/d55FL26/lYVd0TwMgcOQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] + '@next/swc-win32-ia32-msvc@14.2.15': + resolution: {integrity: sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + '@next/swc-win32-x64-msvc@14.2.14': resolution: {integrity: sha512-MZom+OvZ1NZxuRovKt1ApevjiUJTcU2PmdJKL66xUPaJeRywnbGGRWUlaAOwunD6dX+pm83vj979NTC8QXjGWg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@14.2.15': + resolution: {integrity: sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3': resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==} @@ -4882,6 +4972,15 @@ packages: '@octokit/types@9.3.2': resolution: {integrity: sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opentelemetry/api@1.8.0': resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} engines: {node: '>=8.0.0'} @@ -4913,8 +5012,8 @@ packages: engines: {node: '>=18'} hasBin: true - '@polka/url@1.0.0-next.21': - resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} @@ -5480,6 +5579,9 @@ packages: '@types/cookie@0.4.1': resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/cors@2.8.12': resolution: {integrity: sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==} @@ -5600,6 +5702,9 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/mute-stream@0.0.4': + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + '@types/node@20.16.10': resolution: {integrity: sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==} @@ -5666,12 +5771,18 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/statuses@2.0.5': + resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} + '@types/styled-system@5.1.15': resolution: {integrity: sha512-1uls4wipZn8FtYFZ7upRVFDoEeOXTQTs2zuyOZPn02T6rjIxtvj2P2lG5qsxXHhKuKsu3thveCZrtaeLE/ibLg==} '@types/stylis@4.2.5': resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/tsscmp@1.0.0': resolution: {integrity: sha512-rj18XR6c4Ohds86Lq8MI1NMRrXes4eLo4H06e5bJyKucE1rXGsfBBbFGD2oDC+DSufQCpnU3TTW7QAiwLx+7Yw==} @@ -5690,6 +5801,9 @@ packages: '@types/webxr@0.5.14': resolution: {integrity: sha512-UEMMm/Xn3DtEa+gpzUrOcDj+SJS1tk5YodjwOxcqStNhCfPcwgyC5Srg2ToVKyg2Fhq16Ffpb0UWUQHqoT9AMA==} + '@types/wrap-ansi@3.0.0': + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} + '@types/ws@7.4.7': resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} @@ -5775,6 +5889,21 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 + '@vitest/browser@2.1.2': + resolution: {integrity: sha512-tqpGfz2sfjFFNuZ2iLZ6EGRVnH8z18O93ZIicbLsxDhiLgRNz84UcjSvX4pbheuddW+BJeNbLGdM3BU8vohbEg==} + peerDependencies: + playwright: '*' + safaridriver: '*' + vitest: 2.1.2 + webdriverio: '*' + peerDependenciesMeta: + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + '@vitest/coverage-v8@2.1.2': resolution: {integrity: sha512-b7kHrFrs2urS0cOk5N10lttI8UdJ/yP3nB4JYTREvR5o18cR99yPpK4gK8oQgI42BVv0ILWYUSYB7AXkAUDc0g==} peerDependencies: @@ -6732,6 +6861,10 @@ packages: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -6976,6 +7109,10 @@ packages: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} + cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -8372,6 +8509,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql@16.9.0: + resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gtoken@7.0.1: resolution: {integrity: sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==} engines: {node: '>=14.0.0'} @@ -8456,6 +8597,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hermes-estree@0.15.0: resolution: {integrity: sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==} @@ -8803,6 +8947,9 @@ packages: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -9992,8 +10139,8 @@ packages: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - mrmime@1.0.1: - resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} ms@2.0.0: @@ -10005,6 +10152,16 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.4.9: + resolution: {integrity: sha512-1m8xccT6ipN4PTqLinPwmzhxQREuxaEJYdx4nIbggxP8aM7r1e71vE7RtOUSQoAm1LydjGfZKy7370XD/tsuYg==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + multimatch@5.0.0: resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} engines: {node: '>=10'} @@ -10062,6 +10219,24 @@ packages: sass: optional: true + next@14.2.15: + resolution: {integrity: sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + nise@6.0.0: resolution: {integrity: sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==} @@ -10354,6 +10529,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + override-require@1.1.1: resolution: {integrity: sha512-eoJ9YWxFcXbrn2U8FKT6RV+/Kj7fiGAB1VvHzbYKt8xM5ZuKZgCGvnHzDxmreEjcBH28ejg5MiOH4iyY1mQnkg==} @@ -11724,8 +11902,8 @@ packages: sinon@18.0.1: resolution: {integrity: sha512-a2N2TDY1uGviajJ6r4D1CyRAkzE9NNVlYOV1wX5xQDuAk0ONgzgRl0EjCQuRCPxOwp13ghsMwt9Gdldujs39qw==} - sirv@2.0.3: - resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} + sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} engines: {node: '>= 10'} sisteransi@1.0.5: @@ -11885,6 +12063,9 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} @@ -12278,8 +12459,8 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} tr46@0.0.3: @@ -12401,6 +12582,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@4.26.1: + resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -12986,8 +13171,8 @@ packages: utf-8-validate: optional: true - ws@8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -13094,6 +13279,10 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + yoctocolors@2.0.2: resolution: {integrity: sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==} engines: {node: '>=18'} @@ -14273,6 +14462,19 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@bundled-es-modules/cookie@2.0.0': + dependencies: + cookie: 0.5.0 + + '@bundled-es-modules/statuses@1.0.1': + dependencies: + statuses: 2.0.1 + + '@bundled-es-modules/tough-cookie@0.1.6': + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 + '@chakra-ui/anatomy@2.2.2': {} '@chakra-ui/color-mode@2.2.0(react@18.3.1)': @@ -14846,6 +15048,36 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true + '@inquirer/confirm@3.2.0': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 1.5.5 + + '@inquirer/core@9.2.1': + dependencies: + '@inquirer/figures': 1.0.7 + '@inquirer/type': 2.0.0 + '@types/mute-stream': 0.0.4 + '@types/node': 20.16.10 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/figures@1.0.7': {} + + '@inquirer/type@1.5.5': + dependencies: + mute-stream: 1.0.0 + + '@inquirer/type@2.0.0': + dependencies: + mute-stream: 1.0.0 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -15014,6 +15246,15 @@ snapshots: - encoding - supports-color + '@mswjs/interceptors@0.35.9': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@mui/base@5.0.0-beta.30(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.6 @@ -15535,6 +15776,8 @@ snapshots: '@next/env@14.2.14': {} + '@next/env@14.2.15': {} + '@next/eslint-plugin-next@14.2.14': dependencies: glob: 10.3.10 @@ -15542,30 +15785,57 @@ snapshots: '@next/swc-darwin-arm64@14.2.14': optional: true + '@next/swc-darwin-arm64@14.2.15': + optional: true + '@next/swc-darwin-x64@14.2.14': optional: true + '@next/swc-darwin-x64@14.2.15': + optional: true + '@next/swc-linux-arm64-gnu@14.2.14': optional: true + '@next/swc-linux-arm64-gnu@14.2.15': + optional: true + '@next/swc-linux-arm64-musl@14.2.14': optional: true + '@next/swc-linux-arm64-musl@14.2.15': + optional: true + '@next/swc-linux-x64-gnu@14.2.14': optional: true + '@next/swc-linux-x64-gnu@14.2.15': + optional: true + '@next/swc-linux-x64-musl@14.2.14': optional: true + '@next/swc-linux-x64-musl@14.2.15': + optional: true + '@next/swc-win32-arm64-msvc@14.2.14': optional: true + '@next/swc-win32-arm64-msvc@14.2.15': + optional: true + '@next/swc-win32-ia32-msvc@14.2.14': optional: true + '@next/swc-win32-ia32-msvc@14.2.15': + optional: true + '@next/swc-win32-x64-msvc@14.2.14': optional: true + '@next/swc-win32-x64-msvc@14.2.15': + optional: true + '@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3': optional: true @@ -15995,13 +16265,22 @@ snapshots: dependencies: '@octokit/openapi-types': 18.0.0 + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@opentelemetry/api@1.8.0': optional: true - '@pigment-css/nextjs-plugin@0.0.24(@types/react@18.3.10)(next@14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@pigment-css/nextjs-plugin@0.0.24(@types/react@18.3.10)(next@14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@pigment-css/unplugin': 0.0.24(@types/react@18.3.10)(react@18.3.1) - next: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@types/react' - react @@ -16069,7 +16348,7 @@ snapshots: dependencies: playwright: 1.47.2 - '@polka/url@1.0.0-next.21': {} + '@polka/url@1.0.0-next.28': {} '@popperjs/core@2.11.8': {} @@ -16794,14 +17073,14 @@ snapshots: '@theme-ui/css': 0.16.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1)) react: 18.3.1 - '@toolpad/core@0.7.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/icons-material@packages+mui-icons-material+build)(@mui/material-pigment-css@6.1.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material@packages+mui-material+build)(@types/node@20.16.10)(@types/react@18.3.10)(happy-dom@12.10.3)(jsdom@24.0.0)(next@14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.29.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': + '@toolpad/core@0.7.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/icons-material@packages+mui-icons-material+build)(@mui/material-pigment-css@6.1.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material@packages+mui-material+build)(@types/node@20.16.10)(@types/react@18.3.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(next@14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.29.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': dependencies: '@babel/runtime': 7.25.6 '@mui/icons-material': link:packages/mui-icons-material/build '@mui/lab': 6.0.0-beta.10(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material-pigment-css@6.1.2(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(react@18.3.1))(@mui/material@packages+mui-material+build)(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/material': link:packages/mui-material/build '@mui/utils': 6.1.1(@types/react@18.3.10)(react@18.3.1) - '@toolpad/utils': 0.7.0(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(react@18.3.1)(terser@5.29.2) + '@toolpad/utils': 0.7.0(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(react@18.3.1)(terser@5.29.2) '@vitejs/plugin-react': 4.3.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) client-only: 0.0.1 invariant: 2.2.4 @@ -16809,7 +17088,7 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 optionalDependencies: - next: 14.2.14(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@edge-runtime/vm' - '@emotion/react' @@ -16833,14 +17112,14 @@ snapshots: - terser - vite - '@toolpad/utils@0.7.0(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(react@18.3.1)(terser@5.29.2)': + '@toolpad/utils@0.7.0(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(react@18.3.1)(terser@5.29.2)': dependencies: invariant: 2.2.4 prettier: 3.3.3 react: 18.3.1 react-is: 18.3.1 title: 3.5.3 - vitest: 2.1.1(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + vitest: 2.1.1(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2) yaml: 2.5.1 yaml-diff-patch: 2.0.0 transitivePeerDependencies: @@ -16924,6 +17203,8 @@ snapshots: '@types/cookie@0.4.1': {} + '@types/cookie@0.6.0': {} + '@types/cors@2.8.12': {} '@types/css-mediaquery@0.1.4': {} @@ -17048,6 +17329,10 @@ snapshots: '@types/ms@0.7.34': {} + '@types/mute-stream@0.0.4': + dependencies: + '@types/node': 20.16.10 + '@types/node@20.16.10': dependencies: undici-types: 6.19.8 @@ -17120,12 +17405,16 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/statuses@2.0.5': {} + '@types/styled-system@5.1.15': dependencies: csstype: 3.1.3 '@types/stylis@4.2.5': {} + '@types/tough-cookie@4.0.5': {} + '@types/tsscmp@1.0.0': {} '@types/unist@3.0.2': {} @@ -17138,6 +17427,8 @@ snapshots: '@types/webxr@0.5.14': {} + '@types/wrap-ansi@3.0.0': {} + '@types/ws@7.4.7': dependencies: '@types/node': 20.16.10 @@ -17257,7 +17548,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.1.2(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2))': + '@vitest/browser@2.1.2(@vitest/spy@2.1.2)(playwright@1.47.2)(typescript@5.6.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2)': + dependencies: + '@testing-library/dom': 10.4.0 + '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.4.9(typescript@5.6.2))(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) + '@vitest/utils': 2.1.2 + magic-string: 0.30.11 + msw: 2.4.9(typescript@5.6.2) + sirv: 2.0.4 + tinyrainbow: 1.2.0 + vitest: 2.1.2(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2) + ws: 8.18.0 + optionalDependencies: + playwright: 1.47.2 + transitivePeerDependencies: + - '@vitest/spy' + - bufferutil + - typescript + - utf-8-validate + - vite + + '@vitest/coverage-v8@2.1.2(@vitest/browser@2.1.2)(vitest@2.1.2)': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -17271,7 +17583,9 @@ snapshots: std-env: 3.7.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + vitest: 2.1.2(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2) + optionalDependencies: + '@vitest/browser': 2.1.2(@vitest/spy@2.1.2)(playwright@1.47.2)(typescript@5.6.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2) transitivePeerDependencies: - supports-color @@ -17289,20 +17603,22 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(msw@2.4.9(typescript@5.6.2))(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': dependencies: '@vitest/spy': 2.1.1 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: + msw: 2.4.9(typescript@5.6.2) vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) - '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': + '@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(msw@2.4.9(typescript@5.6.2))(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))': dependencies: '@vitest/spy': 2.1.2 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: + msw: 2.4.9(typescript@5.6.2) vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) '@vitest/pretty-format@2.1.1': @@ -18462,6 +18778,8 @@ snapshots: cli-width@3.0.0: {} + cli-width@4.1.0: {} + client-only@0.0.1: {} clipboard-copy@4.0.1: {} @@ -18728,6 +19046,8 @@ snapshots: cookie@0.4.2: {} + cookie@0.5.0: {} + cookie@0.6.0: {} core-js-compat@3.38.1: @@ -20543,6 +20863,8 @@ snapshots: graphemer@1.4.0: {} + graphql@16.9.0: {} + gtoken@7.0.1(encoding@0.1.13): dependencies: gaxios: 6.1.1(encoding@0.1.13) @@ -20637,6 +20959,8 @@ snapshots: he@1.2.0: {} + headers-polyfill@4.0.3: {} + hermes-estree@0.15.0: {} hermes-estree@0.20.1: {} @@ -20992,6 +21316,8 @@ snapshots: is-negative-zero@2.0.3: {} + is-node-process@1.2.0: {} + is-number-object@1.0.7: dependencies: has-tostringtag: 1.0.2 @@ -21381,13 +21707,13 @@ snapshots: rrweb-cssom: 0.6.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.3 + tough-cookie: 4.1.4 w3c-xmlserializer: 5.0.0 webidl-conversions: 7.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - ws: 8.16.0 + ws: 8.18.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -22658,7 +22984,7 @@ snapshots: mri@1.2.0: {} - mrmime@1.0.1: {} + mrmime@2.0.0: {} ms@2.0.0: {} @@ -22666,6 +22992,28 @@ snapshots: ms@2.1.3: {} + msw@2.4.9(typescript@5.6.2): + dependencies: + '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 3.2.0 + '@mswjs/interceptors': 0.35.9 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + chalk: 4.1.2 + graphql: 16.9.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + strict-event-emitter: 0.5.1 + type-fest: 4.26.1 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.6.2 + multimatch@5.0.0: dependencies: '@types/minimatch': 3.0.5 @@ -22728,6 +23076,33 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@14.2.15(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(@playwright/test@1.47.2)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@next/env': 14.2.15 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001649 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(@babel/core@7.25.2)(babel-plugin-macros@3.1.0)(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.15 + '@next/swc-darwin-x64': 14.2.15 + '@next/swc-linux-arm64-gnu': 14.2.15 + '@next/swc-linux-arm64-musl': 14.2.15 + '@next/swc-linux-x64-gnu': 14.2.15 + '@next/swc-linux-x64-musl': 14.2.15 + '@next/swc-win32-arm64-msvc': 14.2.15 + '@next/swc-win32-ia32-msvc': 14.2.15 + '@next/swc-win32-x64-msvc': 14.2.15 + '@opentelemetry/api': 1.8.0 + '@playwright/test': 1.47.2 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + nise@6.0.0: dependencies: '@sinonjs/commons': 3.0.1 @@ -23153,6 +23528,8 @@ snapshots: os-tmpdir@1.0.2: {} + outvariant@1.4.3: {} + override-require@1.1.1: {} p-event@5.0.1: @@ -24704,10 +25081,10 @@ snapshots: nise: 6.0.0 supports-color: 7.2.0 - sirv@2.0.3: + sirv@2.0.4: dependencies: - '@polka/url': 1.0.0-next.21 - mrmime: 1.0.1 + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 totalist: 3.0.1 sisteransi@1.0.5: {} @@ -24887,6 +25264,8 @@ snapshots: streamsearch@1.1.0: {} + strict-event-emitter@0.5.1: {} + string-convert@0.2.1: {} string-width@4.2.3: @@ -25367,7 +25746,7 @@ snapshots: totalist@3.0.1: {} - tough-cookie@4.1.3: + tough-cookie@4.1.4: dependencies: psl: 1.9.0 punycode: 2.3.1 @@ -25464,6 +25843,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@4.26.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -25778,16 +26159,16 @@ snapshots: fsevents: 2.3.3 terser: 5.29.2 - vitest-fail-on-console@0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2)): + vitest-fail-on-console@0.7.1(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2): dependencies: chalk: 5.3.0 vite: 5.4.8(@types/node@20.16.10)(terser@5.29.2) - vitest: 2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2) + vitest: 2.1.2(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2) - vitest@2.1.1(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2): + vitest@2.1.1(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2): dependencies: '@vitest/expect': 2.1.1 - '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) + '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(msw@2.4.9(typescript@5.6.2))(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) '@vitest/pretty-format': 2.1.2 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -25807,6 +26188,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.16.10 + '@vitest/browser': 2.1.2(@vitest/spy@2.1.2)(playwright@1.47.2)(typescript@5.6.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2) happy-dom: 12.10.3 jsdom: 24.0.0 transitivePeerDependencies: @@ -25820,10 +26202,10 @@ snapshots: - supports-color - terser - vitest@2.1.2(@types/node@20.16.10)(happy-dom@12.10.3)(jsdom@24.0.0)(terser@5.29.2): + vitest@2.1.2(@types/node@20.16.10)(@vitest/browser@2.1.2)(happy-dom@12.10.3)(jsdom@24.0.0)(msw@2.4.9(typescript@5.6.2))(terser@5.29.2): dependencies: '@vitest/expect': 2.1.2 - '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) + '@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.4.9(typescript@5.6.2))(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2)) '@vitest/pretty-format': 2.1.2 '@vitest/runner': 2.1.2 '@vitest/snapshot': 2.1.2 @@ -25843,6 +26225,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.16.10 + '@vitest/browser': 2.1.2(@vitest/spy@2.1.2)(playwright@1.47.2)(typescript@5.6.2)(vite@5.4.8(@types/node@20.16.10)(terser@5.29.2))(vitest@2.1.2) happy-dom: 12.10.3 jsdom: 24.0.0 transitivePeerDependencies: @@ -25903,7 +26286,7 @@ snapshots: html-escaper: 2.0.2 opener: 1.5.2 picocolors: 1.1.0 - sirv: 2.0.3 + sirv: 2.0.4 ws: 7.5.9 transitivePeerDependencies: - bufferutil @@ -26133,7 +26516,7 @@ snapshots: ws@8.11.0: {} - ws@8.16.0: {} + ws@8.18.0: {} xcase@2.0.1: {} @@ -26232,6 +26615,8 @@ snapshots: yocto-queue@1.0.0: {} + yoctocolors-cjs@2.1.2: {} + yoctocolors@2.0.2: {} zdog@1.1.3: {} diff --git a/test/integration/mui-system/theme-scoping.test.tsx b/test/integration/mui-system/theme-scoping.test.tsx index fe8040c584e093..d10563f8c6a000 100644 --- a/test/integration/mui-system/theme-scoping.test.tsx +++ b/test/integration/mui-system/theme-scoping.test.tsx @@ -79,7 +79,7 @@ describe('Multiple nested theme providers', () => { originalMatchmedia = window.matchMedia; // Create mocks of localStorage getItem and setItem functions - Object.defineProperty(global, 'localStorage', { + Object.defineProperty(globalThis, 'localStorage', { value: { getItem: spy((key) => storage[key]), setItem: spy((key, value) => { From 39dc4f6afeefaafc456858e1a4a8e1058e13d8ae Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:21:41 +0200 Subject: [PATCH 25/44] Update pnpm-lock.yaml --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7597a1f99dd161..ecc61756fb762b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1954,6 +1954,9 @@ importers: '@mui/internal-test-utils': specifier: workspace:^ version: link:../../packages-internal/test-utils + '@mui/styled-engine-sc': + specifier: workspace:* + version: link:build '@types/chai': specifier: ^4.3.20 version: 4.3.20 From 199bbef75c3d306bc6f932af1b303946e7950bab Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:45:32 +0200 Subject: [PATCH 26/44] Add describeSkipIf shim to test-utils --- packages-internal/test-utils/src/describeSkipIf.tsx | 9 +++++++++ packages-internal/test-utils/src/index.ts | 1 + packages-internal/test-utils/src/init.js | 7 ------- packages-internal/test-utils/src/setupVitest.ts | 4 +--- packages/mui-material/src/Button/Button.test.js | 8 ++++++-- .../mui-material/src/ButtonBase/ButtonBase.test.js | 9 +-------- packages/mui-material/src/Chip/Chip.test.js | 2 +- packages/mui-material/src/Divider/Divider.test.js | 3 +-- packages/mui-material/src/Fab/Fab.test.js | 3 +-- .../src/ListItemButton/ListItemButton.test.js | 3 +-- packages/mui-material/src/Portal/Portal.test.tsx | 4 +--- packages/mui-material/src/Rating/Rating.test.js | 3 +-- packages/mui-material/src/Tabs/Tabs.test.js | 2 +- .../src/TextareaAutosize/TextareaAutosize.test.tsx | 11 ++++++++--- .../src/ToggleButton/ToggleButton.test.js | 3 +-- packages/mui-material/src/Tooltip/Tooltip.test.js | 3 +-- packages/mui-material/src/internal/animate.test.js | 2 +- .../src/useScrollTrigger/useScrollTrigger.test.js | 9 +++++++-- packages/mui-material/test/integration/Menu.test.js | 10 +++------- .../test/integration/PopperChildrenLayout.test.js | 3 +-- 20 files changed, 47 insertions(+), 52 deletions(-) create mode 100644 packages-internal/test-utils/src/describeSkipIf.tsx diff --git a/packages-internal/test-utils/src/describeSkipIf.tsx b/packages-internal/test-utils/src/describeSkipIf.tsx new file mode 100644 index 00000000000000..b1de04e1495447 --- /dev/null +++ b/packages-internal/test-utils/src/describeSkipIf.tsx @@ -0,0 +1,9 @@ +// Shim for vitest describe.skipIf to be able to run mocha and vitest side-by-side +// TODO: Remove after migration to vitest is complete +const describeSkipIf: (condition: boolean) => Mocha.PendingSuiteFunction = + (describe as any).skipIf ?? + function describeSkipIf(condition: boolean) { + return condition ? describe.skip : describe; + }; + +export default describeSkipIf; diff --git a/packages-internal/test-utils/src/index.ts b/packages-internal/test-utils/src/index.ts index 7eec3c3f704fe5..3c05d85cc51d96 100644 --- a/packages-internal/test-utils/src/index.ts +++ b/packages-internal/test-utils/src/index.ts @@ -15,6 +15,7 @@ export {} from './initMatchers'; export * as fireDiscreteEvent from './fireDiscreteEvent'; export { default as flushMicrotasks } from './flushMicrotasks'; export { default as reactMajor } from './reactMajor'; +export { default as describeSkipIf } from './describeSkipIf'; /** * Set to true if console logs during [lifecycles that are invoked twice in `React.StrictMode`](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects) are suppressed. diff --git a/packages-internal/test-utils/src/init.js b/packages-internal/test-utils/src/init.js index e664eb393c2964..85e2fe80a5eb6c 100644 --- a/packages-internal/test-utils/src/init.js +++ b/packages-internal/test-utils/src/init.js @@ -9,10 +9,3 @@ const defaultHidden = !process.env.CI; // adds verbosity for something that might be confusing console.warn(`${defaultHidden ? 'including' : 'excluding'} inaccessible elements by default`); testingLibrary.configure({ defaultHidden }); - -globalThis.describeSkipIf = - (condition) => - (...args) => { - // eslint-disable-next-line no-undef - return (condition ? describe.skip : describe)(...args); - }; diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index c01c99804e0a4e..2462bc01e9565a 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -1,4 +1,4 @@ -import { beforeAll, afterAll, it, describe } from 'vitest'; +import { beforeAll, afterAll, it } from 'vitest'; import * as testingLibrary from '@testing-library/dom'; import failOnConsole from 'vitest-fail-on-console'; import './initMatchers'; @@ -109,5 +109,3 @@ if (isJsdom) { // @ts-expect-error globalThis.window.Touch = Touch; } - -(globalThis as any).describeSkipIf = describe.skipIf; diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index 144992131bc6ca..e79e3ed9f48b07 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -1,6 +1,11 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, screen, simulateKeyboardDevice } from '@mui/internal-test-utils'; +import { + createRenderer, + screen, + simulateKeyboardDevice, + describeSkipIf, +} from '@mui/internal-test-utils'; import { ClassNames } from '@emotion/react'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import Button, { buttonClasses as classes } from '@mui/material/Button'; @@ -624,7 +629,6 @@ describe('); diff --git a/packages/mui-material/src/ButtonBase/ButtonBase.test.js b/packages/mui-material/src/ButtonBase/ButtonBase.test.js index 755cb20a2aabda..7c4e7f58ac77d5 100644 --- a/packages/mui-material/src/ButtonBase/ButtonBase.test.js +++ b/packages/mui-material/src/ButtonBase/ButtonBase.test.js @@ -10,6 +10,7 @@ import { focusVisible, simulatePointerDevice, programmaticFocusTriggersFocusVisible, + describeSkipIf, } from '@mui/internal-test-utils'; import PropTypes from 'prop-types'; import { ThemeProvider, createTheme } from '@mui/material/styles'; @@ -247,8 +248,6 @@ describe('', () => { }); }); - // @ts-expect-error Temporary shim while migrating to vitest - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('ripple', () => { describe('interactions', () => { it('should not have a focus ripple by default', () => { @@ -606,8 +605,6 @@ describe('', () => { }); }); - // @ts-expect-error Temporary shim while migrating to vitest - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focusRipple', () => { it('should pulsate the ripple when focusVisible', async () => { const { getByRole } = render( @@ -913,8 +910,6 @@ describe('', () => { }); }); - // @ts-expect-error Temporary shim while migrating to vitest - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: keydown', () => { it('ripples on repeated keydowns', async () => { const { container, getByText } = render( @@ -1162,8 +1157,6 @@ describe('', () => { }); }); - // @ts-expect-error Temporary shim while migrating to vitest - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: action', () => { it('should be able to focus visible the button', async () => { /** diff --git a/packages/mui-material/src/Chip/Chip.test.js b/packages/mui-material/src/Chip/Chip.test.js index 538c5a3315eb40..c99d9f7c91f151 100644 --- a/packages/mui-material/src/Chip/Chip.test.js +++ b/packages/mui-material/src/Chip/Chip.test.js @@ -8,6 +8,7 @@ import { focusVisible, simulatePointerDevice, programmaticFocusTriggersFocusVisible, + describeSkipIf, } from '@mui/internal-test-utils'; import Avatar from '@mui/material/Avatar'; import Chip, { chipClasses as classes } from '@mui/material/Chip'; @@ -663,7 +664,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('event: focus', () => { it('has a focus-visible polyfill', () => { const { container } = render( {}} />); diff --git a/packages/mui-material/src/Divider/Divider.test.js b/packages/mui-material/src/Divider/Divider.test.js index d447e8f2c0b40d..651c4cfbc0e43f 100644 --- a/packages/mui-material/src/Divider/Divider.test.js +++ b/packages/mui-material/src/Divider/Divider.test.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, screen } from '@mui/internal-test-utils'; +import { createRenderer, screen, describeSkipIf } from '@mui/internal-test-utils'; import { styled } from '@mui/material/styles'; import Divider, { dividerClasses as classes } from '@mui/material/Divider'; import describeConformance from '../../test/describeConformance'; @@ -85,7 +85,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))( 'custom border style', function test() { diff --git a/packages/mui-material/src/Fab/Fab.test.js b/packages/mui-material/src/Fab/Fab.test.js index a96a008b6f5606..679bb53289ee1b 100644 --- a/packages/mui-material/src/Fab/Fab.test.js +++ b/packages/mui-material/src/Fab/Fab.test.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, describeSkipIf } from '@mui/internal-test-utils'; import Fab, { fabClasses as classes } from '@mui/material/Fab'; import ButtonBase, { touchRippleClasses } from '@mui/material/ButtonBase'; import Icon from '@mui/material/Icon'; @@ -160,7 +160,6 @@ describe('', () => { expect(renderedIconChild).to.have.class(childClassName); }); - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('should server-side render', () => { const { container } = renderToString(Fab); diff --git a/packages/mui-material/src/ListItemButton/ListItemButton.test.js b/packages/mui-material/src/ListItemButton/ListItemButton.test.js index 187cdf42837a1e..6a66e55652038c 100644 --- a/packages/mui-material/src/ListItemButton/ListItemButton.test.js +++ b/packages/mui-material/src/ListItemButton/ListItemButton.test.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { act, createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { act, createRenderer, fireEvent, describeSkipIf } from '@mui/internal-test-utils'; import ListItemButton, { listItemButtonClasses as classes } from '@mui/material/ListItemButton'; import ButtonBase from '@mui/material/ButtonBase'; import { ThemeProvider, createTheme } from '@mui/material/styles'; @@ -54,7 +54,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: focusVisibleClassName', () => { it('should merge the class names', async () => { const { getByRole } = render( diff --git a/packages/mui-material/src/Portal/Portal.test.tsx b/packages/mui-material/src/Portal/Portal.test.tsx index c1ad892542e3ac..1b21ed677c4793 100644 --- a/packages/mui-material/src/Portal/Portal.test.tsx +++ b/packages/mui-material/src/Portal/Portal.test.tsx @@ -1,14 +1,12 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, describeSkipIf } from '@mui/internal-test-utils'; import Portal, { PortalProps } from '@mui/material/Portal'; describe('', () => { const { render, renderToString } = createRenderer(); - // @ts-expect-error - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('render nothing on the server', () => { const { container } = renderToString( diff --git a/packages/mui-material/src/Rating/Rating.test.js b/packages/mui-material/src/Rating/Rating.test.js index db687d69ada1ad..5856bc23cba8c5 100644 --- a/packages/mui-material/src/Rating/Rating.test.js +++ b/packages/mui-material/src/Rating/Rating.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { stub, spy } from 'sinon'; -import { act, createRenderer, fireEvent, screen } from '@mui/internal-test-utils'; +import { act, createRenderer, fireEvent, screen, describeSkipIf } from '@mui/internal-test-utils'; import Rating, { ratingClasses as classes } from '@mui/material/Rating'; import { createTheme, ThemeProvider } from '@mui/material/styles'; import describeConformance from '../../test/describeConformance'; @@ -248,7 +248,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))(' integration', () => { [ { diff --git a/packages/mui-material/src/Tabs/Tabs.test.js b/packages/mui-material/src/Tabs/Tabs.test.js index 03910b2b4ee466..b473bb6de214b1 100644 --- a/packages/mui-material/src/Tabs/Tabs.test.js +++ b/packages/mui-material/src/Tabs/Tabs.test.js @@ -9,6 +9,7 @@ import { screen, strictModeDoubleLoggingSuppressed, waitFor, + describeSkipIf, } from '@mui/internal-test-utils'; import Tab from '@mui/material/Tab'; import Tabs, { tabsClasses as classes } from '@mui/material/Tabs'; @@ -368,7 +369,6 @@ describe('', () => { ]); }); - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('hidden tab / tabs', () => { let nodeEnv; diff --git a/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx b/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx index 7d96b420c812bd..ec2c2813996cf8 100644 --- a/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx +++ b/packages/mui-material/src/TextareaAutosize/TextareaAutosize.test.tsx @@ -1,7 +1,14 @@ import * as React from 'react'; import { expect } from 'chai'; import sinon, { spy, stub } from 'sinon'; -import { act, screen, waitFor, createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { + describeSkipIf, + act, + screen, + waitFor, + createRenderer, + fireEvent, +} from '@mui/internal-test-utils'; import TextareaAutosize from '@mui/material/TextareaAutosize'; function getStyleValue(value: string) { @@ -137,8 +144,6 @@ describe('', () => { expect(parseInt(input.style.height, 10)).to.be.within(15, 17); }); - // @ts-expect-error - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('layout', () => { const getComputedStyleStub = new Map>(); function setLayout( diff --git a/packages/mui-material/src/ToggleButton/ToggleButton.test.js b/packages/mui-material/src/ToggleButton/ToggleButton.test.js index 1cbd7c82314d4e..f373e673f1b8b0 100644 --- a/packages/mui-material/src/ToggleButton/ToggleButton.test.js +++ b/packages/mui-material/src/ToggleButton/ToggleButton.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer } from '@mui/internal-test-utils'; +import { describeSkipIf, createRenderer } from '@mui/internal-test-utils'; import ToggleButton, { toggleButtonClasses as classes } from '@mui/material/ToggleButton'; import ButtonBase from '@mui/material/ButtonBase'; import describeConformance from '../../test/describeConformance'; @@ -125,7 +125,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('server-side', () => { it('should server-side render', () => { const { container } = renderToString(Hello World); diff --git a/packages/mui-material/src/Tooltip/Tooltip.test.js b/packages/mui-material/src/Tooltip/Tooltip.test.js index 4bc33e41fa466d..f10f7f731e95c9 100644 --- a/packages/mui-material/src/Tooltip/Tooltip.test.js +++ b/packages/mui-material/src/Tooltip/Tooltip.test.js @@ -10,6 +10,7 @@ import { focusVisible, programmaticFocusTriggersFocusVisible, reactMajor, + describeSkipIf, } from '@mui/internal-test-utils'; import { camelCase } from 'lodash/string'; import Tooltip, { tooltipClasses as classes } from '@mui/material/Tooltip'; @@ -505,7 +506,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('prop: delay', () => { it('should take the enterDelay into account', async () => { const { queryByRole } = render( @@ -877,7 +877,6 @@ describe('', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('focus', () => { it('ignores base focus', async () => { render( diff --git a/packages/mui-material/src/internal/animate.test.js b/packages/mui-material/src/internal/animate.test.js index 296ea769ec52b0..e148ae2605cb56 100644 --- a/packages/mui-material/src/internal/animate.test.js +++ b/packages/mui-material/src/internal/animate.test.js @@ -1,10 +1,10 @@ import { expect } from 'chai'; +import { describeSkipIf } from '@mui/internal-test-utils'; import animate from './animate'; const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isJSDOM = /jsdom/.test(window.navigator.userAgent); -// eslint-disable-next-line no-undef describeSkipIf(isJSDOM || isSafari)('animate', () => { let container; diff --git a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js index 13270aa1d08fb8..0e9e3e6a28241a 100644 --- a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js +++ b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js @@ -1,7 +1,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { expect } from 'chai'; -import { act, createRenderer, RenderCounter, screen } from '@mui/internal-test-utils'; +import { + act, + createRenderer, + RenderCounter, + screen, + describeSkipIf, +} from '@mui/internal-test-utils'; import useScrollTrigger from '@mui/material/useScrollTrigger'; import Container from '@mui/material/Container'; import Box from '@mui/material/Box'; @@ -48,7 +54,6 @@ describe('useScrollTrigger', () => { }); }); - // eslint-disable-next-line no-undef describeSkipIf(!/jsdom/.test(window.navigator.userAgent))('scroll', () => { const triggerRef = React.createRef(); const containerRef = React.createRef(); // Get the scroll container's parent diff --git a/packages/mui-material/test/integration/Menu.test.js b/packages/mui-material/test/integration/Menu.test.js index 80130cd7a1e53e..e27eff1e2fd37b 100644 --- a/packages/mui-material/test/integration/Menu.test.js +++ b/packages/mui-material/test/integration/Menu.test.js @@ -308,22 +308,18 @@ describe(' integration', () => { ); }); - it.only('closes the menu when Tabbing while the list is active', async () => { - const { user } = render(); + it('closes the menu when Tabbing while the list is active', async () => { + render(); const trigger = screen.getByRole('button'); await act(async () => { trigger.focus(); - }); - - await act(async () => { trigger.click(); }); // react-transition-group uses one commit per state transition so we need to wait a bit fireEvent.keyDown(screen.getAllByRole('menuitem')[0], { key: 'Tab' }); - - // await user.keyboard('[Tab]'); + clock.tick(0); expect(screen.getByRole('menu', { hidden: true })).toBeInaccessible(); }); diff --git a/packages/mui-material/test/integration/PopperChildrenLayout.test.js b/packages/mui-material/test/integration/PopperChildrenLayout.test.js index cdce7b73ad1591..8bc1a25fb273fb 100644 --- a/packages/mui-material/test/integration/PopperChildrenLayout.test.js +++ b/packages/mui-material/test/integration/PopperChildrenLayout.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, describeSkipIf } from '@mui/internal-test-utils'; import Collapse from '@mui/material/Collapse'; import Fade from '@mui/material/Fade'; import Grow from '@mui/material/Grow'; @@ -11,7 +11,6 @@ import Popper from '@mui/material/Popper'; const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -// eslint-disable-next-line no-undef describeSkipIf(/jsdom/.test(window.navigator.userAgent))('', () => { const { render } = createRenderer(); From 73c54152651046e3f82947f91ba2977c5b604c21 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:34:12 +0200 Subject: [PATCH 27/44] Fix sequence --- packages-internal/test-utils/src/createRenderer.tsx | 6 ++---- packages/mui-material/vitest.config.ts | 8 +++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index b3d74fdff42b7b..93a0b1c61ad7e2 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -367,9 +367,7 @@ function createVitestClock( } }); afterEach(() => { - if (config) { - vi.useRealTimers(); - } + vi.useRealTimers(); }); } @@ -605,7 +603,7 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende }); afterEach(() => { - if (!isVitest && !clock.isReal()) { + if (!clock.isReal()) { const error = new Error( "Can't cleanup before fake timers are restored.\n" + 'Be sure to:\n' + diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts index 3bf479e5d5c38c..40cebd32665d75 100644 --- a/packages/mui-material/vitest.config.ts +++ b/packages/mui-material/vitest.config.ts @@ -15,6 +15,9 @@ export default defineConfig({ globals: true, setupFiles: [path.resolve(__dirname, '../../packages-internal/test-utils/src/setupVitest')], environment: 'jsdom', + sequence: { + hooks: 'list', + }, environmentOptions: { jsdom: { pretendToBeVisual: true, @@ -46,7 +49,10 @@ export default defineConfig({ '@mui/styled-engine': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine/src'), '@mui/styled-engine-sc': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine-sc/src'), '@mui/styles': path.resolve(MONOREPO_ROOT, './packages/mui-styles/src'), - '@mui/icons-material': path.resolve(MONOREPO_ROOT, './packages/mui-icons-material/lib'), + '@mui/icons-material': path.resolve(MONOREPO_ROOT, './packages/mui-icons-material/lib/esm'), + '@mui/lab': path.resolve(MONOREPO_ROOT, './packages/mui-lab/src'), + '@mui/private-theming': path.resolve(MONOREPO_ROOT, './packages/mui-private-theming/src'), + '@mui/base': path.resolve(MONOREPO_ROOT, './packages/mui-base/src'), }, }, // @mui/material writes JSX in js From 110d779e3d1aa1fb5702bcf1ecbd21f5f24948fb Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:45:24 +0200 Subject: [PATCH 28/44] Update createRenderer.tsx --- packages-internal/test-utils/src/createRenderer.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 93a0b1c61ad7e2..0a9b92539bfbbd 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -616,15 +616,15 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende } cleanup(); - profiler?.report(); + profiler.report(); profiler = null!; emotionCache.sheet.tags.forEach((styleTag) => { - styleTag?.remove(); + styleTag.remove(); }); emotionCache = null!; - serverContainer?.remove(); + serverContainer.remove(); serverContainer = null!; }); From b67121a70a25f7c064ed2c8d1030fca9a1620dcc Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:00:56 +0200 Subject: [PATCH 29/44] Update setupVitest.ts --- packages-internal/test-utils/src/setupVitest.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index 2462bc01e9565a..13bd542963dddd 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -21,15 +21,6 @@ failOnConsole({ } } - // Ignore legacy root deprecation warnings - // TODO: Remove once we no longer use legacy roots. - if ( - message.includes('Use createRoot instead.') || - message.includes('Use hydrateRoot instead.') - ) { - return true; - } - if (message.includes('Warning: useLayoutEffect does nothing on the server')) { // Controversial warning that is commonly ignored by switching to `useEffect` on the server. // https://github.com/facebook/react/issues/14927 From 6afd7c42f51b6992dad4b5ddda812daac096022b Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:19:26 +0200 Subject: [PATCH 30/44] Expand tests --- .../src/pages/fixtures/index.test.js | 2 +- .../vitest.config.ts | 4 ++ .../test/typescript-to-proptypes.test.ts | 2 +- packages-internal/scripts/vitest.config.ts | 4 ++ .../test-utils/src/setupVitest.ts | 10 +++ .../api-docs-builder-core/vitest.config.ts | 4 ++ packages/api-docs-builder/vitest.config.ts | 4 ++ .../vitest.config.ts | 4 ++ packages/markdown/vitest.config.ts | 4 ++ .../mui-base/src/Dropdown/Dropdown.test.tsx | 2 - .../src/Transitions/CssTransition.test.tsx | 29 ++++---- packages/mui-base/src/useList/useList.ts | 10 +-- .../src/useSelect/defaultOptionStringifier.ts | 4 +- packages/mui-base/vitest.config.ts | 4 ++ .../src/v4.0.0/top-level-imports.js | 5 +- packages/mui-codemod/vitest.config.ts | 4 ++ packages/mui-docs/vitest.config.ts | 4 ++ packages/mui-envinfo/vitest.config.ts | 4 ++ packages/mui-icons-material/vitest.config.ts | 4 ++ .../src/Autocomplete/Autocomplete.test.tsx | 2 +- packages/mui-joy/vitest.config.ts | 4 ++ packages/mui-lab/vitest.config.ts | 4 ++ packages/mui-material-nextjs/vitest.config.ts | 4 ++ .../mui-material-pigment-css/vitest.config.ts | 4 ++ packages/mui-material/vitest.config.ts | 66 +------------------ packages/mui-private-theming/vitest.config.ts | 4 ++ .../mui-styled-engine-sc/vitest.config.ts | 4 ++ packages/mui-styled-engine/vitest.config.ts | 4 ++ packages/mui-styles/vitest.config.ts | 4 ++ packages/mui-system/vitest.config.ts | 4 ++ packages/mui-utils/vitest.config.ts | 4 ++ test/e2e/index.test.ts | 2 +- test/regressions/index.test.js | 2 +- vitest.config.ts | 23 +++++++ vitest.shared.ts | 60 +++++++++++++++++ vitest.workspace.ts | 7 ++ 36 files changed, 219 insertions(+), 91 deletions(-) create mode 100644 packages-internal/babel-plugin-minify-errors/vitest.config.ts create mode 100644 packages-internal/scripts/vitest.config.ts create mode 100644 packages/api-docs-builder-core/vitest.config.ts create mode 100644 packages/api-docs-builder/vitest.config.ts create mode 100644 packages/eslint-plugin-material-ui/vitest.config.ts create mode 100644 packages/markdown/vitest.config.ts create mode 100644 packages/mui-base/vitest.config.ts create mode 100644 packages/mui-codemod/vitest.config.ts create mode 100644 packages/mui-docs/vitest.config.ts create mode 100644 packages/mui-envinfo/vitest.config.ts create mode 100644 packages/mui-icons-material/vitest.config.ts create mode 100644 packages/mui-joy/vitest.config.ts create mode 100644 packages/mui-lab/vitest.config.ts create mode 100644 packages/mui-material-nextjs/vitest.config.ts create mode 100644 packages/mui-material-pigment-css/vitest.config.ts create mode 100644 packages/mui-private-theming/vitest.config.ts create mode 100644 packages/mui-styled-engine-sc/vitest.config.ts create mode 100644 packages/mui-styled-engine/vitest.config.ts create mode 100644 packages/mui-styles/vitest.config.ts create mode 100644 packages/mui-system/vitest.config.ts create mode 100644 packages/mui-utils/vitest.config.ts create mode 100644 vitest.config.ts create mode 100644 vitest.shared.ts create mode 100644 vitest.workspace.ts diff --git a/apps/pigment-css-vite-app/src/pages/fixtures/index.test.js b/apps/pigment-css-vite-app/src/pages/fixtures/index.test.js index 499abcd74daa49..e4af2581512ae2 100644 --- a/apps/pigment-css-vite-app/src/pages/fixtures/index.test.js +++ b/apps/pigment-css-vite-app/src/pages/fixtures/index.test.js @@ -104,7 +104,7 @@ async function main() { it(`creates screenshots of ${route}`, async function test() { // With the playwright inspector we might want to call `page.pause` which would lead to a timeout. if (process.env.PWDEBUG) { - this.timeout(0); + this?.timeout?.(0); } const testcase = await renderFixture(index); diff --git a/packages-internal/babel-plugin-minify-errors/vitest.config.ts b/packages-internal/babel-plugin-minify-errors/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages-internal/babel-plugin-minify-errors/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages-internal/scripts/typescript-to-proptypes/test/typescript-to-proptypes.test.ts b/packages-internal/scripts/typescript-to-proptypes/test/typescript-to-proptypes.test.ts index 6b29900311a4a5..1f9fe674c72aa9 100644 --- a/packages-internal/scripts/typescript-to-proptypes/test/typescript-to-proptypes.test.ts +++ b/packages-internal/scripts/typescript-to-proptypes/test/typescript-to-proptypes.test.ts @@ -34,7 +34,7 @@ describe('typescript-to-proptypes', () => { before(function beforeHook() { // Creating a TS program might take a while. - this.timeout(20000); + this?.timeout?.(20000); const buildProject = createTypeScriptProjectBuilder({ test: { diff --git a/packages-internal/scripts/vitest.config.ts b/packages-internal/scripts/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages-internal/scripts/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index 13bd542963dddd..d7cf44bdc9fa7b 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -3,9 +3,19 @@ import * as testingLibrary from '@testing-library/dom'; import failOnConsole from 'vitest-fail-on-console'; import './initMatchers'; +// checking if an element is hidden is quite expensive +// this is only done in CI as a fail safe. It can still explicitly be checked +// in the test files which helps documenting what is part of the DOM but hidden +// from assistive technology +const defaultHidden = !process.env.CI; + +// adds verbosity for something that might be confusing +console.warn(`${defaultHidden ? 'including' : 'excluding'} inaccessible elements by default`); + testingLibrary.configure({ // JSDOM logs errors otherwise on `getComputedStyle(element, pseudoElement)` calls. computedStyleSupportsPseudoElements: false, + defaultHidden, }); // Enable missing act warnings: https://github.com/reactwg/react-18/discussions/102 diff --git a/packages/api-docs-builder-core/vitest.config.ts b/packages/api-docs-builder-core/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/api-docs-builder-core/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/api-docs-builder/vitest.config.ts b/packages/api-docs-builder/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/api-docs-builder/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/eslint-plugin-material-ui/vitest.config.ts b/packages/eslint-plugin-material-ui/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/eslint-plugin-material-ui/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/markdown/vitest.config.ts b/packages/markdown/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/markdown/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-base/src/Dropdown/Dropdown.test.tsx b/packages/mui-base/src/Dropdown/Dropdown.test.tsx index dde3e91b3c4bbc..792d3cdcf5c2d9 100644 --- a/packages/mui-base/src/Dropdown/Dropdown.test.tsx +++ b/packages/mui-base/src/Dropdown/Dropdown.test.tsx @@ -30,7 +30,6 @@ describe('', () => { it('registers a popup id correctly', async () => { function TestComponent() { const { registerPopup, popupId } = React.useContext(DropdownContext)!; - expect(context).not.to.equal(null); React.useEffect(() => { registerPopup('test-popup'); @@ -54,7 +53,6 @@ describe('', () => { function TestComponent() { const { registerTrigger, triggerElement } = React.useContext(DropdownContext)!; - expect(context).not.to.equal(null); React.useEffect(() => { registerTrigger(trigger); diff --git a/packages/mui-base/src/Transitions/CssTransition.test.tsx b/packages/mui-base/src/Transitions/CssTransition.test.tsx index cb2f2980729262..e21cf34e5c3319 100644 --- a/packages/mui-base/src/Transitions/CssTransition.test.tsx +++ b/packages/mui-base/src/Transitions/CssTransition.test.tsx @@ -30,19 +30,7 @@ describe('CssTransition', () => { onExitedSpy.resetHistory(); }); - const { render, clock } = createRenderer(); - - describe('prop: className', () => { - it('applies it unconditionally', () => { - const { getByTestId } = render( - - - , - ); - const root = getByTestId('root'); - expect(root).to.have.class('foo'); - }); - }); + const { render, clock } = createRenderer({ clock: 'fake' }); describe('prop: enterClassName, exitClassName', () => { clock.withFakeTimers(); @@ -65,7 +53,7 @@ describe('CssTransition', () => { clock.runToLast(); }); - it('applies exitClassName, then immediately enterClassName when requested to enter', () => { + it('applies exitClassName, then immediately enterClassName when requested to enter', async () => { const { getByTestId } = render( @@ -79,8 +67,21 @@ describe('CssTransition', () => { expect(root).not.to.have.class('enter'); clock.runToLast(); + expect(root).to.have.class('enter'); expect(root).not.to.have.class('exit'); }); }); + + describe('prop: className', () => { + it('applies it unconditionally', () => { + const { getByTestId } = render( + + + , + ); + const root = getByTestId('root'); + expect(root).to.have.class('foo'); + }); + }); }); diff --git a/packages/mui-base/src/useList/useList.ts b/packages/mui-base/src/useList/useList.ts index 92f922e3c0f97b..45c62c744335bf 100644 --- a/packages/mui-base/src/useList/useList.ts +++ b/packages/mui-base/src/useList/useList.ts @@ -28,13 +28,15 @@ import { EventHandlers } from '../utils/types'; const EMPTY_OBJECT = {}; const NOOP = () => {}; -const defaultItemComparer = (optionA: ItemValue, optionB: ItemValue) => - optionA === optionB; +function defaultItemComparer(optionA: ItemValue, optionB: ItemValue) { + return optionA === optionB; +} const defaultIsItemDisabled = () => false; -const defaultItemStringifier = (item: ItemValue) => - typeof item === 'string' ? item : String(item); +function defaultItemStringifier(item: ItemValue) { + return typeof item === 'string' ? item : String(item); +} const defaultGetInitialState = () => ({ highlightedValue: null, diff --git a/packages/mui-base/src/useSelect/defaultOptionStringifier.ts b/packages/mui-base/src/useSelect/defaultOptionStringifier.ts index 4bb904b243737c..6c593456dfb838 100644 --- a/packages/mui-base/src/useSelect/defaultOptionStringifier.ts +++ b/packages/mui-base/src/useSelect/defaultOptionStringifier.ts @@ -1,6 +1,6 @@ import { SelectOption } from '../useOption'; -const defaultOptionStringifier = (option: SelectOption) => { +function defaultOptionStringifier(option: SelectOption) { const { label, value } = option; if (typeof label === 'string') { return label; @@ -12,6 +12,6 @@ const defaultOptionStringifier = (option: SelectOption // Fallback string representation return String(option); -}; +} export { defaultOptionStringifier }; diff --git a/packages/mui-base/vitest.config.ts b/packages/mui-base/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-base/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-codemod/src/v4.0.0/top-level-imports.js b/packages/mui-codemod/src/v4.0.0/top-level-imports.js index 3851a4b2227b51..28ff1d5ba36dbb 100644 --- a/packages/mui-codemod/src/v4.0.0/top-level-imports.js +++ b/packages/mui-codemod/src/v4.0.0/top-level-imports.js @@ -8,7 +8,10 @@ export default function transformer(fileInfo, api, options) { let requirePath = importModule; if (process.env.NODE_ENV === 'test') { - requirePath = requirePath.replace(/^@material-ui\/core/, '../../../mui-material/src'); + requirePath = requirePath.replace( + /^@material-ui\/core/, + process.env.VITEST ? '@mui/material' : '../../../mui-material/src', + ); } // eslint-disable-next-line global-require, import/no-dynamic-require diff --git a/packages/mui-codemod/vitest.config.ts b/packages/mui-codemod/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-codemod/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-docs/vitest.config.ts b/packages/mui-docs/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-docs/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-envinfo/vitest.config.ts b/packages/mui-envinfo/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-envinfo/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-icons-material/vitest.config.ts b/packages/mui-icons-material/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-icons-material/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx index 3a080d07f1df77..0bfad1ade81062 100644 --- a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx +++ b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx @@ -932,7 +932,7 @@ describe('Joy ', () => { it('should ignore keydown event until the IME is confirmed', function test() { // TODO: Often times out in Firefox 78. // Is this slow because of testing-library or because of the implementation? - this.timeout(4000); + this?.timeout?.(4000); const { getByRole } = render(); const textbox = getByRole('combobox'); diff --git a/packages/mui-joy/vitest.config.ts b/packages/mui-joy/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-joy/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-lab/vitest.config.ts b/packages/mui-lab/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-lab/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-material-nextjs/vitest.config.ts b/packages/mui-material-nextjs/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-material-nextjs/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-material-pigment-css/vitest.config.ts b/packages/mui-material-pigment-css/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-material-pigment-css/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-material/vitest.config.ts b/packages/mui-material/vitest.config.ts index 40cebd32665d75..331c1d8556fb74 100644 --- a/packages/mui-material/vitest.config.ts +++ b/packages/mui-material/vitest.config.ts @@ -1,64 +1,4 @@ -import { defineConfig, configDefaults } from 'vitest/config'; -import * as path from 'path'; +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; -const MONOREPO_ROOT = path.resolve(__dirname, '../..'); - -export default defineConfig({ - test: { - coverage: { - provider: 'v8', - reporter: ['text', 'lcov'], - reportsDirectory: path.resolve(MONOREPO_ROOT, 'coverage'), - include: ['src/**'], - }, - exclude: ['**/*.spec.*'], - globals: true, - setupFiles: [path.resolve(__dirname, '../../packages-internal/test-utils/src/setupVitest')], - environment: 'jsdom', - sequence: { - hooks: 'list', - }, - environmentOptions: { - jsdom: { - pretendToBeVisual: true, - url: 'http://localhost', - }, - }, - fakeTimers: { - // We use performance.now in the codebase - toFake: [...configDefaults.fakeTimers.toFake, 'performance'], - }, - browser: { - enabled: false, // enabled through CLI - name: 'chromium', - provider: 'playwright', - headless: !!process.env.CI, - viewport: { - width: 1024, - height: 896, - }, - }, - }, - - resolve: { - alias: { - '@mui/internal-test-utils': path.resolve(MONOREPO_ROOT, './packages-internal/test-utils/src'), - '@mui/material': path.resolve(MONOREPO_ROOT, './packages/mui-material/src'), - '@mui/system': path.resolve(MONOREPO_ROOT, './packages/mui-system/src'), - '@mui/utils': path.resolve(MONOREPO_ROOT, './packages/mui-utils/src'), - '@mui/styled-engine': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine/src'), - '@mui/styled-engine-sc': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine-sc/src'), - '@mui/styles': path.resolve(MONOREPO_ROOT, './packages/mui-styles/src'), - '@mui/icons-material': path.resolve(MONOREPO_ROOT, './packages/mui-icons-material/lib/esm'), - '@mui/lab': path.resolve(MONOREPO_ROOT, './packages/mui-lab/src'), - '@mui/private-theming': path.resolve(MONOREPO_ROOT, './packages/mui-private-theming/src'), - '@mui/base': path.resolve(MONOREPO_ROOT, './packages/mui-base/src'), - }, - }, - // @mui/material writes JSX in js - esbuild: { - loader: 'tsx', - include: /.*\.[jt]sx?$/, - exclude: [], - }, -}); +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-private-theming/vitest.config.ts b/packages/mui-private-theming/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-private-theming/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-styled-engine-sc/vitest.config.ts b/packages/mui-styled-engine-sc/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-styled-engine-sc/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-styled-engine/vitest.config.ts b/packages/mui-styled-engine/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-styled-engine/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-styles/vitest.config.ts b/packages/mui-styles/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-styles/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-system/vitest.config.ts b/packages/mui-system/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-system/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/packages/mui-utils/vitest.config.ts b/packages/mui-utils/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages/mui-utils/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index 0fbc91ff92629d..638722fe7f22d0 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -100,7 +100,7 @@ describe('e2e', () => { } before(async function beforeHook() { - this.timeout(20000); + this?.timeout?.(20000); browser = await playwright.chromium.launch({ headless: true, diff --git a/test/regressions/index.test.js b/test/regressions/index.test.js index 4eb8657c904c32..b962b0917d0aa1 100644 --- a/test/regressions/index.test.js +++ b/test/regressions/index.test.js @@ -106,7 +106,7 @@ async function main() { it(`creates screenshots of ${route}`, async function test() { // With the playwright inspector we might want to call `page.pause` which would lead to a timeout. if (process.env.PWDEBUG) { - this.timeout(0); + this?.timeout?.(0); } const testcase = await renderFixture(route); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000000000..f1019daf1ddcf4 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from 'vitest/config'; +import * as path from 'path'; + +const MONOREPO_ROOT = path.resolve(__dirname, '.'); + +/** + * See https://vitest.dev/guide/workspace.html + * > The root configuration will only influence global options such as reporters and coverage. + */ + +export default defineConfig({ + test: { + coverage: { + provider: 'v8', + reporter: ['text', 'lcov'], + reportsDirectory: path.resolve(MONOREPO_ROOT, 'coverage'), + include: ['src/**'], + }, + sequence: { + hooks: 'list', + }, + }, +}); diff --git a/vitest.shared.ts b/vitest.shared.ts new file mode 100644 index 00000000000000..fa81e16ba92d66 --- /dev/null +++ b/vitest.shared.ts @@ -0,0 +1,60 @@ +import { defineProject, configDefaults } from 'vitest/config'; +import * as path from 'path'; + +const MONOREPO_ROOT = path.resolve(__dirname, '.'); + +export default defineProject({ + test: { + exclude: ['**/*.spec.*'], + globals: true, + setupFiles: [path.resolve(MONOREPO_ROOT, './packages-internal/test-utils/src/setupVitest')], + environment: 'jsdom', + environmentOptions: { + jsdom: { + pretendToBeVisual: true, + url: 'http://localhost', + }, + }, + fakeTimers: { + // We use performance.now in the codebase + toFake: [...configDefaults.fakeTimers.toFake, 'performance'], + }, + browser: { + enabled: false, // enabled through CLI + name: 'chromium', + provider: 'playwright', + headless: !!process.env.CI, + viewport: { + width: 1024, + height: 896, + }, + }, + env: { + VITEST: 'true', + }, + }, + resolve: { + alias: { + '@mui/internal-test-utils': path.resolve(MONOREPO_ROOT, './packages-internal/test-utils/src'), + '@mui/material': path.resolve(MONOREPO_ROOT, './packages/mui-material/src'), + '@mui/system': path.resolve(MONOREPO_ROOT, './packages/mui-system/src'), + '@mui/utils': path.resolve(MONOREPO_ROOT, './packages/mui-utils/src'), + '@mui/styled-engine': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine/src'), + '@mui/styled-engine-sc': path.resolve(MONOREPO_ROOT, './packages/mui-styled-engine-sc/src'), + '@mui/styles': path.resolve(MONOREPO_ROOT, './packages/mui-styles/src'), + '@mui/icons-material': path.resolve(MONOREPO_ROOT, './packages/mui-icons-material/lib/src'), + '@mui/lab': path.resolve(MONOREPO_ROOT, './packages/mui-lab/src'), + '@mui/private-theming': path.resolve(MONOREPO_ROOT, './packages/mui-private-theming/src'), + '@mui/base': path.resolve(MONOREPO_ROOT, './packages/mui-base/src'), + '@mui/joy': path.resolve(MONOREPO_ROOT, './packages/mui-joy/src'), + '@mui/docs': path.resolve(MONOREPO_ROOT, './packages/mui-docs/src'), + '@mui/material-nextjs': path.resolve(MONOREPO_ROOT, './packages/mui-material-nextjs/src'), + }, + }, + // @mui/material writes JSX in js + esbuild: { + loader: 'tsx', + include: /.*\.[jt]sx?$/, + exclude: [], + }, +}); diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 00000000000000..45bf7cb03dc758 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,7 @@ +import { defineWorkspace } from 'vitest/config'; + +export default defineWorkspace([ + // matches every folder and file inside the `packages` folder + 'packages/*', + 'packages-internal/*', +]); From 6224e168e056a11be8bbca6bc369367b1ce69e86 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:11:37 +0200 Subject: [PATCH 31/44] Create vitest.config.ts --- packages-internal/test-utils/vitest.config.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages-internal/test-utils/vitest.config.ts diff --git a/packages-internal/test-utils/vitest.config.ts b/packages-internal/test-utils/vitest.config.ts new file mode 100644 index 00000000000000..331c1d8556fb74 --- /dev/null +++ b/packages-internal/test-utils/vitest.config.ts @@ -0,0 +1,4 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared'; + +export default mergeConfig(sharedConfig, defineProject({})); From 6e1c0a5d8a959c3a2f12e8429df68f7a5149857e Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:25:08 +0200 Subject: [PATCH 32/44] initMatchers --- .../test-utils/src/initMatchers.test.js | 12 ++++++++---- packages-internal/test-utils/src/mochaHooks.test.js | 5 +++++ packages/api-docs-builder-core/.eslintrc.js | 1 - vitest.shared.ts | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages-internal/test-utils/src/initMatchers.test.js b/packages-internal/test-utils/src/initMatchers.test.js index ae6236539778ec..da2375e032d934 100644 --- a/packages-internal/test-utils/src/initMatchers.test.js +++ b/packages-internal/test-utils/src/initMatchers.test.js @@ -44,12 +44,14 @@ describe('custom matchers', () => { 'Could not match the following console.error calls. ' + "Make sure previous actions didn't call console.error by wrapping them in expect(() => {}).not.toErrorDev(): \n\n" + ' - "expected message"\n' + - ' at Context.', // `Context.it` in node 12.x, `Context.` in later node version + ` at ${process.env.VITEST ? 'Function' : 'Context'}.`, ); // check that the top stackframe points to this test // if this test is moved to another file the next assertion fails expect(caughtError.stack).to.match( - /- "expected message"\s+at Context\.(|it) \(.+\/initMatchers\.test\.js:\d+:\d+\)/, + process.env.VITEST + ? /- "expected message"\s+at Function\. \(.+\/initMatchers\.test\.js:\d+:\d+\)/ + : /- "expected message"\s+at Context\. \(.+\/initMatchers\.test\.js:\d+:\d+\)/, ); }); @@ -66,12 +68,14 @@ describe('custom matchers', () => { 'Recorded unexpected console.error calls: \n\n' + ' - Expected #1 "expected message" to be included in \n' + '"expected Message"\n' + - ' at callback', + ' at ', ); // check that the top stackframe points to this test // if this test is moved to another file the next assertion fails expect(caughtError.stack).to.match( - /"expected Message"\s+at callback \(.+\/initMatchers\.test\.js:\d+:\d+\)/, + process.env.VITEST + ? /"expected Message"\s+at .+\/initMatchers\.test\.js:\d+:\d+/ + : /"expected Message"\s+at callback \(.+\/initMatchers\.test\.js:\d+:\d+\)/, ); }); diff --git a/packages-internal/test-utils/src/mochaHooks.test.js b/packages-internal/test-utils/src/mochaHooks.test.js index 2628a7a0543d68..ea92f1ea5525c8 100644 --- a/packages-internal/test-utils/src/mochaHooks.test.js +++ b/packages-internal/test-utils/src/mochaHooks.test.js @@ -6,6 +6,11 @@ import { createMochaHooks } from './mochaHooks'; import { createRenderer, act } from './createRenderer'; describe('mochaHooks', () => { + if (process.env.VITEST) { + it('TODO:Remove this file once we migrate to mocha', () => {}); + return; + } + // one block per hook. describe('afterEach', () => { describe('on unexpected console.(warn|error) in afterEach', function suite() { diff --git a/packages/api-docs-builder-core/.eslintrc.js b/packages/api-docs-builder-core/.eslintrc.js index c6c75c36b78637..295b0650d3aee0 100644 --- a/packages/api-docs-builder-core/.eslintrc.js +++ b/packages/api-docs-builder-core/.eslintrc.js @@ -1,6 +1,5 @@ module.exports = { rules: { - 'import/no-default-export': 'error', 'import/prefer-default-export': 'off', }, }; diff --git a/vitest.shared.ts b/vitest.shared.ts index fa81e16ba92d66..5818eb701c26c2 100644 --- a/vitest.shared.ts +++ b/vitest.shared.ts @@ -5,7 +5,7 @@ const MONOREPO_ROOT = path.resolve(__dirname, '.'); export default defineProject({ test: { - exclude: ['**/*.spec.*'], + exclude: ['build', '**/*.spec.*'], globals: true, setupFiles: [path.resolve(MONOREPO_ROOT, './packages-internal/test-utils/src/setupVitest')], environment: 'jsdom', From e5128806e9ffc301a987ddd7a6474dc24a6af65e Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:35:21 +0200 Subject: [PATCH 33/44] Update vitest.workspace.ts --- vitest.workspace.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vitest.workspace.ts b/vitest.workspace.ts index 45bf7cb03dc758..8a0abca90f9621 100644 --- a/vitest.workspace.ts +++ b/vitest.workspace.ts @@ -1,7 +1,6 @@ import { defineWorkspace } from 'vitest/config'; export default defineWorkspace([ - // matches every folder and file inside the `packages` folder - 'packages/*', - 'packages-internal/*', + // matches every folder inside the `packages` and `packages-internal` folders containing a config file + '{packages,packages-internal}/*/vitest.config.ts', ]); From d503f302d76ff4223acc3869373ecce728a16297 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:54:21 +0200 Subject: [PATCH 34/44] builder fixes --- packages-internal/test-utils/src/setupVitest.ts | 7 ++++++- packages/mui-icons-material/builder.mjs | 2 +- packages/mui-icons-material/builder.test.mjs | 17 ++++++++++------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages-internal/test-utils/src/setupVitest.ts b/packages-internal/test-utils/src/setupVitest.ts index d7cf44bdc9fa7b..d52705474f2c6c 100644 --- a/packages-internal/test-utils/src/setupVitest.ts +++ b/packages-internal/test-utils/src/setupVitest.ts @@ -55,7 +55,12 @@ failOnConsole({ function wrapIt(itFn: typeof it.only) { return function wrapper(name: string, fn: Function) { return itFn(name, (context) => { - return fn?.call(context); + return fn?.call({ + ...context, + currentTest: { + fullTitle: () => context.task.name, + }, + }); }); }; } diff --git a/packages/mui-icons-material/builder.mjs b/packages/mui-icons-material/builder.mjs index 56b8e003e76248..e86da5d9d91a81 100755 --- a/packages/mui-icons-material/builder.mjs +++ b/packages/mui-icons-material/builder.mjs @@ -9,7 +9,7 @@ import { fileURLToPath } from 'url'; import intersection from 'lodash/intersection.js'; import { Queue } from '@mui/internal-waterfall'; -const currentDirectory = fileURLToPath(new URL('.', import.meta.url)); +const currentDirectory = path.dirname(fileURLToPath(new URL(import.meta.url))); export const RENAME_FILTER_DEFAULT = './renameFilters/default.mjs'; export const RENAME_FILTER_MUI = './renameFilters/material-design-icons.mjs'; diff --git a/packages/mui-icons-material/builder.test.mjs b/packages/mui-icons-material/builder.test.mjs index b74e5becf0da10..a81f2221a41e26 100644 --- a/packages/mui-icons-material/builder.test.mjs +++ b/packages/mui-icons-material/builder.test.mjs @@ -6,7 +6,7 @@ import { fileURLToPath } from 'url'; import fse from 'fs-extra'; import { RENAME_FILTER_MUI, RENAME_FILTER_DEFAULT, getComponentName, handler } from './builder.mjs'; -const currentDirectory = fileURLToPath(new URL('.', import.meta.url)); +const currentDirectory = path.dirname(fileURLToPath(new URL(import.meta.url))); const DISABLE_LOG = true; @@ -43,12 +43,13 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { + // eslint-disable-next-line mocha/handle-done-callback + beforeEach(async function beforeEachHook(ctx) { // DON'T CLEAN UP TO MAKE TEST INSPECTABLE options.outputDir = path.join( os.tmpdir(), 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), + process.env.VITEST ? ctx.task.name : this.currentTest.fullTitle(), ); await fse.emptyDir(options.outputDir); }); @@ -70,12 +71,13 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { + // eslint-disable-next-line mocha/handle-done-callback + beforeEach(async function beforeEachHook(ctx) { // DON'T CLEAN UP TO MAKE TEST INSPECTABLE options.outputDir = path.join( os.tmpdir(), 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), + process.env.VITEST ? ctx.task.name : this.currentTest.fullTitle(), ); await fse.emptyDir(options.outputDir); }); @@ -111,12 +113,13 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { + // eslint-disable-next-line mocha/handle-done-callback + beforeEach(async function beforeEachHook(ctx) { // DON'T CLEAN UP TO MAKE TEST INSPECTABLE options.outputDir = path.join( os.tmpdir(), 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), + process.env.VITEST ? ctx.task.name : this.currentTest.fullTitle(), ); await fse.emptyDir(options.outputDir); }); From d4e0b0276d565d34dd7bf7ca07119152dce07357 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:43:41 +0200 Subject: [PATCH 35/44] wef --- packages/mui-icons-material/builder.test.mjs | 3 ++- packages/mui-joy/src/CssBaseline/CssBaseline.test.tsx | 4 +++- packages/mui-joy/src/Option/Option.test.tsx | 4 +++- packages/mui-lab/src/AlertTitle/AlertTitle.test.js | 3 +++ vitest.shared.ts | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/mui-icons-material/builder.test.mjs b/packages/mui-icons-material/builder.test.mjs index a81f2221a41e26..c987479e6bf51a 100644 --- a/packages/mui-icons-material/builder.test.mjs +++ b/packages/mui-icons-material/builder.test.mjs @@ -124,7 +124,8 @@ describe('builder', () => { await fse.emptyDir(options.outputDir); }); - it('should produce the expected output', async () => { + it.only('should produce the expected output', async () => { + console.log(options); await handler(options); expect(fs.lstatSync(options.outputDir).isDirectory()).to.equal(true); diff --git a/packages/mui-joy/src/CssBaseline/CssBaseline.test.tsx b/packages/mui-joy/src/CssBaseline/CssBaseline.test.tsx index ee4567edd3934e..78987012028674 100644 --- a/packages/mui-joy/src/CssBaseline/CssBaseline.test.tsx +++ b/packages/mui-joy/src/CssBaseline/CssBaseline.test.tsx @@ -1 +1,3 @@ -describe('', () => {}); +describe('', () => { + it('To do', () => {}); +}); diff --git a/packages/mui-joy/src/Option/Option.test.tsx b/packages/mui-joy/src/Option/Option.test.tsx index 518126eb8be5c0..df2d9988113e6b 100644 --- a/packages/mui-joy/src/Option/Option.test.tsx +++ b/packages/mui-joy/src/Option/Option.test.tsx @@ -1 +1,3 @@ -describe('