diff --git a/apps/pigment-css-vite-app/src/Slider/ZeroSlider.test.jsx b/apps/pigment-css-vite-app/src/Slider/ZeroSlider.test.jsx index 27d8d3af5dcc45..c055c1aae605d3 100644 --- a/apps/pigment-css-vite-app/src/Slider/ZeroSlider.test.jsx +++ b/apps/pigment-css-vite-app/src/Slider/ZeroSlider.test.jsx @@ -1,5 +1,5 @@ /* globals expect */ -import { render } from '@testing-library/react'; +import { render } from '@testing-library/react/pure'; import Slider from './ZeroSlider'; describe('Slider', () => { 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 bcb29cde8f1739..db1d6303e57974 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 @@ -101,7 +101,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/package.json b/package.json index e153d4c0f5ea8d..fcf376de97175e 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,8 @@ "@netlify/functions": "^4.2.5", "@slack/bolt": "^4.4.0", "babel-plugin-transform-import-meta": "^2.3.3", - "execa": "^9.6.0" + "execa": "^9.6.0", + "karma-spec-reporter": "^0.0.36" }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.2", @@ -126,6 +127,7 @@ "@types/babel__core": "^7.20.5", "@types/babel__register": "^7.17.3", "@types/lodash": "^4.17.20", + "@types/lodash.kebabcase": "^4.1.9", "@types/mocha": "^10.0.10", "@types/node": "^20.19.11", "@types/react": "^19.1.11", @@ -161,6 +163,7 @@ "karma-webpack": "^5.0.0", "lerna": "^8.2.3", "lodash": "^4.17.21", + "lodash.kebabcase": "^4.1.1", "markdownlint-cli2": "^0.18.1", "mocha": "^11.7.1", "nx": "^20.8.2", @@ -171,6 +174,7 @@ "pretty-quick": "^4.2.2", "process": "^0.11.10", "react": "^19.1.1", + "react-dom": "^19.1.1", "rimraf": "^6.0.1", "serve": "^14.2.4", "stylelint": "^16.23.1", diff --git a/packages-internal/scripts/typescript-to-proptypes/test/boolean-values/optional/input.d.ts b/packages-internal/scripts/typescript-to-proptypes/test/boolean-values-optional/input.d.ts similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/boolean-values/optional/input.d.ts rename to packages-internal/scripts/typescript-to-proptypes/test/boolean-values-optional/input.d.ts diff --git a/packages-internal/scripts/typescript-to-proptypes/test/boolean-values/optional/output.js b/packages-internal/scripts/typescript-to-proptypes/test/boolean-values-optional/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/boolean-values/optional/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/boolean-values-optional/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/boolean-values/required/input.d.ts b/packages-internal/scripts/typescript-to-proptypes/test/boolean-values-required/input.d.ts similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/boolean-values/required/input.d.ts rename to packages-internal/scripts/typescript-to-proptypes/test/boolean-values-required/input.d.ts diff --git a/packages-internal/scripts/typescript-to-proptypes/test/boolean-values/required/output.js b/packages-internal/scripts/typescript-to-proptypes/test/boolean-values-required/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/boolean-values/required/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/boolean-values-required/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/generator/html-elements/input.d.ts b/packages-internal/scripts/typescript-to-proptypes/test/generator-html-elements/input.d.ts similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/generator/html-elements/input.d.ts rename to packages-internal/scripts/typescript-to-proptypes/test/generator-html-elements/input.d.ts diff --git a/packages-internal/scripts/typescript-to-proptypes/test/generator/html-elements/output.js b/packages-internal/scripts/typescript-to-proptypes/test/generator-html-elements/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/generator/html-elements/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/generator-html-elements/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/input.tsx b/packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/input.tsx similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/input.tsx rename to packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/input.tsx diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/options.ts b/packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/options.ts similarity index 74% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/options.ts rename to packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/options.ts index d35ea30af4d3a1..efe5ba8f88074b 100644 --- a/packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/options.ts +++ b/packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/options.ts @@ -1,4 +1,4 @@ -import { TestOptions } from '../../types'; +import { TestOptions } from '../types'; const options: TestOptions = { injector: { diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/output.js b/packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/all-props-ignored/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/injector-all-props-ignored/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/input.tsx b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/input.tsx similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/input.tsx rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/input.tsx diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/options.ts b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/options.ts similarity index 83% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/options.ts rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/options.ts index 4f2b75b3f6572a..d5ff5d1b91822b 100644 --- a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/options.ts +++ b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/options.ts @@ -1,4 +1,4 @@ -import { TestOptions } from '../../types'; +import { TestOptions } from '../types'; const options: TestOptions = { injector: { diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/output.js b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-component-based/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-component-based/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/input.tsx b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/input.tsx similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/input.tsx rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/input.tsx diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/options.ts b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/options.ts similarity index 90% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/options.ts rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/options.ts index 9adc283b899f15..4d02a7bd516771 100644 --- a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/options.ts +++ b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/options.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { TestOptions } from '../../types'; +import { TestOptions } from '../types'; const options: TestOptions = { injector: { diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/output.js b/packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/should-include-filename-based/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/injector-should-include-filename-based/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/string-props/input.tsx b/packages-internal/scripts/typescript-to-proptypes/test/injector-string-props/input.tsx similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/string-props/input.tsx rename to packages-internal/scripts/typescript-to-proptypes/test/injector-string-props/input.tsx diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/string-props/output.js b/packages-internal/scripts/typescript-to-proptypes/test/injector-string-props/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/string-props/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/injector-string-props/output.js diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/input.tsx b/packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/input.tsx similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/input.tsx rename to packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/input.tsx diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/options.ts b/packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/options.ts similarity index 74% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/options.ts rename to packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/options.ts index 933d5e31648e14..d661de3167b01c 100644 --- a/packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/options.ts +++ b/packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/options.ts @@ -1,4 +1,4 @@ -import { TestOptions } from '../../types'; +import { TestOptions } from '../types'; const options: TestOptions = { injector: { diff --git a/packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/output.js b/packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/output.js similarity index 100% rename from packages-internal/scripts/typescript-to-proptypes/test/injector/whitelisted-props/output.js rename to packages-internal/scripts/typescript-to-proptypes/test/injector-whitelisted-props/output.js 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..d49f7b87c3353f 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 @@ -1,3 +1,4 @@ +/// import path from 'path'; import fs from 'fs'; import * as ts from 'typescript'; @@ -11,7 +12,7 @@ import { getPropTypesFromFile } from '../src/getPropTypesFromFile'; import { TestOptions } from './types'; const testCases = glob - .sync('**/input.{d.ts,ts,tsx}', { absolute: true, cwd: __dirname }) + .sync('*/input.{d.ts,ts,tsx}', { absolute: true, cwd: __dirname }) .map((testPath) => { const dirname = path.dirname(testPath); const name = path.dirname(path.relative(__dirname, testPath)); @@ -32,9 +33,10 @@ describe('typescript-to-proptypes', () => { return cachedProject; } + // @ts-expect-error Second argument is vitest before(function beforeHook() { // Creating a TS program might take a while. - this.timeout(20000); + this?.timeout?.(20000); const buildProject = createTypeScriptProjectBuilder({ test: { @@ -52,7 +54,7 @@ describe('typescript-to-proptypes', () => { // testCases.map((testCase) => testCase.inputPath), // ttp.loadConfig(path.resolve(__dirname, '../tsconfig.json')), // ); - }); + }, 20000); testCases.forEach((testCase) => { const { name: testName, inputPath, inputJS, outputPath } = testCase; @@ -61,7 +63,7 @@ describe('typescript-to-proptypes', () => { const project = getProject(); let options: TestOptions = {}; try { - const optionsModule = await import(`./${testName}/options`); + const optionsModule: any = await import(`./${testName}/options.ts`); options = optionsModule.default; } catch (error) { // Assume "Cannot find module" which means "no options". diff --git a/packages-internal/test-utils/src/chai-augmentation.d.ts b/packages-internal/test-utils/src/chai-augmentation.d.ts new file mode 100644 index 00000000000000..f21a470c3f9135 --- /dev/null +++ b/packages-internal/test-utils/src/chai-augmentation.d.ts @@ -0,0 +1,8 @@ +/* eslint-disable import/prefer-default-export */ +import 'chai'; +import type { AssertionError as RealAssertionError } from 'assertion-error'; + +declare module 'chai' { + // Looks like they forgot to export the AssertionError type in @types/chai + export const AssertionError: typeof RealAssertionError; +} diff --git a/packages-internal/test-utils/src/chaiPlugin.ts b/packages-internal/test-utils/src/chaiPlugin.ts index bbaeeb30e55797..4bd8c34780aeb8 100644 --- a/packages-internal/test-utils/src/chaiPlugin.ts +++ b/packages-internal/test-utils/src/chaiPlugin.ts @@ -1,16 +1,16 @@ import { isInaccessible } from '@testing-library/dom'; import { prettyDOM } from '@testing-library/react/pure'; -import type chaiType from 'chai'; -import { AssertionError } from 'chai'; +import * as chai from 'chai'; import { computeAccessibleDescription, computeAccessibleName } from 'dom-accessibility-api'; import formatUtil from 'format-util'; -import _ from 'lodash'; +// avoid loading whole lodash, it takes ~50ms to initialize +import kebabCase from 'lodash.kebabcase'; import './chai.types'; const isKarma = Boolean(process.env.KARMA); function isInJSDOM() { - return /jsdom/.test(window.navigator.userAgent); + return window.navigator.userAgent.includes('jsdom'); } // chai#utils.elToString that looks like stringified elements in testing-library @@ -21,7 +21,7 @@ function elementToString(element: Element | null | undefined) { return String(element); } -const chaiPlugin: Parameters<(typeof chaiType)['use']>[0] = (chaiAPI, utils) => { +const chaiPlugin: Parameters[0] = (chaiAPI, utils) => { const blockElements = new Set([ 'html', 'address', @@ -202,7 +202,7 @@ const chaiPlugin: Parameters<(typeof chaiType)['use']>[0] = (chaiAPI, utils) => // This is closer to actual CSS and required for getPropertyValue anyway. const expectedStyle: Record = {}; Object.keys(expectedStyleUnnormalized).forEach((cssProperty) => { - const hyphenCasedPropertyName = _.kebabCase(cssProperty); + const hyphenCasedPropertyName = kebabCase(cssProperty); const isVendorPrefixed = /^(moz|ms|o|webkit)-/.test(hyphenCasedPropertyName); const propertyName = isVendorPrefixed ? `-${hyphenCasedPropertyName}` @@ -279,7 +279,7 @@ const chaiPlugin: Parameters<(typeof chaiType)['use']>[0] = (chaiAPI, utils) => 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();`'; + 'If results differ between real browsers and JSDOM, skip the test in JSDOM e.g. `if (window.navigator.userAgent.includes("jsdom")) 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}`; @@ -316,7 +316,7 @@ const chaiPlugin: Parameters<(typeof chaiType)['use']>[0] = (chaiAPI, utils) => 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)}`); + throw new chai.AssertionError(`Expected an Element but got ${String(element)}`); } assertMatchingStyles.call(this, element.style, expectedStyleUnnormalized, { @@ -331,7 +331,7 @@ const chaiPlugin: Parameters<(typeof chaiType)['use']>[0] = (chaiAPI, utils) => 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)}`); + throw new chai.AssertionError(`Expected an Element but got ${String(element)}`); } const computedStyle = element.ownerDocument.defaultView!.getComputedStyle(element); diff --git a/packages-internal/test-utils/src/describeConformance.tsx b/packages-internal/test-utils/src/describeConformance.tsx index 551c8a2633cd67..5851084310afa5 100644 --- a/packages-internal/test-utils/src/describeConformance.tsx +++ b/packages-internal/test-utils/src/describeConformance.tsx @@ -774,7 +774,7 @@ function testThemeStyleOverrides( ) { describe('theme style overrides:', () => { it("respect theme's styleOverrides custom state", async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); @@ -831,7 +831,7 @@ function testThemeStyleOverrides( }); it("respect theme's styleOverrides slots", async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); @@ -944,7 +944,7 @@ function testThemeStyleOverrides( }); it('overrideStyles does not replace each other in slots', async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); @@ -1027,7 +1027,7 @@ function testThemeVariants( ) { describe('theme variants:', () => { it("respect theme's variants", async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); @@ -1084,7 +1084,7 @@ function testThemeVariants( }); it('supports custom variant', async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); @@ -1140,7 +1140,12 @@ function testThemeCustomPalette( describe('theme extended palette:', () => { it('should render without errors', function test(t = {}) { const { render, ThemeProvider, createTheme } = getOptions(); - if (!/jsdom/.test(window.navigator.userAgent) || !render || !ThemeProvider || !createTheme) { + if ( + !window.navigator.userAgent.includes('jsdom') || + !render || + !ThemeProvider || + !createTheme + ) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-expressions this?.skip?.() ?? t?.skip(); diff --git a/packages-internal/test-utils/src/fireDiscreteEvent.ts b/packages-internal/test-utils/src/fireDiscreteEvent.ts index a48f70d9ecbf9a..245b65ed4e29fd 100644 --- a/packages-internal/test-utils/src/fireDiscreteEvent.ts +++ b/packages-internal/test-utils/src/fireDiscreteEvent.ts @@ -1,4 +1,4 @@ -import { configure, fireEvent, getConfig } from '@testing-library/react'; +import { configure, fireEvent, getConfig } from '@testing-library/react/pure'; import reactMajor from './reactMajor'; const noWrapper = (callback: () => void) => callback(); diff --git a/packages-internal/test-utils/src/focusVisible.ts b/packages-internal/test-utils/src/focusVisible.ts index 1c6e10b23d1c29..af0ef8dfc5c2c8 100644 --- a/packages-internal/test-utils/src/focusVisible.ts +++ b/packages-internal/test-utils/src/focusVisible.ts @@ -3,7 +3,9 @@ import { act, fireEvent } from './createRenderer'; export default function focusVisible(element: HTMLElement) { act(() => { element.blur(); - fireEvent.keyDown(document.body, { key: 'Tab' }); + }); + fireEvent.keyDown(document.body, { key: 'Tab' }); + act(() => { element.focus(); }); } diff --git a/packages-internal/test-utils/src/initPlaywrightMatchers.ts b/packages-internal/test-utils/src/initPlaywrightMatchers.ts index 855c4ac9a5c897..b9a926f23959c9 100644 --- a/packages-internal/test-utils/src/initPlaywrightMatchers.ts +++ b/packages-internal/test-utils/src/initPlaywrightMatchers.ts @@ -1,4 +1,4 @@ -import chai, { AssertionError } from 'chai'; +import * as chai from 'chai'; import * as DomTestingLibrary from '@testing-library/dom'; import type { ElementHandle } from '@playwright/test'; @@ -33,7 +33,9 @@ chai.use((chaiAPI, utils) => { chai.Assertion.addMethod('toHaveFocus', async function elementHandleIsFocused() { const $elementOrHandle: ElementHandle | Promise = utils.flag(this, 'object'); if ($elementOrHandle == null) { - throw new AssertionError(`Expected an element handle but got ${String($elementOrHandle)}.`); + throw new chai.AssertionError( + `Expected an element handle but got ${String($elementOrHandle)}.`, + ); } const $element = typeof ($elementOrHandle as Promise).then === 'function' @@ -66,7 +68,9 @@ chai.use((chaiAPI, utils) => { async function elementHandleHasAttribute(attributeName: string, attributeValue?: string) { const $elementOrHandle: ElementHandle | Promise = utils.flag(this, 'object'); if ($elementOrHandle == null) { - throw new AssertionError(`Expected an element handle but got ${String($elementOrHandle)}.`); + throw new chai.AssertionError( + `Expected an element handle but got ${String($elementOrHandle)}.`, + ); } const $element = typeof ($elementOrHandle as Promise).then === 'function' diff --git a/packages/markdown/extractImports.test.js b/packages/markdown/extractImports.test.mjs similarity index 96% rename from packages/markdown/extractImports.test.js rename to packages/markdown/extractImports.test.mjs index d9845294ab48ad..c4d8b3aba35854 100644 --- a/packages/markdown/extractImports.test.js +++ b/packages/markdown/extractImports.test.mjs @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import extractImports from './extractImports'; +import extractImports from './extractImports.mjs'; describe('extractImports', () => { it('finds all imports', () => { diff --git a/packages/markdown/parseMarkdown.test.js b/packages/markdown/parseMarkdown.test.mjs similarity index 99% rename from packages/markdown/parseMarkdown.test.js rename to packages/markdown/parseMarkdown.test.mjs index 9319bd2b20e76a..5a909acb6face2 100644 --- a/packages/markdown/parseMarkdown.test.js +++ b/packages/markdown/parseMarkdown.test.mjs @@ -7,7 +7,7 @@ import { getCodeblock, renderMarkdown, createRender, -} from './parseMarkdown'; +} from './parseMarkdown.mjs'; describe('parseMarkdown', () => { describe('getTitle', () => { diff --git a/packages/markdown/prepareMarkdown.test.js b/packages/markdown/prepareMarkdown.test.mjs similarity index 99% rename from packages/markdown/prepareMarkdown.test.js rename to packages/markdown/prepareMarkdown.test.mjs index 111777c4e2743d..14233efbc7f483 100644 --- a/packages/markdown/prepareMarkdown.test.js +++ b/packages/markdown/prepareMarkdown.test.mjs @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import prepareMarkdown from './prepareMarkdown'; +import prepareMarkdown from './prepareMarkdown.mjs'; describe('prepareMarkdown', () => { const defaultParams = { diff --git a/packages/markdown/textToHash.test.js b/packages/markdown/textToHash.test.mjs similarity index 96% rename from packages/markdown/textToHash.test.js rename to packages/markdown/textToHash.test.mjs index b8f8afa4265e93..e8fb448adcf624 100644 --- a/packages/markdown/textToHash.test.js +++ b/packages/markdown/textToHash.test.mjs @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { parseInline as renderInlineMarkdown } from 'marked'; -import textToHash from './textToHash'; +import textToHash from './textToHash.mjs'; describe('textToHash', () => { it('should hash as expected', () => { diff --git a/packages/mui-codemod/package.json b/packages/mui-codemod/package.json index d4738909f07229..7634cbc64829a9 100644 --- a/packages/mui-codemod/package.json +++ b/packages/mui-codemod/package.json @@ -39,6 +39,8 @@ "yargs": "^17.7.2" }, "devDependencies": { + "@material-ui/core": "^4.12.4", + "@mui/material-v5": "npm:@mui/material@5.17.1", "@types/chai": "^4.3.20", "@types/jscodeshift": "0.12.0", "chai": "^6.0.1" diff --git a/packages/mui-codemod/src/v4.0.0/optimal-imports.js b/packages/mui-codemod/src/v4.0.0/optimal-imports.js index 567ae9e85374fd..2428e3ef2ac7e6 100644 --- a/packages/mui-codemod/src/v4.0.0/optimal-imports.js +++ b/packages/mui-codemod/src/v4.0.0/optimal-imports.js @@ -2,13 +2,6 @@ import { dirname } from 'path'; import addImports from 'jscodeshift-add-imports'; import getJSExports from '../util/getJSExports'; -// istanbul ignore next -if (process.env.NODE_ENV === 'test') { - const resolve = require.resolve; - require.resolve = (source) => - resolve(source.replace(/^@material-ui\/core\/es/, '../../../mui-material/src')); -} - export default function transformer(fileInfo, api, options) { const j = api.jscodeshift; const importModule = options.importModule || '@material-ui/core'; 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..669c7dc924968e 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 @@ -5,11 +5,7 @@ export default function transformer(fileInfo, api, options) { const importModule = options.importModule || '@material-ui/core'; const targetModule = options.targetModule || '@material-ui/core'; - let requirePath = importModule; - - if (process.env.NODE_ENV === 'test') { - requirePath = requirePath.replace(/^@material-ui\/core/, '../../../mui-material/src'); - } + const requirePath = importModule; // eslint-disable-next-line global-require, import/no-dynamic-require const whitelist = require(requirePath); diff --git a/packages/mui-codemod/src/v5.0.0/optimal-imports.js b/packages/mui-codemod/src/v5.0.0/optimal-imports.js index a0be6c3e078916..a5a97cebd0880d 100644 --- a/packages/mui-codemod/src/v5.0.0/optimal-imports.js +++ b/packages/mui-codemod/src/v5.0.0/optimal-imports.js @@ -2,17 +2,6 @@ import { dirname } from 'path'; import addImports from 'jscodeshift-add-imports'; import getJSExports from '../util/getJSExports'; -// istanbul ignore next -if (process.env.NODE_ENV === 'test') { - const resolve = require.resolve; - require.resolve = (source) => - resolve( - source - .replace(/^@material-ui\/core\/es/, '../../../mui-material/src') - .replace(/^@material-ui\/core\/modern/, '../../../mui-material/src'), - ); -} - export default function transformer(fileInfo, api, options) { const j = api.jscodeshift; const importModule = options.importModule || '@material-ui/core'; diff --git a/packages/mui-codemod/src/v5.0.0/top-level-imports.js b/packages/mui-codemod/src/v5.0.0/top-level-imports.js index 347af368ad86cc..6609a8c105f283 100644 --- a/packages/mui-codemod/src/v5.0.0/top-level-imports.js +++ b/packages/mui-codemod/src/v5.0.0/top-level-imports.js @@ -2,20 +2,18 @@ import { dirname } from 'path'; import addImports from 'jscodeshift-add-imports'; import getJSExports from '../util/getJSExports'; -// istanbul ignore next -if (process.env.NODE_ENV === 'test') { - const resolve = require.resolve; - require.resolve = (source) => - resolve(source.replace(/^@mui\/material\/modern/, '../../../mui-material/src')); -} - export default function transformer(fileInfo, api, options) { const j = api.jscodeshift; const importModule = options.importModule || '@mui/material'; const targetModule = options.targetModule || '@mui/material'; + let resolveModule = importModule; + if (process.env.NODE_ENV === 'test') { + resolveModule = resolveModule.replace(/^@mui\/material/, '@mui/material-v5'); + } + const whitelist = getJSExports( - require.resolve(`${importModule}/modern`, { + require.resolve(`${resolveModule}/modern`, { paths: [dirname(fileInfo.path)], }), ); diff --git a/packages/mui-codemod/src/v5.0.0/top-level-imports.test.js b/packages/mui-codemod/src/v5.0.0/top-level-imports.test.js index 29018b0b90104c..ed4e9322d1d41b 100644 --- a/packages/mui-codemod/src/v5.0.0/top-level-imports.test.js +++ b/packages/mui-codemod/src/v5.0.0/top-level-imports.test.js @@ -16,6 +16,7 @@ describe('@mui/codemod', () => { describe('v5.0.0', () => { describe('top-level-imports', () => { it('convert path as needed', () => { + this?.timeout?.(20000); const actual = transform( { source: read('./top-level-imports.test/actual.js'), diff --git a/packages/mui-envinfo/src/envinfo.test.js b/packages/mui-envinfo/src/envinfo.test.js index 6a362b47e43c91..030ae7cc7de4b0 100644 --- a/packages/mui-envinfo/src/envinfo.test.js +++ b/packages/mui-envinfo/src/envinfo.test.js @@ -17,7 +17,7 @@ describe('@mui/envinfo', () => { it('includes info about the environment relevant to MUI', function test() { // only run in node - if (!/jsdom/.test(window.navigator.userAgent)) { + if (!window.navigator.userAgent.includes('jsdom')) { this.skip(); } diff --git a/packages/mui-icons-material/builder.mjs b/packages/mui-icons-material/builder.mjs index 30a8e136afab5f..bc868a32a82dae 100755 --- a/packages/mui-icons-material/builder.mjs +++ b/packages/mui-icons-material/builder.mjs @@ -10,7 +10,7 @@ import intersection from 'lodash/intersection.js'; import { Queue } from '@mui/internal-waterfall'; import { hideBin } from 'yargs/helpers'; -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 866492a53c0a8f..52e675f9b72bea 100644 --- a/packages/mui-icons-material/builder.test.mjs +++ b/packages/mui-icons-material/builder.test.mjs @@ -5,7 +5,7 @@ import path from 'path'; import { fileURLToPath } from 'url'; 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; @@ -42,15 +42,27 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { - // DON'T CLEAN UP TO MAKE TEST INSPECTABLE - options.outputDir = path.join( - os.tmpdir(), - 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), - ); - await emptyDir(options.outputDir); - }); + beforeEach( + process.env.VITEST + ? async function beforeEachHook(ctx) { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + ctx.task.name, + ); + await emptyDir(options.outputDir); + } + : async function beforeEachHook() { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + this.currentTest.fullTitle(), + ); + await emptyDir(options.outputDir); + }, + ); it('script outputs to directory', async () => { await handler(options); @@ -69,15 +81,27 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { - // DON'T CLEAN UP TO MAKE TEST INSPECTABLE - options.outputDir = path.join( - os.tmpdir(), - 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), - ); - await emptyDir(options.outputDir); - }); + beforeEach( + process.env.VITEST + ? async function beforeEachHook(ctx) { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + ctx.task.name, + ); + await emptyDir(options.outputDir); + } + : async function beforeEachHook() { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + this.currentTest.fullTitle(), + ); + await emptyDir(options.outputDir); + }, + ); it('script outputs to directory', async () => { await handler(options); @@ -110,15 +134,27 @@ describe('builder', () => { outputDir: null, }; - beforeEach(async function beforeEachHook() { - // DON'T CLEAN UP TO MAKE TEST INSPECTABLE - options.outputDir = path.join( - os.tmpdir(), - 'material-ui-icons-builder-test', - this.currentTest.fullTitle(), - ); - await emptyDir(options.outputDir); - }); + beforeEach( + process.env.VITEST + ? async function beforeEachHook(ctx) { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + ctx.task.name, + ); + await emptyDir(options.outputDir); + } + : async function beforeEachHook() { + // DON'T CLEAN UP TO MAKE TEST INSPECTABLE + options.outputDir = path.join( + os.tmpdir(), + 'material-ui-icons-builder-test', + this.currentTest.fullTitle(), + ); + await emptyDir(options.outputDir); + }, + ); it('should produce the expected output', async () => { await handler(options); diff --git a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx index b8ff2c801884f9..8468865f806e47 100644 --- a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx +++ b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx @@ -155,7 +155,7 @@ describe('Joy ', () => { it('should set the focus on the first item when possible', () => { const options = ['one', 'two']; - const { getByRole, setProps } = render( + const { getAllByRole, getByRole, setProps } = render( , ); const textbox = getByRole('combobox'); @@ -164,7 +164,7 @@ describe('Joy ', () => { setProps({ options, loading: false }); expect(textbox).to.have.attribute( 'aria-activedescendant', - screen.getAllByRole('option')[0].getAttribute('id')!, + getAllByRole('option')[0].getAttribute('id')!, ); }); @@ -256,7 +256,7 @@ describe('Joy ', () => { }); expect(container.textContent).to.equal('onetwothree'); // Depending on the subset of components used in this test run the computed `visibility` changes in JSDOM. - if (!/jsdom/.test(window.navigator.userAgent)) { + if (!window.navigator.userAgent.includes('jsdom')) { expect(getAllByRole('button', { hidden: false })).to.have.lengthOf(5); } }); @@ -280,7 +280,7 @@ describe('Joy ', () => { }); expect(container.textContent).to.equal('onetwothree'); // Depending on the subset of components used in this test run the computed `visibility` changes in JSDOM. - if (!/jsdom/.test(window.navigator.userAgent)) { + if (!window.navigator.userAgent.includes('jsdom')) { expect(getAllByRole('button', { hidden: false })).to.have.lengthOf(5); } }); @@ -531,42 +531,42 @@ describe('Joy ', () => { expect(screen.getByRole('combobox')).to.have.property('value', ''); }); - it('should fail validation if a required field has no value', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + it('should fail validation if a required field has no value', async function test() { + if (window.navigator.userAgent.includes('jsdom')) { // Enable once https://github.com/jsdom/jsdom/issues/2898 is resolved this.skip(); } const handleSubmit = spy((event) => event.preventDefault()); - render( + const { user, getByRole } = render(
, ); - screen.getByRole('button', { name: 'Submit' }).click(); + await user.click(getByRole('button', { name: 'Submit' })); expect(handleSubmit.callCount).to.equal(0); }); - it('should fail validation if a required field has a value', function test() { + it('should fail validation if a required field has a value', async function test() { // Unclear how native Constraint validation can be enabled for `multiple` - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // Enable once https://github.com/jsdom/jsdom/issues/2898 is resolved // The test is passing in JSDOM but form validation is buggy in JSDOM so we rather skip than have false confidence this.skip(); } const handleSubmit = spy((event) => event.preventDefault()); - render( + const { user, getByRole } = render(
, ); - screen.getByRole('button', { name: 'Submit' }).click(); + await user.click(getByRole('button', { name: 'Submit' })); expect(handleSubmit.callCount).to.equal(0); }); @@ -588,8 +588,8 @@ describe('Joy ', () => { ); } - const { setProps } = render(); - let textbox = screen.getByRole('combobox'); + const { setProps, getByRole } = render(); + let textbox = getByRole('combobox'); fireEvent.keyDown(textbox, { key: 'Enter' }); expect(handleSubmit.callCount).to.equal(1); @@ -603,7 +603,7 @@ describe('Joy ', () => { expect(handleSubmit.callCount).to.equal(2); setProps({ key: 'test-2', multiple: true, freeSolo: true }); - textbox = screen.getByRole('combobox'); + textbox = getByRole('combobox'); fireEvent.change(textbox, { target: { value: 'o' } }); fireEvent.keyDown(textbox, { key: 'Enter' }); @@ -613,7 +613,7 @@ describe('Joy ', () => { expect(handleSubmit.callCount).to.equal(3); setProps({ key: 'test-3', freeSolo: true }); - textbox = screen.getByRole('combobox'); + textbox = getByRole('combobox'); fireEvent.change(textbox, { target: { value: 'o' } }); fireEvent.keyDown(textbox, { key: 'Enter' }); @@ -624,7 +624,7 @@ describe('Joy ', () => { it('should prevent the disabled option to trigger actions but allow focus with disabledItemsFocusable', () => { const handleSubmit = spy(); const handleChange = spy(); - const { getAllByRole } = render( + const { getAllByRole, getByRole } = render(
{ if (!event.defaultPrevented && event.key === 'Enter') { @@ -644,7 +644,7 @@ describe('Joy ', () => { ); let options; - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); @@ -909,7 +909,7 @@ describe('Joy ', () => { , ); - fireEvent.keyDown(screen.getByRole('combobox'), { key: 'ArrowDown' }); + fireEvent.keyDown(getByRole('combobox'), { key: 'ArrowDown' }); expect(getByRole('combobox')).to.have.attribute( 'aria-activedescendant', getAllByRole('option')[0].getAttribute('id')!, @@ -921,7 +921,7 @@ describe('Joy ', () => { , ); - fireEvent.keyDown(screen.getByRole('combobox'), { key: 'ArrowUp' }); + fireEvent.keyDown(getByRole('combobox'), { key: 'ArrowUp' }); const options = getAllByRole('option'); expect(getByRole('combobox')).to.have.attribute( 'aria-activedescendant', @@ -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'); @@ -980,8 +980,10 @@ describe('Joy ', () => { describe('listbox wrapping behavior', () => { it('wraps around when navigating the list by default', () => { - const { getAllByRole } = render(); - const textbox = screen.getByRole('combobox'); + const { getAllByRole, getByRole } = render( + , + ); + const textbox = getByRole('combobox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); fireEvent.keyDown(textbox, { key: 'ArrowUp' }); @@ -1105,22 +1107,24 @@ describe('Joy ', () => { }); it('should close the popup when disabled is true', () => { - const { setProps } = render(); - const textbox = screen.getByRole('combobox'); + const { setProps, getByRole, queryByRole } = render( + , + ); + const textbox = getByRole('combobox'); act(() => { textbox.focus(); }); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); - expect(screen.queryByRole('listbox')).not.to.equal(null); + expect(queryByRole('listbox')).not.to.equal(null); setProps({ disabled: true }); - expect(screen.queryByRole('listbox')).to.equal(null); + expect(queryByRole('listbox')).to.equal(null); }); it('should not crash when autoSelect & freeSolo are set, text is focused & disabled gets truthy', () => { - const { setProps } = render( + const { setProps, getByRole } = render( , ); - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); act(() => { textbox.focus(); }); @@ -1245,13 +1249,13 @@ describe('Joy ', () => { groupBy={(option) => String(option.group)} />, ); + const options = screen.getAllByRole('option').map((el) => el.textContent); + expect(options).to.have.length(7); + expect(options).to.deep.equal(['A', 'D', 'E', 'B', 'G', 'F', 'C']); }).toWarnDev([ 'returns duplicated headers', !strictModeDoubleLoggingSuppressed && 'returns duplicated headers', ]); - const options = screen.getAllByRole('option').map((el) => el.textContent); - expect(options).to.have.length(7); - expect(options).to.deep.equal(['A', 'D', 'E', 'B', 'G', 'F', 'C']); }); it('warn if the type of the value is wrong', () => { @@ -1283,7 +1287,7 @@ describe('Joy ', () => { describe('prop: options', () => { it('should scroll selected option into view when multiple elements with role as listbox available', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } render( @@ -1324,9 +1328,11 @@ describe('Joy ', () => { }); it('should keep focus on selected option and not reset to top option when options updated', () => { - const { setProps } = render(); - const textbox = screen.getByRole('combobox'); - const listbox = screen.getByRole('listbox'); + const { setProps, getByRole } = render( + , + ); + const textbox = getByRole('combobox'); + const listbox = getByRole('listbox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'one' fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'two' @@ -1339,7 +1345,7 @@ describe('Joy ', () => { }); it('should keep focus when multiple options are selected and not reset to top option when options updated', () => { - const { setProps } = render( + const { setProps, getByRole } = render( ', () => { autoFocus />, ); - const textbox = screen.getByRole('combobox'); - const listbox = screen.getByRole('listbox'); + const textbox = getByRole('combobox'); + const listbox = getByRole('listbox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); @@ -1364,7 +1370,7 @@ describe('Joy ', () => { it('should keep focus when multiple options are selected by not resetting to the top option when options are updated and when options are provided as objects', () => { const value = [{ label: 'one' }]; const options = [{ label: 'one' }, { label: 'two' }, { label: 'three' }]; - const { setProps } = render( + const { setProps, getByRole } = render( ', () => { open />, ); - const textbox = screen.getByRole('combobox'); - const listbox = screen.getByRole('listbox'); + const textbox = getByRole('combobox'); + const listbox = getByRole('listbox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); @@ -1390,11 +1396,11 @@ describe('Joy ', () => { }); it('should keep focus on selected option when options updates and when options are provided as objects', () => { - const { setProps } = render( + const { setProps, getByRole } = render( , ); - const textbox = screen.getByRole('combobox'); - const listbox = screen.getByRole('listbox'); + const textbox = getByRole('combobox'); + const listbox = getByRole('listbox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'one' fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'two' @@ -1413,9 +1419,11 @@ describe('Joy ', () => { }); it("should reset the highlight when previously highlighted option doesn't exists in new options", () => { - const { setProps } = render(); - const textbox = screen.getByRole('combobox'); - const listbox = screen.getByRole('listbox'); + const { setProps, getByRole } = render( + , + ); + const textbox = getByRole('combobox'); + const listbox = getByRole('listbox'); fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'one' fireEvent.keyDown(textbox, { key: 'ArrowDown' }); // goes to 'two' @@ -1748,7 +1756,7 @@ describe('Joy ', () => { it('should not delete exiting tag when try to add it twice', () => { const handleChange = spy(); const options = ['one', 'two']; - const { container } = render( + const { container, getByRole } = render( ', () => { multiple />, ); - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); fireEvent.change(textbox, { target: { value: 'three' } }); fireEvent.keyDown(textbox, { key: 'Enter' }); @@ -1927,9 +1935,9 @@ describe('Joy ', () => { ); } - const { user } = render(); + const { user, getByText } = render(); - await user.click(screen.getByText('Reset')); + await user.click(getByText('Reset')); // eslint-disable-next-line no-nested-ternary const expectedCallCount = reactMajor >= 19 ? 3 : reactMajor === 18 ? 4 : 2; @@ -1942,7 +1950,7 @@ describe('Joy ', () => { it('provides a reason on clear', async () => { const handleInputChange = spy(); const options = [{ name: 'foo' }]; - const { user } = render( + const { user, getByLabelText } = render( ', () => { />, ); - await user.click(screen.getByLabelText('Clear')); + await user.click(getByLabelText('Clear')); expect(handleInputChange.lastCall.args[1]).to.equal(''); expect(handleInputChange.lastCall.args[2]).to.equal('clear'); @@ -1961,7 +1969,7 @@ describe('Joy ', () => { it('provides a reason on blur', async () => { const handleInputChange = spy(); const options = [{ name: 'foo' }]; - const { user } = render( + const { user, getByRole } = render( ', () => { clearOnBlur />, ); - await user.type(screen.getByRole('combobox'), options[0].name); + await user.type(getByRole('combobox'), options[0].name); await user.tab(); expect(handleInputChange.lastCall.args[1]).to.equal(''); @@ -1980,7 +1988,7 @@ describe('Joy ', () => { it('provides a reason on select option', async () => { const handleInputChange = spy(); const options = [{ name: 'foo' }]; - const { user } = render( + const { user, getByLabelText, getByRole } = render( ', () => { />, ); - await user.click(screen.getByLabelText('Open')); - await user.click(screen.getByRole('option', { name: options[0].name })); + await user.click(getByLabelText('Open')); + await user.click(getByRole('option', { name: options[0].name })); expect(handleInputChange.lastCall.args[1]).to.equal(options[0].name); expect(handleInputChange.lastCall.args[2]).to.equal('selectOption'); @@ -1999,7 +2007,7 @@ describe('Joy ', () => { it('provides a reason on remove option', async () => { const handleInputChange = spy(); const options = [{ name: 'foo' }]; - const { user } = render( + const { user, getByRole } = render( ', () => { />, ); - await user.type(screen.getByRole('combobox'), `${options[0].name}{Enter}`); + await user.type(getByRole('combobox'), `${options[0].name}{Enter}`); expect(handleInputChange.lastCall.args[1]).to.equal(''); expect(handleInputChange.lastCall.args[2]).to.equal('removeOption'); @@ -2120,7 +2128,7 @@ describe('Joy ', () => { }); it('should update the input value when getOptionLabel changes', () => { - const { setProps } = render( + const { setProps, getByRole } = render( ', () => { getOptionLabel={(option) => option} />, ); - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); expect(textbox).to.have.property('value', 'one'); setProps({ getOptionLabel: (option: string) => option.toUpperCase(), @@ -2137,7 +2145,7 @@ describe('Joy ', () => { }); it('should not update the input value when users is focusing', () => { - const { setProps } = render( + const { setProps, getByRole } = render( ', () => { autoFocus />, ); - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); expect(textbox).to.have.property('value', 'one'); fireEvent.change(textbox, { target: { value: 'a' } }); setProps({ @@ -2461,7 +2469,7 @@ describe('Joy ', () => { }); it('should not be able to delete the tag when multiple=true', () => { - const { container } = render( + const { container, getByRole } = render( ', () => { />, ); - const textbox = screen.getByRole('combobox'); + const textbox = getByRole('combobox'); act(() => { textbox.focus(); }); diff --git a/packages/mui-joy/src/Box/Box.test.tsx b/packages/mui-joy/src/Box/Box.test.tsx index 87644fe248ef20..286e4ecca53a80 100644 --- a/packages/mui-joy/src/Box/Box.test.tsx +++ b/packages/mui-joy/src/Box/Box.test.tsx @@ -28,7 +28,7 @@ describe('Joy ', () => { })); it('respects theme from context', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -93,7 +93,7 @@ describe('Joy ', () => { }); it('color', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -111,7 +111,7 @@ describe('Joy ', () => { }); it('bgcolor', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -129,7 +129,7 @@ describe('Joy ', () => { }); it('backgroundColor', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -147,7 +147,7 @@ describe('Joy ', () => { }); it('borderRadius', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -168,7 +168,7 @@ describe('Joy ', () => { }); it('boxShadow', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -186,7 +186,7 @@ describe('Joy ', () => { }); it('fontSize', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -204,7 +204,7 @@ describe('Joy ', () => { }); it('fontWeight', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -222,7 +222,7 @@ describe('Joy ', () => { }); it('lineHeight', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); diff --git a/packages/mui-joy/src/Button/Button.test.tsx b/packages/mui-joy/src/Button/Button.test.tsx index 47e10fce89fec8..208313d30c8598 100644 --- a/packages/mui-joy/src/Button/Button.test.tsx +++ b/packages/mui-joy/src/Button/Button.test.tsx @@ -137,7 +137,7 @@ describe('Joy
); } - const { setProps, getByRole } = render(, { strict: reactMajor <= 18 }); + const { setProps } = render(, { strict: reactMajor <= 18 }); expect(screen.getByTestId('root')).toHaveFocus(); act(() => { - getByRole('textbox').focus(); + screen.getByRole('textbox').focus(); }); - expect(getByRole('textbox')).not.toHaveFocus(); + expect(screen.getByRole('textbox')).not.toHaveFocus(); setProps({ isEnabled: () => false }); act(() => { - getByRole('textbox').focus(); + screen.getByRole('textbox').focus(); }); - expect(getByRole('textbox')).toHaveFocus(); + expect(screen.getByRole('textbox')).toHaveFocus(); }); it('restores focus when closed', () => { diff --git a/packages/mui-material/src/Zoom/Zoom.test.js b/packages/mui-material/src/Zoom/Zoom.test.js index 211df55f1b18ae..4f9ff28b94c495 100644 --- a/packages/mui-material/src/Zoom/Zoom.test.js +++ b/packages/mui-material/src/Zoom/Zoom.test.js @@ -122,7 +122,7 @@ describe('', () => { describe('prop: timeout', () => { it('should render the default theme values by default', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -141,7 +141,7 @@ describe('', () => { }); it('should render the custom theme values', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -165,7 +165,7 @@ describe('', () => { }); it('should render the values provided via prop', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } diff --git a/packages/mui-material/src/internal/SwitchBase.test.js b/packages/mui-material/src/internal/SwitchBase.test.js index 303e49bac1b679..6efec79f5f1b86 100644 --- a/packages/mui-material/src/internal/SwitchBase.test.js +++ b/packages/mui-material/src/internal/SwitchBase.test.js @@ -369,7 +369,7 @@ describe('', () => { }); describe('focus/blur', () => { - it('forwards focus/blur events and notifies the FormControl', () => { + it('forwards focus/blur events and notifies the FormControl', async () => { function FocusMonitor(props) { const { focused } = useFormControl(); @@ -391,14 +391,14 @@ describe('', () => { ); const checkbox = getByRole('checkbox'); - act(() => { + await act(async () => { checkbox.focus(); }); expect(getByTestId('focus-monitor')).to.have.text('focused: true'); expect(handleFocus.callCount).to.equal(1); - act(() => { + await act(async () => { checkbox.blur(); }); @@ -409,7 +409,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(); } @@ -422,7 +422,7 @@ describe('', () => { expect(() => { setProps({ checked: true }); - global.didWarnControlledToUncontrolled = true; + globalThis.didWarnControlledToUncontrolled = true; }).toErrorDev([ reactMajor === 16 && 'Warning: A component is changing an uncontrolled input of type checkbox to be controlled.', @@ -435,7 +435,7 @@ describe('', () => { }); it('should error when controlled and changed to uncontrolled', function test() { - if (global.didWarnControlledToUncontrolled) { + if (globalThis.didWarnControlledToUncontrolled) { this.skip(); } @@ -448,7 +448,7 @@ describe('', () => { expect(() => { setProps({ checked: undefined }); - global.didWarnControlledToUncontrolled = true; + globalThis.didWarnControlledToUncontrolled = true; }).toErrorDev([ reactMajor === 16 && 'Warning: A component is changing an uncontrolled input of type checkbox to be controlled.', diff --git a/packages/mui-material/src/internal/animate.test.js b/packages/mui-material/src/internal/animate.test.js index 239c2c48dddfcd..461c95289fc1b3 100644 --- a/packages/mui-material/src/internal/animate.test.js +++ b/packages/mui-material/src/internal/animate.test.js @@ -1,22 +1,15 @@ import { expect } from 'chai'; +import describeSkipIf from '@mui/internal-test-utils/describeSkipIf'; import animate from './animate'; -describe('animate', () => { +const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); +const isJSDOM = window.navigator.userAgent.includes('jsdom'); + +describeSkipIf(isJSDOM || isSafari)('animate', () => { let container; + // eslint-disable-next-line mocha/no-top-level-hooks 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', @@ -30,40 +23,44 @@ describe('animate', () => { document.body.appendChild(container); }); + // eslint-disable-next-line mocha/no-top-level-hooks after(() => { if (container !== undefined) { document.body.removeChild(container); } }); - it('should work', (done) => { - container.scrollLeft = 200; - expect(container.scrollLeft).to.equal(200); - animate('scrollLeft', container, 300, {}, (err) => { - expect(err).to.equal(null); - expect(container.scrollLeft).to.equal(300); - done(); - }); - }); + it('should work', () => + new Promise((done) => { + container.scrollLeft = 200; + expect(container.scrollLeft).to.equal(200); + animate('scrollLeft', container, 300, {}, (err) => { + expect(err).to.equal(null); + expect(container.scrollLeft).to.equal(300); + done(); + }); + })); - it('should work when asking for the current value', (done) => { - container.scrollLeft = 200; - expect(container.scrollLeft).to.equal(200); - animate('scrollLeft', container, 200, {}, (err) => { - expect(err.message).to.equal('Element already at target position'); + it('should work when asking for the current value', () => + new Promise((done) => { + container.scrollLeft = 200; expect(container.scrollLeft).to.equal(200); - done(); - }); - }); + animate('scrollLeft', container, 200, {}, (err) => { + expect(err.message).to.equal('Element already at target position'); + expect(container.scrollLeft).to.equal(200); + done(); + }); + })); - it('should be able to cancel the animation', (done) => { - container.scrollLeft = 200; - expect(container.scrollLeft).to.equal(200); - const cancel = animate('scrollLeft', container, 300, {}, (err) => { - expect(err.message).to.equal('Animation cancelled'); + it('should be able to cancel the animation', () => + new Promise((done) => { + container.scrollLeft = 200; expect(container.scrollLeft).to.equal(200); - done(); - }); - cancel(); - }); + const cancel = animate('scrollLeft', container, 300, {}, (err) => { + expect(err.message).to.equal('Animation cancelled'); + expect(container.scrollLeft).to.equal(200); + done(); + }); + cancel(); + })); }); diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.test.js b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js index 067b4392e6c728..e34307a8dc87f3 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.test.js +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js @@ -335,7 +335,10 @@ describe('[Material UI] ThemeProviderWithVars', () => { }); it("should use numeric values in system's spacing", function test() { - if (/jsdom/.test(window.navigator.userAgent) || !/WebKit/.test(window.navigator.userAgent)) { + if ( + window.navigator.userAgent.includes('jsdom') || + !/WebKit/.test(window.navigator.userAgent) + ) { this.skip(); } @@ -468,13 +471,13 @@ describe('[Material UI] ThemeProviderWithVars', () => { ); } - const { container } = render(); + const view = render(); - expect(container).to.have.text(`2 light`); + expect(view.container).to.have.text(`2 light`); fireEvent.click(screen.getByRole('button')); - expect(container).to.have.text(`2 light`); + expect(view.container).to.have.text(`2 light`); }); it('palette mode should change if not using CSS variables', () => { @@ -503,13 +506,13 @@ describe('[Material UI] ThemeProviderWithVars', () => { ); } - const { container } = render(); + const view = render(); - expect(container).to.have.text(`2 light ${createTheme().palette.primary.main}`); + expect(view.container).to.have.text(`2 light ${createTheme().palette.primary.main}`); fireEvent.click(screen.getByRole('button')); - expect(container).to.have.text( + expect(view.container).to.have.text( `3 dark ${createTheme({ palette: { mode: 'dark' } }).palette.primary.main}`, ); }); @@ -540,12 +543,12 @@ describe('[Material UI] ThemeProviderWithVars', () => { ); } - const { container } = render(); + const view = render(); - expect(container).to.have.text(`2 light`); + expect(view.container).to.have.text(`2 light`); fireEvent.click(screen.getByRole('button')); - expect(container).to.have.text(`3 dark`); + expect(view.container).to.have.text(`3 dark`); }); }); diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index d75bf230279f75..c8c616665a82d0 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -476,7 +476,7 @@ describe('createTheme', () => { }); it('should apply the correct borderRadius styles via sx prop if theme values are 0', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); diff --git a/packages/mui-material/src/styles/extendTheme.test.js b/packages/mui-material/src/styles/extendTheme.test.js index a6b334bf9bf167..4477dbad97021a 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/useAutocomplete/useAutocomplete.test.js b/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js index 81b9468b90d694..209d0bb323a93d 100644 --- a/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js +++ b/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js @@ -51,9 +51,9 @@ describe('useAutocomplete', () => { ); } - const { rerender } = render(); + const view = render(); const [fooOptionAsFirst, barOptionAsSecond] = screen.getAllByRole('option'); - rerender(); + view.rerender(); const [barOptionAsFirst, fooOptionAsSecond] = screen.getAllByRole('option'); // If the DOM nodes are not preserved VO will not read the first option again since it thinks it didn't change. @@ -242,7 +242,7 @@ describe('useAutocomplete', () => { it('should warn if the input is not binded', function test() { // TODO is this fixed? - if (!/jsdom/.test(window.navigator.userAgent)) { + if (!window.navigator.userAgent.includes('jsdom')) { // can't catch render errors in the browser for unknown reason // tried try-catch + error boundary + window onError preventDefault this.skip(); diff --git a/packages/mui-material/src/useMediaQuery/useMediaQuery.test.js b/packages/mui-material/src/useMediaQuery/useMediaQuery.test.js index 2f1059ef72926c..f717ac171fc271 100644 --- a/packages/mui-material/src/useMediaQuery/useMediaQuery.test.js +++ b/packages/mui-material/src/useMediaQuery/useMediaQuery.test.js @@ -247,11 +247,11 @@ describe('useMediaQuery', () => { ); } - const { unmount } = render(); + const view = render(); expect(screen.getByTestId('matches').textContent).to.equal('false'); expect(getRenderCountRef.current()).to.equal(usesUseSyncExternalStore ? 1 : 2); - unmount(); + view.unmount(); render(); expect(screen.getByTestId('matches').textContent).to.equal('false'); diff --git a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js index fceb9a8e08df8e..bca4b55e9c25f2 100644 --- a/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js +++ b/packages/mui-material/src/useScrollTrigger/useScrollTrigger.test.js @@ -2,6 +2,7 @@ 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 describeSkipIf from '@mui/internal-test-utils/describeSkipIf'; import useScrollTrigger from '@mui/material/useScrollTrigger'; import Container from '@mui/material/Container'; import Box from '@mui/material/Box'; @@ -68,7 +69,7 @@ describe('useScrollTrigger', () => { }); }); - describe('scroll', () => { + describeSkipIf(!window.navigator.userAgent.includes('jsdom'))('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 @@ -95,13 +96,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..8911b1bbe7fa9c 100644 --- a/packages/mui-material/test/integration/Menu.test.js +++ b/packages/mui-material/test/integration/Menu.test.js @@ -314,11 +314,15 @@ describe(' integration', () => { 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 act(async () => { + fireEvent.keyDown(screen.getAllByRole('menuitem')[0], { key: 'Tab' }); + }); clock.tick(0); expect(screen.getByRole('menu', { hidden: true })).toBeInaccessible(); diff --git a/packages/mui-material/test/integration/MenuList.test.js b/packages/mui-material/test/integration/MenuList.test.js index 957b23c2fe8a2e..feea2491fcc471 100644 --- a/packages/mui-material/test/integration/MenuList.test.js +++ b/packages/mui-material/test/integration/MenuList.test.js @@ -529,7 +529,7 @@ describe(' integration', () => { }); it('should not get focusVisible class on click', async function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // JSDOM doesn't support :focus-visible this.skip(); } diff --git a/packages/mui-material/test/integration/PopperChildrenLayout.test.js b/packages/mui-material/test/integration/PopperChildrenLayout.test.js index 507ad32719ea8e..4642723cb02759 100644 --- a/packages/mui-material/test/integration/PopperChildrenLayout.test.js +++ b/packages/mui-material/test/integration/PopperChildrenLayout.test.js @@ -2,6 +2,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; import { createRenderer } from '@mui/internal-test-utils'; +import describeSkipIf from '@mui/internal-test-utils/describeSkipIf'; import Collapse from '@mui/material/Collapse'; import Fade from '@mui/material/Fade'; import Grow from '@mui/material/Grow'; @@ -9,27 +10,21 @@ 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(window.navigator.userAgent.includes('jsdom'))('', () => { + 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); }); diff --git a/packages/mui-styled-engine-sc/src/GlobalStyles/GlobalStyles.test.js b/packages/mui-styled-engine-sc/src/GlobalStyles/GlobalStyles.test.js index 85f44f455476d0..e10d2594efe6cd 100644 --- a/packages/mui-styled-engine-sc/src/GlobalStyles/GlobalStyles.test.js +++ b/packages/mui-styled-engine-sc/src/GlobalStyles/GlobalStyles.test.js @@ -9,7 +9,7 @@ describe('GlobalStyles', () => { const { render } = createRenderer(); it('should add global styles', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -26,7 +26,7 @@ describe('GlobalStyles', () => { }); it('should add global styles using JS syntax', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -43,7 +43,7 @@ describe('GlobalStyles', () => { }); it('should add global styles using function', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -71,7 +71,7 @@ describe('GlobalStyles', () => { }); it('should give precedence to styled()', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -92,7 +92,7 @@ describe('GlobalStyles', () => { }); it('should give precedence to styled() using JS syntax', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } diff --git a/packages/mui-styled-engine/src/GlobalStyles/GlobalStyles.test.js b/packages/mui-styled-engine/src/GlobalStyles/GlobalStyles.test.js index 500a5dfdfce657..30c9bf6b2da3ac 100644 --- a/packages/mui-styled-engine/src/GlobalStyles/GlobalStyles.test.js +++ b/packages/mui-styled-engine/src/GlobalStyles/GlobalStyles.test.js @@ -9,7 +9,7 @@ describe('GlobalStyles', () => { const { render } = createRenderer(); it('should add global styles', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -26,7 +26,7 @@ describe('GlobalStyles', () => { }); it('should add global styles using JS syntax', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -43,7 +43,7 @@ describe('GlobalStyles', () => { }); it('should add global styles using function', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -71,7 +71,7 @@ describe('GlobalStyles', () => { }); it('should give precedence to styled()', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -92,7 +92,7 @@ describe('GlobalStyles', () => { }); it('should give precedence to styled() using JS syntax', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } diff --git a/packages/mui-system/src/Box/Box.test.js b/packages/mui-system/src/Box/Box.test.js index 227b6c6955e737..b39bd3f370e167 100644 --- a/packages/mui-system/src/Box/Box.test.js +++ b/packages/mui-system/src/Box/Box.test.js @@ -58,7 +58,7 @@ describe('', () => { }); it('respect properties order when generating the CSS', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -100,7 +100,7 @@ describe('', () => { }); it('respect border-*-color properties order when generating the CSS', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -164,7 +164,7 @@ describe('', () => { }); it('respect properties order when generating the CSS from the sx prop', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); @@ -285,7 +285,7 @@ describe('', () => { describe('prop: maxWidth', () => { it('should resolve breakpoints with custom units', function test() { - const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const isJSDOM = window.navigator.userAgent.includes('jsdom'); if (isJSDOM) { this.skip(); diff --git a/packages/mui-system/src/Grid/Grid.test.js b/packages/mui-system/src/Grid/Grid.test.js index af0ae24ec5cc41..ea813110b22ad9 100644 --- a/packages/mui-system/src/Grid/Grid.test.js +++ b/packages/mui-system/src/Grid/Grid.test.js @@ -48,7 +48,7 @@ describe('System ', () => { }); it('should apply the styles necessary for variable width nested item when set to auto', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { // Need full CSS resolution this.skip(); } @@ -118,7 +118,7 @@ describe('System ', () => { describe('spacing', () => { it('should generate the right values', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -128,7 +128,7 @@ describe('System ', () => { spacing: (factor) => `${0.25 * factor}rem`, }); - const { rerender } = render( + const view = render(
@@ -144,7 +144,7 @@ describe('System ', () => { columnGap: `${0.5 * remValue}px`, // 0.5rem }); - rerender( + view.rerender(
@@ -179,16 +179,16 @@ describe('System ', () => { }); it('should apply nowrap class and style', () => { - const { container } = render(); - expect(container.firstChild).to.have.class('MuiGrid-wrap-xs-nowrap'); + const view = render(); + expect(view.container.firstChild).to.have.class('MuiGrid-wrap-xs-nowrap'); expect(screen.getByTestId('wrap')).toHaveComputedStyle({ flexWrap: 'nowrap', }); }); it('should apply wrap-reverse class and style', () => { - const { container } = render(); - expect(container.firstChild).to.have.class('MuiGrid-wrap-xs-wrap-reverse'); + const view = render(); + expect(view.container.firstChild).to.have.class('MuiGrid-wrap-xs-wrap-reverse'); expect(screen.getByTestId('wrap')).toHaveComputedStyle({ flexWrap: 'wrap-reverse', }); diff --git a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js index 02baa5f52f06ff..c1b0aab6c5e971 100644 --- a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js +++ b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js @@ -21,7 +21,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/createTheme/createTheme.test.js b/packages/mui-system/src/createTheme/createTheme.test.js index f61d382625f914..2f0459ed322f31 100644 --- a/packages/mui-system/src/createTheme/createTheme.test.js +++ b/packages/mui-system/src/createTheme/createTheme.test.js @@ -58,7 +58,7 @@ describe('createTheme', () => { describe('system', () => { it('resolves system when used inside styled()', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } @@ -96,7 +96,7 @@ describe('createTheme', () => { }); it('resolves system when used inside variants', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { + if (window.navigator.userAgent.includes('jsdom')) { this.skip(); } diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js index 9c699b7f1ff7ee..bdcc56800ebd23 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js @@ -105,7 +105,7 @@ describe('createCssVarsProvider', () => { const { allColorSchemes } = useColorScheme(); return
{allColorSchemes.join(',')}
; } - const { rerender } = render( + const view = render( , @@ -113,7 +113,7 @@ describe('createCssVarsProvider', () => { expect(screen.getByTestId('all-colorSchemes').textContent).to.equal('light,dark'); - rerender( + view.rerender( { @@ -61,14 +60,15 @@ describe('deepmerge', () => { expect({}).not.to.have.property('isAdmin'); }); - it('should merge objects across realms', function test() { - if (!/jsdom/.test(window.navigator.userAgent)) { + it('should merge objects across realms', async function test() { + if (!window.navigator.userAgent.includes('jsdom')) { // vm is only available in Node.js. // We could use https://github.com/browserify/vm-browserify to run the test in an iframe when // in Karma but it doesn't seem we need to go as far. this.skip(); } + const { runInNewContext } = await import('vm'); const vmObject = runInNewContext('({hello: "realm"})'); const result = deepmerge({ hello: 'original' }, vmObject); expect(result.hello).to.equal('realm'); diff --git a/packages/mui-utils/src/elementAcceptingRef/elementAcceptingRef.test.tsx b/packages/mui-utils/src/elementAcceptingRef/elementAcceptingRef.test.tsx index 259f3c46770c90..fb0c1bec7e61dc 100644 --- a/packages/mui-utils/src/elementAcceptingRef/elementAcceptingRef.test.tsx +++ b/packages/mui-utils/src/elementAcceptingRef/elementAcceptingRef.test.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { expect } from 'chai'; import PropTypes from 'prop-types'; import { createRenderer, waitFor, reactMajor } from '@mui/internal-test-utils'; +import describeSkipIf from '@mui/internal-test-utils/describeSkipIf'; import elementAcceptingRef from './elementAcceptingRef'; describe('elementAcceptingRef', () => { @@ -21,14 +22,7 @@ describe('elementAcceptingRef', () => { PropTypes.resetWarningCache(); }); - describe('acceptance when not required', () => { - before(function beforeCallback() { - if (reactMajor >= 19) { - // React 19 removed prop types support - this.skip(); - } - }); - + describeSkipIf(reactMajor >= 19)('acceptance when not required', () => { function assertPass(element: any, { shouldMount = true } = {}) { function testAct() { checkPropType(element); @@ -113,14 +107,7 @@ describe('elementAcceptingRef', () => { }); }); - describe('rejections', () => { - before(function beforeCallback() { - if (reactMajor >= 19) { - // React 19 removed prop types support - this.skip(); - } - }); - + describeSkipIf(reactMajor >= 19)('rejections', () => { function assertFail(Component: any, hint: string) { expect(() => { checkPropType(Component); diff --git a/packages/mui-utils/src/getScrollbarSize/getScrollbarSize.test.ts b/packages/mui-utils/src/getScrollbarSize/getScrollbarSize.test.ts index 75409922795a6b..a80674f6fd08ad 100644 --- a/packages/mui-utils/src/getScrollbarSize/getScrollbarSize.test.ts +++ b/packages/mui-utils/src/getScrollbarSize/getScrollbarSize.test.ts @@ -16,7 +16,10 @@ describe('getScrollbarSize', () => { }); it('should return correct value when using a custom scrollbar', function test() { - if (/jsdom/.test(window.navigator.userAgent) || !/WebKit/.test(window.navigator.userAgent)) { + if ( + window.navigator.userAgent.includes('jsdom') || + !/WebKit/.test(window.navigator.userAgent) + ) { this.skip(); } diff --git a/packages/mui-utils/src/isFocusVisible/isFocusVisible.ts b/packages/mui-utils/src/isFocusVisible/isFocusVisible.ts index e45c3660340d93..54a3d21fd1784c 100644 --- a/packages/mui-utils/src/isFocusVisible/isFocusVisible.ts +++ b/packages/mui-utils/src/isFocusVisible/isFocusVisible.ts @@ -7,7 +7,7 @@ export default function isFocusVisible(element: Element): boolean { } catch (error) { // Do not warn on jsdom tests, otherwise all tests that rely on focus have to be skipped // Tests that rely on `:focus-visible` will still have to be skipped in jsdom - if (process.env.NODE_ENV !== 'production' && !/jsdom/.test(window.navigator.userAgent)) { + if (process.env.NODE_ENV !== 'production' && !window.navigator.userAgent.includes('jsdom')) { console.warn( [ 'MUI: The `:focus-visible` pseudo class is not supported in this browser.', diff --git a/packages/mui-utils/src/useForkRef/useForkRef.test.tsx b/packages/mui-utils/src/useForkRef/useForkRef.test.tsx index 7564de2637127a..3369318f5ac318 100644 --- a/packages/mui-utils/src/useForkRef/useForkRef.test.tsx +++ b/packages/mui-utils/src/useForkRef/useForkRef.test.tsx @@ -48,9 +48,8 @@ describe('useForkRef', () => { expect(() => { render(); + expect(screen.getByTestId('hasRef')).to.have.text('true'); }).not.toErrorDev(); - - expect(screen.getByTestId('hasRef')).to.have.text('true'); }); it('does nothing if none of the forked branches requires a ref', () => { diff --git a/packages/mui-utils/src/useId/useId.test.tsx b/packages/mui-utils/src/useId/useId.test.tsx index 89b5dfadf73c6c..a0f3120aa0266b 100644 --- a/packages/mui-utils/src/useId/useId.test.tsx +++ b/packages/mui-utils/src/useId/useId.test.tsx @@ -94,7 +94,8 @@ describe('useId', () => { const id = useId(); return ; } - renderToString(); + const { hydrate } = renderToString(); + hydrate(); expect(screen.getByTestId('target').id).not.to.equal(''); }); diff --git a/packages/mui-utils/src/useIsFocusVisible/useIsFocusVisible.test.tsx b/packages/mui-utils/src/useIsFocusVisible/useIsFocusVisible.test.tsx index be35b5d2a2d875..819e978ea0b4fc 100644 --- a/packages/mui-utils/src/useIsFocusVisible/useIsFocusVisible.test.tsx +++ b/packages/mui-utils/src/useIsFocusVisible/useIsFocusVisible.test.tsx @@ -8,6 +8,7 @@ import { simulatePointerDevice, programmaticFocusTriggersFocusVisible, } from '@mui/internal-test-utils'; +import describeSkipIf from '@mui/internal-test-utils/describeSkipIf'; import useIsFocusVisible, { teardown as teardownFocusVisible } from './useIsFocusVisible'; import useForkRef from '../useForkRef'; @@ -64,14 +65,8 @@ describe('useIsFocusVisible', () => { teardownFocusVisible(document); }); - describe('focus inside shadowRoot', () => { - before(function beforeHook() { - // Only run on HeadlessChrome which has native shadowRoot support. - if (!/HeadlessChrome/.test(window.navigator.userAgent)) { - this.skip(); - } - }); - + const isHeadlessChrome = /HeadlessChrome/.test(window.navigator.userAgent); + describeSkipIf(!isHeadlessChrome)('focus inside shadowRoot', () => { let rootElement: HTMLDivElement; let reactRoot: ReactDOMClient.Root; 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; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1abc6b78d80bb..2894c59ca295e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,9 @@ importers: execa: specifier: ^9.6.0 version: 9.6.0 + karma-spec-reporter: + specifier: ^0.0.36 + version: 0.0.36(karma@6.4.4) devDependencies: '@arethetypeswrong/cli': specifier: ^0.18.2 @@ -109,6 +112,9 @@ importers: '@types/lodash': specifier: ^4.17.20 version: 4.17.20 + '@types/lodash.kebabcase': + specifier: ^4.1.9 + version: 4.1.9 '@types/mocha': specifier: ^10.0.10 version: 10.0.10 @@ -214,6 +220,9 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 + lodash.kebabcase: + specifier: ^4.1.1 + version: 4.1.1 markdownlint-cli2: specifier: ^0.18.1 version: 0.18.1 @@ -244,6 +253,9 @@ importers: react: specifier: ^19.1.1 version: 19.1.1 + react-dom: + specifier: ^19.1.1 + version: 19.1.1(react@19.1.1) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1195,6 +1207,12 @@ importers: specifier: ^17.7.2 version: 17.7.2 devDependencies: + '@material-ui/core': + specifier: ^4.12.4 + version: 4.12.4(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@mui/material-v5': + specifier: npm:@mui/material@5.17.1 + version: '@mui/material@5.17.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)' '@types/chai': specifier: ^4.3.20 version: 4.3.20 @@ -3144,6 +3162,9 @@ packages: '@emotion/css@11.13.4': resolution: {integrity: sha512-CthbOD5EBw+iN0rfM96Tuv5kaZN4nxPyYDvGUs0bc7wZBBiU/0mse+l+0O9RshW2d+v5HH1cme+BAbLJ/3Folw==} + '@emotion/hash@0.8.0': + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} @@ -3860,6 +3881,56 @@ packages: engines: {node: '>=18'} hasBin: true + '@material-ui/core@4.12.4': + resolution: {integrity: sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==} + engines: {node: '>=8.0.0'} + deprecated: Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5. + peerDependencies: + '@types/react': ^16.8.6 || ^17.0.0 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@material-ui/styles@4.11.5': + resolution: {integrity: sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==} + engines: {node: '>=8.0.0'} + deprecated: Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5. + peerDependencies: + '@types/react': ^16.8.6 || ^17.0.0 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@material-ui/system@4.12.2': + resolution: {integrity: sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==} + engines: {node: '>=8.0.0'} + peerDependencies: + '@types/react': ^16.8.6 || ^17.0.0 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@material-ui/types@5.1.0': + resolution: {integrity: sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==} + peerDependencies: + '@types/react': '*' + peerDependenciesMeta: + '@types/react': + optional: true + + '@material-ui/utils@4.11.3': + resolution: {integrity: sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==} + engines: {node: '>=8.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + '@mswjs/interceptors@0.37.6': resolution: {integrity: sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==} engines: {node: '>=18'} @@ -3912,8 +3983,8 @@ packages: '@types/react': optional: true - '@mui/core-downloads-tracker@5.15.14': - resolution: {integrity: sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==} + '@mui/core-downloads-tracker@5.18.0': + resolution: {integrity: sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==} '@mui/internal-babel-plugin-display-name@1.0.4-canary.7': resolution: {integrity: sha512-2i7FP53GJJKR5OqHIJLh1VAhqRW+u0TwZOTeIScfg0txvgI/FW/g9m5TcHqHCU4X8NdqqS2KU8gAM1FHKG2vQA==} @@ -3978,12 +4049,29 @@ packages: '@types/react': optional: true - '@mui/private-theming@5.16.5': - resolution: {integrity: sha512-CSLg0YkpDqg0aXOxtjo3oTMd3XWMxvNb5d0v4AYVqwOltU8q6GvnZjhWyCLjGSCrcgfwm6/VDjaKLPlR14wxIA==} + '@mui/material@5.17.1': + resolution: {integrity: sha512-2B33kQf+GmPnrvXXweWAx+crbiUEsxCdCN979QDYnlH9ox4pd+0/IBriWLV+l6ORoBF60w39cWjFnJYGFdzXcw==} engines: {node: '>=12.0.0'} peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + '@emotion/react': ^11.5.0 + '@emotion/styled': ^11.3.0 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + '@types/react': + optional: true + + '@mui/private-theming@5.17.1': + resolution: {integrity: sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -3998,13 +4086,13 @@ packages: '@types/react': optional: true - '@mui/styled-engine@5.16.4': - resolution: {integrity: sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==} + '@mui/styled-engine@5.18.0': + resolution: {integrity: sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.4.1 '@emotion/styled': ^11.3.0 - react: ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -4024,14 +4112,14 @@ packages: '@emotion/styled': optional: true - '@mui/system@5.16.5': - resolution: {integrity: sha512-uzIUGdrWddUx1HPxW4+B2o4vpgKyRxGe/8BxbfXVDPNPHX75c782TseoCnR/VyfnZJfqX87GcxDmnZEE1c031g==} + '@mui/system@5.18.0': + resolution: {integrity: sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -5537,6 +5625,9 @@ packages: '@types/katex@0.16.7': resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + '@types/lodash.kebabcase@4.1.9': + resolution: {integrity: sha512-kPrrmcVOhSsjAVRovN0lRfrbuidfg0wYsrQa5IYuoQO1fpHHGSme66oyiYA/5eQPVl8Z95OA3HG0+d2SvYC85w==} + '@types/lodash@4.17.20': resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} @@ -7221,6 +7312,9 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-vendor@2.0.8: + resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -7242,6 +7336,9 @@ packages: resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==} engines: {node: '>=18'} + csstype@2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -8779,6 +8876,9 @@ packages: resolution: {integrity: sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==} engines: {node: '>=4'} + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -9403,9 +9503,30 @@ packages: resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==} engines: {node: '>=12', npm: '>=6'} + jss-plugin-camel-case@10.10.0: + resolution: {integrity: sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==} + + jss-plugin-default-unit@10.10.0: + resolution: {integrity: sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==} + + jss-plugin-global@10.10.0: + resolution: {integrity: sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==} + + jss-plugin-nested@10.10.0: + resolution: {integrity: sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==} + + jss-plugin-props-sort@10.10.0: + resolution: {integrity: sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==} + + jss-plugin-rule-value-function@10.10.0: + resolution: {integrity: sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==} + jss-plugin-template@10.10.0: resolution: {integrity: sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==} + jss-plugin-vendor-prefixer@10.10.0: + resolution: {integrity: sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==} + jss-rtl@0.3.0: resolution: {integrity: sha512-rg9jJmP1bAyhNOAp+BDZgOP/lMm4+oQ76qGueupDQ68Wq+G+6SGvCZvhIEg8OHSONRWOwFT6skCI+APGi8DgmA==} peerDependencies: @@ -9461,6 +9582,11 @@ packages: karma-sourcemap-loader@0.4.0: resolution: {integrity: sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==} + karma-spec-reporter@0.0.36: + resolution: {integrity: sha512-11bvOl1x6ryKZph7kmbmMpbi8vsngEGxGOoeTlIcDaH3ab3j8aPJnZ+r+K/SS0sBSGy5VGkGYO2+hLct7hw/6w==} + peerDependencies: + karma: '>=0.9' + karma-webpack@5.0.0: resolution: {integrity: sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA==} engines: {node: '>= 6'} @@ -9713,6 +9839,9 @@ packages: lodash.isundefined@3.0.1: resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + lodash.keys@4.2.0: resolution: {integrity: sha512-J79MkJcp7Df5mizHiVNpjoHXLi4HLjh9VLS/M7lQSGoQ+0oQ+lWEigREkqKyizPB1IawvQLLKY8mzEcm1tkyxQ==} @@ -10953,6 +11082,9 @@ packages: engines: {node: '>=18'} hasBin: true + popper.js@1.16.1-lts: + resolution: {integrity: sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -15016,6 +15148,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@emotion/hash@0.8.0': {} + '@emotion/hash@0.9.2': {} '@emotion/is-prop-valid@1.2.2': @@ -15661,6 +15795,71 @@ snapshots: - encoding - supports-color + '@material-ui/core@4.12.4(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.3 + '@material-ui/styles': 4.11.5(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@material-ui/system': 4.12.2(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@material-ui/types': 5.1.0(@types/react@19.1.11) + '@material-ui/utils': 4.11.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@types/react-transition-group': 4.4.12(@types/react@19.1.11) + clsx: 1.2.1 + hoist-non-react-statics: 3.3.2 + popper.js: 1.16.1-lts + prop-types: 15.8.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-is: 17.0.2 + react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.11 + + '@material-ui/styles@4.11.5(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.3 + '@emotion/hash': 0.8.0 + '@material-ui/types': 5.1.0(@types/react@19.1.11) + '@material-ui/utils': 4.11.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 1.2.1 + csstype: 2.6.21 + hoist-non-react-statics: 3.3.2 + jss: 10.10.0 + jss-plugin-camel-case: 10.10.0 + jss-plugin-default-unit: 10.10.0 + jss-plugin-global: 10.10.0 + jss-plugin-nested: 10.10.0 + jss-plugin-props-sort: 10.10.0 + jss-plugin-rule-value-function: 10.10.0 + jss-plugin-vendor-prefixer: 10.10.0 + prop-types: 15.8.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.11 + + '@material-ui/system@4.12.2(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.3 + '@material-ui/utils': 4.11.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + csstype: 2.6.21 + prop-types: 15.8.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.11 + + '@material-ui/types@5.1.0(@types/react@19.1.11)': + optionalDependencies: + '@types/react': 19.1.11 + + '@material-ui/utils@4.11.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.3 + prop-types: 15.8.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-is: 17.0.2 + '@mswjs/interceptors@0.37.6': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -15727,7 +15926,7 @@ snapshots: optionalDependencies: '@types/react': 19.1.11 - '@mui/core-downloads-tracker@5.15.14': {} + '@mui/core-downloads-tracker@5.18.0': {} '@mui/internal-babel-plugin-display-name@1.0.4-canary.7(@babel/core@7.28.3)(@babel/preset-react@7.27.1(@babel/core@7.28.3))': dependencies: @@ -15839,8 +16038,8 @@ snapshots: dependencies: '@babel/runtime': 7.28.3 '@mui/base': 5.0.0-beta.31(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@mui/core-downloads-tracker': 5.15.14 - '@mui/system': 5.16.5(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) + '@mui/core-downloads-tracker': 5.18.0 + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) '@mui/types': 7.4.5(@types/react@19.1.11) '@mui/utils': 5.17.1(@types/react@19.1.11)(react@19.1.1) clsx: 2.1.1 @@ -15856,8 +16055,8 @@ snapshots: dependencies: '@babel/runtime': 7.28.3 '@mui/base': 5.0.0-beta.31(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@mui/core-downloads-tracker': 5.15.14 - '@mui/system': 5.16.5(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) + '@mui/core-downloads-tracker': 5.18.0 + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) '@mui/types': 7.4.5(@types/react@19.1.11) '@mui/utils': 5.17.1(@types/react@19.1.11)(react@19.1.1) '@types/react-transition-group': 4.4.12(@types/react@19.1.11) @@ -15873,7 +16072,28 @@ snapshots: '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) '@types/react': 19.1.11 - '@mui/private-theming@5.16.5(@types/react@19.1.11)(react@19.1.1)': + '@mui/material@5.17.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.3 + '@mui/core-downloads-tracker': 5.18.0 + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) + '@mui/types': 7.2.24(@types/react@19.1.11) + '@mui/utils': 5.17.1(@types/react@19.1.11)(react@19.1.1) + '@popperjs/core': 2.11.8 + '@types/react-transition-group': 4.4.12(@types/react@19.1.11) + clsx: 2.1.1 + csstype: 3.1.3 + prop-types: 15.8.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-is: 19.1.1 + react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@19.1.11)(react@19.1.1) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) + '@types/react': 19.1.11 + + '@mui/private-theming@5.17.1(@types/react@19.1.11)(react@19.1.1)': dependencies: '@babel/runtime': 7.28.3 '@mui/utils': 5.17.1(@types/react@19.1.11)(react@19.1.1) @@ -15891,10 +16111,11 @@ snapshots: optionalDependencies: '@types/react': 19.1.11 - '@mui/styled-engine@5.16.4(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(react@19.1.1)': + '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(react@19.1.1)': dependencies: '@babel/runtime': 7.28.3 '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 csstype: 3.1.3 prop-types: 15.8.1 react: 19.1.1 @@ -15915,12 +16136,12 @@ snapshots: '@emotion/react': 11.14.0(@types/react@19.1.11)(react@19.1.1) '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1) - '@mui/system@5.16.5(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1)': + '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1)': dependencies: '@babel/runtime': 7.28.3 - '@mui/private-theming': 5.16.5(@types/react@19.1.11)(react@19.1.1) - '@mui/styled-engine': 5.16.4(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(react@19.1.1) - '@mui/types': 7.4.5(@types/react@19.1.11) + '@mui/private-theming': 5.17.1(@types/react@19.1.11)(react@19.1.1) + '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(react@19.1.1) + '@mui/types': 7.2.24(@types/react@19.1.11) '@mui/utils': 5.17.1(@types/react@19.1.11)(react@19.1.1) clsx: 2.1.1 csstype: 3.1.3 @@ -17710,6 +17931,10 @@ snapshots: '@types/katex@0.16.7': {} + '@types/lodash.kebabcase@4.1.9': + dependencies: + '@types/lodash': 4.17.20 + '@types/lodash@4.17.20': {} '@types/mdast@4.0.4': @@ -19756,6 +19981,11 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 + css-vendor@2.0.8: + dependencies: + '@babel/runtime': 7.28.3 + is-in-browser: 1.1.3 + css-what@6.1.0: {} cssesc@3.0.0: {} @@ -19771,6 +20001,8 @@ snapshots: '@asamuzakjp/css-color': 2.8.3 rrweb-cssom: 0.8.0 + csstype@2.6.21: {} + csstype@3.1.3: {} custom-event@1.0.1: {} @@ -21672,6 +21904,8 @@ snapshots: hyperlinker@1.0.0: {} + hyphenate-style-name@1.1.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -22277,12 +22511,51 @@ snapshots: ms: 2.1.3 semver: 7.7.2 + jss-plugin-camel-case@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + hyphenate-style-name: 1.1.0 + jss: 10.10.0 + + jss-plugin-default-unit@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + jss: 10.10.0 + + jss-plugin-global@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + jss: 10.10.0 + + jss-plugin-nested@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-props-sort@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + jss: 10.10.0 + + jss-plugin-rule-value-function@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + jss: 10.10.0 + tiny-warning: 1.0.3 + jss-plugin-template@10.10.0: dependencies: '@babel/runtime': 7.28.3 jss: 10.10.0 tiny-warning: 1.0.3 + jss-plugin-vendor-prefixer@10.10.0: + dependencies: + '@babel/runtime': 7.28.3 + css-vendor: 2.0.8 + jss: 10.10.0 + jss-rtl@0.3.0(jss@10.10.0): dependencies: jss: 10.10.0 @@ -22364,6 +22637,11 @@ snapshots: dependencies: graceful-fs: 4.2.11 + karma-spec-reporter@0.0.36(karma@6.4.4): + dependencies: + colors: 1.4.0 + karma: 6.4.4 + karma-webpack@5.0.0(webpack@5.101.3): dependencies: glob: 7.2.3 @@ -22702,6 +22980,8 @@ snapshots: lodash.isundefined@3.0.1: {} + lodash.kebabcase@4.1.1: {} + lodash.keys@4.2.0: {} lodash.mapvalues@4.6.0: {} @@ -24221,6 +24501,8 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + popper.js@1.16.1-lts: {} + possible-typed-array-names@1.0.0: {} postcss-cli@11.0.1(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.4): diff --git a/stylelint.config.mjs b/stylelint.config.mjs index ca13b1c788288e..39707dd541c722 100644 --- a/stylelint.config.mjs +++ b/stylelint.config.mjs @@ -11,7 +11,7 @@ export default { }, overrides: [ { - files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.tsx'], + files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.mts', '**/*.ts', '**/*.tsx'], customSyntax: 'postcss-styled-syntax', }, { diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index a99e474870a360..92cd9aeccff45f 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -94,7 +94,7 @@ describe('e2e', () => { } before(async function beforeHook() { - this.timeout(20000); + this?.timeout?.(20000); browser = await chromium.launch({ headless: true, diff --git a/test/integration/mui-system/theme-scoping.test.tsx b/test/integration/mui-system/theme-scoping.test.tsx index 0b56ea104aa38f..e395c06553985b 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) => { diff --git a/test/karma.conf.js b/test/karma.conf.js index e38f4568f3e9e7..fd0995105ce51c 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -85,6 +85,7 @@ module.exports = function setKarmaConfig(config) { 'karma-sourcemap-loader', 'karma-webpack', 'karma-firefox-launcher', + 'karma-spec-reporter', ], /** * possible values: @@ -105,7 +106,7 @@ module.exports = function setKarmaConfig(config) { }, // The CI branch fixes double log issue // https://github.com/karma-runner/karma/issues/2342 - reporters: ['dots', ...(CI ? ['coverage-istanbul'] : [])], + reporters: CI ? ['dots', 'coverage-istanbul'] : ['spec'], webpack: { mode: 'development', devtool: CI ? 'inline-source-map' : 'eval-source-map', @@ -199,7 +200,7 @@ module.exports = function setKarmaConfig(config) { customLaunchers: { chromeHeadless: { base: 'ChromeHeadless', - flags: ['--no-sandbox'], + flags: ['--no-sandbox', '--use-mock-keychain'], }, }, singleRun: CI, diff --git a/test/regressions/index.test.js b/test/regressions/index.test.js index 0878a1bb434998..4c31f934242137 100644 --- a/test/regressions/index.test.js +++ b/test/regressions/index.test.js @@ -110,7 +110,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);