diff --git a/.mocharc.js b/.mocharc.js index 9425179503b39a..55786c4cf30aed 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -20,4 +20,7 @@ module.exports = { '**/build/**', 'docs/.next/**', ], + // detect-modules doesn't work with @babel/register + // https://github.com/babel/babel/issues/6737 + 'node-option': ['no-experimental-detect-module'], }; diff --git a/package.json b/package.json index 4cac32afb30e5a..d48330b2b05432 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,7 @@ "@pigment-css/react": "0.0.30", "@playwright/test": "1.51.1", "@types/babel__core": "^7.20.5", + "@types/babel__register": "^7.17.3", "@types/fs-extra": "^11.0.4", "@types/lodash": "^4.17.16", "@types/mocha": "^10.0.10", diff --git a/packages-internal/test-utils/src/createRenderer.tsx b/packages-internal/test-utils/src/createRenderer.tsx index 0a9b92539bfbbd..f6f9cfa64cf367 100644 --- a/packages-internal/test-utils/src/createRenderer.tsx +++ b/packages-internal/test-utils/src/createRenderer.tsx @@ -12,6 +12,7 @@ import { screen as rtlScreen, Screen, render as testingLibraryRender, + RenderOptions as TestingLibraryRenderOptions, within, } from '@testing-library/react/pure'; import { userEvent } from '@testing-library/user-event'; @@ -201,7 +202,7 @@ const customQueries = { findAllDescriptionsOf, }; -interface RenderConfiguration { +interface RenderConfiguration extends Pick { /** * https://testing-library.com/docs/react-testing-library/api#container */ @@ -232,7 +233,7 @@ interface ServerRenderConfiguration extends RenderConfiguration { container: HTMLElement; } -export type RenderOptions = Partial; +export type RenderOptions = Omit, 'reactStrictMode'>; export interface MuiRenderResult extends RenderResult { user: ReturnType; @@ -256,7 +257,7 @@ function render( element: React.ReactElement, configuration: ClientRenderConfiguration, ): MuiRenderResult { - const { container, hydrate, wrapper } = configuration; + const { container, hydrate, wrapper, reactStrictMode } = configuration; const testingLibraryRenderResult = traceSync('render', () => testingLibraryRender(element, { @@ -264,6 +265,7 @@ function render( hydrate, queries: { ...queries, ...customQueries }, wrapper, + reactStrictMode, }), ); const result: MuiRenderResult = { @@ -628,24 +630,16 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende serverContainer = null!; }); - function createWrapper(options: Partial) { - const { - strict = globalStrict, - strictEffects = globalStrictEffects, - wrapper: InnerWrapper = React.Fragment, - } = options; + function createWrapper(options: Pick) { + const { wrapper: InnerWrapper = React.Fragment } = options; - const usesLegacyRoot = reactMajor < 18; - const Mode = strict && (strictEffects || usesLegacyRoot) ? React.StrictMode : React.Fragment; return function Wrapper({ children }: { children?: React.ReactNode }) { return ( - - - - {children} - - - + + + {children} + + ); }; } @@ -661,8 +655,14 @@ export function createRenderer(globalOptions: CreateRendererOptions = {}): Rende ); } + const usesLegacyRoot = reactMajor < 18; + const reactStrictMode = + (options.strict ?? globalStrict) && + ((options.strictEffects ?? globalStrictEffects) || usesLegacyRoot); + return render(element, { ...options, + reactStrictMode, hydrate: false, wrapper: createWrapper(options), }); diff --git a/packages-internal/test-utils/src/setupBabel.js b/packages-internal/test-utils/src/setupBabel.js index 02f5188fccc980..5ed7605010d0f7 100644 --- a/packages-internal/test-utils/src/setupBabel.js +++ b/packages-internal/test-utils/src/setupBabel.js @@ -1,3 +1,3 @@ require('@babel/register')({ - extensions: ['.js', '.mjs', '.ts', '.tsx'], + extensions: ['.js', '.mjs', '.cjs', '.jsx', '.ts', '.tsx'], }); diff --git a/packages/mui-base/src/FocusTrap/FocusTrap.test.tsx b/packages/mui-base/src/FocusTrap/FocusTrap.test.tsx index 1cca94309e0e8d..123b18ebfa1472 100644 --- a/packages/mui-base/src/FocusTrap/FocusTrap.test.tsx +++ b/packages/mui-base/src/FocusTrap/FocusTrap.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { expect } from 'chai'; -import { act, createRenderer, screen } from '@mui/internal-test-utils'; +import { act, createRenderer, reactMajor, screen } from '@mui/internal-test-utils'; import { FocusTrap } from '@mui/base/FocusTrap'; import { Portal } from '@mui/base/Portal'; @@ -219,7 +219,7 @@ describe('', () => { ); } - const { setProps, getByRole } = render(); + const { setProps, getByRole } = render(, { strict: reactMajor <= 18 }); expect(screen.getByTestId('root')).toHaveFocus(); act(() => { diff --git a/packages/mui-base/src/Input/Input.test.tsx b/packages/mui-base/src/Input/Input.test.tsx index c9b18bf518a03c..85b3614b62d2df 100644 --- a/packages/mui-base/src/Input/Input.test.tsx +++ b/packages/mui-base/src/Input/Input.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { createRenderer, fireEvent, screen, act } from '@mui/internal-test-utils'; +import { createRenderer, fireEvent, screen, act, reactMajor } from '@mui/internal-test-utils'; import { expect } from 'chai'; import { spy } from 'sinon'; import { Input, inputClasses, InputOwnerState } from '@mui/base/Input'; @@ -281,8 +281,8 @@ describe('', () => { ); }).toErrorDev([ 'MUI: You have provided a `slots.input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', - // React 18 Strict Effects run mount effects twice - React.version.startsWith('18') && + // React Strict Mode runs mount effects twice + reactMajor >= 18 && 'MUI: You have provided a `slots.input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', ]); }); diff --git a/packages/mui-base/src/Portal/Portal.test.tsx b/packages/mui-base/src/Portal/Portal.test.tsx index 4b9b0a6f9a6b3f..92f9bb2df38b92 100644 --- a/packages/mui-base/src/Portal/Portal.test.tsx +++ b/packages/mui-base/src/Portal/Portal.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, reactMajor } from '@mui/internal-test-utils'; import { Portal, PortalProps } from '@mui/base/Portal'; describe('', () => { @@ -44,6 +44,7 @@ describe('', () => {

