Convert DOMPropertyOperations-test to createRoot (#27911)
Convert DOMPropertyOperations-test to createRoot --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/27911). * #27914 * __->__ #27911
Jan Kassens committed
Jan 9, 2024 at 15:30 UTC
ef2859d50bb6b4b31b304f4fe4bb43dc273a9b54
1 file changed
+468
-273
packages/react-dom/src/__tests__/DOMPropertyOperations-test.js
+468
-273
@@ -17,12 +17,14 @@ const {
17
18
describe('DOMPropertyOperations', () => {
19
let React;
20
- let ReactDOM;
20
+ let ReactDOMClient;
21
+ let act;
22
23
beforeEach(() => {
24
jest.resetModules();
25
React = require('react');
25
- ReactDOM = require('react-dom');
26
+ ReactDOMClient = require('react-dom/client');
27
+ ({act} = require('internal-test-utils'));
28
});
29
30
// Sets a value in a way that React doesn't see,
@@ -37,25 +39,34 @@ describe('DOMPropertyOperations', () => {
39
).set;
40
41
describe('setValueForProperty', () => {
40
- it('should set values as properties by default', () => {
42
+ it('should set values as properties by default', async () => {
43
const container = document.createElement('div');
42
- ReactDOM.render(<div title="Tip!" />, container);
44
+ const root = ReactDOMClient.createRoot(container);
45
+ await act(() => {
46
+ root.render(<div title="Tip!" />);
47
+ });
48
expect(container.firstChild.title).toBe('Tip!');
49
});
50
46
- it('should set values as attributes if necessary', () => {
51
+ it('should set values as attributes if necessary', async () => {
52
const container = document.createElement('div');
48
- ReactDOM.render(<div role="#" />, container);
53
+ const root = ReactDOMClient.createRoot(container);
54
+ await act(() => {
55
+ root.render(<div role="#" />);
56
+ });
57
expect(container.firstChild.getAttribute('role')).toBe('#');
58
expect(container.firstChild.role).toBeUndefined();
59
});
60
53
- it('should set values as namespace attributes if necessary', () => {
61
+ it('should set values as namespace attributes if necessary', async () => {
62
const container = document.createElementNS(
63
'http://www.w3.org/2000/svg',
64
'svg',
65
);
58
- ReactDOM.render(<image xlinkHref="about:blank" />, container);
66
+ const root = ReactDOMClient.createRoot(container);
67
+ await act(() => {
68
+ root.render(<image xlinkHref="about:blank" />);
69
+ });
70
expect(
71
container.firstChild.getAttributeNS(
72
'http://www.w3.org/1999/xlink',
@@ -64,23 +75,38 @@ describe('DOMPropertyOperations', () => {
75
).toBe('about:blank');
76
});
77
67
- it('should set values as boolean properties', () => {
78
+ it('should set values as boolean properties', async () => {
79
const container = document.createElement('div');
69
- ReactDOM.render(<div disabled="disabled" />, container);
80
+ const root = ReactDOMClient.createRoot(container);
81
+ await act(() => {
82
+ root.render(<div disabled="disabled" />);
83
+ });
84
expect(container.firstChild.getAttribute('disabled')).toBe('');
71
- ReactDOM.render(<div disabled={true} />, container);
85
+ await act(() => {
86
+ root.render(<div disabled={true} />);
87
+ });
88
expect(container.firstChild.getAttribute('disabled')).toBe('');
73
- ReactDOM.render(<div disabled={false} />, container);
89
+ await act(() => {
90
+ root.render(<div disabled={false} />);
91
+ });
92
expect(container.firstChild.getAttribute('disabled')).toBe(null);
75
- ReactDOM.render(<div disabled={true} />, container);
76
- ReactDOM.render(<div disabled={null} />, container);
93
+ await act(() => {
94
+ root.render(<div disabled={true} />);
95
+ });
96
+ await act(() => {
97
+ root.render(<div disabled={null} />);
98
+ });
99
expect(container.firstChild.getAttribute('disabled')).toBe(null);
78
- ReactDOM.render(<div disabled={true} />, container);
79
- ReactDOM.render(<div disabled={undefined} />, container);
100
+ await act(() => {
101
+ root.render(<div disabled={true} />);
102
+ });
103
+ await act(() => {
104
+ root.render(<div disabled={undefined} />);
105
+ });
106
expect(container.firstChild.getAttribute('disabled')).toBe(null);
107
});
108
83
- it('should convert attribute values to string first', () => {
109
+ it('should convert attribute values to string first', async () => {
110
// Browsers default to this behavior, but some test environments do not.
111
// This ensures that we have consistent behavior.
112
const obj = {
@@ -90,13 +116,19 @@ describe('DOMPropertyOperations', () => {
116
};
117
118
const container = document.createElement('div');
93
- ReactDOM.render(<div className={obj} />, container);
119
+ const root = ReactDOMClient.createRoot(container);
120
+ await act(() => {
121
+ root.render(<div className={obj} />);
122
+ });
123
expect(container.firstChild.getAttribute('class')).toBe('css-class');
124
});
125
97
- it('should not remove empty attributes for special input properties', () => {
126
+ it('should not remove empty attributes for special input properties', async () => {
127
const container = document.createElement('div');
99
- ReactDOM.render(<input value="" onChange={() => {}} />, container);
128
+ const root = ReactDOMClient.createRoot(container);
129
+ await act(() => {
130
+ root.render(<input value="" onChange={() => {}} />);
131
+ });
132
if (disableInputAttributeSyncing) {
133
expect(container.firstChild.hasAttribute('value')).toBe(false);
134
} else {
@@ -105,79 +137,114 @@ describe('DOMPropertyOperations', () => {
137
expect(container.firstChild.value).toBe('');
138
});
139
108
- it('should not remove empty attributes for special option properties', () => {
140
+ it('should not remove empty attributes for special option properties', async () => {
141
const container = document.createElement('div');
110
- ReactDOM.render(
111
- <select>
112
- <option value="">empty</option>
113
- <option>filled</option>
114
- </select>,
115
- container,
116
- );
142
+ const root = ReactDOMClient.createRoot(container);
143
+ await act(() => {
144
+ root.render(
145
+ <select>
146
+ <option value="">empty</option>
147
+ <option>filled</option>
148
+ </select>,
149
+ );
150
+ });
151
// Regression test for https://github.com/facebook/react/issues/6219
152
expect(container.firstChild.firstChild.value).toBe('');
153
expect(container.firstChild.lastChild.value).toBe('filled');
154
});
155
122
- it('should remove for falsey boolean properties', () => {
156
+ it('should remove for falsey boolean properties', async () => {
157
const container = document.createElement('div');
124
- ReactDOM.render(<div allowFullScreen={false} />, container);
158
+ const root = ReactDOMClient.createRoot(container);
159
+ await act(() => {
160
+ root.render(<div allowFullScreen={false} />);
161
+ });
162
expect(container.firstChild.hasAttribute('allowFullScreen')).toBe(false);
163
});
164
128
- it('should remove when setting custom attr to null', () => {
165
+ it('should remove when setting custom attr to null', async () => {
166
const container = document.createElement('div');
130
- ReactDOM.render(<div data-foo="bar" />, container);
167
+ const root = ReactDOMClient.createRoot(container);
168
+ await act(() => {
169
+ root.render(<div data-foo="bar" />);
170
+ });
171
expect(container.firstChild.hasAttribute('data-foo')).toBe(true);
132
- ReactDOM.render(<div data-foo={null} />, container);
172
+ await act(() => {
173
+ root.render(<div data-foo={null} />);
174
+ });
175
expect(container.firstChild.hasAttribute('data-foo')).toBe(false);
176
});
177
136
- it('should set className to empty string instead of null', () => {
178
+ it('should set className to empty string instead of null', async () => {
179
const container = document.createElement('div');
138
- ReactDOM.render(<div className="selected" />, container);
180
+ const root = ReactDOMClient.createRoot(container);
181
+ await act(() => {
182
+ root.render(<div className="selected" />);
183
+ });
184
expect(container.firstChild.className).toBe('selected');
140
- ReactDOM.render(<div className={null} />, container);
185
+ await act(() => {
186
+ root.render(<div className={null} />);
187
+ });
188
// className should be '', not 'null' or null (which becomes 'null' in
189
// some browsers)
190
expect(container.firstChild.className).toBe('');
191
expect(container.firstChild.getAttribute('class')).toBe(null);
192
});
193
147
- it('should remove property properly for boolean properties', () => {
194
+ it('should remove property properly for boolean properties', async () => {
195
const container = document.createElement('div');
149
- ReactDOM.render(<div hidden={true} />, container);
196
+ const root = ReactDOMClient.createRoot(container);
197
+ await act(() => {
198
+ root.render(<div hidden={true} />);
199
+ });
200
expect(container.firstChild.hasAttribute('hidden')).toBe(true);
151
- ReactDOM.render(<div hidden={false} />, container);
201
+ await act(() => {
202
+ root.render(<div hidden={false} />);
203
+ });
204
expect(container.firstChild.hasAttribute('hidden')).toBe(false);
205
});
206
155
- it('should always assign the value attribute for non-inputs', function () {
207
+ it('should always assign the value attribute for non-inputs', async () => {
208
const container = document.createElement('div');
157
- ReactDOM.render(<progress />, container);
209
+ const root = ReactDOMClient.createRoot(container);
210
+ await act(() => {
211
+ root.render(<progress />);
212
+ });
213
spyOnDevAndProd(container.firstChild, 'setAttribute');
159
- ReactDOM.render(<progress value={30} />, container);
160
- ReactDOM.render(<progress value="30" />, container);
214
+ await act(() => {
215
+ root.render(<progress value={30} />);
216
+ });
217
+ await act(() => {
218
+ root.render(<progress value="30" />);
219
+ });
220
expect(container.firstChild.setAttribute).toHaveBeenCalledTimes(2);
221
});
222
164
- it('should return the progress to intermediate state on null value', () => {
223
+ it('should return the progress to intermediate state on null value', async () => {
224
const container = document.createElement('div');
166
- ReactDOM.render(<progress value={30} />, container);
167
- ReactDOM.render(<progress value={null} />, container);
225
+ const root = ReactDOMClient.createRoot(container);
226
+ await act(() => {
227
+ root.render(<progress value={30} />);
228
+ });
229
+ await act(() => {
230
+ root.render(<progress value={null} />);
231
+ });
232
// Ensure we move progress back to an indeterminate state.
233
// Regression test for https://github.com/facebook/react/issues/6119
234
expect(container.firstChild.hasAttribute('value')).toBe(false);
235
});
236
237
// @gate enableCustomElementPropertySupport
174
- it('custom element custom events lowercase', () => {
238
+ it('custom element custom events lowercase', async () => {
239
const oncustomevent = jest.fn();
240
function Test() {
241
return <my-custom-element oncustomevent={oncustomevent} />;
242
}
243
const container = document.createElement('div');
180
- ReactDOM.render(<Test />, container);
244
+ const root = ReactDOMClient.createRoot(container);
245
+ await act(() => {
246
+ root.render(<Test />);
247
+ });
248
container
249
.querySelector('my-custom-element')
250
.dispatchEvent(new Event('customevent'));
@@ -185,13 +252,16 @@ describe('DOMPropertyOperations', () => {
252
});
253
254
// @gate enableCustomElementPropertySupport
188
- it('custom element custom events uppercase', () => {
255
+ it('custom element custom events uppercase', async () => {
256
const oncustomevent = jest.fn();
257
function Test() {
258
return <my-custom-element onCustomevent={oncustomevent} />;
259
}
260
const container = document.createElement('div');
194
- ReactDOM.render(<Test />, container);
261
+ const root = ReactDOMClient.createRoot(container);
262
+ await act(() => {
263
+ root.render(<Test />);
264
+ });
265
container
266
.querySelector('my-custom-element')
267
.dispatchEvent(new Event('Customevent'));
@@ -199,13 +269,16 @@ describe('DOMPropertyOperations', () => {
269
});
270
271
// @gate enableCustomElementPropertySupport
202
- it('custom element custom event with dash in name', () => {
272
+ it('custom element custom event with dash in name', async () => {
273
const oncustomevent = jest.fn();
274
function Test() {
275
return <my-custom-element oncustom-event={oncustomevent} />;
276
}
277
const container = document.createElement('div');
208
- ReactDOM.render(<Test />, container);
278
+ const root = ReactDOMClient.createRoot(container);
279
+ await act(() => {
280
+ root.render(<Test />);
281
+ });
282
container
283
.querySelector('my-custom-element')
284
.dispatchEvent(new Event('custom-event'));
@@ -213,48 +286,59 @@ describe('DOMPropertyOperations', () => {
286
});
287
288
// @gate enableCustomElementPropertySupport
216
- it('custom element remove event handler', () => {
289
+ it('custom element remove event handler', async () => {
290
const oncustomevent = jest.fn();
291
function Test(props) {
292
return <my-custom-element oncustomevent={props.handler} />;
293
}
294
295
const container = document.createElement('div');
223
- ReactDOM.render(<Test handler={oncustomevent} />, container);
296
+ const root = ReactDOMClient.createRoot(container);
297
+ await act(() => {
298
+ root.render(<Test handler={oncustomevent} />);
299
+ });
300
const customElement = container.querySelector('my-custom-element');
301
customElement.dispatchEvent(new Event('customevent'));
302
expect(oncustomevent).toHaveBeenCalledTimes(1);
303
228
- ReactDOM.render(<Test handler={false} />, container);
304
+ await act(() => {
305
+ root.render(<Test handler={false} />);
306
+ });
307
// Make sure that the second render didn't create a new element. We want
308
// to make sure removeEventListener actually gets called on the same element.
309
expect(customElement).toBe(customElement);
310
customElement.dispatchEvent(new Event('customevent'));
311
expect(oncustomevent).toHaveBeenCalledTimes(1);
312
235
- ReactDOM.render(<Test handler={oncustomevent} />, container);
313
+ await act(() => {
314
+ root.render(<Test handler={oncustomevent} />);
315
+ });
316
customElement.dispatchEvent(new Event('customevent'));
317
expect(oncustomevent).toHaveBeenCalledTimes(2);
318
319
const oncustomevent2 = jest.fn();
240
- ReactDOM.render(<Test handler={oncustomevent2} />, container);
320
+ await act(() => {
321
+ root.render(<Test handler={oncustomevent2} />);
322
+ });
323
customElement.dispatchEvent(new Event('customevent'));
324
expect(oncustomevent).toHaveBeenCalledTimes(2);
325
expect(oncustomevent2).toHaveBeenCalledTimes(1);
326
});
327
246
- it('custom elements shouldnt have non-functions for on* attributes treated as event listeners', () => {
328
+ it('custom elements shouldnt have non-functions for on* attributes treated as event listeners', async () => {
329
const container = document.createElement('div');
248
- ReactDOM.render(
249
- <my-custom-element
250
- onstring={'hello'}
251
- onobj={{hello: 'world'}}
252
- onarray={['one', 'two']}
253
- ontrue={true}
254
- onfalse={false}
255
- />,
256
- container,
257
- );
330
+ const root = ReactDOMClient.createRoot(container);
331
+ await act(() => {
332
+ root.render(
333
+ <my-custom-element
334
+ onstring={'hello'}
335
+ onobj={{hello: 'world'}}
336
+ onarray={['one', 'two']}
337
+ ontrue={true}
338
+ onfalse={false}
339
+ />,
340
+ );
341
+ });
342
const customElement = container.querySelector('my-custom-element');
343
expect(customElement.getAttribute('onstring')).toBe('hello');
344
expect(customElement.getAttribute('onobj')).toBe('[object Object]');
@@ -274,7 +358,7 @@ describe('DOMPropertyOperations', () => {
358
customElement.dispatchEvent(new Event('false'));
359
});
360
277
- it('custom elements should still have onClick treated like regular elements', () => {
361
+ it('custom elements should still have onClick treated like regular elements', async () => {
362
let syntheticClickEvent = null;
363
const syntheticEventHandler = jest.fn(
364
event => (syntheticClickEvent = event),
@@ -287,7 +371,10 @@ describe('DOMPropertyOperations', () => {
371
372
const container = document.createElement('div');
373
document.body.appendChild(container);
290
- ReactDOM.render(<Test />, container);
374
+ const root = ReactDOMClient.createRoot(container);
375
+ await act(() => {
376
+ root.render(<Test />);
377
+ });
378
379
const customElement = container.querySelector('my-custom-element');
380
customElement.onclick = nativeEventHandler;
@@ -299,12 +386,15 @@ describe('DOMPropertyOperations', () => {
386
});
387
388
// @gate enableCustomElementPropertySupport
302
- it('custom elements should have working onChange event listeners', () => {
389
+ it('custom elements should have working onChange event listeners', async () => {
390
let reactChangeEvent = null;
391
const eventHandler = jest.fn(event => (reactChangeEvent = event));
392
const container = document.createElement('div');
393
document.body.appendChild(container);
307
- ReactDOM.render(<my-custom-element onChange={eventHandler} />, container);
394
+ const root = ReactDOMClient.createRoot(container);
395
+ await act(() => {
396
+ root.render(<my-custom-element onChange={eventHandler} />);
397
+ });
398
const customElement = container.querySelector('my-custom-element');
399
let expectedHandlerCallCount = 0;
400
@@ -315,21 +405,28 @@ describe('DOMPropertyOperations', () => {
405
expect(reactChangeEvent.nativeEvent).toBe(changeEvent);
406
407
// Also make sure that removing and re-adding the event listener works
318
- ReactDOM.render(<my-custom-element />, container);
408
+ await act(() => {
409
+ root.render(<my-custom-element />);
410
+ });
411
customElement.dispatchEvent(new Event('change', {bubbles: true}));
412
expect(eventHandler).toHaveBeenCalledTimes(expectedHandlerCallCount);
321
- ReactDOM.render(<my-custom-element onChange={eventHandler} />, container);
413
+ await act(() => {
414
+ root.render(<my-custom-element onChange={eventHandler} />);
415
+ });
416
customElement.dispatchEvent(new Event('change', {bubbles: true}));
417
expectedHandlerCallCount++;
418
expect(eventHandler).toHaveBeenCalledTimes(expectedHandlerCallCount);
419
});
420
327
- it('custom elements should have working onInput event listeners', () => {
421
+ it('custom elements should have working onInput event listeners', async () => {
422
let reactInputEvent = null;
423
const eventHandler = jest.fn(event => (reactInputEvent = event));
424
const container = document.createElement('div');
425
document.body.appendChild(container);
332
- ReactDOM.render(<my-custom-element onInput={eventHandler} />, container);
426
+ const root = ReactDOMClient.createRoot(container);
427
+ await act(() => {
428
+ root.render(<my-custom-element onInput={eventHandler} />);
429
+ });
430
const customElement = container.querySelector('my-custom-element');
431
let expectedHandlerCallCount = 0;
432
@@ -340,28 +437,34 @@ describe('DOMPropertyOperations', () => {
437
expect(reactInputEvent.nativeEvent).toBe(inputEvent);
438
439
// Also make sure that removing and re-adding the event listener works
343
- ReactDOM.render(<my-custom-element />, container);
440
+ await act(() => {
441
+ root.render(<my-custom-element />);
442
+ });
443
customElement.dispatchEvent(new Event('input', {bubbles: true}));
444
expect(eventHandler).toHaveBeenCalledTimes(expectedHandlerCallCount);
346
- ReactDOM.render(<my-custom-element onInput={eventHandler} />, container);
445
+ await act(() => {
446
+ root.render(<my-custom-element onInput={eventHandler} />);
447
+ });
448
customElement.dispatchEvent(new Event('input', {bubbles: true}));
449
expectedHandlerCallCount++;
450
expect(eventHandler).toHaveBeenCalledTimes(expectedHandlerCallCount);
451
});
452
453
// @gate enableCustomElementPropertySupport
353
- it('custom elements should have separate onInput and onChange handling', () => {
454
+ it('custom elements should have separate onInput and onChange handling', async () => {
455
const container = document.createElement('div');
456
document.body.appendChild(container);
457
+ const root = ReactDOMClient.createRoot(container);
458
const inputEventHandler = jest.fn();
459
const changeEventHandler = jest.fn();
358
- ReactDOM.render(
359
- <my-custom-element
360
- onInput={inputEventHandler}
361
- onChange={changeEventHandler}
362
- />,
363
- container,
364
- );
460
+ await act(() => {
461
+ root.render(
462
+ <my-custom-element
463
+ onInput={inputEventHandler}
464
+ onChange={changeEventHandler}
465
+ />,
466
+ );
467
+ });
468
const customElement = container.querySelector('my-custom-element');
469
470
customElement.dispatchEvent(new Event('input', {bubbles: true}));
@@ -374,34 +477,36 @@ describe('DOMPropertyOperations', () => {
477
});
478
479
// @gate enableCustomElementPropertySupport
377
- it('custom elements should be able to remove and re-add custom event listeners', () => {
480
+ it('custom elements should be able to remove and re-add custom event listeners', async () => {
481
const container = document.createElement('div');
482
document.body.appendChild(container);
483
+ const root = ReactDOMClient.createRoot(container);
484
const eventHandler = jest.fn();
381
- ReactDOM.render(
382
- <my-custom-element oncustomevent={eventHandler} />,
383
- container,
384
- );
485
+ await act(() => {
486
+ root.render(<my-custom-element oncustomevent={eventHandler} />);
487
+ });
488
489
const customElement = container.querySelector('my-custom-element');
490
customElement.dispatchEvent(new Event('customevent'));
491
expect(eventHandler).toHaveBeenCalledTimes(1);
492
390
- ReactDOM.render(<my-custom-element />, container);
493
+ await act(() => {
494
+ root.render(<my-custom-element />);
495
+ });
496
customElement.dispatchEvent(new Event('customevent'));
497
expect(eventHandler).toHaveBeenCalledTimes(1);
498
394
- ReactDOM.render(
395
- <my-custom-element oncustomevent={eventHandler} />,
396
- container,
397
- );
499
+ await act(() => {
500
+ root.render(<my-custom-element oncustomevent={eventHandler} />);
501
+ });
502
customElement.dispatchEvent(new Event('customevent'));
503
expect(eventHandler).toHaveBeenCalledTimes(2);
504
});
505
402
- it('<input is=...> should have the same onChange/onInput/onClick behavior as <input>', () => {
506
+ it('<input is=...> should have the same onChange/onInput/onClick behavior as <input>', async () => {
507
const container = document.createElement('div');
508
document.body.appendChild(container);
509
+ const root = ReactDOMClient.createRoot(container);
510
const regularOnInputHandler = jest.fn();
511
const regularOnChangeHandler = jest.fn();
512
const regularOnClickHandler = jest.fn();
@@ -416,22 +521,23 @@ describe('DOMPropertyOperations', () => {
521
customOnChangeHandler.mockClear();
522
customOnClickHandler.mockClear();
523
}
419
- ReactDOM.render(
420
- <div>
421
- <input
422
- onInput={regularOnInputHandler}
423
- onChange={regularOnChangeHandler}
424
- onClick={regularOnClickHandler}
425
- />
426
- <input
427
- is="my-custom-element"
428
- onInput={customOnInputHandler}
429
- onChange={customOnChangeHandler}
430
- onClick={customOnClickHandler}
431
- />
432
- </div>,
433
- container,
434
- );
524
+ await act(() => {
525
+ root.render(
526
+ <div>
527
+ <input
528
+ onInput={regularOnInputHandler}
529
+ onChange={regularOnChangeHandler}
530
+ onClick={regularOnClickHandler}
531
+ />
532
+ <input
533
+ is="my-custom-element"
534
+ onInput={customOnInputHandler}
535
+ onChange={customOnChangeHandler}
536
+ onClick={customOnClickHandler}
537
+ />
538
+ </div>,
539
+ );
540
+ });
541
542
const regularInput = container.querySelector(
543
'input:not([is=my-custom-element])',
@@ -490,9 +596,10 @@ describe('DOMPropertyOperations', () => {
596
expect(customOnClickHandler).toHaveBeenCalledTimes(0);
597
});
598
493
- it('<input type=radio is=...> should have the same onChange/onInput/onClick behavior as <input type=radio>', () => {
599
+ it('<input type=radio is=...> should have the same onChange/onInput/onClick behavior as <input type=radio>', async () => {
600
const container = document.createElement('div');
601
document.body.appendChild(container);
602
+ const root = ReactDOMClient.createRoot(container);
603
const regularOnInputHandler = jest.fn();
604
const regularOnChangeHandler = jest.fn();
605
const regularOnClickHandler = jest.fn();
@@ -507,24 +614,25 @@ describe('DOMPropertyOperations', () => {
614
customOnChangeHandler.mockClear();
615
customOnClickHandler.mockClear();
616
}
510
- ReactDOM.render(
511
- <div>
512
- <input
513
- type="radio"
514
- onInput={regularOnInputHandler}
515
- onChange={regularOnChangeHandler}
516
- onClick={regularOnClickHandler}
517
- />
518
- <input
519
- is="my-custom-element"
520
- type="radio"
521
- onInput={customOnInputHandler}
522
- onChange={customOnChangeHandler}
523
- onClick={customOnClickHandler}
524
- />
525
- </div>,
526
- container,
527
- );
617
+ await act(() => {
618
+ root.render(
619
+ <div>
620
+ <input
621
+ type="radio"
622
+ onInput={regularOnInputHandler}
623
+ onChange={regularOnChangeHandler}
624
+ onClick={regularOnClickHandler}
625
+ />
626
+ <input
627
+ is="my-custom-element"
628
+ type="radio"
629
+ onInput={customOnInputHandler}
630
+ onChange={customOnChangeHandler}
631
+ onClick={customOnClickHandler}
632
+ />
633
+ </div>,
634
+ );
635
+ });
636
637
const regularInput = container.querySelector(
638
'input:not([is=my-custom-element])',
@@ -572,9 +680,10 @@ describe('DOMPropertyOperations', () => {
680
expect(customOnClickHandler).toHaveBeenCalledTimes(1);
681
});
682
575
- it('<select is=...> should have the same onChange/onInput/onClick behavior as <select>', () => {
683
+ it('<select is=...> should have the same onChange/onInput/onClick behavior as <select>', async () => {
684
const container = document.createElement('div');
685
document.body.appendChild(container);
686
+ const root = ReactDOMClient.createRoot(container);
687
const regularOnInputHandler = jest.fn();
688
const regularOnChangeHandler = jest.fn();
689
const regularOnClickHandler = jest.fn();
@@ -589,22 +698,23 @@ describe('DOMPropertyOperations', () => {
698
customOnChangeHandler.mockClear();
699
customOnClickHandler.mockClear();
700
}
592
- ReactDOM.render(
593
- <div>
594
- <select
595
- onInput={regularOnInputHandler}
596
- onChange={regularOnChangeHandler}
597
- onClick={regularOnClickHandler}
598
- />
599
- <select
600
- is="my-custom-element"
601
- onInput={customOnInputHandler}
602
- onChange={customOnChangeHandler}
603
- onClick={customOnClickHandler}
604
- />
605
- </div>,
606
- container,
607
- );
701
+ await act(() => {
702
+ root.render(
703
+ <div>
704
+ <select
705
+ onInput={regularOnInputHandler}
706
+ onChange={regularOnChangeHandler}
707
+ onClick={regularOnClickHandler}
708
+ />
709
+ <select
710
+ is="my-custom-element"
711
+ onInput={customOnInputHandler}
712
+ onChange={customOnChangeHandler}
713
+ onClick={customOnClickHandler}
714
+ />
715
+ </div>,
716
+ );
717
+ });
718
719
const regularSelect = container.querySelector(
720
'select:not([is=my-custom-element])',
@@ -649,9 +759,10 @@ describe('DOMPropertyOperations', () => {
759
});
760
761
// @gate enableCustomElementPropertySupport
652
- it('onChange/onInput/onClick on div with various types of children', () => {
762
+ it('onChange/onInput/onClick on div with various types of children', async () => {
763
const container = document.createElement('div');
764
document.body.appendChild(container);
765
+ const root = ReactDOMClient.createRoot(container);
766
const onChangeHandler = jest.fn();
767
const onInputHandler = jest.fn();
768
const onClickHandler = jest.fn();
@@ -660,17 +771,18 @@ describe('DOMPropertyOperations', () => {
771
onInputHandler.mockClear();
772
onClickHandler.mockClear();
773
}
663
- ReactDOM.render(
664
- <div
665
- onChange={onChangeHandler}
666
- onInput={onInputHandler}
667
- onClick={onClickHandler}>
668
- <my-custom-element />
669
- <input />
670
- <input is="my-custom-element" />
671
- </div>,
672
- container,
673
- );
774
+ await act(() => {
775
+ root.render(
776
+ <div
777
+ onChange={onChangeHandler}
778
+ onInput={onInputHandler}
779
+ onClick={onClickHandler}>
780
+ <my-custom-element />
781
+ <input />
782
+ <input is="my-custom-element" />
783
+ </div>,
784
+ );
785
+ });
786
const customElement = container.querySelector('my-custom-element');
787
const regularInput = container.querySelector(
788
'input:not([is="my-custom-element"])',
@@ -728,21 +840,23 @@ describe('DOMPropertyOperations', () => {
840
expect(onClickHandler).toBeCalledTimes(1);
841
});
842
731
- it('custom element onChange/onInput/onClick with event target input child', () => {
843
+ it('custom element onChange/onInput/onClick with event target input child', async () => {
844
const container = document.createElement('div');
845
document.body.appendChild(container);
846
+ const root = ReactDOMClient.createRoot(container);
847
const onChangeHandler = jest.fn();
848
const onInputHandler = jest.fn();
849
const onClickHandler = jest.fn();
737
- ReactDOM.render(
738
- <my-custom-element
739
- onChange={onChangeHandler}
740
- onInput={onInputHandler}
741
- onClick={onClickHandler}>
742
- <input />
743
- </my-custom-element>,
744
- container,
745
- );
850
+ await act(() => {
851
+ root.render(
852
+ <my-custom-element
853
+ onChange={onChangeHandler}
854
+ onInput={onInputHandler}
855
+ onClick={onClickHandler}>
856
+ <input />
857
+ </my-custom-element>,
858
+ );
859
+ });
860
861
const input = container.querySelector('input');
862
setUntrackedValue.call(input, 'hello');
@@ -763,21 +877,23 @@ describe('DOMPropertyOperations', () => {
877
expect(onClickHandler).toBeCalledTimes(1);
878
});
879
766
- it('custom element onChange/onInput/onClick with event target div child', () => {
880
+ it('custom element onChange/onInput/onClick with event target div child', async () => {
881
const container = document.createElement('div');
882
document.body.appendChild(container);
883
+ const root = ReactDOMClient.createRoot(container);
884
const onChangeHandler = jest.fn();
885
const onInputHandler = jest.fn();
886
const onClickHandler = jest.fn();
772
- ReactDOM.render(
773
- <my-custom-element
774
- onChange={onChangeHandler}
775
- onInput={onInputHandler}
776
- onClick={onClickHandler}>
777
- <div />
778
- </my-custom-element>,
779
- container,
780
- );
887
+ await act(() => {
888
+ root.render(
889
+ <my-custom-element
890
+ onChange={onChangeHandler}
891
+ onInput={onInputHandler}
892
+ onClick={onClickHandler}>
893
+ <div />
894
+ </my-custom-element>,
895
+ );
896
+ });
897
898
const div = container.querySelector('div');
899
div.dispatchEvent(new Event('input', {bubbles: true}));
@@ -798,21 +914,23 @@ describe('DOMPropertyOperations', () => {
914
expect(onClickHandler).toBeCalledTimes(1);
915
});
916
801
- it('div onChange/onInput/onClick with event target div child', () => {
917
+ it('div onChange/onInput/onClick with event target div child', async () => {
918
const container = document.createElement('div');
919
document.body.appendChild(container);
920
+ const root = ReactDOMClient.createRoot(container);
921
const onChangeHandler = jest.fn();
922
const onInputHandler = jest.fn();
923
const onClickHandler = jest.fn();
807
- ReactDOM.render(
808
- <div
809
- onChange={onChangeHandler}
810
- onInput={onInputHandler}
811
- onClick={onClickHandler}>
812
- <div />
813
- </div>,
814
- container,
815
- );
924
+ await act(() => {
925
+ root.render(
926
+ <div
927
+ onChange={onChangeHandler}
928
+ onInput={onInputHandler}
929
+ onClick={onClickHandler}>
930
+ <div />
931
+ </div>,
932
+ );
933
+ });
934
935
const div = container.querySelector('div > div');
936
div.dispatchEvent(new Event('input', {bubbles: true}));
@@ -834,21 +952,23 @@ describe('DOMPropertyOperations', () => {
952
});
953
954
// @gate enableCustomElementPropertySupport
837
- it('custom element onChange/onInput/onClick with event target custom element child', () => {
955
+ it('custom element onChange/onInput/onClick with event target custom element child', async () => {
956
const container = document.createElement('div');
957
document.body.appendChild(container);
958
+ const root = ReactDOMClient.createRoot(container);
959
const onChangeHandler = jest.fn();
960
const onInputHandler = jest.fn();
961
const onClickHandler = jest.fn();
843
- ReactDOM.render(
844
- <my-custom-element
845
- onChange={onChangeHandler}
846
- onInput={onInputHandler}
847
- onClick={onClickHandler}>
848
- <other-custom-element />
849
- </my-custom-element>,
850
- container,
851
- );
962
+ await act(() => {
963
+ root.render(
964
+ <my-custom-element
965
+ onChange={onChangeHandler}
966
+ onInput={onInputHandler}
967
+ onClick={onClickHandler}>
968
+ <other-custom-element />
969
+ </my-custom-element>,
970
+ );
971
+ });
972
973
const customChild = container.querySelector('other-custom-element');
974
customChild.dispatchEvent(new Event('input', {bubbles: true}));
@@ -868,7 +988,7 @@ describe('DOMPropertyOperations', () => {
988
});
989
990
// @gate enableCustomElementPropertySupport
871
- it('custom elements should allow custom events with capture event listeners', () => {
991
+ it('custom elements should allow custom events with capture event listeners', async () => {
992
const oncustomeventCapture = jest.fn();
993
const oncustomevent = jest.fn();
994
function Test() {
@@ -881,7 +1001,10 @@ describe('DOMPropertyOperations', () => {
1001
);
1002
}
1003
const container = document.createElement('div');
884
- ReactDOM.render(<Test />, container);
1004
+ const root = ReactDOMClient.createRoot(container);
1005
+ await act(() => {
1006
+ root.render(<Test />);
1007
+ });
1008
container
1009
.querySelector('my-custom-element > div')
1010
.dispatchEvent(new Event('customevent', {bubbles: false}));
@@ -889,106 +1012,148 @@ describe('DOMPropertyOperations', () => {
1012
expect(oncustomevent).toHaveBeenCalledTimes(0);
1013
});
1014
892
- it('innerHTML should not work on custom elements', () => {
1015
+ it('innerHTML should not work on custom elements', async () => {
1016
const container = document.createElement('div');
894
- ReactDOM.render(<my-custom-element innerHTML="foo" />, container);
1017
+ const root = ReactDOMClient.createRoot(container);
1018
+ await act(() => {
1019
+ root.render(<my-custom-element innerHTML="foo" />);
1020
+ });
1021
const customElement = container.querySelector('my-custom-element');
1022
expect(customElement.getAttribute('innerHTML')).toBe(null);
1023
expect(customElement.hasChildNodes()).toBe(false);
1024
1025
// Render again to verify the update codepath doesn't accidentally let
1026
// something through.
901
- ReactDOM.render(<my-custom-element innerHTML="bar" />, container);
1027
+ await act(() => {
1028
+ root.render(<my-custom-element innerHTML="bar" />);
1029
+ });
1030
expect(customElement.getAttribute('innerHTML')).toBe(null);
1031
expect(customElement.hasChildNodes()).toBe(false);
1032
});
1033
1034
// @gate enableCustomElementPropertySupport
907
- it('innerText should not work on custom elements', () => {
1035
+ it('innerText should not work on custom elements', async () => {
1036
const container = document.createElement('div');
909
- ReactDOM.render(<my-custom-element innerText="foo" />, container);
1037
+ const root = ReactDOMClient.createRoot(container);
1038
+ await act(() => {
1039
+ root.render(<my-custom-element innerText="foo" />);
1040
+ });
1041
const customElement = container.querySelector('my-custom-element');
1042
expect(customElement.getAttribute('innerText')).toBe(null);
1043
expect(customElement.hasChildNodes()).toBe(false);
1044
1045
// Render again to verify the update codepath doesn't accidentally let
1046
// something through.
916
- ReactDOM.render(<my-custom-element innerText="bar" />, container);
1047
+ await act(() => {
1048
+ root.render(<my-custom-element innerText="bar" />);
1049
+ });
1050
expect(customElement.getAttribute('innerText')).toBe(null);
1051
expect(customElement.hasChildNodes()).toBe(false);
1052
});
1053
1054
// @gate enableCustomElementPropertySupport
922
- it('textContent should not work on custom elements', () => {
1055
+ it('textContent should not work on custom elements', async () => {
1056
const container = document.createElement('div');
924
- ReactDOM.render(<my-custom-element textContent="foo" />, container);
1057
+ const root = ReactDOMClient.createRoot(container);
1058
+ await act(() => {
1059
+ root.render(<my-custom-element textContent="foo" />);
1060
+ });
1061
const customElement = container.querySelector('my-custom-element');
1062
expect(customElement.getAttribute('textContent')).toBe(null);
1063
expect(customElement.hasChildNodes()).toBe(false);
1064
1065
// Render again to verify the update codepath doesn't accidentally let
1066
// something through.
931
- ReactDOM.render(<my-custom-element textContent="bar" />, container);
1067
+ await act(() => {
1068
+ root.render(<my-custom-element textContent="bar" />);
1069
+ });
1070
expect(customElement.getAttribute('textContent')).toBe(null);
1071
expect(customElement.hasChildNodes()).toBe(false);
1072
});
1073
1074
// @gate enableCustomElementPropertySupport
937
- it('values should not be converted to booleans when assigning into custom elements', () => {
1075
+ it('values should not be converted to booleans when assigning into custom elements', async () => {
1076
const container = document.createElement('div');
1077
document.body.appendChild(container);
940
- ReactDOM.render(<my-custom-element />, container);
1078
+ const root = ReactDOMClient.createRoot(container);
1079
+ await act(() => {
1080
+ root.render(<my-custom-element />);
1081
+ });
1082
const customElement = container.querySelector('my-custom-element');
1083
customElement.foo = null;
1084
1085
// true => string
945
- ReactDOM.render(<my-custom-element foo={true} />, container);
1086
+ await act(() => {
1087
+ root.render(<my-custom-element foo={true} />);
1088
+ });
1089
expect(customElement.foo).toBe(true);
947
- ReactDOM.render(<my-custom-element foo="bar" />, container);
1090
+ await act(() => {
1091
+ root.render(<my-custom-element foo="bar" />);
1092
+ });
1093
expect(customElement.foo).toBe('bar');
1094
1095
// false => string
951
- ReactDOM.render(<my-custom-element foo={false} />, container);
1096
+ await act(() => {
1097
+ root.render(<my-custom-element foo={false} />);
1098
+ });
1099
expect(customElement.foo).toBe(false);
953
- ReactDOM.render(<my-custom-element foo="bar" />, container);
1100
+ await act(() => {
1101
+ root.render(<my-custom-element foo="bar" />);
1102
+ });
1103
expect(customElement.foo).toBe('bar');
1104
1105
// true => null
957
- ReactDOM.render(<my-custom-element foo={true} />, container);
1106
+ await act(() => {
1107
+ root.render(<my-custom-element foo={true} />);
1108
+ });
1109
expect(customElement.foo).toBe(true);
959
- ReactDOM.render(<my-custom-element foo={null} />, container);
1110
+ await act(() => {
1111
+ root.render(<my-custom-element foo={null} />);
1112
+ });
1113
expect(customElement.foo).toBe(null);
1114
1115
// false => null
963
- ReactDOM.render(<my-custom-element foo={false} />, container);
1116
+ await act(() => {
1117
+ root.render(<my-custom-element foo={false} />);
1118
+ });
1119
expect(customElement.foo).toBe(false);
965
- ReactDOM.render(<my-custom-element foo={null} />, container);
1120
+ await act(() => {
1121
+ root.render(<my-custom-element foo={null} />);
1122
+ });
1123
expect(customElement.foo).toBe(null);
1124
});
1125
1126
// @gate enableCustomElementPropertySupport
970
- it('boolean props should not be stringified in attributes', () => {
1127
+ it('boolean props should not be stringified in attributes', async () => {
1128
const container = document.createElement('div');
1129
document.body.appendChild(container);
973
- ReactDOM.render(<my-custom-element foo={true} />, container);
1130
+ const root = ReactDOMClient.createRoot(container);
1131
+ await act(() => {
1132
+ root.render(<my-custom-element foo={true} />);
1133
+ });
1134
const customElement = container.querySelector('my-custom-element');
1135
1136
expect(customElement.getAttribute('foo')).toBe('');
1137
1138
// true => false
979
- ReactDOM.render(<my-custom-element foo={false} />, container);
1139
+ await act(() => {
1140
+ root.render(<my-custom-element foo={false} />);
1141
+ });
1142
1143
expect(customElement.getAttribute('foo')).toBe(null);
1144
});
1145
1146
// @gate enableCustomElementPropertySupport
985
- it('custom element custom event handlers assign multiple types', () => {
1147
+ it('custom element custom event handlers assign multiple types', async () => {
1148
const container = document.createElement('div');
1149
document.body.appendChild(container);
1150
+ const root = ReactDOMClient.createRoot(container);
1151
const oncustomevent = jest.fn();
1152
1153
// First render with string
991
- ReactDOM.render(<my-custom-element oncustomevent={'foo'} />, container);
1154
+ await act(() => {
1155
+ root.render(<my-custom-element oncustomevent={'foo'} />);
1156
+ });
1157
const customelement = container.querySelector('my-custom-element');
1158
customelement.dispatchEvent(new Event('customevent'));
1159
expect(oncustomevent).toHaveBeenCalledTimes(0);
@@ -996,34 +1161,36 @@ describe('DOMPropertyOperations', () => {
1161
expect(customelement.getAttribute('oncustomevent')).toBe('foo');
1162
1163
// string => event listener
999
- ReactDOM.render(
1000
- <my-custom-element oncustomevent={oncustomevent} />,
1001
- container,
1002
- );
1164
+ await act(() => {
1165
+ root.render(<my-custom-element oncustomevent={oncustomevent} />);
1166
+ });
1167
customelement.dispatchEvent(new Event('customevent'));
1168
expect(oncustomevent).toHaveBeenCalledTimes(1);
1169
expect(customelement.oncustomevent).toBe(undefined);
1170
expect(customelement.getAttribute('oncustomevent')).toBe(null);
1171
1172
// event listener => string
1009
- ReactDOM.render(<my-custom-element oncustomevent={'foo'} />, container);
1173
+ await act(() => {
1174
+ root.render(<my-custom-element oncustomevent={'foo'} />);
1175
+ });
1176
customelement.dispatchEvent(new Event('customevent'));
1177
expect(oncustomevent).toHaveBeenCalledTimes(1);
1178
expect(customelement.oncustomevent).toBe(undefined);
1179
expect(customelement.getAttribute('oncustomevent')).toBe('foo');
1180
1181
// string => nothing
1016
- ReactDOM.render(<my-custom-element />, container);
1182
+ await act(() => {
1183
+ root.render(<my-custom-element />);
1184
+ });
1185
customelement.dispatchEvent(new Event('customevent'));
1186
expect(oncustomevent).toHaveBeenCalledTimes(1);
1187
expect(customelement.oncustomevent).toBe(undefined);
1188
expect(customelement.getAttribute('oncustomevent')).toBe(null);
1189
1190
// nothing => event listener
1023
- ReactDOM.render(
1024
- <my-custom-element oncustomevent={oncustomevent} />,
1025
- container,
1026
- );
1191
+ await act(() => {
1192
+ root.render(<my-custom-element oncustomevent={oncustomevent} />);
1193
+ });
1194
customelement.dispatchEvent(new Event('customevent'));
1195
expect(oncustomevent).toHaveBeenCalledTimes(2);
1196
expect(customelement.oncustomevent).toBe(undefined);
@@ -1031,13 +1198,16 @@ describe('DOMPropertyOperations', () => {
1198
});
1199
1200
// @gate enableCustomElementPropertySupport
1034
- it('custom element custom event handlers assign multiple types with setter', () => {
1201
+ it('custom element custom event handlers assign multiple types with setter', async () => {
1202
const container = document.createElement('div');
1203
document.body.appendChild(container);
1204
+ const root = ReactDOMClient.createRoot(container);
1205
const oncustomevent = jest.fn();
1206
1207
// First render with nothing
1040
- ReactDOM.render(<my-custom-element />, container);
1208
+ await act(() => {
1209
+ root.render(<my-custom-element />);
1210
+ });
1211
const customelement = container.querySelector('my-custom-element');
1212
// Install a setter to activate the `in` heuristic
1213
Object.defineProperty(customelement, 'oncustomevent', {
@@ -1051,34 +1221,36 @@ describe('DOMPropertyOperations', () => {
1221
expect(customelement.oncustomevent).toBe(undefined);
1222
1223
// nothing => event listener
1054
- ReactDOM.render(
1055
- <my-custom-element oncustomevent={oncustomevent} />,
1056
- container,
1057
- );
1224
+ await act(() => {
1225
+ root.render(<my-custom-element oncustomevent={oncustomevent} />);
1226
+ });
1227
customelement.dispatchEvent(new Event('customevent'));
1228
expect(oncustomevent).toHaveBeenCalledTimes(1);
1229
expect(customelement.oncustomevent).toBe(null);
1230
expect(customelement.getAttribute('oncustomevent')).toBe(null);
1231
1232
// event listener => string
1064
- ReactDOM.render(<my-custom-element oncustomevent={'foo'} />, container);
1233
+ await act(() => {
1234
+ root.render(<my-custom-element oncustomevent={'foo'} />);
1235
+ });
1236
customelement.dispatchEvent(new Event('customevent'));
1237
expect(oncustomevent).toHaveBeenCalledTimes(1);
1238
expect(customelement.oncustomevent).toBe('foo');
1239
expect(customelement.getAttribute('oncustomevent')).toBe(null);
1240
1241
// string => event listener
1071
- ReactDOM.render(
1072
- <my-custom-element oncustomevent={oncustomevent} />,
1073
- container,
1074
- );
1242
+ await act(() => {
1243
+ root.render(<my-custom-element oncustomevent={oncustomevent} />);
1244
+ });
1245
customelement.dispatchEvent(new Event('customevent'));
1246
expect(oncustomevent).toHaveBeenCalledTimes(2);
1247
expect(customelement.oncustomevent).toBe(null);
1248
expect(customelement.getAttribute('oncustomevent')).toBe(null);
1249
1250
// event listener => nothing
1081
- ReactDOM.render(<my-custom-element />, container);
1251
+ await act(() => {
1252
+ root.render(<my-custom-element />);
1253
+ });
1254
customelement.dispatchEvent(new Event('customevent'));
1255
expect(oncustomevent).toHaveBeenCalledTimes(2);
1256
expect(customelement.oncustomevent).toBe(null);
@@ -1086,10 +1258,13 @@ describe('DOMPropertyOperations', () => {
1258
});
1259
1260
// @gate enableCustomElementPropertySupport
1089
- it('assigning to a custom element property should not remove attributes', () => {
1261
+ it('assigning to a custom element property should not remove attributes', async () => {
1262
const container = document.createElement('div');
1263
document.body.appendChild(container);
1092
- ReactDOM.render(<my-custom-element foo="one" />, container);
1264
+ const root = ReactDOMClient.createRoot(container);
1265
+ await act(() => {
1266
+ root.render(<my-custom-element foo="one" />);
1267
+ });
1268
const customElement = container.querySelector('my-custom-element');
1269
expect(customElement.getAttribute('foo')).toBe('one');
1270
@@ -1102,16 +1277,21 @@ describe('DOMPropertyOperations', () => {
1277
return this._foo;
1278
},
1279
});
1105
- ReactDOM.render(<my-custom-element foo="two" />, container);
1280
+ await act(() => {
1281
+ root.render(<my-custom-element foo="two" />);
1282
+ });
1283
expect(customElement.foo).toBe('two');
1284
expect(customElement.getAttribute('foo')).toBe('one');
1285
});
1286
1287
// @gate enableCustomElementPropertySupport
1111
- it('custom element properties should accept functions', () => {
1288
+ it('custom element properties should accept functions', async () => {
1289
const container = document.createElement('div');
1290
document.body.appendChild(container);
1114
- ReactDOM.render(<my-custom-element />, container);
1291
+ const root = ReactDOMClient.createRoot(container);
1292
+ await act(() => {
1293
+ root.render(<my-custom-element />);
1294
+ });
1295
const customElement = container.querySelector('my-custom-element');
1296
1297
// Install a setter to activate the `in` heuristic
@@ -1126,44 +1306,56 @@ describe('DOMPropertyOperations', () => {
1306
function myFunction() {
1307
return 'this is myFunction';
1308
}
1129
- ReactDOM.render(<my-custom-element foo={myFunction} />, container);
1309
+ await act(() => {
1310
+ root.render(<my-custom-element foo={myFunction} />);
1311
+ });
1312
expect(customElement.foo).toBe(myFunction);
1313
1314
// Also remove and re-add the property for good measure
1133
- ReactDOM.render(<my-custom-element />, container);
1315
+ await act(() => {
1316
+ root.render(<my-custom-element />);
1317
+ });
1318
expect(customElement.foo).toBe(null);
1135
- ReactDOM.render(<my-custom-element foo={myFunction} />, container);
1319
+ await act(() => {
1320
+ root.render(<my-custom-element foo={myFunction} />);
1321
+ });
1322
expect(customElement.foo).toBe(myFunction);
1323
});
1324
});
1325
1326
describe('deleteValueForProperty', () => {
1141
- it('should remove attributes for normal properties', () => {
1327
+ it('should remove attributes for normal properties', async () => {
1328
const container = document.createElement('div');
1143
- ReactDOM.render(<div title="foo" />, container);
1329
+ const root = ReactDOMClient.createRoot(container);
1330
+ await act(() => {
1331
+ root.render(<div title="foo" />);
1332
+ });
1333
expect(container.firstChild.getAttribute('title')).toBe('foo');
1145
- ReactDOM.render(<div />, container);
1334
+ await act(() => {
1335
+ root.render(<div />);
1336
+ });
1337
expect(container.firstChild.getAttribute('title')).toBe(null);
1338
});
1339
1149
- it('should not remove attributes for special properties', () => {
1340
+ it('should not remove attributes for special properties', async () => {
1341
const container = document.createElement('div');
1151
- ReactDOM.render(
1152
- <input type="text" value="foo" onChange={function () {}} />,
1153
- container,
1154
- );
1342
+ const root = ReactDOMClient.createRoot(container);
1343
+ await act(() => {
1344
+ root.render(
1345
+ <input type="text" value="foo" onChange={function () {}} />,
1346
+ );
1347
+ });
1348
if (disableInputAttributeSyncing) {
1349
expect(container.firstChild.hasAttribute('value')).toBe(false);
1350
} else {
1351
expect(container.firstChild.getAttribute('value')).toBe('foo');
1352
}
1353
expect(container.firstChild.value).toBe('foo');
1161
- expect(() =>
1162
- ReactDOM.render(
1163
- <input type="text" onChange={function () {}} />,
1164
- container,
1165
- ),
1166
- ).toErrorDev(
1354
+ await expect(async () => {
1355
+ await act(() => {
1356
+ root.render(<input type="text" onChange={function () {}} />);
1357
+ });
1358
+ }).toErrorDev(
1359
'A component is changing a controlled input to be uncontrolled',
1360
);
1361
if (disableInputAttributeSyncing) {
@@ -1174,9 +1366,12 @@ describe('DOMPropertyOperations', () => {
1366
expect(container.firstChild.value).toBe('foo');
1367
});
1368
1177
- it('should not remove attributes for custom component tag', () => {
1369
+ it('should not remove attributes for custom component tag', async () => {
1370
const container = document.createElement('div');
1179
- ReactDOM.render(<my-icon size="5px" />, container);
1371
+ const root = ReactDOMClient.createRoot(container);
1372
+ await act(() => {
1373
+ root.render(<my-icon size="5px" />);
1374
+ });
1375
expect(container.firstChild.getAttribute('size')).toBe('5px');
1376
});
1377
});