diff --git a/packages/react-dom/src/__tests__/ReactDOMOption-test.js b/packages/react-dom/src/__tests__/ReactDOMOption-test.js index b8dc69b3f6b7d..156fc822f3944 100644 --- a/packages/react-dom/src/__tests__/ReactDOMOption-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMOption-test.js @@ -11,16 +11,18 @@ describe('ReactDOMOption', () => { let React; - let ReactDOM; + let ReactDOMClient; let ReactDOMServer; let ReactTestUtils; + let act; beforeEach(() => { jest.resetModules(); React = require('react'); - ReactDOM = require('react-dom'); + ReactDOMClient = require('react-dom/client'); ReactDOMServer = require('react-dom/server'); ReactTestUtils = require('react-dom/test-utils'); + act = require('internal-test-utils').act; }); it('should flatten children to a string', () => { @@ -182,19 +184,28 @@ describe('ReactDOMOption', () => { expect(node.innerHTML).toBe('foobar'); }); - it('should set attribute for empty value', () => { + it('should set attribute for empty value', async () => { const container = document.createElement('div'); - const option = ReactDOM.render(, container); + const root = ReactDOMClient.createRoot(container); + let option; + await act(() => { + root.render(); + }); + option = container.firstChild; expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe(''); - ReactDOM.render(, container); + await act(() => { + root.render(); + }); + option = container.firstChild; expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe('lava'); }); - it('should allow ignoring `value` on option', () => { + it('should allow ignoring `value` on option', async () => { const a = 'a'; + let node; const stub = ( {}}> monkey @@ -204,15 +215,22 @@ describe('ReactDOMOption', () => { ); const options = stub.props.children; const container = document.createElement('div'); - const node = ReactDOM.render(stub, container); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(stub); + }); + node = container.firstChild; expect(node.selectedIndex).toBe(1); - ReactDOM.render({options}, container); + await act(() => { + root.render({options}); + }); + node = container.firstChild; expect(node.selectedIndex).toEqual(2); }); - it('generates a warning and hydration error when an invalid nested tag is used as a child', () => { + it('generates a warning and hydration error when an invalid nested tag is used as a child', async () => { const ref = React.createRef(); const children = ( @@ -229,16 +247,27 @@ describe('ReactDOMOption', () => { expect(container.firstChild.getAttribute('value')).toBe(null); expect(container.firstChild.getAttribute('defaultValue')).toBe(null); - const option = container.firstChild.firstChild; + let option = container.firstChild.firstChild; expect(option.nodeName).toBe('OPTION'); expect(option.textContent).toBe('BarFooBaz'); expect(option.selected).toBe(true); - expect(() => ReactDOM.hydrate(children, container)).toErrorDev([ - 'Text content did not match. Server: "FooBaz" Client: "Foo"', - 'validateDOMNesting(...): cannot appear as a child of .', - ]); + await expect(async () => { + await act(async () => { + ReactDOMClient.hydrateRoot(container, children); + }); + }).toErrorDev( + [ + 'Warning: Text content did not match. Server: "FooBaz" Client: "Foo"', + 'Warning: An error occurred during hydration. The server HTML was replaced with client content in ', + 'Warning: validateDOMNesting(...): cannot appear as a child of ', + 'Error: Text content does not match server-rendered HTML.', + 'Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.', + ], + {withoutStack: 1}, + ); + option = container.firstChild.firstChild; expect(option.textContent).toBe('BarFooBaz'); expect(option.selected).toBe(true); diff --git a/scripts/jest/matchers/toWarnDev.js b/scripts/jest/matchers/toWarnDev.js index 88ae8661e9964..d61f3707b035c 100644 --- a/scripts/jest/matchers/toWarnDev.js +++ b/scripts/jest/matchers/toWarnDev.js @@ -86,7 +86,8 @@ const createMatcherFor = (consoleMethod, matcherName) => // doesn't match the number of arguments. // We'll fail the test if it happens. let argIndex = 0; - format.replace(/%s/g, () => argIndex++); + // console.* could have been called with a non-string e.g. `console.error(new Error())` + String(format).replace(/%s/g, () => argIndex++); if (argIndex !== args.length) { lastWarningWithMismatchingFormat = { format,