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() {