@samitouri / QOS-React / commits / 1deda7690f

Remove ReactTestUtils from ReactDOMComponent (#28334)

Sebastian Silbermann committed Feb 20, 2024 at 16:52 UTC 1deda7690fc95d873b14cbcb0ee6c8f1dd1395a3
1 file changed +675 -318
packages/react-dom/src/__tests__/ReactDOMComponent-test.js
+675 -318
@@ -11,7 +11,6 @@
11
12 describe('ReactDOMComponent', () => {
13 let React;
14 - let ReactTestUtils;
14 let ReactDOM;
15 let ReactDOMClient;
16 let ReactDOMServer;
@@ -25,7 +24,6 @@ describe('ReactDOMComponent', () => {
24 ReactDOM = require('react-dom');
25 ReactDOMClient = require('react-dom/client');
26 ReactDOMServer = require('react-dom/server');
28 - ReactTestUtils = require('react-dom/test-utils');
27 act = require('internal-test-utils').act;
28 });
29
@@ -162,7 +160,7 @@ describe('ReactDOMComponent', () => {
160 expect(stubStyle.lineHeight).toBe('');
161 });
162
165 - it('should throw when mutating style objects', () => {
163 + it('should throw when mutating style objects', async () => {
164 const style = {border: '1px solid black'};
165
166 class App extends React.Component {
@@ -173,7 +171,12 @@ describe('ReactDOMComponent', () => {
171 }
172 }
173
176 - ReactTestUtils.renderIntoDocument(<App />);
174 + const container = document.createElement('div');
175 + const root = ReactDOMClient.createRoot(container);
176 + await act(() => {
177 + root.render(<App />);
178 + });
179 +
180 if (__DEV__) {
181 expect(() => (style.position = 'absolute')).toThrow();
182 }
@@ -298,14 +301,18 @@ describe('ReactDOMComponent', () => {
301 expect(container.firstChild.getAttribute('CHILDREN')).toBe('5');
302 });
303
301 - it('should not warn for "0" as a unitless style value', () => {
304 + it('should not warn for "0" as a unitless style value', async () => {
305 class Component extends React.Component {
306 render() {
307 return <div style={{margin: '0'}} />;
308 }
309 }
310
308 - ReactTestUtils.renderIntoDocument(<Component />);
311 + const container = document.createElement('div');
312 + const root = ReactDOMClient.createRoot(container);
313 + await act(() => {
314 + root.render(<Component />);
315 + });
316 });
317
318 it('should warn nicely about NaN in style', async () => {
@@ -906,28 +913,36 @@ describe('ReactDOMComponent', () => {
913 ]);
914 });
915
909 - it('should reject attribute key injection attack on mount for regular DOM', () => {
910 - expect(() => {
916 + it('should reject attribute key injection attack on mount for regular DOM', async () => {
917 + await expect(async () => {
918 for (let i = 0; i < 3; i++) {
919 const container = document.createElement('div');
913 - ReactDOM.render(
914 - React.createElement(
915 - 'div',
916 - {'blah" onclick="beevil" noise="hi': 'selected'},
917 - null,
918 - ),
919 - container,
920 - );
920 + let root = ReactDOMClient.createRoot(container);
921 + await act(() => {
922 + root.render(
923 + React.createElement(
924 + 'div',
925 + {'blah" onclick="beevil" noise="hi': 'selected'},
926 + null,
927 + ),
928 + );
929 + });
930 +
931 expect(container.firstChild.attributes.length).toBe(0);
922 - ReactDOM.unmountComponentAtNode(container);
923 - ReactDOM.render(
924 - React.createElement(
925 - 'div',
926 - {'></div><script>alert("hi")</script>': 'selected'},
927 - null,
928 - ),
929 - container,
930 - );
932 + await act(() => {
933 + root.unmount();
934 + });
935 + root = ReactDOMClient.createRoot(container);
936 + await act(() => {
937 + root.render(
938 + React.createElement(
939 + 'div',
940 + {'></div><script>alert("hi")</script>': 'selected'},
941 + null,
942 + ),
943 + );
944 + });
945 +
946 expect(container.firstChild.attributes.length).toBe(0);
947 }
948 }).toErrorDev([
@@ -936,28 +951,37 @@ describe('ReactDOMComponent', () => {
951 ]);
952 });
953
939 - it('should reject attribute key injection attack on mount for custom elements', () => {
940 - expect(() => {
954 + it('should reject attribute key injection attack on mount for custom elements', async () => {
955 + await expect(async () => {
956 for (let i = 0; i < 3; i++) {
957 const container = document.createElement('div');
943 - ReactDOM.render(
944 - React.createElement(
945 - 'x-foo-component',
946 - {'blah" onclick="beevil" noise="hi': 'selected'},
947 - null,
948 - ),
949 - container,
950 - );
958 + let root = ReactDOMClient.createRoot(container);
959 +
960 + await act(() => {
961 + root.render(
962 + React.createElement(
963 + 'x-foo-component',
964 + {'blah" onclick="beevil" noise="hi': 'selected'},
965 + null,
966 + ),
967 + );
968 + });
969 +
970 expect(container.firstChild.attributes.length).toBe(0);
952 - ReactDOM.unmountComponentAtNode(container);
953 - ReactDOM.render(
954 - React.createElement(
955 - 'x-foo-component',
956 - {'></x-foo-component><script>alert("hi")</script>': 'selected'},
957 - null,
958 - ),
959 - container,
960 - );
971 + await act(() => {
972 + root.unmount();
973 + });
974 + root = ReactDOMClient.createRoot(container);
975 + await act(() => {
976 + root.render(
977 + React.createElement(
978 + 'x-foo-component',
979 + {'></x-foo-component><script>alert("hi")</script>': 'selected'},
980 + null,
981 + ),
982 + );
983 + });
984 +
985 expect(container.firstChild.attributes.length).toBe(0);
986 }
987 }).toErrorDev([
@@ -966,29 +990,36 @@ describe('ReactDOMComponent', () => {
990 ]);
991 });
992
969 - it('should reject attribute key injection attack on update for regular DOM', () => {
970 - expect(() => {
993 + it('should reject attribute key injection attack on update for regular DOM', async () => {
994 + await expect(async () => {
995 for (let i = 0; i < 3; i++) {
996 const container = document.createElement('div');
997 const beforeUpdate = React.createElement('div', {}, null);
974 - ReactDOM.render(beforeUpdate, container);
975 - ReactDOM.render(
976 - React.createElement(
977 - 'div',
978 - {'blah" onclick="beevil" noise="hi': 'selected'},
979 - null,
980 - ),
981 - container,
982 - );
998 + const root = ReactDOMClient.createRoot(container);
999 + await act(() => {
1000 + root.render(beforeUpdate);
1001 + });
1002 + await act(() => {
1003 + root.render(
1004 + React.createElement(
1005 + 'div',
1006 + {'blah" onclick="beevil" noise="hi': 'selected'},
1007 + null,
1008 + ),
1009 + );
1010 + });
1011 +
1012 expect(container.firstChild.attributes.length).toBe(0);
984 - ReactDOM.render(
985 - React.createElement(
986 - 'div',
987 - {'></div><script>alert("hi")</script>': 'selected'},
988 - null,
989 - ),
990 - container,
991 - );
1013 + await act(() => {
1014 + root.render(
1015 + React.createElement(
1016 + 'div',
1017 + {'></div><script>alert("hi")</script>': 'selected'},
1018 + null,
1019 + ),
1020 + );
1021 + });
1022 +
1023 expect(container.firstChild.attributes.length).toBe(0);
1024 }
1025 }).toErrorDev([
@@ -997,29 +1028,36 @@ describe('ReactDOMComponent', () => {
1028 ]);
1029 });
1030
1000 - it('should reject attribute key injection attack on update for custom elements', () => {
1001 - expect(() => {
1031 + it('should reject attribute key injection attack on update for custom elements', async () => {
1032 + await expect(async () => {
1033 for (let i = 0; i < 3; i++) {
1034 const container = document.createElement('div');
1035 const beforeUpdate = React.createElement('x-foo-component', {}, null);
1005 - ReactDOM.render(beforeUpdate, container);
1006 - ReactDOM.render(
1007 - React.createElement(
1008 - 'x-foo-component',
1009 - {'blah" onclick="beevil" noise="hi': 'selected'},
1010 - null,
1011 - ),
1012 - container,
1013 - );
1036 + const root = ReactDOMClient.createRoot(container);
1037 + await act(() => {
1038 + root.render(beforeUpdate);
1039 + });
1040 + await act(() => {
1041 + root.render(
1042 + React.createElement(
1043 + 'x-foo-component',
1044 + {'blah" onclick="beevil" noise="hi': 'selected'},
1045 + null,
1046 + ),
1047 + );
1048 + });
1049 +
1050 expect(container.firstChild.attributes.length).toBe(0);
1015 - ReactDOM.render(
1016 - React.createElement(
1017 - 'x-foo-component',
1018 - {'></x-foo-component><script>alert("hi")</script>': 'selected'},
1019 - null,
1020 - ),
1021 - container,
1022 - );
1051 + await act(() => {
1052 + root.render(
1053 + React.createElement(
1054 + 'x-foo-component',
1055 + {'></x-foo-component><script>alert("hi")</script>': 'selected'},
1056 + null,
1057 + ),
1058 + );
1059 + });
1060 +
1061 expect(container.firstChild.attributes.length).toBe(0);
1062 }
1063 }).toErrorDev([
@@ -1615,31 +1653,50 @@ describe('ReactDOMComponent', () => {
1653 expect(returnedValue).toContain('</BR>');
1654 });
1655
1618 - it('should warn on upper case HTML tags, not SVG nor custom tags', () => {
1619 - ReactTestUtils.renderIntoDocument(
1620 - React.createElement('svg', null, React.createElement('PATH')),
1621 - );
1622 - ReactTestUtils.renderIntoDocument(React.createElement('CUSTOM-TAG'));
1656 + it('should warn on upper case HTML tags, not SVG nor custom tags', async () => {
1657 + let container = document.createElement('div');
1658 + let root = ReactDOMClient.createRoot(container);
1659 + await act(() => {
1660 + root.render(
1661 + React.createElement('svg', null, React.createElement('PATH')),
1662 + );
1663 + });
1664
1624 - expect(() =>
1625 - ReactTestUtils.renderIntoDocument(React.createElement('IMG')),
1626 - ).toErrorDev(
1665 + container = document.createElement('div');
1666 + root = ReactDOMClient.createRoot(container);
1667 + await act(() => {
1668 + root.render(React.createElement('CUSTOM-TAG'));
1669 + });
1670 +
1671 + await expect(async () => {
1672 + container = document.createElement('div');
1673 + root = ReactDOMClient.createRoot(container);
1674 +
1675 + await act(() => {
1676 + root.render(React.createElement('IMG'));
1677 + });
1678 + }).toErrorDev(
1679 '<IMG /> is using incorrect casing. ' +
1680 'Use PascalCase for React components, ' +
1681 'or lowercase for HTML elements.',
1682 );
1683 });
1684
1633 - it('should warn on props reserved for future use', () => {
1634 - expect(() =>
1635 - ReactTestUtils.renderIntoDocument(<div aria="hello" />),
1636 - ).toErrorDev(
1685 + it('should warn on props reserved for future use', async () => {
1686 + await expect(async () => {
1687 + const container = document.createElement('div');
1688 + const root = ReactDOMClient.createRoot(container);
1689 +
1690 + await act(() => {
1691 + root.render(<div aria="hello" />);
1692 + });
1693 + }).toErrorDev(
1694 'The `aria` attribute is reserved for future use in React. ' +
1695 'Pass individual `aria-` attributes instead.',
1696 );
1697 });
1698
1642 - it('should warn if the tag is unrecognized', () => {
1699 + it('should warn if the tag is unrecognized', async () => {
1700 let realToString;
1701 try {
1702 realToString = Object.prototype.toString;
@@ -1652,19 +1709,44 @@ describe('ReactDOMComponent', () => {
1709 };
1710 Object.prototype.toString = wrappedToString; // eslint-disable-line no-extend-native
1711
1655 - expect(() => ReactTestUtils.renderIntoDocument(<bar />)).toErrorDev(
1656 - 'The tag <bar> is unrecognized in this browser',
1657 - );
1712 + await expect(async () => {
1713 + const container = document.createElement('div');
1714 + const root = ReactDOMClient.createRoot(container);
1715 +
1716 + await act(() => {
1717 + root.render(<bar />);
1718 + });
1719 + }).toErrorDev('The tag <bar> is unrecognized in this browser');
1720 // Test deduplication
1659 - expect(() => ReactTestUtils.renderIntoDocument(<foo />)).toErrorDev(
1660 - 'The tag <foo> is unrecognized in this browser',
1661 - );
1662 - ReactTestUtils.renderIntoDocument(<foo />);
1663 - ReactTestUtils.renderIntoDocument(<time />);
1721 + await expect(async () => {
1722 + const container = document.createElement('div');
1723 + const root = ReactDOMClient.createRoot(container);
1724 +
1725 + await act(() => {
1726 + root.render(<foo />);
1727 + });
1728 + }).toErrorDev('The tag <foo> is unrecognized in this browser');
1729 + let container = document.createElement('div');
1730 + let root = ReactDOMClient.createRoot(container);
1731 + await act(() => {
1732 + root.render(<foo />);
1733 + });
1734 +
1735 + container = document.createElement('div');
1736 + root = ReactDOMClient.createRoot(container);
1737 + await act(() => {
1738 + root.render(<time />);
1739 + });
1740 +
1741 // Corner case. Make sure out deduplication logic doesn't break with weird tag.
1665 - expect(() =>
1666 - ReactTestUtils.renderIntoDocument(<hasOwnProperty />),
1667 - ).toErrorDev([
1742 + await expect(async () => {
1743 + container = document.createElement('div');
1744 + root = ReactDOMClient.createRoot(container);
1745 +
1746 + await act(() => {
1747 + root.render(<hasOwnProperty />);
1748 + });
1749 + }).toErrorDev([
1750 '<hasOwnProperty /> is using incorrect casing. ' +
1751 'Use PascalCase for React components, ' +
1752 'or lowercase for HTML elements.',
@@ -2069,26 +2151,42 @@ describe('ReactDOMComponent', () => {
2151 );
2152 });
2153
2072 - it('should throw when an invalid tag name is used', () => {
2154 + it('should throw when an invalid tag name is used', async () => {
2155 const hackzor = React.createElement('script tag');
2074 - expect(() => ReactTestUtils.renderIntoDocument(hackzor)).toThrow();
2156 + const container = document.createElement('div');
2157 + const root = ReactDOMClient.createRoot(container);
2158 + await expect(
2159 + act(() => {
2160 + root.render(hackzor);
2161 + }),
2162 + ).rejects.toThrow();
2163 });
2164
2077 - it('should throw when an attack vector is used', () => {
2165 + it('should throw when an attack vector is used', async () => {
2166 const hackzor = React.createElement('div><img /><div');
2079 - expect(() => ReactTestUtils.renderIntoDocument(hackzor)).toThrow();
2167 + const container = document.createElement('div');
2168 + const root = ReactDOMClient.createRoot(container);
2169 + await expect(
2170 + act(() => {
2171 + root.render(hackzor);
2172 + }),
2173 + ).rejects.toThrow();
2174 });
2175 });
2176
2177 describe('nesting validation', () => {
2084 - it('warns on invalid nesting', () => {
2085 - expect(() => {
2086 - ReactTestUtils.renderIntoDocument(
2087 - <div>
2088 - <tr />
2089 - <tr />
2090 - </div>,
2091 - );
2178 + it('warns on invalid nesting', async () => {
2179 + const container = document.createElement('div');
2180 + const root = ReactDOMClient.createRoot(container);
2181 + await expect(async () => {
2182 + await act(() => {
2183 + root.render(
2184 + <div>
2185 + <tr />
2186 + <tr />
2187 + </div>,
2188 + );
2189 + });
2190 }).toErrorDev([
2191 'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
2192 '<div>.' +
@@ -2118,7 +2216,7 @@ describe('ReactDOMComponent', () => {
2216 );
2217 });
2218
2121 - it('warns nicely for table rows', () => {
2219 + it('warns nicely for table rows', async () => {
2220 class Row extends React.Component {
2221 render() {
2222 return <tr>x</tr>;
@@ -2135,7 +2233,14 @@ describe('ReactDOMComponent', () => {
2233 }
2234 }
2235
2138 - expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toErrorDev([
2236 + await expect(async () => {
2237 + const container = document.createElement('div');
2238 + const root = ReactDOMClient.createRoot(container);
2239 +
2240 + await act(() => {
2241 + root.render(<Foo />);
2242 + });
2243 + }).toErrorDev([
2244 'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
2245 '<table>. Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated ' +
2246 'by the browser.' +
@@ -2216,7 +2321,7 @@ describe('ReactDOMComponent', () => {
2321 ]);
2322 });
2323
2219 - it('gives useful context in warnings', () => {
2324 + it('gives useful context in warnings', async () => {
2325 function Row() {
2326 return <tr />;
2327 }
@@ -2234,7 +2339,13 @@ describe('ReactDOMComponent', () => {
2339 function App1() {
2340 return <Viz1 />;
2341 }
2237 - expect(() => ReactTestUtils.renderIntoDocument(<App1 />)).toErrorDev(
2342 + await expect(async () => {
2343 + const container = document.createElement('div');
2344 + const root = ReactDOMClient.createRoot(container);
2345 + await act(() => {
2346 + root.render(<App1 />);
2347 + });
2348 + }).toErrorDev(
2349 '\n in tr (at **)' +
2350 '\n in Row (at **)' +
2351 '\n in FancyRow (at **)' +
@@ -2243,7 +2354,7 @@ describe('ReactDOMComponent', () => {
2354 );
2355 });
2356
2246 - it('gives useful context in warnings 2', () => {
2357 + it('gives useful context in warnings 2', async () => {
2358 function Row() {
2359 return <tr />;
2360 }
@@ -2273,7 +2384,14 @@ describe('ReactDOMComponent', () => {
2384 function App2() {
2385 return <Viz2 />;
2386 }
2276 - expect(() => ReactTestUtils.renderIntoDocument(<App2 />)).toErrorDev(
2387 + await expect(async () => {
2388 + const container = document.createElement('div');
2389 + const root = ReactDOMClient.createRoot(container);
2390 +
2391 + await act(() => {
2392 + root.render(<App2 />);
2393 + });
2394 + }).toErrorDev(
2395 '\n in tr (at **)' +
2396 '\n in Row (at **)' +
2397 '\n in FancyRow (at **)' +
@@ -2284,7 +2402,7 @@ describe('ReactDOMComponent', () => {
2402 );
2403 });
2404
2287 - it('gives useful context in warnings 3', () => {
2405 + it('gives useful context in warnings 3', async () => {
2406 function Row() {
2407 return <tr />;
2408 }
@@ -2303,12 +2421,17 @@ describe('ReactDOMComponent', () => {
2421 return <Table>{this.props.children}</Table>;
2422 }
2423 }
2306 - expect(() => {
2307 - ReactTestUtils.renderIntoDocument(
2308 - <FancyTable>
2309 - <FancyRow />
2310 - </FancyTable>,
2311 - );
2424 + await expect(async () => {
2425 + const container = document.createElement('div');
2426 + const root = ReactDOMClient.createRoot(container);
2427 +
2428 + await act(() => {
2429 + root.render(
2430 + <FancyTable>
2431 + <FancyRow />
2432 + </FancyTable>,
2433 + );
2434 + });
2435 }).toErrorDev(
2436 '\n in tr (at **)' +
2437 '\n in Row (at **)' +
@@ -2319,7 +2442,7 @@ describe('ReactDOMComponent', () => {
2442 );
2443 });
2444
2322 - it('gives useful context in warnings 4', () => {
2445 + it('gives useful context in warnings 4', async () => {
2446 function Row() {
2447 return <tr />;
2448 }
@@ -2327,12 +2450,17 @@ describe('ReactDOMComponent', () => {
2450 return <Row />;
2451 }
2452
2330 - expect(() => {
2331 - ReactTestUtils.renderIntoDocument(
2332 - <table>
2333 - <FancyRow />
2334 - </table>,
2335 - );
2453 + await expect(async () => {
2454 + const container = document.createElement('div');
2455 + const root = ReactDOMClient.createRoot(container);
2456 +
2457 + await act(() => {
2458 + root.render(
2459 + <table>
2460 + <FancyRow />
2461 + </table>,
2462 + );
2463 + });
2464 }).toErrorDev(
2465 '\n in tr (at **)' +
2466 '\n in Row (at **)' +
@@ -2341,7 +2469,7 @@ describe('ReactDOMComponent', () => {
2469 );
2470 });
2471
2344 - it('gives useful context in warnings 5', () => {
2472 + it('gives useful context in warnings 5', async () => {
2473 class Table extends React.Component {
2474 render() {
2475 return <table>{this.props.children}</table>;
@@ -2354,12 +2482,16 @@ describe('ReactDOMComponent', () => {
2482 }
2483 }
2484
2357 - expect(() => {
2358 - ReactTestUtils.renderIntoDocument(
2359 - <FancyTable>
2360 - <tr />
2361 - </FancyTable>,
2362 - );
2485 + await expect(async () => {
2486 + const container = document.createElement('div');
2487 + const root = ReactDOMClient.createRoot(container);
2488 + await act(() => {
2489 + root.render(
2490 + <FancyTable>
2491 + <tr />
2492 + </FancyTable>,
2493 + );
2494 + });
2495 }).toErrorDev(
2496 '\n in tr (at **)' +
2497 '\n in table (at **)' +
@@ -2373,14 +2505,18 @@ describe('ReactDOMComponent', () => {
2505 }
2506 }
2507
2376 - expect(() => {
2377 - ReactTestUtils.renderIntoDocument(
2378 - <Link>
2379 - <div>
2380 - <Link />
2381 - </div>
2382 - </Link>,
2383 - );
2508 + await expect(async () => {
2509 + const container = document.createElement('div');
2510 + const root = ReactDOMClient.createRoot(container);
2511 + await act(() => {
2512 + root.render(
2513 + <Link>
2514 + <div>
2515 + <Link />
2516 + </div>
2517 + </Link>,
2518 + );
2519 + });
2520 }).toErrorDev(
2521 '\n in a (at **)' +
2522 '\n in Link (at **)' +
@@ -2420,32 +2556,48 @@ describe('ReactDOMComponent', () => {
2556 // without access to the event system (which we don't bundle).
2557 });
2558
2423 - it('should warn about incorrect casing on properties', () => {
2424 - expect(() => {
2425 - ReactTestUtils.renderIntoDocument(
2426 - React.createElement('input', {type: 'text', tabindex: '1'}),
2427 - );
2559 + it('should warn about incorrect casing on properties', async () => {
2560 + await expect(async () => {
2561 + const container = document.createElement('div');
2562 + const root = ReactDOMClient.createRoot(container);
2563 + await act(() => {
2564 + root.render(
2565 + React.createElement('input', {type: 'text', tabindex: '1'}),
2566 + );
2567 + });
2568 }).toErrorDev('tabIndex');
2569 });
2570
2431 - it('should warn about incorrect casing on event handlers', () => {
2432 - expect(() => {
2433 - ReactTestUtils.renderIntoDocument(
2434 - React.createElement('input', {type: 'text', oninput: '1'}),
2435 - );
2571 + it('should warn about incorrect casing on event handlers', async () => {
2572 + await expect(async () => {
2573 + const container = document.createElement('div');
2574 + const root = ReactDOMClient.createRoot(container);
2575 +
2576 + await act(() => {
2577 + root.render(
2578 + React.createElement('input', {type: 'text', oninput: '1'}),
2579 + );
2580 + });
2581 }).toErrorDev('onInput');
2437 - expect(() => {
2438 - ReactTestUtils.renderIntoDocument(
2439 - React.createElement('input', {type: 'text', onKeydown: '1'}),
2440 - );
2582 + await expect(async () => {
2583 + const container = document.createElement('div');
2584 + const root = ReactDOMClient.createRoot(container);
2585 +
2586 + await act(() => {
2587 + root.render(
2588 + React.createElement('input', {type: 'text', onKeydown: '1'}),
2589 + );
2590 + });
2591 }).toErrorDev('onKeyDown');
2592 });
2593
2444 - it('should warn about class', () => {
2445 - expect(() => {
2446 - ReactTestUtils.renderIntoDocument(
2447 - React.createElement('div', {class: 'muffins'}),
2448 - );
2594 + it('should warn about class', async () => {
2595 + await expect(async () => {
2596 + const container = document.createElement('div');
2597 + const root = ReactDOMClient.createRoot(container);
2598 + await act(() => {
2599 + root.render(React.createElement('div', {class: 'muffins'}));
2600 + });
2601 }).toErrorDev('className');
2602 });
2603
@@ -2457,31 +2609,57 @@ describe('ReactDOMComponent', () => {
2609 }).toErrorDev('className');
2610 });
2611
2460 - it('should warn about props that are no longer supported', () => {
2461 - ReactTestUtils.renderIntoDocument(<div />);
2612 + it('should warn about props that are no longer supported', async () => {
2613 + let container = document.createElement('div');
2614 + let root = ReactDOMClient.createRoot(container);
2615 + await act(() => {
2616 + root.render(<div />);
2617 + });
2618
2463 - expect(() =>
2464 - ReactTestUtils.renderIntoDocument(<div onFocusIn={() => {}} />),
2465 - ).toErrorDev(
2466 - 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
2467 - );
2468 - expect(() =>
2469 - ReactTestUtils.renderIntoDocument(<div onFocusOut={() => {}} />),
2470 - ).toErrorDev(
2619 + await expect(async () => {
2620 + container = document.createElement('div');
2621 + root = ReactDOMClient.createRoot(container);
2622 +
2623 + await act(() => {
2624 + root.render(<div onFocusIn={() => {}} />);
2625 + });
2626 + }).toErrorDev(
2627 + 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
2628 + );
2629 + await expect(async () => {
2630 + container = document.createElement('div');
2631 + root = ReactDOMClient.createRoot(container);
2632 + await act(() => {
2633 + root.render(<div onFocusOut={() => {}} />);
2634 + });
2635 + }).toErrorDev(
2636 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
2637 );
2638 });
2639
2475 - it('should warn about props that are no longer supported without case sensitivity', () => {
2476 - ReactTestUtils.renderIntoDocument(<div />);
2477 - expect(() =>
2478 - ReactTestUtils.renderIntoDocument(<div onfocusin={() => {}} />),
2479 - ).toErrorDev(
2640 + it('should warn about props that are no longer supported without case sensitivity', async () => {
2641 + let container = document.createElement('div');
2642 + let root = ReactDOMClient.createRoot(container);
2643 + await act(() => {
2644 + root.render(<div />);
2645 + });
2646 +
2647 + await expect(async () => {
2648 + container = document.createElement('div');
2649 + root = ReactDOMClient.createRoot(container);
2650 + await act(() => {
2651 + root.render(<div onfocusin={() => {}} />);
2652 + });
2653 + }).toErrorDev(
2654 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
2655 );
2482 - expect(() =>
2483 - ReactTestUtils.renderIntoDocument(<div onfocusout={() => {}} />),
2484 - ).toErrorDev(
2656 + await expect(async () => {
2657 + container = document.createElement('div');
2658 + root = ReactDOMClient.createRoot(container);
2659 + await act(() => {
2660 + root.render(<div onfocusout={() => {}} />);
2661 + });
2662 + }).toErrorDev(
2663 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
2664 );
2665 });
@@ -2514,15 +2692,23 @@ describe('ReactDOMComponent', () => {
2692 );
2693 });
2694
2517 - it('gives source code refs for unknown prop warning', () => {
2518 - expect(() =>
2519 - ReactTestUtils.renderIntoDocument(<div class="paladin" />),
2520 - ).toErrorDev(
2695 + it('gives source code refs for unknown prop warning', async () => {
2696 + await expect(async () => {
2697 + const container = document.createElement('div');
2698 + const root = ReactDOMClient.createRoot(container);
2699 + await act(() => {
2700 + root.render(<div class="paladin" />);
2701 + });
2702 + }).toErrorDev(
2703 'Warning: Invalid DOM property `class`. Did you mean `className`?\n in div (at **)',
2704 );
2523 - expect(() =>
2524 - ReactTestUtils.renderIntoDocument(<input type="text" onclick="1" />),
2525 - ).toErrorDev(
2705 + await expect(async () => {
2706 + const container = document.createElement('div');
2707 + const root = ReactDOMClient.createRoot(container);
2708 + await act(() => {
2709 + root.render(<input type="text" onclick="1" />);
2710 + });
2711 + }).toErrorDev(
2712 'Warning: Invalid event handler property `onclick`. Did you mean ' +
2713 '`onClick`?\n in input (at **)',
2714 );
@@ -2547,29 +2733,40 @@ describe('ReactDOMComponent', () => {
2733 );
2734 });
2735
2550 - it('gives source code refs for unknown prop warning for update render', () => {
2551 - const container = document.createElement('div');
2736 + it('gives source code refs for unknown prop warning for update render', async () => {
2737 + let container = document.createElement('div');
2738 + let root = ReactDOMClient.createRoot(container);
2739 + await act(() => {
2740 + root.render(<div className="paladin" />);
2741 + });
2742
2553 - ReactTestUtils.renderIntoDocument(<div className="paladin" />, container);
2554 - expect(() =>
2555 - ReactTestUtils.renderIntoDocument(<div class="paladin" />, container),
2556 - ).toErrorDev(
2743 + container = document.createElement('div');
2744 + root = ReactDOMClient.createRoot(container);
2745 + await expect(async () => {
2746 + await act(() => {
2747 + root.render(<div class="paladin" />);
2748 + });
2749 + }).toErrorDev(
2750 'Warning: Invalid DOM property `class`. Did you mean `className`?\n in div (at **)',
2751 );
2752 });
2753
2561 - it('gives source code refs for unknown prop warning for exact elements', () => {
2562 - expect(() =>
2563 - ReactTestUtils.renderIntoDocument(
2564 - <div className="foo1">
2565 - <span class="foo2" />
2566 - <div onClick={() => {}} />
2567 - <strong onclick={() => {}} />
2568 - <div className="foo5" />
2569 - <div className="foo6" />
2570 - </div>,
2571 - ),
2572 - ).toErrorDev([
2754 + it('gives source code refs for unknown prop warning for exact elements', async () => {
2755 + await expect(async () => {
2756 + const container = document.createElement('div');
2757 + const root = ReactDOMClient.createRoot(container);
2758 + await act(() => {
2759 + root.render(
2760 + <div className="foo1">
2761 + <span class="foo2" />
2762 + <div onClick={() => {}} />
2763 + <strong onclick={() => {}} />
2764 + <div className="foo5" />
2765 + <div className="foo6" />
2766 + </div>,
2767 + );
2768 + });
2769 + }).toErrorDev([
2770 'Invalid DOM property `class`. Did you mean `className`?\n in span (at **)',
2771 'Invalid event handler property `onclick`. Did you mean `onClick`?\n in strong (at **)',
2772 ]);
@@ -2594,9 +2791,7 @@ describe('ReactDOMComponent', () => {
2791 ]);
2792 });
2793
2597 - it('gives source code refs for unknown prop warning for exact elements in composition', () => {
2598 - const container = document.createElement('div');
2599 -
2794 + it('gives source code refs for unknown prop warning for exact elements in composition', async () => {
2795 class Parent extends React.Component {
2796 render() {
2797 return (
@@ -2634,9 +2829,13 @@ describe('ReactDOMComponent', () => {
2829 }
2830 }
2831
2637 - expect(() =>
2638 - ReactTestUtils.renderIntoDocument(<Parent />, container),
2639 - ).toErrorDev([
2832 + await expect(async () => {
2833 + const container = document.createElement('div');
2834 + const root = ReactDOMClient.createRoot(container);
2835 + await act(() => {
2836 + root.render(<Parent />);
2837 + });
2838 + }).toErrorDev([
2839 'Invalid DOM property `class`. Did you mean `className`?\n in span (at **)',
2840 'Invalid event handler property `onclick`. Did you mean `onClick`?\n in strong (at **)',
2841 ]);
@@ -2692,20 +2891,26 @@ describe('ReactDOMComponent', () => {
2891 ]);
2892 });
2893
2695 - it('should suggest property name if available', () => {
2696 - expect(() =>
2697 - ReactTestUtils.renderIntoDocument(
2698 - React.createElement('label', {for: 'test'}),
2699 - ),
2700 - ).toErrorDev(
2894 + it('should suggest property name if available', async () => {
2895 + await expect(async () => {
2896 + const container = document.createElement('div');
2897 + const root = ReactDOMClient.createRoot(container);
2898 + await act(() => {
2899 + root.render(React.createElement('label', {for: 'test'}));
2900 + });
2901 + }).toErrorDev(
2902 'Warning: Invalid DOM property `for`. Did you mean `htmlFor`?\n in label',
2903 );
2904
2704 - expect(() =>
2705 - ReactTestUtils.renderIntoDocument(
2706 - React.createElement('input', {type: 'text', autofocus: true}),
2707 - ),
2708 - ).toErrorDev(
2905 + await expect(async () => {
2906 + const container = document.createElement('div');
2907 + const root = ReactDOMClient.createRoot(container);
2908 + await act(() => {
2909 + root.render(
2910 + React.createElement('input', {type: 'text', autofocus: true}),
2911 + );
2912 + });
2913 + }).toErrorDev(
2914 'Warning: Invalid DOM property `autofocus`. Did you mean `autoFocus`?\n in input',
2915 );
2916 });
@@ -2762,10 +2967,15 @@ describe('ReactDOMComponent', () => {
2967 });
2968
2969 describe('Attributes with aliases', function () {
2765 - it('sets aliased attributes on HTML attributes', function () {
2970 + it('sets aliased attributes on HTML attributes', async function () {
2971 let el;
2767 - expect(() => {
2768 - el = ReactTestUtils.renderIntoDocument(<div class="test" />);
2972 + await expect(async () => {
2973 + const container = document.createElement('div');
2974 + const root = ReactDOMClient.createRoot(container);
2975 +
2976 + await act(() => {
2977 + root.render(<div class="test" ref={current => (el = current)} />);
2978 + });
2979 }).toErrorDev(
2980 'Warning: Invalid DOM property `class`. Did you mean `className`?',
2981 );
@@ -2773,10 +2983,15 @@ describe('ReactDOMComponent', () => {
2983 expect(el.className).toBe('test');
2984 });
2985
2776 - it('sets incorrectly cased aliased attributes on HTML attributes with a warning', function () {
2986 + it('sets incorrectly cased aliased attributes on HTML attributes with a warning', async function () {
2987 let el;
2778 - expect(() => {
2779 - el = ReactTestUtils.renderIntoDocument(<div cLASS="test" />);
2988 + await expect(async () => {
2989 + const container = document.createElement('div');
2990 + const root = ReactDOMClient.createRoot(container);
2991 +
2992 + await act(() => {
2993 + root.render(<div cLASS="test" ref={current => (el = current)} />);
2994 + });
2995 }).toErrorDev(
2996 'Warning: Invalid DOM property `cLASS`. Did you mean `className`?',
2997 );
@@ -2784,14 +2999,19 @@ describe('ReactDOMComponent', () => {
2999 expect(el.className).toBe('test');
3000 });
3001
2787 - it('sets aliased attributes on SVG elements with a warning', function () {
3002 + it('sets aliased attributes on SVG elements with a warning', async function () {
3003 let el;
2789 - expect(() => {
2790 - el = ReactTestUtils.renderIntoDocument(
2791 - <svg>
2792 - <text arabic-form="initial" />
2793 - </svg>,
2794 - );
3004 + await expect(async () => {
3005 + const container = document.createElement('div');
3006 + const root = ReactDOMClient.createRoot(container);
3007 +
3008 + await act(() => {
3009 + root.render(
3010 + <svg ref={current => (el = current)}>
3011 + <text arabic-form="initial" />
3012 + </svg>,
3013 + );
3014 + });
3015 }).toErrorDev(
3016 'Warning: Invalid DOM property `arabic-form`. Did you mean `arabicForm`?',
3017 );
@@ -2800,18 +3020,26 @@ describe('ReactDOMComponent', () => {
3020 expect(text.hasAttribute('arabic-form')).toBe(true);
3021 });
3022
2803 - it('sets aliased attributes on custom elements', function () {
2804 - const el = ReactTestUtils.renderIntoDocument(
2805 - <div is="custom-element" class="test" />,
2806 - );
3023 + it('sets aliased attributes on custom elements', async function () {
3024 + const container = document.createElement('div');
3025 + const root = ReactDOMClient.createRoot(container);
3026 + await act(() => {
3027 + root.render(<div is="custom-element" class="test" />);
3028 + });
3029
3030 + const el = container.firstChild;
3031 expect(el.getAttribute('class')).toBe('test');
3032 });
3033
2811 - it('aliased attributes on custom elements with bad casing', function () {
2812 - const el = ReactTestUtils.renderIntoDocument(
2813 - <div is="custom-element" claSS="test" />,
2814 - );
3034 + it('aliased attributes on custom elements with bad casing', async function () {
3035 + const container = document.createElement('div');
3036 + const root = ReactDOMClient.createRoot(container);
3037 +
3038 + await act(() => {
3039 + root.render(<div is="custom-element" claSS="test" />);
3040 + });
3041 +
3042 + const el = container.firstChild;
3043
3044 expect(el.getAttribute('class')).toBe('test');
3045 });
@@ -2831,8 +3059,15 @@ describe('ReactDOMComponent', () => {
3059 });
3060
3061 describe('Custom attributes', function () {
2834 - it('allows assignment of custom attributes with string values', () => {
2835 - const el = ReactTestUtils.renderIntoDocument(<div whatever="30" />);
3062 + it('allows assignment of custom attributes with string values', async () => {
3063 + const container = document.createElement('div');
3064 + const root = ReactDOMClient.createRoot(container);
3065 +
3066 + await act(() => {
3067 + root.render(<div whatever="30" />);
3068 + });
3069 +
3070 + const el = container.firstChild;
3071
3072 expect(el.getAttribute('whatever')).toBe('30');
3073 });
@@ -2853,10 +3088,15 @@ describe('ReactDOMComponent', () => {
3088 expect(container.firstChild.hasAttribute('whatever')).toBe(false);
3089 });
3090
2856 - it('does not assign a boolean custom attributes as a string', function () {
3091 + it('does not assign a boolean custom attributes as a string', async function () {
3092 let el;
2858 - expect(() => {
2859 - el = ReactTestUtils.renderIntoDocument(<div whatever={true} />);
3093 + await expect(async () => {
3094 + const container = document.createElement('div');
3095 + const root = ReactDOMClient.createRoot(container);
3096 +
3097 + await act(() => {
3098 + root.render(<div whatever={true} ref={current => (el = current)} />);
3099 + });
3100 }).toErrorDev(
3101 'Received `true` for a non-boolean attribute `whatever`.\n\n' +
3102 'If you want to write it to the DOM, pass a string instead: ' +
@@ -2866,11 +3106,18 @@ describe('ReactDOMComponent', () => {
3106 expect(el.hasAttribute('whatever')).toBe(false);
3107 });
3108
2869 - it('does not assign an implicit boolean custom attributes', function () {
3109 + it('does not assign an implicit boolean custom attributes', async function () {
3110 let el;
2871 - expect(() => {
2872 - // eslint-disable-next-line react/jsx-boolean-value
2873 - el = ReactTestUtils.renderIntoDocument(<div whatever />);
3111 + await expect(async () => {
3112 + const container = document.createElement('div');
3113 + const root = ReactDOMClient.createRoot(container);
3114 +
3115 + await act(() => {
3116 + root.render(
3117 + // eslint-disable-next-line react/jsx-boolean-value
3118 + <div whatever ref={current => (el = current)} />,
3119 + );
3120 + });
3121 }).toErrorDev(
3122 'Received `true` for a non-boolean attribute `whatever`.\n\n' +
3123 'If you want to write it to the DOM, pass a string instead: ' +
@@ -2880,23 +3127,44 @@ describe('ReactDOMComponent', () => {
3127 expect(el.hasAttribute('whatever')).toBe(false);
3128 });
3129
2883 - it('assigns a numeric custom attributes as a string', function () {
2884 - const el = ReactTestUtils.renderIntoDocument(<div whatever={3} />);
3130 + it('assigns a numeric custom attributes as a string', async function () {
3131 + const container = document.createElement('div');
3132 + const root = ReactDOMClient.createRoot(container);
3133 +
3134 + await act(() => {
3135 + root.render(<div whatever={3} />);
3136 + });
3137 +
3138 + const el = container.firstChild;
3139
3140 expect(el.getAttribute('whatever')).toBe('3');
3141 });
3142
2889 - it('will not assign a function custom attributes', function () {
3143 + it('will not assign a function custom attributes', async function () {
3144 let el;
2891 - expect(() => {
2892 - el = ReactTestUtils.renderIntoDocument(<div whatever={() => {}} />);
3145 + await expect(async () => {
3146 + const container = document.createElement('div');
3147 + const root = ReactDOMClient.createRoot(container);
3148 +
3149 + await act(() => {
3150 + root.render(
3151 + <div whatever={() => {}} ref={current => (el = current)} />,
3152 + );
3153 + });
3154 }).toErrorDev('Warning: Invalid value for prop `whatever` on <div> tag');
3155
3156 expect(el.hasAttribute('whatever')).toBe(false);
3157 });
3158
2898 - it('will assign an object custom attributes', function () {
2899 - const el = ReactTestUtils.renderIntoDocument(<div whatever={{}} />);
3159 + it('will assign an object custom attributes', async function () {
3160 + const container = document.createElement('div');
3161 + const root = ReactDOMClient.createRoot(container);
3162 +
3163 + await act(() => {
3164 + root.render(<div whatever={{}} />);
3165 + });
3166 +
3167 + const el = container.firstChild;
3168 expect(el.getAttribute('whatever')).toBe('[object Object]');
3169 });
3170
@@ -2924,10 +3192,17 @@ describe('ReactDOMComponent', () => {
3192 expect(container.firstChild.innerHTML).toEqual('2020-01-01');
3193 });
3194
2927 - it('allows cased data attributes', () => {
3195 + it('allows cased data attributes', async () => {
3196 let el;
2929 - expect(() => {
2930 - el = ReactTestUtils.renderIntoDocument(<div data-fooBar="true" />);
3197 + await expect(async () => {
3198 + const container = document.createElement('div');
3199 + const root = ReactDOMClient.createRoot(container);
3200 +
3201 + await act(() => {
3202 + root.render(
3203 + <div data-fooBar="true" ref={current => (el = current)} />,
3204 + );
3205 + });
3206 }).toErrorDev(
3207 'React does not recognize the `data-fooBar` prop on a DOM element. ' +
3208 'If you intentionally want it to appear in the DOM as a custom ' +
@@ -2939,10 +3214,15 @@ describe('ReactDOMComponent', () => {
3214 expect(el.getAttribute('data-foobar')).toBe('true');
3215 });
3216
2942 - it('allows cased custom attributes', () => {
3217 + it('allows cased custom attributes', async () => {
3218 let el;
2944 - expect(() => {
2945 - el = ReactTestUtils.renderIntoDocument(<div fooBar="true" />);
3219 + await expect(async () => {
3220 + const container = document.createElement('div');
3221 + const root = ReactDOMClient.createRoot(container);
3222 +
3223 + await act(() => {
3224 + root.render(<div fooBar="true" ref={current => (el = current)} />);
3225 + });
3226 }).toErrorDev(
3227 'React does not recognize the `fooBar` prop on a DOM element. ' +
3228 'If you intentionally want it to appear in the DOM as a custom ' +
@@ -2954,10 +3234,15 @@ describe('ReactDOMComponent', () => {
3234 expect(el.getAttribute('foobar')).toBe('true');
3235 });
3236
2957 - it('warns on NaN attributes', () => {
3237 + it('warns on NaN attributes', async () => {
3238 let el;
2959 - expect(() => {
2960 - el = ReactTestUtils.renderIntoDocument(<div whatever={NaN} />);
3239 + await expect(async () => {
3240 + const container = document.createElement('div');
3241 + const root = ReactDOMClient.createRoot(container);
3242 +
3243 + await act(() => {
3244 + root.render(<div whatever={NaN} ref={current => (el = current)} />);
3245 + });
3246 }).toErrorDev(
3247 'Warning: Received NaN for the `whatever` attribute. If this is ' +
3248 'expected, cast the value to a string.\n in div',
@@ -2981,10 +3266,15 @@ describe('ReactDOMComponent', () => {
3266 expect(el.hasAttribute('whatever')).toBe(false);
3267 });
3268
2984 - it('warns on bad casing of known HTML attributes', function () {
3269 + it('warns on bad casing of known HTML attributes', async function () {
3270 let el;
2986 - expect(() => {
2987 - el = ReactTestUtils.renderIntoDocument(<div SiZe="30" />);
3271 + await expect(async () => {
3272 + const container = document.createElement('div');
3273 + const root = ReactDOMClient.createRoot(container);
3274 +
3275 + await act(() => {
3276 + root.render(<div SiZe="30" ref={current => (el = current)} />);
3277 + });
3278 }).toErrorDev(
3279 'Warning: Invalid DOM property `SiZe`. Did you mean `size`?',
3280 );
@@ -2994,8 +3284,15 @@ describe('ReactDOMComponent', () => {
3284 });
3285
3286 describe('Object stringification', function () {
2997 - it('allows objects on known properties', function () {
2998 - const el = ReactTestUtils.renderIntoDocument(<div acceptCharset={{}} />);
3287 + it('allows objects on known properties', async function () {
3288 + const container = document.createElement('div');
3289 + const root = ReactDOMClient.createRoot(container);
3290 +
3291 + await act(() => {
3292 + root.render(<div acceptCharset={{}} />);
3293 + });
3294 +
3295 + const el = container.firstChild;
3296 expect(el.getAttribute('accept-charset')).toBe('[object Object]');
3297 });
3298
@@ -3050,27 +3347,46 @@ describe('ReactDOMComponent', () => {
3347 );
3348 });
3349
3053 - it('allows objects that inherit a custom toString method', function () {
3350 + it('allows objects that inherit a custom toString method', async function () {
3351 const parent = {toString: () => 'hello.jpg'};
3352 const child = Object.create(parent);
3056 - const el = ReactTestUtils.renderIntoDocument(<img src={child} />);
3353 + const container = document.createElement('div');
3354 + const root = ReactDOMClient.createRoot(container);
3355 +
3356 + await act(() => {
3357 + root.render(<img src={child} />);
3358 + });
3359 +
3360 + const el = container.firstChild;
3361
3362 expect(el.src).toBe('http://localhost/hello.jpg');
3363 });
3364
3061 - it('assigns ajaxify (an important internal FB attribute)', function () {
3365 + it('assigns ajaxify (an important internal FB attribute)', async function () {
3366 const options = {toString: () => 'ajaxy'};
3063 - const el = ReactTestUtils.renderIntoDocument(<div ajaxify={options} />);
3367 + const container = document.createElement('div');
3368 + const root = ReactDOMClient.createRoot(container);
3369 +
3370 + await act(() => {
3371 + root.render(<div ajaxify={options} />);
3372 + });
3373 +
3374 + const el = container.firstChild;
3375
3376 expect(el.getAttribute('ajaxify')).toBe('ajaxy');
3377 });
3378 });
3379
3380 describe('String boolean attributes', function () {
3070 - it('does not assign string boolean attributes for custom attributes', function () {
3381 + it('does not assign string boolean attributes for custom attributes', async function () {
3382 let el;
3072 - expect(() => {
3073 - el = ReactTestUtils.renderIntoDocument(<div whatever={true} />);
3383 + await expect(async () => {
3384 + const container = document.createElement('div');
3385 + const root = ReactDOMClient.createRoot(container);
3386 +
3387 + await act(() => {
3388 + root.render(<div whatever={true} ref={current => (el = current)} />);
3389 + });
3390 }).toErrorDev(
3391 'Received `true` for a non-boolean attribute `whatever`.\n\n' +
3392 'If you want to write it to the DOM, pass a string instead: ' +
@@ -3080,31 +3396,57 @@ describe('ReactDOMComponent', () => {
3396 expect(el.hasAttribute('whatever')).toBe(false);
3397 });
3398
3083 - it('stringifies the boolean true for allowed attributes', function () {
3084 - const el = ReactTestUtils.renderIntoDocument(<div spellCheck={true} />);
3399 + it('stringifies the boolean true for allowed attributes', async function () {
3400 + const container = document.createElement('div');
3401 + const root = ReactDOMClient.createRoot(container);
3402 +
3403 + await act(() => {
3404 + root.render(<div spellCheck={true} />);
3405 + });
3406 +
3407 + const el = container.firstChild;
3408
3409 expect(el.getAttribute('spellCheck')).toBe('true');
3410 });
3411
3089 - it('stringifies the boolean false for allowed attributes', function () {
3090 - const el = ReactTestUtils.renderIntoDocument(<div spellCheck={false} />);
3412 + it('stringifies the boolean false for allowed attributes', async function () {
3413 + const container = document.createElement('div');
3414 + const root = ReactDOMClient.createRoot(container);
3415 +
3416 + await act(() => {
3417 + root.render(<div spellCheck={false} />);
3418 + });
3419 +
3420 + const el = container.firstChild;
3421
3422 expect(el.getAttribute('spellCheck')).toBe('false');
3423 });
3424
3095 - it('stringifies implicit booleans for allowed attributes', function () {
3096 - // eslint-disable-next-line react/jsx-boolean-value
3097 - const el = ReactTestUtils.renderIntoDocument(<div spellCheck />);
3425 + it('stringifies implicit booleans for allowed attributes', async function () {
3426 + const container = document.createElement('div');
3427 + const root = ReactDOMClient.createRoot(container);
3428 +
3429 + await act(() => {
3430 + // eslint-disable-next-line react/jsx-boolean-value
3431 + root.render(<div spellCheck />);
3432 + });
3433 +
3434 + const el = container.firstChild;
3435
3436 expect(el.getAttribute('spellCheck')).toBe('true');
3437 });
3438 });
3439
3440 describe('Boolean attributes', function () {
3104 - it('warns on the ambiguous string value "false"', function () {
3441 + it('warns on the ambiguous string value "false"', async function () {
3442 let el;
3106 - expect(() => {
3107 - el = ReactTestUtils.renderIntoDocument(<div hidden="false" />);
3443 + await expect(async () => {
3444 + const container = document.createElement('div');
3445 + const root = ReactDOMClient.createRoot(container);
3446 +
3447 + await act(() => {
3448 + root.render(<div hidden="false" ref={current => (el = current)} />);
3449 + });
3450 }).toErrorDev(
3451 'Received the string `false` for the boolean attribute `hidden`. ' +
3452 'The browser will interpret it as a truthy value. ' +
@@ -3114,10 +3456,15 @@ describe('ReactDOMComponent', () => {
3456 expect(el.getAttribute('hidden')).toBe('');
3457 });
3458
3117 - it('warns on the potentially-ambiguous string value "true"', function () {
3459 + it('warns on the potentially-ambiguous string value "true"', async function () {
3460 let el;
3119 - expect(() => {
3120 - el = ReactTestUtils.renderIntoDocument(<div hidden="true" />);
3461 + await expect(async () => {
3462 + const container = document.createElement('div');
3463 + const root = ReactDOMClient.createRoot(container);
3464 +
3465 + await act(() => {
3466 + root.render(<div hidden="true" ref={current => (el = current)} />);
3467 + });
3468 }).toErrorDev(
3469 'Received the string `true` for the boolean attribute `hidden`. ' +
3470 'Although this works, it will not work as expected if you pass the string "false". ' +
@@ -3129,14 +3476,19 @@ describe('ReactDOMComponent', () => {
3476 });
3477
3478 describe('Hyphenated SVG elements', function () {
3132 - it('the font-face element is not a custom element', function () {
3479 + it('the font-face element is not a custom element', async function () {
3480 let el;
3134 - expect(() => {
3135 - el = ReactTestUtils.renderIntoDocument(
3136 - <svg>
3137 - <font-face x-height={false} />
3138 - </svg>,
3139 - );
3481 + await expect(async () => {
3482 + const container = document.createElement('div');
3483 + const root = ReactDOMClient.createRoot(container);
3484 +
3485 + await act(() => {
3486 + root.render(
3487 + <svg ref={current => (el = current)}>
3488 + <font-face x-height={false} />
3489 + </svg>,
3490 + );
3491 + });
3492 }).toErrorDev(
3493 'Warning: Invalid DOM property `x-height`. Did you mean `xHeight`',
3494 );
@@ -3146,14 +3498,19 @@ describe('ReactDOMComponent', () => {
3498 );
3499 });
3500
3149 - it('the font-face element does not allow unknown boolean values', function () {
3501 + it('the font-face element does not allow unknown boolean values', async function () {
3502 let el;
3151 - expect(() => {
3152 - el = ReactTestUtils.renderIntoDocument(
3153 - <svg>
3154 - <font-face whatever={false} />
3155 - </svg>,
3156 - );
3503 + await expect(async () => {
3504 + const container = document.createElement('div');
3505 + const root = ReactDOMClient.createRoot(container);
3506 +
3507 + await act(() => {
3508 + root.render(
3509 + <svg ref={current => (el = current)}>
3510 + <font-face whatever={false} />
3511 + </svg>,
3512 + );
3513 + });
3514 }).toErrorDev(
3515 'Received `false` for a non-boolean attribute `whatever`.\n\n' +
3516 'If you want to write it to the DOM, pass a string instead: ' +
@@ -3324,7 +3681,7 @@ describe('ReactDOMComponent', () => {
3681 expect(typeof portalContainer.onclick).toBe('function');
3682 });
3683
3327 - it('does not add onclick handler to the React root', () => {
3684 + it('does not add onclick handler to the React root in legacy mode', () => {
3685 const container = document.createElement('div');
3686
3687 function Component() {