Foo

, + { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); @@ -57,6 +58,7 @@ describe('', () => {

Foo

, + { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); diff --git a/packages/mui-base/src/useAutocomplete/useAutocomplete.test.js b/packages/mui-base/src/useAutocomplete/useAutocomplete.test.js index 438ac78cf52fff..d912c128de5363 100644 --- a/packages/mui-base/src/useAutocomplete/useAutocomplete.test.js +++ b/packages/mui-base/src/useAutocomplete/useAutocomplete.test.js @@ -313,6 +313,14 @@ describe('useAutocomplete', () => { aboveErrorTestComponentMessage, aboveErrorTestComponentMessage, ], + 19: [ + muiErrorMessage, + muiErrorMessage, + nodeErrorMessage, + nodeErrorMessage, + nodeErrorMessage, + nodeErrorMessage, + ], }; const devErrorMessages = errorMessagesByReactMajor[reactMajor] || defaultErrorMessages; diff --git a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx index 3a080d07f1df77..b8ff2c801884f9 100644 --- a/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx +++ b/packages/mui-joy/src/Autocomplete/Autocomplete.test.tsx @@ -1931,7 +1931,8 @@ describe('Joy ', () => { await user.click(screen.getByText('Reset')); - const expectedCallCount = reactMajor === 18 ? 4 : 2; + // eslint-disable-next-line no-nested-ternary + const expectedCallCount = reactMajor >= 19 ? 3 : reactMajor === 18 ? 4 : 2; expect(handleInputChange.callCount).to.equal(expectedCallCount); expect(handleInputChange.args[expectedCallCount - 1][1]).to.equal(options[1].name); @@ -2209,7 +2210,8 @@ describe('Joy ', () => { expect(handleHighlightChange.callCount).to.equal( // FIXME: highlighted index implementation should be implemented using React not the DOM. - reactMajor >= 18 ? 4 : 3, + // eslint-disable-next-line no-nested-ternary + reactMajor >= 19 ? 5 : reactMajor >= 18 ? 4 : 3, ); if (reactMajor >= 18) { expect(handleHighlightChange.args[2][0]).to.equal(undefined); @@ -2223,7 +2225,8 @@ describe('Joy ', () => { fireEvent.keyDown(textbox, { key: 'ArrowDown' }); expect(handleHighlightChange.callCount).to.equal( // FIXME: highlighted index implementation should be implemented using React not the DOM. - reactMajor >= 18 ? 5 : 4, + // eslint-disable-next-line no-nested-ternary + reactMajor >= 19 ? 6 : reactMajor >= 18 ? 5 : 4, ); expect(handleHighlightChange.lastCall.args[0]).not.to.equal(undefined); expect(handleHighlightChange.lastCall.args[1]).to.equal(options[1]); @@ -2240,7 +2243,8 @@ describe('Joy ', () => { fireEvent.mouseMove(firstOption); expect(handleHighlightChange.callCount).to.equal( // FIXME: highlighted index implementation should be implemented using React not the DOM. - reactMajor >= 18 ? 4 : 3, + // eslint-disable-next-line no-nested-ternary + reactMajor >= 19 ? 5 : reactMajor >= 18 ? 4 : 3, ); if (reactMajor >= 18) { expect(handleHighlightChange.args[2][0]).to.equal(undefined); diff --git a/packages/mui-material/src/InputBase/InputBase.test.js b/packages/mui-material/src/InputBase/InputBase.test.js index f89f452661bc4c..fa6207bcf3fa52 100644 --- a/packages/mui-material/src/InputBase/InputBase.test.js +++ b/packages/mui-material/src/InputBase/InputBase.test.js @@ -282,7 +282,7 @@ describe('', () => { let expectedOccurrences = 1; - if (reactMajor === 18) { + if (reactMajor >= 18) { expectedOccurrences = 2; } @@ -507,7 +507,7 @@ describe('', () => { let expectedOccurrences = 1; - if (reactMajor === 18) { + if (reactMajor >= 18) { expectedOccurrences = 2; } expect(() => { diff --git a/packages/mui-material/src/Portal/Portal.test.tsx b/packages/mui-material/src/Portal/Portal.test.tsx index 3fe0b934c78bf5..6579fbcf36b59c 100644 --- a/packages/mui-material/src/Portal/Portal.test.tsx +++ b/packages/mui-material/src/Portal/Portal.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, reactMajor } from '@mui/internal-test-utils'; import Portal, { PortalProps } from '@mui/material/Portal'; describe('', () => { @@ -44,6 +44,7 @@ describe('', () => {

Foo

, + { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); @@ -57,6 +58,7 @@ describe('', () => {

Foo

, + { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); diff --git a/packages/mui-material/src/Select/Select.test.js b/packages/mui-material/src/Select/Select.test.js index 100b69b1ca4a9f..4599548c848d92 100644 --- a/packages/mui-material/src/Select/Select.test.js +++ b/packages/mui-material/src/Select/Select.test.js @@ -380,7 +380,7 @@ describe('