Convert ReactMultiChild-test.js to createRoot (#28117)
Matt Carroll committed
Jan 26, 2024 at 13:18 UTC
759811b0627384e5dde8ac81397cb2b8c7390298
1 file changed
+153
-104
packages/react-dom/src/__tests__/ReactMultiChild-test.js
+153
-104
@@ -11,17 +11,20 @@
11
12
describe('ReactMultiChild', () => {
13
let React;
14
- let ReactDOM;
14
+ let ReactDOMClient;
15
+ let act;
16
17
beforeEach(() => {
18
jest.resetModules();
19
React = require('react');
19
- ReactDOM = require('react-dom');
20
+ ReactDOMClient = require('react-dom/client');
21
+ act = require('internal-test-utils').act;
22
});
23
24
describe('reconciliation', () => {
23
- it('should update children when possible', () => {
25
+ it('should update children when possible', async () => {
26
const container = document.createElement('div');
27
+ const root = ReactDOMClient.createRoot(container);
28
29
const mockMount = jest.fn();
30
const mockUpdate = jest.fn();
@@ -40,31 +43,34 @@ describe('ReactMultiChild', () => {
43
expect(mockUpdate).toHaveBeenCalledTimes(0);
44
expect(mockUnmount).toHaveBeenCalledTimes(0);
45
43
- ReactDOM.render(
44
- <div>
45
- <MockComponent />
46
- </div>,
47
- container,
48
- );
46
+ await act(async () => {
47
+ root.render(
48
+ <div>
49
+ <MockComponent />
50
+ </div>,
51
+ );
52
+ });
53
54
expect(mockMount).toHaveBeenCalledTimes(1);
55
expect(mockUpdate).toHaveBeenCalledTimes(0);
56
expect(mockUnmount).toHaveBeenCalledTimes(0);
57
54
- ReactDOM.render(
55
- <div>
56
- <MockComponent />
57
- </div>,
58
- container,
59
- );
58
+ await act(async () => {
59
+ root.render(
60
+ <div>
61
+ <MockComponent />
62
+ </div>,
63
+ );
64
+ });
65
66
expect(mockMount).toHaveBeenCalledTimes(1);
67
expect(mockUpdate).toHaveBeenCalledTimes(1);
68
expect(mockUnmount).toHaveBeenCalledTimes(0);
69
});
70
66
- it('should replace children with different constructors', () => {
71
+ it('should replace children with different constructors', async () => {
72
const container = document.createElement('div');
73
+ const root = ReactDOMClient.createRoot(container);
74
75
const mockMount = jest.fn();
76
const mockUnmount = jest.fn();
@@ -80,29 +86,32 @@ describe('ReactMultiChild', () => {
86
expect(mockMount).toHaveBeenCalledTimes(0);
87
expect(mockUnmount).toHaveBeenCalledTimes(0);
88
83
- ReactDOM.render(
84
- <div>
85
- <MockComponent />
86
- </div>,
87
- container,
88
- );
89
+ await act(async () => {
90
+ root.render(
91
+ <div>
92
+ <MockComponent />
93
+ </div>,
94
+ );
95
+ });
96
97
expect(mockMount).toHaveBeenCalledTimes(1);
98
expect(mockUnmount).toHaveBeenCalledTimes(0);
99
93
- ReactDOM.render(
94
- <div>
95
- <span />
96
- </div>,
97
- container,
98
- );
100
+ await act(async () => {
101
+ root.render(
102
+ <div>
103
+ <span />
104
+ </div>,
105
+ );
106
+ });
107
108
expect(mockMount).toHaveBeenCalledTimes(1);
109
expect(mockUnmount).toHaveBeenCalledTimes(1);
110
});
111
104
- it('should NOT replace children with different owners', () => {
112
+ it('should NOT replace children with different owners', async () => {
113
const container = document.createElement('div');
114
+ const root = ReactDOMClient.createRoot(container);
115
116
const mockMount = jest.fn();
117
const mockUnmount = jest.fn();
@@ -124,24 +133,28 @@ describe('ReactMultiChild', () => {
133
expect(mockMount).toHaveBeenCalledTimes(0);
134
expect(mockUnmount).toHaveBeenCalledTimes(0);
135
127
- ReactDOM.render(<WrapperComponent />, container);
136
+ await act(async () => {
137
+ root.render(<WrapperComponent />);
138
+ });
139
140
expect(mockMount).toHaveBeenCalledTimes(1);
141
expect(mockUnmount).toHaveBeenCalledTimes(0);
142
132
- ReactDOM.render(
133
- <WrapperComponent>
134
- <MockComponent />
135
- </WrapperComponent>,
136
- container,
137
- );
143
+ await act(async () => {
144
+ root.render(
145
+ <WrapperComponent>
146
+ <MockComponent />
147
+ </WrapperComponent>,
148
+ );
149
+ });
150
151
expect(mockMount).toHaveBeenCalledTimes(1);
152
expect(mockUnmount).toHaveBeenCalledTimes(0);
153
});
154
143
- it('should replace children with different keys', () => {
155
+ it('should replace children with different keys', async () => {
156
const container = document.createElement('div');
157
+ const root = ReactDOMClient.createRoot(container);
158
159
const mockMount = jest.fn();
160
const mockUnmount = jest.fn();
@@ -157,29 +170,32 @@ describe('ReactMultiChild', () => {
170
expect(mockMount).toHaveBeenCalledTimes(0);
171
expect(mockUnmount).toHaveBeenCalledTimes(0);
172
160
- ReactDOM.render(
161
- <div>
162
- <MockComponent key="A" />
163
- </div>,
164
- container,
165
- );
173
+ await act(async () => {
174
+ root.render(
175
+ <div>
176
+ <MockComponent key="A" />
177
+ </div>,
178
+ );
179
+ });
180
181
expect(mockMount).toHaveBeenCalledTimes(1);
182
expect(mockUnmount).toHaveBeenCalledTimes(0);
183
170
- ReactDOM.render(
171
- <div>
172
- <MockComponent key="B" />
173
- </div>,
174
- container,
175
- );
184
+ await act(async () => {
185
+ root.render(
186
+ <div>
187
+ <MockComponent key="B" />
188
+ </div>,
189
+ );
190
+ });
191
192
expect(mockMount).toHaveBeenCalledTimes(2);
193
expect(mockUnmount).toHaveBeenCalledTimes(1);
194
});
195
181
- it('should warn for duplicated array keys with component stack info', () => {
196
+ it('should warn for duplicated array keys with component stack info', async () => {
197
const container = document.createElement('div');
198
+ const root = ReactDOMClient.createRoot(container);
199
200
class WrapperComponent extends React.Component {
201
render() {
@@ -196,14 +212,15 @@ describe('ReactMultiChild', () => {
212
);
213
}
214
}
199
-
200
- ReactDOM.render(<Parent>{[<div key="1" />]}</Parent>, container);
201
-
202
- expect(() =>
203
- ReactDOM.render(
204
- <Parent>{[<div key="1" />, <div key="1" />]}</Parent>,
205
- container,
206
- ),
215
+ await act(async () => {
216
+ root.render(<Parent>{[<div key="1" />]}</Parent>);
217
+ });
218
+
219
+ await expect(
220
+ async () =>
221
+ await act(async () => {
222
+ root.render(<Parent>{[<div key="1" />, <div key="1" />]}</Parent>);
223
+ }),
224
).toErrorDev(
225
'Encountered two children with the same key, `1`. ' +
226
'Keys should be unique so that components maintain their identity ' +
@@ -217,8 +234,9 @@ describe('ReactMultiChild', () => {
234
);
235
});
236
220
- it('should warn for duplicated iterable keys with component stack info', () => {
237
+ it('should warn for duplicated iterable keys with component stack info', async () => {
238
const container = document.createElement('div');
239
+ const root = ReactDOMClient.createRoot(container);
240
241
class WrapperComponent extends React.Component {
242
render() {
@@ -253,17 +271,19 @@ describe('ReactMultiChild', () => {
271
},
272
};
273
}
256
-
257
- ReactDOM.render(
258
- <Parent>{createIterable([<div key="1" />])}</Parent>,
259
- container,
260
- );
261
-
262
- expect(() =>
263
- ReactDOM.render(
264
- <Parent>{createIterable([<div key="1" />, <div key="1" />])}</Parent>,
265
- container,
266
- ),
274
+ await act(async () => {
275
+ root.render(<Parent>{createIterable([<div key="1" />])}</Parent>);
276
+ });
277
+
278
+ await expect(
279
+ async () =>
280
+ await act(async () => {
281
+ root.render(
282
+ <Parent>
283
+ {createIterable([<div key="1" />, <div key="1" />])}
284
+ </Parent>,
285
+ );
286
+ }),
287
).toErrorDev(
288
'Encountered two children with the same key, `1`. ' +
289
'Keys should be unique so that components maintain their identity ' +
@@ -278,7 +298,7 @@ describe('ReactMultiChild', () => {
298
});
299
});
300
281
- it('should warn for using maps as children with owner info', () => {
301
+ it('should warn for using maps as children with owner info', async () => {
302
class Parent extends React.Component {
303
render() {
304
return (
@@ -294,7 +314,13 @@ describe('ReactMultiChild', () => {
314
}
315
}
316
const container = document.createElement('div');
297
- expect(() => ReactDOM.render(<Parent />, container)).toErrorDev(
317
+ const root = ReactDOMClient.createRoot(container);
318
+ await expect(
319
+ async () =>
320
+ await act(async () => {
321
+ root.render(<Parent />);
322
+ }),
323
+ ).toErrorDev(
324
'Using Maps as children is not supported. ' +
325
'Use an array of keyed ReactElements instead.\n' +
326
' in div (at **)\n' +
@@ -302,15 +328,18 @@ describe('ReactMultiChild', () => {
328
);
329
});
330
305
- it('should warn for using generators as children', () => {
331
+ it('should warn for using generators as children', async () => {
332
function* Foo() {
333
yield <h1 key="1">Hello</h1>;
334
yield <h1 key="2">World</h1>;
335
}
336
311
- const div = document.createElement('div');
312
- expect(() => {
313
- ReactDOM.render(<Foo />, div);
337
+ const container = document.createElement('div');
338
+ const root = ReactDOMClient.createRoot(container);
339
+ await expect(async () => {
340
+ await act(async () => {
341
+ root.render(<Foo />);
342
+ });
343
}).toErrorDev(
344
'Using Generators as children is unsupported and will likely yield ' +
345
'unexpected results because enumerating a generator mutates it. You may ' +
@@ -320,10 +349,12 @@ describe('ReactMultiChild', () => {
349
);
350
351
// Test de-duplication
323
- ReactDOM.render(<Foo />, div);
352
+ await act(async () => {
353
+ root.render(<Foo />);
354
+ });
355
});
356
326
- it('should not warn for using generators in legacy iterables', () => {
357
+ it('should not warn for using generators in legacy iterables', async () => {
358
const fooIterable = {
359
'@@iterator': function* () {
360
yield <h1 key="1">Hello</h1>;
@@ -335,15 +366,20 @@ describe('ReactMultiChild', () => {
366
return fooIterable;
367
}
368
338
- const div = document.createElement('div');
339
- ReactDOM.render(<Foo />, div);
340
- expect(div.textContent).toBe('HelloWorld');
369
+ const container = document.createElement('div');
370
+ const root = ReactDOMClient.createRoot(container);
371
+ await act(async () => {
372
+ root.render(<Foo />);
373
+ });
374
+ expect(container.textContent).toBe('HelloWorld');
375
342
- ReactDOM.render(<Foo />, div);
343
- expect(div.textContent).toBe('HelloWorld');
376
+ await act(async () => {
377
+ root.render(<Foo />);
378
+ });
379
+ expect(container.textContent).toBe('HelloWorld');
380
});
381
346
- it('should not warn for using generators in modern iterables', () => {
382
+ it('should not warn for using generators in modern iterables', async () => {
383
const fooIterable = {
384
[Symbol.iterator]: function* () {
385
yield <h1 key="1">Hello</h1>;
@@ -356,14 +392,19 @@ describe('ReactMultiChild', () => {
392
}
393
394
const div = document.createElement('div');
359
- ReactDOM.render(<Foo />, div);
395
+ const root = ReactDOMClient.createRoot(div);
396
+ await act(async () => {
397
+ root.render(<Foo />);
398
+ });
399
expect(div.textContent).toBe('HelloWorld');
400
362
- ReactDOM.render(<Foo />, div);
401
+ await act(async () => {
402
+ root.render(<Foo />);
403
+ });
404
expect(div.textContent).toBe('HelloWorld');
405
});
406
366
- it('should reorder bailed-out children', () => {
407
+ it('should reorder bailed-out children', async () => {
408
class LetterInner extends React.Component {
409
render() {
410
return <div>{this.props.char}</div>;
@@ -393,15 +434,20 @@ describe('ReactMultiChild', () => {
434
}
435
436
const container = document.createElement('div');
437
+ const root = ReactDOMClient.createRoot(container);
438
439
// Two random strings -- some additions, some removals, some moves
398
- ReactDOM.render(<Letters letters="XKwHomsNjIkBcQWFbiZU" />, container);
440
+ await act(async () => {
441
+ root.render(<Letters letters="XKwHomsNjIkBcQWFbiZU" />);
442
+ });
443
expect(container.textContent).toBe('XKwHomsNjIkBcQWFbiZU');
400
- ReactDOM.render(<Letters letters="EHCjpdTUuiybDvhRJwZt" />, container);
444
+ await act(async () => {
445
+ root.render(<Letters letters="EHCjpdTUuiybDvhRJwZt" />);
446
+ });
447
expect(container.textContent).toBe('EHCjpdTUuiybDvhRJwZt');
448
});
449
404
- it('prepares new children before unmounting old', () => {
450
+ it('prepares new children before unmounting old', async () => {
451
const log = [];
452
453
class Spy extends React.Component {
@@ -426,20 +472,23 @@ describe('ReactMultiChild', () => {
472
const SpyB = props => <Spy {...props} />;
473
474
const container = document.createElement('div');
429
- ReactDOM.render(
430
- <div>
431
- <SpyA key="one" name="oneA" />
432
- <SpyA key="two" name="twoA" />
433
- </div>,
434
- container,
435
- );
436
- ReactDOM.render(
437
- <div>
438
- <SpyB key="one" name="oneB" />
439
- <SpyB key="two" name="twoB" />
440
- </div>,
441
- container,
442
- );
475
+ const root = ReactDOMClient.createRoot(container);
476
+ await act(async () => {
477
+ root.render(
478
+ <div>
479
+ <SpyA key="one" name="oneA" />
480
+ <SpyA key="two" name="twoA" />
481
+ </div>,
482
+ );
483
+ });
484
+ await act(async () => {
485
+ root.render(
486
+ <div>
487
+ <SpyB key="one" name="oneB" />
488
+ <SpyB key="two" name="twoB" />
489
+ </div>,
490
+ );
491
+ });
492
493
expect(log).toEqual([
494
'oneA componentWillMount',