Convert ReactDOMInput-test to createRoot (#28084)
Convert ReactDOMInput-test to createRoot
Jan Kassens committed
Jan 25, 2024 at 14:22 UTC
a7fa58d8b6e8306f9c4f4135e702f1bc7a099a49
1 file changed
+998
-680
packages/react-dom/src/__tests__/ReactDOMInput-test.js
+998
-680
@@ -25,6 +25,7 @@ describe('ReactDOMInput', () => {
25
let setUntrackedValue;
26
let setUntrackedChecked;
27
let container;
28
+ let root;
29
30
function dispatchEventOnNode(node, type) {
31
node.dispatchEvent(new Event(type, {bubbles: true, cancelable: true}));
@@ -99,6 +100,7 @@ describe('ReactDOMInput', () => {
100
101
container = document.createElement('div');
102
document.body.appendChild(container);
103
+ root = ReactDOMClient.createRoot(container);
104
});
105
106
afterEach(() => {
@@ -106,9 +108,11 @@ describe('ReactDOMInput', () => {
108
jest.restoreAllMocks();
109
});
110
109
- it('should warn for controlled value of 0 with missing onChange', () => {
110
- expect(() => {
111
- ReactDOM.render(<input type="text" value={0} />, container);
111
+ it('should warn for controlled value of 0 with missing onChange', async () => {
112
+ await expect(async () => {
113
+ await act(() => {
114
+ root.render(<input type="text" value={0} />);
115
+ });
116
}).toErrorDev(
117
'Warning: You provided a `value` prop to a form ' +
118
'field without an `onChange` handler. This will render a read-only ' +
@@ -117,9 +121,11 @@ describe('ReactDOMInput', () => {
121
);
122
});
123
120
- it('should warn for controlled value of "" with missing onChange', () => {
121
- expect(() => {
122
- ReactDOM.render(<input type="text" value="" />, container);
124
+ it('should warn for controlled value of "" with missing onChange', async () => {
125
+ await expect(async () => {
126
+ await act(() => {
127
+ root.render(<input type="text" value="" />);
128
+ });
129
}).toErrorDev(
130
'Warning: You provided a `value` prop to a form ' +
131
'field without an `onChange` handler. This will render a read-only ' +
@@ -128,9 +134,11 @@ describe('ReactDOMInput', () => {
134
);
135
});
136
131
- it('should warn for controlled value of "0" with missing onChange', () => {
132
- expect(() => {
133
- ReactDOM.render(<input type="text" value="0" />, container);
137
+ it('should warn for controlled value of "0" with missing onChange', async () => {
138
+ await expect(async () => {
139
+ await act(() => {
140
+ root.render(<input type="text" value="0" />);
141
+ });
142
}).toErrorDev(
143
'Warning: You provided a `value` prop to a form ' +
144
'field without an `onChange` handler. This will render a read-only ' +
@@ -139,72 +147,95 @@ describe('ReactDOMInput', () => {
147
);
148
});
149
142
- it('should warn for controlled value of false with missing onChange', () => {
143
- expect(() =>
144
- ReactDOM.render(<input type="checkbox" checked={false} />, container),
145
- ).toErrorDev(
150
+ it('should warn for controlled value of false with missing onChange', async () => {
151
+ await expect(async () => {
152
+ await act(() => {
153
+ root.render(<input type="checkbox" checked={false} />);
154
+ });
155
+ }).toErrorDev(
156
'Warning: You provided a `checked` prop to a form field without an `onChange` handler.',
157
);
158
});
159
150
- it('should warn with checked and no onChange handler with readOnly specified', () => {
151
- ReactDOM.render(
152
- <input type="checkbox" checked={false} readOnly={true} />,
153
- container,
154
- );
155
- ReactDOM.unmountComponentAtNode(container);
160
+ it('should warn with checked and no onChange handler with readOnly specified', async () => {
161
+ await act(() => {
162
+ root.render(<input type="checkbox" checked={false} readOnly={true} />);
163
+ });
164
+ root.unmount();
165
+ root = ReactDOMClient.createRoot(container);
166
157
- expect(() =>
158
- ReactDOM.render(
159
- <input type="checkbox" checked={false} readOnly={false} />,
160
- container,
161
- ),
162
- ).toErrorDev(
167
+ await expect(async () => {
168
+ await act(() => {
169
+ root.render(<input type="checkbox" checked={false} readOnly={false} />);
170
+ });
171
+ }).toErrorDev(
172
'Warning: You provided a `checked` prop to a form field without an `onChange` handler. ' +
173
'This will render a read-only field. If the field should be mutable use `defaultChecked`. ' +
174
'Otherwise, set either `onChange` or `readOnly`.',
175
);
176
});
177
169
- it('should not warn about missing onChange in uncontrolled inputs', () => {
170
- ReactDOM.render(<input />, container);
171
- ReactDOM.unmountComponentAtNode(container);
172
- ReactDOM.render(<input value={undefined} />, container);
173
- ReactDOM.unmountComponentAtNode(container);
174
- ReactDOM.render(<input type="text" />, container);
175
- ReactDOM.unmountComponentAtNode(container);
176
- ReactDOM.render(<input type="text" value={undefined} />, container);
177
- ReactDOM.unmountComponentAtNode(container);
178
- ReactDOM.render(<input type="checkbox" />, container);
179
- ReactDOM.unmountComponentAtNode(container);
180
- ReactDOM.render(<input type="checkbox" checked={undefined} />, container);
178
+ it('should not warn about missing onChange in uncontrolled inputs', async () => {
179
+ await act(() => {
180
+ root.render(<input />);
181
+ });
182
+ root.unmount();
183
+ root = ReactDOMClient.createRoot(container);
184
+ await act(() => {
185
+ root.render(<input value={undefined} />);
186
+ });
187
+ root.unmount();
188
+ root = ReactDOMClient.createRoot(container);
189
+ await act(() => {
190
+ root.render(<input type="text" />);
191
+ });
192
+ root.unmount();
193
+ root = ReactDOMClient.createRoot(container);
194
+ await act(() => {
195
+ root.render(<input type="text" value={undefined} />);
196
+ });
197
+ root.unmount();
198
+ root = ReactDOMClient.createRoot(container);
199
+ await act(() => {
200
+ root.render(<input type="checkbox" />);
201
+ });
202
+ root.unmount();
203
+ root = ReactDOMClient.createRoot(container);
204
+ await act(() => {
205
+ root.render(<input type="checkbox" checked={undefined} />);
206
+ });
207
});
208
183
- it('should not warn with value and onInput handler', () => {
184
- ReactDOM.render(<input value="..." onInput={() => {}} />, container);
209
+ it('should not warn with value and onInput handler', async () => {
210
+ await act(() => {
211
+ root.render(<input value="..." onInput={() => {}} />);
212
+ });
213
});
214
187
- it('should properly control a value even if no event listener exists', () => {
188
- let node;
189
-
190
- expect(() => {
191
- node = ReactDOM.render(<input type="text" value="lion" />, container);
215
+ it('should properly control a value even if no event listener exists', async () => {
216
+ await expect(async () => {
217
+ await act(() => {
218
+ root.render(<input type="text" value="lion" />);
219
+ });
220
}).toErrorDev(
221
'Warning: You provided a `value` prop to a form field without an `onChange` handler.',
222
);
223
+ const node = container.firstChild;
224
expect(isValueDirty(node)).toBe(true);
225
226
setUntrackedValue.call(node, 'giraffe');
227
228
// This must use the native event dispatching. If we simulate, we will
229
// bypass the lazy event attachment system so we won't actually test this.
201
- dispatchEventOnNode(node, 'input');
230
+ await act(() => {
231
+ dispatchEventOnNode(node, 'input');
232
+ });
233
234
expect(node.value).toBe('lion');
235
expect(isValueDirty(node)).toBe(true);
236
});
237
207
- it('should control a value in reentrant events', () => {
238
+ it('should control a value in reentrant events', async () => {
239
class ControlledInputs extends React.Component {
240
state = {value: 'lion'};
241
a = null;
@@ -240,23 +271,35 @@ describe('ReactDOMInput', () => {
271
}
272
}
273
243
- const instance = ReactDOM.render(<ControlledInputs />, container);
274
+ const ref = React.createRef();
275
+ await act(() => {
276
+ root.render(<ControlledInputs ref={ref} />);
277
+ });
278
+ const instance = ref.current;
279
280
// Focus the field so we can later blur it.
281
// Don't remove unless you've verified the fix in #8240 is still covered.
247
- instance.a.focus();
282
+ await act(() => {
283
+ instance.a.focus();
284
+ });
285
setUntrackedValue.call(instance.a, 'giraffe');
286
// This must use the native event dispatching. If we simulate, we will
287
// bypass the lazy event attachment system so we won't actually test this.
251
- dispatchEventOnNode(instance.a, 'input');
252
- dispatchEventOnNode(instance.a, 'blur');
253
- dispatchEventOnNode(instance.a, 'focusout');
288
+ await act(() => {
289
+ dispatchEventOnNode(instance.a, 'input');
290
+ });
291
+ await act(() => {
292
+ dispatchEventOnNode(instance.a, 'blur');
293
+ });
294
+ await act(() => {
295
+ dispatchEventOnNode(instance.a, 'focusout');
296
+ });
297
298
expect(instance.a.value).toBe('giraffe');
299
expect(instance.switchedFocus).toBe(true);
300
});
301
259
- it('should control values in reentrant events with different targets', () => {
302
+ it('should control values in reentrant events with different targets', async () => {
303
class ControlledInputs extends React.Component {
304
state = {value: 'lion'};
305
a = null;
@@ -288,21 +331,29 @@ describe('ReactDOMInput', () => {
331
}
332
}
333
291
- const instance = ReactDOM.render(<ControlledInputs />, container);
334
+ const ref = React.createRef();
335
+ await act(() => {
336
+ root.render(<ControlledInputs ref={ref} />);
337
+ });
338
+ const instance = ref.current;
339
340
setUntrackedValue.call(instance.a, 'giraffe');
341
// This must use the native event dispatching. If we simulate, we will
342
// bypass the lazy event attachment system so we won't actually test this.
296
- dispatchEventOnNode(instance.a, 'input');
343
+ await act(() => {
344
+ dispatchEventOnNode(instance.a, 'input');
345
+ });
346
347
expect(instance.a.value).toBe('lion');
348
expect(instance.b.checked).toBe(true);
349
});
350
351
describe('switching text inputs between numeric and string numbers', () => {
303
- it('does change the number 2 to "2.0" with no change handler', () => {
304
- const stub = <input type="text" value={2} onChange={jest.fn()} />;
305
- const node = ReactDOM.render(stub, container);
352
+ it('does change the number 2 to "2.0" with no change handler', async () => {
353
+ await act(() => {
354
+ root.render(<input type="text" value={2} onChange={jest.fn()} />);
355
+ });
356
+ const node = container.firstChild;
357
358
setUntrackedValue.call(node, '2.0');
359
dispatchEventOnNode(node, 'input');
@@ -315,9 +366,11 @@ describe('ReactDOMInput', () => {
366
}
367
});
368
318
- it('does change the string "2" to "2.0" with no change handler', () => {
319
- const stub = <input type="text" value={'2'} onChange={jest.fn()} />;
320
- const node = ReactDOM.render(stub, container);
369
+ it('does change the string "2" to "2.0" with no change handler', async () => {
370
+ await act(() => {
371
+ root.render(<input type="text" value={'2'} onChange={jest.fn()} />);
372
+ });
373
+ const node = container.firstChild;
374
375
setUntrackedValue.call(node, '2.0');
376
dispatchEventOnNode(node, 'input');
@@ -330,7 +383,7 @@ describe('ReactDOMInput', () => {
383
}
384
});
385
333
- it('changes the number 2 to "2.0" using a change handler', () => {
386
+ it('changes the number 2 to "2.0" using a change handler', async () => {
387
class Stub extends React.Component {
388
state = {
389
value: 2,
@@ -345,8 +398,10 @@ describe('ReactDOMInput', () => {
398
}
399
}
400
348
- const stub = ReactDOM.render(<Stub />, container);
349
- const node = ReactDOM.findDOMNode(stub);
401
+ await act(() => {
402
+ root.render(<Stub />);
403
+ });
404
+ const node = container.firstChild;
405
406
setUntrackedValue.call(node, '2.0');
407
dispatchEventOnNode(node, 'input');
@@ -360,7 +415,7 @@ describe('ReactDOMInput', () => {
415
});
416
});
417
363
- it('does change the string ".98" to "0.98" with no change handler', () => {
418
+ it('does change the string ".98" to "0.98" with no change handler', async () => {
419
class Stub extends React.Component {
420
state = {
421
value: '.98',
@@ -370,20 +425,24 @@ describe('ReactDOMInput', () => {
425
}
426
}
427
373
- let stub;
374
- expect(() => {
375
- stub = ReactDOM.render(<Stub />, container);
428
+ const ref = React.createRef();
429
+ await expect(async () => {
430
+ await act(() => {
431
+ root.render(<Stub ref={ref} />);
432
+ });
433
}).toErrorDev(
434
'You provided a `value` prop to a form field ' +
435
'without an `onChange` handler.',
436
);
380
- const node = ReactDOM.findDOMNode(stub);
381
- stub.setState({value: '0.98'});
437
+ const node = container.firstChild;
438
+ await act(() => {
439
+ ref.current.setState({value: '0.98'});
440
+ });
441
442
expect(node.value).toEqual('0.98');
443
});
444
386
- it('performs a state change from "" to 0', () => {
445
+ it('performs a state change from "" to 0', async () => {
446
class Stub extends React.Component {
447
state = {
448
value: '',
@@ -393,40 +452,43 @@ describe('ReactDOMInput', () => {
452
}
453
}
454
396
- const stub = ReactDOM.render(<Stub />, container);
397
- const node = ReactDOM.findDOMNode(stub);
398
- stub.setState({value: 0});
455
+ const ref = React.createRef();
456
+ await act(() => {
457
+ root.render(<Stub ref={ref} />);
458
+ });
459
+ const node = container.firstChild;
460
+ await act(() => {
461
+ ref.current.setState({value: 0});
462
+ });
463
464
expect(node.value).toEqual('0');
465
});
466
403
- it('updates the value on radio buttons from "" to 0', function () {
404
- ReactDOM.render(
405
- <input type="radio" value="" onChange={function () {}} />,
406
- container,
407
- );
408
- ReactDOM.render(
409
- <input type="radio" value={0} onChange={function () {}} />,
410
- container,
411
- );
467
+ it('updates the value on radio buttons from "" to 0', async () => {
468
+ await act(() => {
469
+ root.render(<input type="radio" value="" onChange={function () {}} />);
470
+ });
471
+ await act(() => {
472
+ root.render(<input type="radio" value={0} onChange={function () {}} />);
473
+ });
474
expect(container.firstChild.value).toBe('0');
475
expect(container.firstChild.getAttribute('value')).toBe('0');
476
});
477
416
- it('updates the value on checkboxes from "" to 0', function () {
417
- ReactDOM.render(
418
- <input type="checkbox" value="" onChange={function () {}} />,
419
- container,
420
- );
421
- ReactDOM.render(
422
- <input type="checkbox" value={0} onChange={function () {}} />,
423
- container,
424
- );
478
+ it('updates the value on checkboxes from "" to 0', async () => {
479
+ await act(() => {
480
+ root.render(<input type="checkbox" value="" onChange={function () {}} />);
481
+ });
482
+ await act(() => {
483
+ root.render(
484
+ <input type="checkbox" value={0} onChange={function () {}} />,
485
+ );
486
+ });
487
expect(container.firstChild.value).toBe('0');
488
expect(container.firstChild.getAttribute('value')).toBe('0');
489
});
490
429
- it('distinguishes precision for extra zeroes in string number values', () => {
491
+ it('distinguishes precision for extra zeroes in string number values', async () => {
492
class Stub extends React.Component {
493
state = {
494
value: '3.0000',
@@ -436,37 +498,45 @@ describe('ReactDOMInput', () => {
498
}
499
}
500
439
- let stub;
440
-
441
- expect(() => {
442
- stub = ReactDOM.render(<Stub />, container);
501
+ const ref = React.createRef();
502
+ await expect(async () => {
503
+ await act(() => {
504
+ root.render(<Stub ref={ref} />);
505
+ });
506
}).toErrorDev(
507
'You provided a `value` prop to a form field ' +
508
'without an `onChange` handler.',
509
);
447
- const node = ReactDOM.findDOMNode(stub);
448
- stub.setState({value: '3'});
510
+ const node = container.firstChild;
511
+ await act(() => {
512
+ ref.current.setState({value: '3'});
513
+ });
514
515
expect(node.value).toEqual('3');
516
});
517
453
- it('should display `defaultValue` of number 0', () => {
454
- const stub = <input type="text" defaultValue={0} />;
455
- const node = ReactDOM.render(stub, container);
518
+ it('should display `defaultValue` of number 0', async () => {
519
+ await act(() => {
520
+ root.render(<input type="text" defaultValue={0} />);
521
+ });
522
+ const node = container.firstChild;
523
524
expect(node.getAttribute('value')).toBe('0');
525
expect(node.value).toBe('0');
526
});
527
461
- it('only assigns defaultValue if it changes', () => {
528
+ it('only assigns defaultValue if it changes', async () => {
529
class Test extends React.Component {
530
render() {
531
return <input defaultValue="0" />;
532
}
533
}
534
468
- const component = ReactDOM.render(<Test />, container);
469
- const node = ReactDOM.findDOMNode(component);
535
+ const ref = React.createRef();
536
+ await act(() => {
537
+ root.render(<Test ref={ref} />);
538
+ });
539
+ const node = container.firstChild;
540
541
Object.defineProperty(node, 'defaultValue', {
542
get() {
@@ -479,28 +549,36 @@ describe('ReactDOMInput', () => {
549
},
550
});
551
482
- component.forceUpdate();
552
+ await act(() => {
553
+ ref.current.forceUpdate();
554
+ });
555
});
556
485
- it('should display "true" for `defaultValue` of `true`', () => {
557
+ it('should display "true" for `defaultValue` of `true`', async () => {
558
const stub = <input type="text" defaultValue={true} />;
487
- const node = ReactDOM.render(stub, container);
559
+ await act(() => {
560
+ root.render(stub);
561
+ });
562
+ const node = container.firstChild;
563
564
expect(node.value).toBe('true');
565
});
566
492
- it('should display "false" for `defaultValue` of `false`', () => {
567
+ it('should display "false" for `defaultValue` of `false`', async () => {
568
const stub = <input type="text" defaultValue={false} />;
494
- const node = ReactDOM.render(stub, container);
569
+ await act(() => {
570
+ root.render(stub);
571
+ });
572
+ const node = container.firstChild;
573
574
expect(node.value).toBe('false');
575
});
576
499
- it('should update `defaultValue` for uncontrolled input', () => {
500
- const node = ReactDOM.render(
501
- <input type="text" defaultValue="0" />,
502
- container,
503
- );
577
+ it('should update `defaultValue` for uncontrolled input', async () => {
578
+ await act(() => {
579
+ root.render(<input type="text" defaultValue="0" />);
580
+ });
581
+ const node = container.firstChild;
582
583
expect(node.value).toBe('0');
584
expect(node.defaultValue).toBe('0');
@@ -510,7 +588,9 @@ describe('ReactDOMInput', () => {
588
expect(isValueDirty(node)).toBe(true);
589
}
590
513
- ReactDOM.render(<input type="text" defaultValue="1" />, container);
591
+ await act(() => {
592
+ root.render(<input type="text" defaultValue="1" />);
593
+ });
594
595
if (disableInputAttributeSyncing) {
596
expect(node.value).toBe('1');
@@ -523,16 +603,18 @@ describe('ReactDOMInput', () => {
603
}
604
});
605
526
- it('should update `defaultValue` for uncontrolled date/time input', () => {
527
- const node = ReactDOM.render(
528
- <input type="date" defaultValue="1980-01-01" />,
529
- container,
530
- );
606
+ it('should update `defaultValue` for uncontrolled date/time input', async () => {
607
+ await act(() => {
608
+ root.render(<input type="date" defaultValue="1980-01-01" />);
609
+ });
610
+ const node = container.firstChild;
611
612
expect(node.value).toBe('1980-01-01');
613
expect(node.defaultValue).toBe('1980-01-01');
614
535
- ReactDOM.render(<input type="date" defaultValue="2000-01-01" />, container);
615
+ await act(() => {
616
+ root.render(<input type="date" defaultValue="2000-01-01" />);
617
+ });
618
619
if (disableInputAttributeSyncing) {
620
expect(node.value).toBe('2000-01-01');
@@ -542,19 +624,23 @@ describe('ReactDOMInput', () => {
624
expect(node.defaultValue).toBe('2000-01-01');
625
}
626
545
- ReactDOM.render(<input type="date" />, container);
627
+ await act(() => {
628
+ root.render(<input type="date" />);
629
+ });
630
});
631
548
- it('should take `defaultValue` when changing to uncontrolled input', () => {
549
- const node = ReactDOM.render(
550
- <input type="text" value="0" readOnly={true} />,
551
- container,
552
- );
632
+ it('should take `defaultValue` when changing to uncontrolled input', async () => {
633
+ await act(() => {
634
+ root.render(<input type="text" value="0" readOnly={true} />);
635
+ });
636
+ const node = container.firstChild;
637
expect(node.value).toBe('0');
638
expect(isValueDirty(node)).toBe(true);
555
- expect(() =>
556
- ReactDOM.render(<input type="text" defaultValue="1" />, container),
557
- ).toErrorDev(
639
+ await expect(async () => {
640
+ await act(() => {
641
+ root.render(<input type="text" defaultValue="1" />);
642
+ });
643
+ }).toErrorDev(
644
'A component is changing a controlled input to be uncontrolled.',
645
);
646
expect(node.value).toBe('0');
@@ -580,8 +666,11 @@ describe('ReactDOMInput', () => {
666
expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
667
});
668
583
- it('should render name attribute if it is supplied', () => {
584
- const node = ReactDOM.render(<input type="text" name="name" />, container);
669
+ it('should render name attribute if it is supplied', async () => {
670
+ await act(() => {
671
+ root.render(<input type="text" name="name" />);
672
+ });
673
+ const node = container.firstChild;
674
expect(node.name).toBe('name');
675
expect(container.firstChild.getAttribute('name')).toBe('name');
676
});
@@ -594,8 +683,10 @@ describe('ReactDOMInput', () => {
683
expect(div.firstChild.getAttribute('name')).toBe('name');
684
});
685
597
- it('should not render name attribute if it is not supplied', () => {
598
- ReactDOM.render(<input type="text" />, container);
686
+ it('should not render name attribute if it is not supplied', async () => {
687
+ await act(() => {
688
+ root.render(<input type="text" />);
689
+ });
690
expect(container.firstChild.getAttribute('name')).toBe(null);
691
});
692
@@ -607,7 +698,7 @@ describe('ReactDOMInput', () => {
698
expect(div.firstChild.getAttribute('name')).toBe(null);
699
});
700
610
- it('should display "foobar" for `defaultValue` of `objToString`', () => {
701
+ it('should display "foobar" for `defaultValue` of `objToString`', async () => {
702
const objToString = {
703
toString: function () {
704
return 'foobar';
@@ -615,7 +706,10 @@ describe('ReactDOMInput', () => {
706
};
707
708
const stub = <input type="text" defaultValue={objToString} />;
618
- const node = ReactDOM.render(stub, container);
709
+ await act(() => {
710
+ root.render(stub);
711
+ });
712
+ const node = container.firstChild;
713
714
expect(node.value).toBe('foobar');
715
});
@@ -631,10 +725,12 @@ describe('ReactDOMInput', () => {
725
return '2020-01-01';
726
}
727
}
728
+ const legacyContainer = document.createElement('div');
729
+ document.body.appendChild(legacyContainer);
730
const test = () =>
731
ReactDOM.render(
732
<input defaultValue={new TemporalLike()} type="date" />,
637
- container,
733
+ legacyContainer,
734
);
735
expect(() =>
736
expect(test).toThrowError(new TypeError('prod message')),
@@ -644,7 +740,7 @@ describe('ReactDOMInput', () => {
740
);
741
});
742
647
- it('should throw for text inputs if `defaultValue` is an object where valueOf() throws', () => {
743
+ it('should throw for text inputs if `defaultValue` is an object where valueOf() throws', async () => {
744
class TemporalLike {
745
valueOf() {
746
// Throwing here is the behavior of ECMAScript "Temporal" date/time API.
@@ -655,20 +751,19 @@ describe('ReactDOMInput', () => {
751
return '2020-01-01';
752
}
753
}
658
- const test = () =>
659
- ReactDOM.render(
660
- <input defaultValue={new TemporalLike()} type="text" />,
661
- container,
754
+ await expect(async () => {
755
+ await expect(async () => {
756
+ await act(() => {
757
+ root.render(<input defaultValue={new TemporalLike()} type="text" />);
758
+ });
759
+ }).toErrorDev(
760
+ 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
761
+ 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
762
);
663
- expect(() =>
664
- expect(test).toThrowError(new TypeError('prod message')),
665
- ).toErrorDev(
666
- 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
667
- 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
668
- );
763
+ }).rejects.toThrowError(new TypeError('prod message'));
764
});
765
671
- it('should throw for date inputs if `value` is an object where valueOf() throws', () => {
766
+ it('should throw for date inputs if `value` is an object where valueOf() throws', async () => {
767
class TemporalLike {
768
valueOf() {
769
// Throwing here is the behavior of ECMAScript "Temporal" date/time API.
@@ -679,20 +774,25 @@ describe('ReactDOMInput', () => {
774
return '2020-01-01';
775
}
776
}
682
- const test = () =>
683
- ReactDOM.render(
684
- <input value={new TemporalLike()} type="date" onChange={() => {}} />,
685
- container,
777
+ await expect(async () => {
778
+ await expect(async () => {
779
+ await act(() => {
780
+ root.render(
781
+ <input
782
+ value={new TemporalLike()}
783
+ type="date"
784
+ onChange={() => {}}
785
+ />,
786
+ );
787
+ });
788
+ }).toErrorDev(
789
+ 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
790
+ 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
791
);
687
- expect(() =>
688
- expect(test).toThrowError(new TypeError('prod message')),
689
- ).toErrorDev(
690
- 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
691
- 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
692
- );
792
+ }).rejects.toThrowError(new TypeError('prod message'));
793
});
794
695
- it('should throw for text inputs if `value` is an object where valueOf() throws', () => {
795
+ it('should throw for text inputs if `value` is an object where valueOf() throws', async () => {
796
class TemporalLike {
797
valueOf() {
798
// Throwing here is the behavior of ECMAScript "Temporal" date/time API.
@@ -703,55 +803,66 @@ describe('ReactDOMInput', () => {
803
return '2020-01-01';
804
}
805
}
706
- const test = () =>
707
- ReactDOM.render(
708
- <input value={new TemporalLike()} type="text" onChange={() => {}} />,
709
- container,
806
+ await expect(async () => {
807
+ await expect(async () => {
808
+ await act(() => {
809
+ root.render(
810
+ <input
811
+ value={new TemporalLike()}
812
+ type="text"
813
+ onChange={() => {}}
814
+ />,
815
+ );
816
+ });
817
+ }).toErrorDev(
818
+ 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
819
+ 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
820
);
711
- expect(() =>
712
- expect(test).toThrowError(new TypeError('prod message')),
713
- ).toErrorDev(
714
- 'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
715
- 'strings, not TemporalLike. This value must be coerced to a string before using it here.',
716
- );
821
+ }).rejects.toThrowError(new TypeError('prod message'));
822
});
823
719
- it('should display `value` of number 0', () => {
720
- const stub = <input type="text" value={0} onChange={emptyFunction} />;
721
- const node = ReactDOM.render(stub, container);
824
+ it('should display `value` of number 0', async () => {
825
+ await act(() => {
826
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
827
+ });
828
+ const node = container.firstChild;
829
830
expect(node.value).toBe('0');
831
});
832
726
- it('should allow setting `value` to `true`', () => {
727
- let stub = <input type="text" value="yolo" onChange={emptyFunction} />;
728
- const node = ReactDOM.render(stub, container);
833
+ it('should allow setting `value` to `true`', async () => {
834
+ await act(() => {
835
+ root.render(<input type="text" value="yolo" onChange={emptyFunction} />);
836
+ });
837
+ const node = container.firstChild;
838
839
expect(node.value).toBe('yolo');
840
732
- stub = ReactDOM.render(
733
- <input type="text" value={true} onChange={emptyFunction} />,
734
- container,
735
- );
841
+ await act(() => {
842
+ root.render(<input type="text" value={true} onChange={emptyFunction} />);
843
+ });
844
expect(node.value).toEqual('true');
845
});
846
739
- it('should allow setting `value` to `false`', () => {
740
- let stub = <input type="text" value="yolo" onChange={emptyFunction} />;
741
- const node = ReactDOM.render(stub, container);
847
+ it('should allow setting `value` to `false`', async () => {
848
+ await act(() => {
849
+ root.render(<input type="text" value="yolo" onChange={emptyFunction} />);
850
+ });
851
+ const node = container.firstChild;
852
853
expect(node.value).toBe('yolo');
854
745
- stub = ReactDOM.render(
746
- <input type="text" value={false} onChange={emptyFunction} />,
747
- container,
748
- );
855
+ await act(() => {
856
+ root.render(<input type="text" value={false} onChange={emptyFunction} />);
857
+ });
858
expect(node.value).toEqual('false');
859
});
860
752
- it('should allow setting `value` to `objToString`', () => {
753
- let stub = <input type="text" value="foo" onChange={emptyFunction} />;
754
- const node = ReactDOM.render(stub, container);
861
+ it('should allow setting `value` to `objToString`', async () => {
862
+ await act(() => {
863
+ root.render(<input type="text" value="foo" onChange={emptyFunction} />);
864
+ });
865
+ const node = container.firstChild;
866
867
expect(node.value).toBe('foo');
868
@@ -760,15 +871,18 @@ describe('ReactDOMInput', () => {
871
return 'foobar';
872
},
873
};
763
- stub = ReactDOM.render(
764
- <input type="text" value={objToString} onChange={emptyFunction} />,
765
- container,
766
- );
874
+ await act(() => {
875
+ root.render(
876
+ <input type="text" value={objToString} onChange={emptyFunction} />,
877
+ );
878
+ });
879
expect(node.value).toEqual('foobar');
880
});
881
770
- it('should not incur unnecessary DOM mutations', () => {
771
- ReactDOM.render(<input value="a" onChange={() => {}} />, container);
882
+ it('should not incur unnecessary DOM mutations', async () => {
883
+ await act(() => {
884
+ root.render(<input value="a" onChange={() => {}} />);
885
+ });
886
887
const node = container.firstChild;
888
let nodeValue = 'a';
@@ -782,15 +896,21 @@ describe('ReactDOMInput', () => {
896
}),
897
});
898
785
- ReactDOM.render(<input value="a" onChange={() => {}} />, container);
899
+ await act(() => {
900
+ root.render(<input value="a" onChange={() => {}} />);
901
+ });
902
expect(nodeValueSetter).toHaveBeenCalledTimes(0);
903
788
- ReactDOM.render(<input value="b" onChange={() => {}} />, container);
904
+ await act(() => {
905
+ root.render(<input value="b" onChange={() => {}} />);
906
+ });
907
expect(nodeValueSetter).toHaveBeenCalledTimes(1);
908
});
909
792
- it('should not incur unnecessary DOM mutations for numeric type conversion', () => {
793
- ReactDOM.render(<input value="0" onChange={() => {}} />, container);
910
+ it('should not incur unnecessary DOM mutations for numeric type conversion', async () => {
911
+ await act(() => {
912
+ root.render(<input value="0" onChange={() => {}} />);
913
+ });
914
915
const node = container.firstChild;
916
let nodeValue = '0';
@@ -804,12 +924,16 @@ describe('ReactDOMInput', () => {
924
}),
925
});
926
807
- ReactDOM.render(<input value={0} onChange={() => {}} />, container);
927
+ await act(() => {
928
+ root.render(<input value={0} onChange={() => {}} />);
929
+ });
930
expect(nodeValueSetter).toHaveBeenCalledTimes(0);
931
});
932
811
- it('should not incur unnecessary DOM mutations for the boolean type conversion', () => {
812
- ReactDOM.render(<input value="true" onChange={() => {}} />, container);
933
+ it('should not incur unnecessary DOM mutations for the boolean type conversion', async () => {
934
+ await act(() => {
935
+ root.render(<input value="true" onChange={() => {}} />);
936
+ });
937
938
const node = container.firstChild;
939
let nodeValue = 'true';
@@ -823,34 +947,46 @@ describe('ReactDOMInput', () => {
947
}),
948
});
949
826
- ReactDOM.render(<input value={true} onChange={() => {}} />, container);
950
+ await act(() => {
951
+ root.render(<input value={true} onChange={() => {}} />);
952
+ });
953
expect(nodeValueSetter).toHaveBeenCalledTimes(0);
954
});
955
830
- it('should properly control a value of number `0`', () => {
831
- const stub = <input type="text" value={0} onChange={emptyFunction} />;
832
- const node = ReactDOM.render(stub, container);
956
+ it('should properly control a value of number `0`', async () => {
957
+ await act(() => {
958
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
959
+ });
960
+ const node = container.firstChild;
961
962
setUntrackedValue.call(node, 'giraffe');
963
dispatchEventOnNode(node, 'input');
964
expect(node.value).toBe('0');
965
});
966
839
- it('should properly control 0.0 for a text input', () => {
840
- const stub = <input type="text" value={0} onChange={emptyFunction} />;
841
- const node = ReactDOM.render(stub, container);
967
+ it('should properly control 0.0 for a text input', async () => {
968
+ await act(() => {
969
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
970
+ });
971
+ const node = container.firstChild;
972
973
setUntrackedValue.call(node, '0.0');
844
- dispatchEventOnNode(node, 'input');
974
+ await act(() => {
975
+ dispatchEventOnNode(node, 'input');
976
+ });
977
expect(node.value).toBe('0');
978
});
979
848
- it('should properly control 0.0 for a number input', () => {
849
- const stub = <input type="number" value={0} onChange={emptyFunction} />;
850
- const node = ReactDOM.render(stub, container);
980
+ it('should properly control 0.0 for a number input', async () => {
981
+ await act(() => {
982
+ root.render(<input type="number" value={0} onChange={emptyFunction} />);
983
+ });
984
+ const node = container.firstChild;
985
986
setUntrackedValue.call(node, '0.0');
853
- dispatchEventOnNode(node, 'input');
987
+ await act(() => {
988
+ dispatchEventOnNode(node, 'input');
989
+ });
990
991
if (disableInputAttributeSyncing) {
992
expect(node.value).toBe('0.0');
@@ -864,18 +1000,16 @@ describe('ReactDOMInput', () => {
1000
}
1001
});
1002
867
- it('should properly transition from an empty value to 0', function () {
868
- ReactDOM.render(
869
- <input type="text" value="" onChange={emptyFunction} />,
870
- container,
871
- );
1003
+ it('should properly transition from an empty value to 0', async () => {
1004
+ await act(() => {
1005
+ root.render(<input type="text" value="" onChange={emptyFunction} />);
1006
+ });
1007
const node = container.firstChild;
1008
expect(isValueDirty(node)).toBe(false);
1009
875
- ReactDOM.render(
876
- <input type="text" value={0} onChange={emptyFunction} />,
877
- container,
878
- );
1010
+ await act(() => {
1011
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
1012
+ });
1013
1014
expect(node.value).toBe('0');
1015
expect(isValueDirty(node)).toBe(true);
@@ -887,33 +1021,29 @@ describe('ReactDOMInput', () => {
1021
}
1022
});
1023
890
- it('should properly transition from 0 to an empty value', function () {
891
- ReactDOM.render(
892
- <input type="text" value={0} onChange={emptyFunction} />,
893
- container,
894
- );
1024
+ it('should properly transition from 0 to an empty value', async () => {
1025
+ await act(() => {
1026
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
1027
+ });
1028
const node = container.firstChild;
1029
expect(isValueDirty(node)).toBe(true);
1030
898
- ReactDOM.render(
899
- <input type="text" value="" onChange={emptyFunction} />,
900
- container,
901
- );
1031
+ await act(() => {
1032
+ root.render(<input type="text" value="" onChange={emptyFunction} />);
1033
+ });
1034
1035
expect(node.value).toBe('');
1036
expect(node.defaultValue).toBe('');
1037
expect(isValueDirty(node)).toBe(true);
1038
});
1039
908
- it('should properly transition a text input from 0 to an empty 0.0', function () {
909
- ReactDOM.render(
910
- <input type="text" value={0} onChange={emptyFunction} />,
911
- container,
912
- );
913
- ReactDOM.render(
914
- <input type="text" value="0.0" onChange={emptyFunction} />,
915
- container,
916
- );
1040
+ it('should properly transition a text input from 0 to an empty 0.0', async () => {
1041
+ await act(() => {
1042
+ root.render(<input type="text" value={0} onChange={emptyFunction} />);
1043
+ });
1044
+ await act(() => {
1045
+ root.render(<input type="text" value="0.0" onChange={emptyFunction} />);
1046
+ });
1047
1048
const node = container.firstChild;
1049
@@ -925,15 +1055,13 @@ describe('ReactDOMInput', () => {
1055
}
1056
});
1057
928
- it('should properly transition a number input from "" to 0', function () {
929
- ReactDOM.render(
930
- <input type="number" value="" onChange={emptyFunction} />,
931
- container,
932
- );
933
- ReactDOM.render(
934
- <input type="number" value={0} onChange={emptyFunction} />,
935
- container,
936
- );
1058
+ it('should properly transition a number input from "" to 0', async () => {
1059
+ await act(() => {
1060
+ root.render(<input type="number" value="" onChange={emptyFunction} />);
1061
+ });
1062
+ await act(() => {
1063
+ root.render(<input type="number" value={0} onChange={emptyFunction} />);
1064
+ });
1065
1066
const node = container.firstChild;
1067
@@ -945,15 +1073,13 @@ describe('ReactDOMInput', () => {
1073
}
1074
});
1075
948
- it('should properly transition a number input from "" to "0"', function () {
949
- ReactDOM.render(
950
- <input type="number" value="" onChange={emptyFunction} />,
951
- container,
952
- );
953
- ReactDOM.render(
954
- <input type="number" value="0" onChange={emptyFunction} />,
955
- container,
956
- );
1076
+ it('should properly transition a number input from "" to "0"', async () => {
1077
+ await act(() => {
1078
+ root.render(<input type="number" value="" onChange={emptyFunction} />);
1079
+ });
1080
+ await act(() => {
1081
+ root.render(<input type="number" value="0" onChange={emptyFunction} />);
1082
+ });
1083
1084
const node = container.firstChild;
1085
@@ -965,31 +1091,36 @@ describe('ReactDOMInput', () => {
1091
}
1092
});
1093
968
- it('should have the correct target value', () => {
1094
+ it('should have the correct target value', async () => {
1095
let handled = false;
1096
const handler = function (event) {
1097
expect(event.target.nodeName).toBe('INPUT');
1098
handled = true;
1099
};
974
- const stub = <input type="text" value={0} onChange={handler} />;
975
- const node = ReactDOM.render(stub, container);
1100
+ await act(() => {
1101
+ root.render(<input type="text" value={0} onChange={handler} />);
1102
+ });
1103
+ const node = container.firstChild;
1104
1105
setUntrackedValue.call(node, 'giraffe');
1106
979
- dispatchEventOnNode(node, 'input');
1107
+ await act(() => {
1108
+ dispatchEventOnNode(node, 'input');
1109
+ });
1110
1111
expect(handled).toBe(true);
1112
});
1113
984
- it('should restore uncontrolled inputs to last defaultValue upon reset', () => {
1114
+ it('should restore uncontrolled inputs to last defaultValue upon reset', async () => {
1115
const inputRef = React.createRef();
986
- ReactDOM.render(
987
- <form>
988
- <input defaultValue="default1" ref={inputRef} />
989
- <input type="reset" />
990
- </form>,
991
- container,
992
- );
1116
+ await act(() => {
1117
+ root.render(
1118
+ <form>
1119
+ <input defaultValue="default1" ref={inputRef} />
1120
+ <input type="reset" />
1121
+ </form>,
1122
+ );
1123
+ });
1124
expect(inputRef.current.value).toBe('default1');
1125
if (disableInputAttributeSyncing) {
1126
expect(isValueDirty(inputRef.current)).toBe(false);
@@ -1002,13 +1133,14 @@ describe('ReactDOMInput', () => {
1133
expect(inputRef.current.value).toBe('changed');
1134
expect(isValueDirty(inputRef.current)).toBe(true);
1135
1005
- ReactDOM.render(
1006
- <form>
1007
- <input defaultValue="default2" ref={inputRef} />
1008
- <input type="reset" />
1009
- </form>,
1010
- container,
1011
- );
1136
+ await act(() => {
1137
+ root.render(
1138
+ <form>
1139
+ <input defaultValue="default2" ref={inputRef} />
1140
+ <input type="reset" />
1141
+ </form>,
1142
+ );
1143
+ });
1144
expect(inputRef.current.value).toBe('changed');
1145
expect(isValueDirty(inputRef.current)).toBe(true);
1146
@@ -1020,9 +1152,11 @@ describe('ReactDOMInput', () => {
1152
expect(isValueDirty(inputRef.current)).toBe(false);
1153
});
1154
1023
- it('should not set a value for submit buttons unnecessarily', () => {
1155
+ it('should not set a value for submit buttons unnecessarily', async () => {
1156
const stub = <input type="submit" />;
1025
- ReactDOM.render(stub, container);
1157
+ await act(() => {
1158
+ root.render(stub);
1159
+ });
1160
const node = container.firstChild;
1161
1162
// The value shouldn't be '', or else the button will have no text; it
@@ -1032,18 +1166,21 @@ describe('ReactDOMInput', () => {
1166
expect(node.hasAttribute('value')).toBe(false);
1167
});
1168
1035
- it('should remove the value attribute on submit inputs when value is updated to undefined', () => {
1169
+ it('should remove the value attribute on submit inputs when value is updated to undefined', async () => {
1170
const stub = <input type="submit" value="foo" onChange={emptyFunction} />;
1037
- ReactDOM.render(stub, container);
1171
+ await act(() => {
1172
+ root.render(stub);
1173
+ });
1174
1175
// Not really relevant to this particular test, but changing to undefined
1176
// should nonetheless trigger a warning
1041
- expect(() =>
1042
- ReactDOM.render(
1043
- <input type="submit" value={undefined} onChange={emptyFunction} />,
1044
- container,
1045
- ),
1046
- ).toErrorDev(
1177
+ await expect(async () => {
1178
+ await act(() => {
1179
+ root.render(
1180
+ <input type="submit" value={undefined} onChange={emptyFunction} />,
1181
+ );
1182
+ });
1183
+ }).toErrorDev(
1184
'A component is changing a controlled input to be uncontrolled.',
1185
);
1186
@@ -1051,18 +1188,21 @@ describe('ReactDOMInput', () => {
1188
expect(node.getAttribute('value')).toBe(null);
1189
});
1190
1054
- it('should remove the value attribute on reset inputs when value is updated to undefined', () => {
1191
+ it('should remove the value attribute on reset inputs when value is updated to undefined', async () => {
1192
const stub = <input type="reset" value="foo" onChange={emptyFunction} />;
1056
- ReactDOM.render(stub, container);
1193
+ await act(() => {
1194
+ root.render(stub);
1195
+ });
1196
1197
// Not really relevant to this particular test, but changing to undefined
1198
// should nonetheless trigger a warning
1060
- expect(() =>
1061
- ReactDOM.render(
1062
- <input type="reset" value={undefined} onChange={emptyFunction} />,
1063
- container,
1064
- ),
1065
- ).toErrorDev(
1199
+ await expect(async () => {
1200
+ await act(() => {
1201
+ root.render(
1202
+ <input type="reset" value={undefined} onChange={emptyFunction} />,
1203
+ );
1204
+ });
1205
+ }).toErrorDev(
1206
'A component is changing a controlled input to be uncontrolled.',
1207
);
1208
@@ -1070,44 +1210,56 @@ describe('ReactDOMInput', () => {
1210
expect(node.getAttribute('value')).toBe(null);
1211
});
1212
1073
- it('should set a value on a submit input', () => {
1213
+ it('should set a value on a submit input', async () => {
1214
const stub = <input type="submit" value="banana" />;
1075
- ReactDOM.render(stub, container);
1215
+ await act(() => {
1216
+ root.render(stub);
1217
+ });
1218
const node = container.firstChild;
1219
1220
expect(node.getAttribute('value')).toBe('banana');
1221
});
1222
1081
- it('should not set an undefined value on a submit input', () => {
1223
+ it('should not set an undefined value on a submit input', async () => {
1224
const stub = <input type="submit" value={undefined} />;
1083
- ReactDOM.render(stub, container);
1225
+ await act(() => {
1226
+ root.render(stub);
1227
+ });
1228
const node = container.firstChild;
1229
1230
// Note: it shouldn't be an empty string
1231
// because that would erase the "submit" label.
1232
expect(node.getAttribute('value')).toBe(null);
1233
1090
- ReactDOM.render(stub, container);
1234
+ await act(() => {
1235
+ root.render(stub);
1236
+ });
1237
expect(node.getAttribute('value')).toBe(null);
1238
});
1239
1094
- it('should not set an undefined value on a reset input', () => {
1240
+ it('should not set an undefined value on a reset input', async () => {
1241
const stub = <input type="reset" value={undefined} />;
1096
- ReactDOM.render(stub, container);
1242
+ await act(() => {
1243
+ root.render(stub);
1244
+ });
1245
const node = container.firstChild;
1246
1247
// Note: it shouldn't be an empty string
1248
// because that would erase the "reset" label.
1249
expect(node.getAttribute('value')).toBe(null);
1250
1103
- ReactDOM.render(stub, container);
1251
+ await act(() => {
1252
+ root.render(stub);
1253
+ });
1254
expect(node.getAttribute('value')).toBe(null);
1255
});
1256
1107
- it('should not set a null value on a submit input', () => {
1257
+ it('should not set a null value on a submit input', async () => {
1258
const stub = <input type="submit" value={null} />;
1109
- expect(() => {
1110
- ReactDOM.render(stub, container);
1259
+ await expect(async () => {
1260
+ await act(() => {
1261
+ root.render(stub);
1262
+ });
1263
}).toErrorDev('`value` prop on `input` should not be null');
1264
const node = container.firstChild;
1265
@@ -1115,14 +1267,18 @@ describe('ReactDOMInput', () => {
1267
// because that would erase the "submit" label.
1268
expect(node.getAttribute('value')).toBe(null);
1269
1118
- ReactDOM.render(stub, container);
1270
+ await act(() => {
1271
+ root.render(stub);
1272
+ });
1273
expect(node.getAttribute('value')).toBe(null);
1274
});
1275
1122
- it('should not set a null value on a reset input', () => {
1276
+ it('should not set a null value on a reset input', async () => {
1277
const stub = <input type="reset" value={null} />;
1124
- expect(() => {
1125
- ReactDOM.render(stub, container);
1278
+ await expect(async () => {
1279
+ await act(() => {
1280
+ root.render(stub);
1281
+ });
1282
}).toErrorDev('`value` prop on `input` should not be null');
1283
const node = container.firstChild;
1284
@@ -1130,35 +1286,43 @@ describe('ReactDOMInput', () => {
1286
// because that would erase the "reset" label.
1287
expect(node.getAttribute('value')).toBe(null);
1288
1133
- ReactDOM.render(stub, container);
1289
+ await act(() => {
1290
+ root.render(stub);
1291
+ });
1292
expect(node.getAttribute('value')).toBe(null);
1293
});
1294
1137
- it('should set a value on a reset input', () => {
1295
+ it('should set a value on a reset input', async () => {
1296
const stub = <input type="reset" value="banana" />;
1139
- ReactDOM.render(stub, container);
1297
+ await act(() => {
1298
+ root.render(stub);
1299
+ });
1300
const node = container.firstChild;
1301
1302
expect(node.getAttribute('value')).toBe('banana');
1303
});
1304
1145
- it('should set an empty string value on a submit input', () => {
1305
+ it('should set an empty string value on a submit input', async () => {
1306
const stub = <input type="submit" value="" />;
1147
- ReactDOM.render(stub, container);
1307
+ await act(() => {
1308
+ root.render(stub);
1309
+ });
1310
const node = container.firstChild;
1311
1312
expect(node.getAttribute('value')).toBe('');
1313
});
1314
1153
- it('should set an empty string value on a reset input', () => {
1315
+ it('should set an empty string value on a reset input', async () => {
1316
const stub = <input type="reset" value="" />;
1155
- ReactDOM.render(stub, container);
1317
+ await act(() => {
1318
+ root.render(stub);
1319
+ });
1320
const node = container.firstChild;
1321
1322
expect(node.getAttribute('value')).toBe('');
1323
});
1324
1161
- it('should control radio buttons', () => {
1325
+ it('should control radio buttons', async () => {
1326
class RadioGroup extends React.Component {
1327
aRef = React.createRef();
1328
bRef = React.createRef();
@@ -1199,7 +1363,11 @@ describe('ReactDOMInput', () => {
1363
}
1364
}
1365
1202
- const stub = ReactDOM.render(<RadioGroup />, container);
1366
+ const ref = React.createRef();
1367
+ await act(() => {
1368
+ root.render(<RadioGroup ref={ref} />);
1369
+ });
1370
+ const stub = ref.current;
1371
const aNode = stub.aRef.current;
1372
const bNode = stub.bRef.current;
1373
const cNode = stub.cRef.current;
@@ -1240,7 +1408,9 @@ describe('ReactDOMInput', () => {
1408
}
1409
1410
// Now let's run the actual ReactDOMInput change event handler
1243
- dispatchEventOnNode(bNode, 'click');
1411
+ await act(() => {
1412
+ dispatchEventOnNode(bNode, 'click');
1413
+ });
1414
1415
// The original state should have been restored
1416
expect(aNode.checked).toBe(true);
@@ -1288,6 +1458,10 @@ describe('ReactDOMInput', () => {
1458
);
1459
}
1460
const html = ReactDOMServer.renderToString(<App />);
1461
+ // Create a fresh container, not attached a root yet
1462
+ container.remove();
1463
+ container = document.createElement('div');
1464
+ document.body.appendChild(container);
1465
container.innerHTML = html;
1466
const [a, b, c] = container.querySelectorAll('input');
1467
expect(a.checked).toBe(true);
@@ -1376,6 +1550,10 @@ describe('ReactDOMInput', () => {
1550
);
1551
}
1552
const html = ReactDOMServer.renderToString(<App />);
1553
+ // Create a fresh container, not attached a root yet
1554
+ container.remove();
1555
+ container = document.createElement('div');
1556
+ document.body.appendChild(container);
1557
container.innerHTML = html;
1558
const [a, b, c] = container.querySelectorAll('input');
1559
expect(a.checked).toBe(true);
@@ -1421,7 +1599,7 @@ describe('ReactDOMInput', () => {
1599
assertInputTrackingIsCurrent(container);
1600
});
1601
1424
- it('should check the correct radio when the selected name moves', () => {
1602
+ it('should check the correct radio when the selected name moves', async () => {
1603
class App extends React.Component {
1604
state = {
1605
updated: false,
@@ -1452,40 +1630,48 @@ describe('ReactDOMInput', () => {
1630
}
1631
}
1632
1455
- const stub = ReactDOM.render(<App />, container);
1456
- const buttonNode = ReactDOM.findDOMNode(stub).childNodes[0];
1457
- const firstRadioNode = ReactDOM.findDOMNode(stub).childNodes[1];
1633
+ await act(() => {
1634
+ root.render(<App />);
1635
+ });
1636
+ const node = container.firstChild;
1637
+ const buttonNode = node.childNodes[0];
1638
+ const firstRadioNode = node.childNodes[1];
1639
expect(isCheckedDirty(firstRadioNode)).toBe(true);
1640
expect(firstRadioNode.checked).toBe(false);
1641
assertInputTrackingIsCurrent(container);
1461
- dispatchEventOnNode(buttonNode, 'click');
1642
+ await act(() => {
1643
+ dispatchEventOnNode(buttonNode, 'click');
1644
+ });
1645
expect(firstRadioNode.checked).toBe(true);
1646
assertInputTrackingIsCurrent(container);
1464
- dispatchEventOnNode(buttonNode, 'click');
1647
+ await act(() => {
1648
+ dispatchEventOnNode(buttonNode, 'click');
1649
+ });
1650
expect(firstRadioNode.checked).toBe(false);
1651
assertInputTrackingIsCurrent(container);
1652
});
1653
1469
- it("shouldn't get tricked by changing radio names, part 2", () => {
1470
- ReactDOM.render(
1471
- <div>
1472
- <input
1473
- type="radio"
1474
- name="a"
1475
- value="1"
1476
- checked={true}
1477
- onChange={() => {}}
1478
- />
1479
- <input
1480
- type="radio"
1481
- name="a"
1482
- value="2"
1483
- checked={false}
1484
- onChange={() => {}}
1485
- />
1486
- </div>,
1487
- container,
1488
- );
1654
+ it("shouldn't get tricked by changing radio names, part 2", async () => {
1655
+ await act(() => {
1656
+ root.render(
1657
+ <div>
1658
+ <input
1659
+ type="radio"
1660
+ name="a"
1661
+ value="1"
1662
+ checked={true}
1663
+ onChange={() => {}}
1664
+ />
1665
+ <input
1666
+ type="radio"
1667
+ name="a"
1668
+ value="2"
1669
+ checked={false}
1670
+ onChange={() => {}}
1671
+ />
1672
+ </div>,
1673
+ );
1674
+ });
1675
const one = container.querySelector('input[name="a"][value="1"]');
1676
const two = container.querySelector('input[name="a"][value="2"]');
1677
expect(one.checked).toBe(true);
@@ -1494,25 +1680,26 @@ describe('ReactDOMInput', () => {
1680
expect(isCheckedDirty(two)).toBe(true);
1681
assertInputTrackingIsCurrent(container);
1682
1497
- ReactDOM.render(
1498
- <div>
1499
- <input
1500
- type="radio"
1501
- name="a"
1502
- value="1"
1503
- checked={true}
1504
- onChange={() => {}}
1505
- />
1506
- <input
1507
- type="radio"
1508
- name="b"
1509
- value="2"
1510
- checked={true}
1511
- onChange={() => {}}
1512
- />
1513
- </div>,
1514
- container,
1515
- );
1683
+ await act(() => {
1684
+ root.render(
1685
+ <div>
1686
+ <input
1687
+ type="radio"
1688
+ name="a"
1689
+ value="1"
1690
+ checked={true}
1691
+ onChange={() => {}}
1692
+ />
1693
+ <input
1694
+ type="radio"
1695
+ name="b"
1696
+ value="2"
1697
+ checked={true}
1698
+ onChange={() => {}}
1699
+ />
1700
+ </div>,
1701
+ );
1702
+ });
1703
expect(one.checked).toBe(true);
1704
expect(two.checked).toBe(true);
1705
expect(isCheckedDirty(one)).toBe(true);
@@ -1521,6 +1708,9 @@ describe('ReactDOMInput', () => {
1708
});
1709
1710
it('should control radio buttons if the tree updates during render', () => {
1711
+ container.remove();
1712
+ container = document.createElement('div');
1713
+ document.body.appendChild(container);
1714
const sharedParent = container;
1715
const container1 = document.createElement('div');
1716
const container2 = document.createElement('div');
@@ -1600,7 +1790,7 @@ describe('ReactDOMInput', () => {
1790
assertInputTrackingIsCurrent(container);
1791
});
1792
1603
- it('should control radio buttons if the tree updates during render (case 2; #26876)', () => {
1793
+ it('should control radio buttons if the tree updates during render (case 2; #26876)', async () => {
1794
let thunk = null;
1795
function App() {
1796
const [disabled, setDisabled] = React.useState(false);
@@ -1634,7 +1824,9 @@ describe('ReactDOMInput', () => {
1824
</>
1825
);
1826
}
1637
- ReactDOM.render(<App />, container);
1827
+ await act(() => {
1828
+ root.render(<App />);
1829
+ });
1830
const [one, two] = container.querySelectorAll('input');
1831
expect(one.checked).toBe(true);
1832
expect(two.checked).toBe(false);
@@ -1644,7 +1836,9 @@ describe('ReactDOMInput', () => {
1836
1837
// Click two
1838
setUntrackedChecked.call(two, true);
1647
- dispatchEventOnNode(two, 'click');
1839
+ await act(() => {
1840
+ dispatchEventOnNode(two, 'click');
1841
+ });
1842
expect(one.checked).toBe(true);
1843
expect(two.checked).toBe(false);
1844
expect(isCheckedDirty(one)).toBe(true);
@@ -1652,7 +1846,7 @@ describe('ReactDOMInput', () => {
1846
assertInputTrackingIsCurrent(container);
1847
1848
// After a delay...
1655
- ReactDOM.unstable_batchedUpdates(thunk);
1849
+ await act(thunk);
1850
expect(one.checked).toBe(false);
1851
expect(two.checked).toBe(true);
1852
expect(isCheckedDirty(one)).toBe(true);
@@ -1661,7 +1855,9 @@ describe('ReactDOMInput', () => {
1855
1856
// Click back to one
1857
setUntrackedChecked.call(one, true);
1664
- dispatchEventOnNode(one, 'click');
1858
+ await act(() => {
1859
+ dispatchEventOnNode(one, 'click');
1860
+ });
1861
expect(one.checked).toBe(false);
1862
expect(two.checked).toBe(true);
1863
expect(isCheckedDirty(one)).toBe(true);
@@ -1669,7 +1865,7 @@ describe('ReactDOMInput', () => {
1865
assertInputTrackingIsCurrent(container);
1866
1867
// After a delay...
1672
- ReactDOM.unstable_batchedUpdates(thunk);
1868
+ await act(thunk);
1869
expect(one.checked).toBe(true);
1870
expect(two.checked).toBe(false);
1871
expect(isCheckedDirty(one)).toBe(true);
@@ -1677,19 +1873,18 @@ describe('ReactDOMInput', () => {
1873
assertInputTrackingIsCurrent(container);
1874
});
1875
1680
- it('should warn with value and no onChange handler and readOnly specified', () => {
1681
- ReactDOM.render(
1682
- <input type="text" value="zoink" readOnly={true} />,
1683
- container,
1684
- );
1685
- ReactDOM.unmountComponentAtNode(container);
1876
+ it('should warn with value and no onChange handler and readOnly specified', async () => {
1877
+ await act(() => {
1878
+ root.render(<input type="text" value="zoink" readOnly={true} />);
1879
+ });
1880
+ root.unmount();
1881
+ root = ReactDOMClient.createRoot(container);
1882
1687
- expect(() =>
1688
- ReactDOM.render(
1689
- <input type="text" value="zoink" readOnly={false} />,
1690
- container,
1691
- ),
1692
- ).toErrorDev(
1883
+ await expect(async () => {
1884
+ await act(() => {
1885
+ root.render(<input type="text" value="zoink" readOnly={false} />);
1886
+ });
1887
+ }).toErrorDev(
1888
'Warning: You provided a `value` prop to a form ' +
1889
'field without an `onChange` handler. This will render a read-only ' +
1890
'field. If the field should be mutable use `defaultValue`. ' +
@@ -1698,27 +1893,36 @@ describe('ReactDOMInput', () => {
1893
);
1894
});
1895
1701
- it('should have a this value of undefined if bind is not used', () => {
1896
+ it('should have a this value of undefined if bind is not used', async () => {
1897
expect.assertions(1);
1898
const unboundInputOnChange = function () {
1899
expect(this).toBe(undefined);
1900
};
1901
1902
const stub = <input type="text" onChange={unboundInputOnChange} />;
1708
- const node = ReactDOM.render(stub, container);
1903
+ await act(() => {
1904
+ root.render(stub);
1905
+ });
1906
+ const node = container.firstChild;
1907
1908
setUntrackedValue.call(node, 'giraffe');
1711
- dispatchEventOnNode(node, 'input');
1909
+ await act(() => {
1910
+ dispatchEventOnNode(node, 'input');
1911
+ });
1912
});
1913
1714
- it('should update defaultValue to empty string', () => {
1715
- ReactDOM.render(<input type="text" defaultValue={'foo'} />, container);
1914
+ it('should update defaultValue to empty string', async () => {
1915
+ await act(() => {
1916
+ root.render(<input type="text" defaultValue={'foo'} />);
1917
+ });
1918
if (disableInputAttributeSyncing) {
1919
expect(isValueDirty(container.firstChild)).toBe(false);
1920
} else {
1921
expect(isValueDirty(container.firstChild)).toBe(true);
1922
}
1721
- ReactDOM.render(<input type="text" defaultValue={''} />, container);
1923
+ await act(() => {
1924
+ root.render(<input type="text" defaultValue={''} />);
1925
+ });
1926
expect(container.firstChild.defaultValue).toBe('');
1927
if (disableInputAttributeSyncing) {
1928
expect(isValueDirty(container.firstChild)).toBe(false);
@@ -1727,31 +1931,37 @@ describe('ReactDOMInput', () => {
1931
}
1932
});
1933
1730
- it('should warn if value is null', () => {
1731
- expect(() =>
1732
- ReactDOM.render(<input type="text" value={null} />, container),
1733
- ).toErrorDev(
1934
+ it('should warn if value is null', async () => {
1935
+ await expect(async () => {
1936
+ await act(() => {
1937
+ root.render(<input type="text" value={null} />);
1938
+ });
1939
+ }).toErrorDev(
1940
'`value` prop on `input` should not be null. ' +
1941
'Consider using an empty string to clear the component or `undefined` ' +
1942
'for uncontrolled components.',
1943
);
1738
- ReactDOM.unmountComponentAtNode(container);
1944
+ root.unmount();
1945
1740
- ReactDOM.render(<input type="text" value={null} />, container);
1946
+ root = ReactDOMClient.createRoot(container);
1947
+ await act(() => {
1948
+ root.render(<input type="text" value={null} />);
1949
+ });
1950
});
1951
1743
- it('should warn if checked and defaultChecked props are specified', () => {
1744
- expect(() =>
1745
- ReactDOM.render(
1746
- <input
1747
- type="radio"
1748
- checked={true}
1749
- defaultChecked={true}
1750
- readOnly={true}
1751
- />,
1752
- container,
1753
- ),
1754
- ).toErrorDev(
1952
+ it('should warn if checked and defaultChecked props are specified', async () => {
1953
+ await expect(async () => {
1954
+ await act(() => {
1955
+ root.render(
1956
+ <input
1957
+ type="radio"
1958
+ checked={true}
1959
+ defaultChecked={true}
1960
+ readOnly={true}
1961
+ />,
1962
+ );
1963
+ });
1964
+ }).toErrorDev(
1965
'A component contains an input of type radio with both checked and defaultChecked props. ' +
1966
'Input elements must be either controlled or uncontrolled ' +
1967
'(specify either the checked prop, or the defaultChecked prop, but not ' +
@@ -1759,26 +1969,29 @@ describe('ReactDOMInput', () => {
1969
'element and remove one of these props. More info: ' +
1970
'https://reactjs.org/link/controlled-components',
1971
);
1762
- ReactDOM.unmountComponentAtNode(container);
1763
-
1764
- ReactDOM.render(
1765
- <input
1766
- type="radio"
1767
- checked={true}
1768
- defaultChecked={true}
1769
- readOnly={true}
1770
- />,
1771
- container,
1772
- );
1972
+ root.unmount();
1973
+
1974
+ root = ReactDOMClient.createRoot(container);
1975
+ await act(() => {
1976
+ root.render(
1977
+ <input
1978
+ type="radio"
1979
+ checked={true}
1980
+ defaultChecked={true}
1981
+ readOnly={true}
1982
+ />,
1983
+ );
1984
+ });
1985
});
1986
1775
- it('should warn if value and defaultValue props are specified', () => {
1776
- expect(() =>
1777
- ReactDOM.render(
1778
- <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
1779
- container,
1780
- ),
1781
- ).toErrorDev(
1987
+ it('should warn if value and defaultValue props are specified', async () => {
1988
+ await expect(async () => {
1989
+ await act(() => {
1990
+ root.render(
1991
+ <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
1992
+ );
1993
+ });
1994
+ }).toErrorDev(
1995
'A component contains an input of type text with both value and defaultValue props. ' +
1996
'Input elements must be either controlled or uncontrolled ' +
1997
'(specify either the value prop, or the defaultValue prop, but not ' +
@@ -1786,20 +1999,29 @@ describe('ReactDOMInput', () => {
1999
'element and remove one of these props. More info: ' +
2000
'https://reactjs.org/link/controlled-components',
2001
);
1789
- ReactDOM.unmountComponentAtNode(container);
2002
+ await (() => {
2003
+ root.unmount();
2004
+ });
2005
1791
- ReactDOM.render(
1792
- <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
1793
- container,
1794
- );
2006
+ await act(() => {
2007
+ root.render(
2008
+ <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
2009
+ );
2010
+ });
2011
});
2012
1797
- it('should warn if controlled input switches to uncontrolled (value is undefined)', () => {
2013
+ it('should warn if controlled input switches to uncontrolled (value is undefined)', async () => {
2014
const stub = (
2015
<input type="text" value="controlled" onChange={emptyFunction} />
2016
);
1801
- ReactDOM.render(stub, container);
1802
- expect(() => ReactDOM.render(<input type="text" />, container)).toErrorDev(
2017
+ await act(() => {
2018
+ root.render(stub);
2019
+ });
2020
+ await expect(async () => {
2021
+ await act(() => {
2022
+ root.render(<input type="text" />);
2023
+ });
2024
+ }).toErrorDev(
2025
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2026
'This is likely caused by the value changing from a defined to ' +
2027
'undefined, which should not happen. ' +
@@ -1809,14 +2031,18 @@ describe('ReactDOMInput', () => {
2031
);
2032
});
2033
1812
- it('should warn if controlled input switches to uncontrolled (value is null)', () => {
2034
+ it('should warn if controlled input switches to uncontrolled (value is null)', async () => {
2035
const stub = (
2036
<input type="text" value="controlled" onChange={emptyFunction} />
2037
);
1816
- ReactDOM.render(stub, container);
1817
- expect(() =>
1818
- ReactDOM.render(<input type="text" value={null} />, container),
1819
- ).toErrorDev([
2038
+ await act(() => {
2039
+ root.render(stub);
2040
+ });
2041
+ await expect(async () => {
2042
+ await act(() => {
2043
+ root.render(<input type="text" value={null} />);
2044
+ });
2045
+ }).toErrorDev([
2046
'`value` prop on `input` should not be null. ' +
2047
'Consider using an empty string to clear the component or `undefined` for uncontrolled components',
2048
'Warning: A component is changing a controlled input to be uncontrolled. ' +
@@ -1828,17 +2054,18 @@ describe('ReactDOMInput', () => {
2054
]);
2055
});
2056
1831
- it('should warn if controlled input switches to uncontrolled with defaultValue', () => {
2057
+ it('should warn if controlled input switches to uncontrolled with defaultValue', async () => {
2058
const stub = (
2059
<input type="text" value="controlled" onChange={emptyFunction} />
2060
);
1835
- ReactDOM.render(stub, container);
1836
- expect(() =>
1837
- ReactDOM.render(
1838
- <input type="text" defaultValue="uncontrolled" />,
1839
- container,
1840
- ),
1841
- ).toErrorDev(
2061
+ await act(() => {
2062
+ root.render(stub);
2063
+ });
2064
+ await expect(async () => {
2065
+ await act(() => {
2066
+ root.render(<input type="text" defaultValue="uncontrolled" />);
2067
+ });
2068
+ }).toErrorDev(
2069
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2070
'This is likely caused by the value changing from a defined to ' +
2071
'undefined, which should not happen. ' +
@@ -1848,12 +2075,16 @@ describe('ReactDOMInput', () => {
2075
);
2076
});
2077
1851
- it('should warn if uncontrolled input (value is undefined) switches to controlled', () => {
2078
+ it('should warn if uncontrolled input (value is undefined) switches to controlled', async () => {
2079
const stub = <input type="text" />;
1853
- ReactDOM.render(stub, container);
1854
- expect(() =>
1855
- ReactDOM.render(<input type="text" value="controlled" />, container),
1856
- ).toErrorDev(
2080
+ await act(() => {
2081
+ root.render(stub);
2082
+ });
2083
+ await expect(async () => {
2084
+ await act(() => {
2085
+ root.render(<input type="text" value="controlled" />);
2086
+ });
2087
+ }).toErrorDev(
2088
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2089
'This is likely caused by the value changing from undefined to ' +
2090
'a defined value, which should not happen. ' +
@@ -1863,15 +2094,21 @@ describe('ReactDOMInput', () => {
2094
);
2095
});
2096
1866
- it('should warn if uncontrolled input (value is null) switches to controlled', () => {
2097
+ it('should warn if uncontrolled input (value is null) switches to controlled', async () => {
2098
const stub = <input type="text" value={null} />;
1868
- expect(() => ReactDOM.render(stub, container)).toErrorDev(
2099
+ await expect(async () => {
2100
+ await act(() => {
2101
+ root.render(stub);
2102
+ });
2103
+ }).toErrorDev(
2104
'`value` prop on `input` should not be null. ' +
2105
'Consider using an empty string to clear the component or `undefined` for uncontrolled components.',
2106
);
1872
- expect(() =>
1873
- ReactDOM.render(<input type="text" value="controlled" />, container),
1874
- ).toErrorDev(
2107
+ await expect(async () => {
2108
+ await act(() => {
2109
+ root.render(<input type="text" value="controlled" />);
2110
+ });
2111
+ }).toErrorDev(
2112
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2113
'This is likely caused by the value changing from undefined to ' +
2114
'a defined value, which should not happen. ' +
@@ -1881,14 +2118,18 @@ describe('ReactDOMInput', () => {
2118
);
2119
});
2120
1884
- it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', () => {
2121
+ it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', async () => {
2122
const stub = (
2123
<input type="checkbox" checked={true} onChange={emptyFunction} />
2124
);
1888
- ReactDOM.render(stub, container);
1889
- expect(() =>
1890
- ReactDOM.render(<input type="checkbox" />, container),
1891
- ).toErrorDev(
2125
+ await act(() => {
2126
+ root.render(stub);
2127
+ });
2128
+ await expect(async () => {
2129
+ await act(() => {
2130
+ root.render(<input type="checkbox" />);
2131
+ });
2132
+ }).toErrorDev(
2133
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2134
'This is likely caused by the value changing from a defined to ' +
2135
'undefined, which should not happen. ' +
@@ -1898,14 +2139,18 @@ describe('ReactDOMInput', () => {
2139
);
2140
});
2141
1901
- it('should warn if controlled checkbox switches to uncontrolled (checked is null)', () => {
2142
+ it('should warn if controlled checkbox switches to uncontrolled (checked is null)', async () => {
2143
const stub = (
2144
<input type="checkbox" checked={true} onChange={emptyFunction} />
2145
);
1905
- ReactDOM.render(stub, container);
1906
- expect(() =>
1907
- ReactDOM.render(<input type="checkbox" checked={null} />, container),
1908
- ).toErrorDev(
2146
+ await act(() => {
2147
+ root.render(stub);
2148
+ });
2149
+ await expect(async () => {
2150
+ await act(() => {
2151
+ root.render(<input type="checkbox" checked={null} />);
2152
+ });
2153
+ }).toErrorDev(
2154
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2155
'This is likely caused by the value changing from a defined to ' +
2156
'undefined, which should not happen. ' +
@@ -1915,17 +2160,18 @@ describe('ReactDOMInput', () => {
2160
);
2161
});
2162
1918
- it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', () => {
2163
+ it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', async () => {
2164
const stub = (
2165
<input type="checkbox" checked={true} onChange={emptyFunction} />
2166
);
1922
- ReactDOM.render(stub, container);
1923
- expect(() =>
1924
- ReactDOM.render(
1925
- <input type="checkbox" defaultChecked={true} />,
1926
- container,
1927
- ),
1928
- ).toErrorDev(
2167
+ await act(() => {
2168
+ root.render(stub);
2169
+ });
2170
+ await expect(async () => {
2171
+ await act(() => {
2172
+ root.render(<input type="checkbox" defaultChecked={true} />);
2173
+ });
2174
+ }).toErrorDev(
2175
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2176
'This is likely caused by the value changing from a defined to ' +
2177
'undefined, which should not happen. ' +
@@ -1935,12 +2181,16 @@ describe('ReactDOMInput', () => {
2181
);
2182
});
2183
1938
- it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', () => {
2184
+ it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', async () => {
2185
const stub = <input type="checkbox" />;
1940
- ReactDOM.render(stub, container);
1941
- expect(() =>
1942
- ReactDOM.render(<input type="checkbox" checked={true} />, container),
1943
- ).toErrorDev(
2186
+ await act(() => {
2187
+ root.render(stub);
2188
+ });
2189
+ await expect(async () => {
2190
+ await act(() => {
2191
+ root.render(<input type="checkbox" checked={true} />);
2192
+ });
2193
+ }).toErrorDev(
2194
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2195
'This is likely caused by the value changing from undefined to ' +
2196
'a defined value, which should not happen. ' +
@@ -1950,12 +2200,16 @@ describe('ReactDOMInput', () => {
2200
);
2201
});
2202
1953
- it('should warn if uncontrolled checkbox (checked is null) switches to controlled', () => {
2203
+ it('should warn if uncontrolled checkbox (checked is null) switches to controlled', async () => {
2204
const stub = <input type="checkbox" checked={null} />;
1955
- ReactDOM.render(stub, container);
1956
- expect(() =>
1957
- ReactDOM.render(<input type="checkbox" checked={true} />, container),
1958
- ).toErrorDev(
2205
+ await act(() => {
2206
+ root.render(stub);
2207
+ });
2208
+ await expect(async () => {
2209
+ await act(() => {
2210
+ root.render(<input type="checkbox" checked={true} />);
2211
+ });
2212
+ }).toErrorDev(
2213
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2214
'This is likely caused by the value changing from undefined to ' +
2215
'a defined value, which should not happen. ' +
@@ -1965,10 +2219,16 @@ describe('ReactDOMInput', () => {
2219
);
2220
});
2221
1968
- it('should warn if controlled radio switches to uncontrolled (checked is undefined)', () => {
2222
+ it('should warn if controlled radio switches to uncontrolled (checked is undefined)', async () => {
2223
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1970
- ReactDOM.render(stub, container);
1971
- expect(() => ReactDOM.render(<input type="radio" />, container)).toErrorDev(
2224
+ await act(() => {
2225
+ root.render(stub);
2226
+ });
2227
+ await expect(async () => {
2228
+ await act(() => {
2229
+ root.render(<input type="radio" />);
2230
+ });
2231
+ }).toErrorDev(
2232
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2233
'This is likely caused by the value changing from a defined to ' +
2234
'undefined, which should not happen. ' +
@@ -1978,12 +2238,16 @@ describe('ReactDOMInput', () => {
2238
);
2239
});
2240
1981
- it('should warn if controlled radio switches to uncontrolled (checked is null)', () => {
2241
+ it('should warn if controlled radio switches to uncontrolled (checked is null)', async () => {
2242
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1983
- ReactDOM.render(stub, container);
1984
- expect(() =>
1985
- ReactDOM.render(<input type="radio" checked={null} />, container),
1986
- ).toErrorDev(
2243
+ await act(() => {
2244
+ root.render(stub);
2245
+ });
2246
+ await expect(async () => {
2247
+ await act(() => {
2248
+ root.render(<input type="radio" checked={null} />);
2249
+ });
2250
+ }).toErrorDev(
2251
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2252
'This is likely caused by the value changing from a defined to ' +
2253
'undefined, which should not happen. ' +
@@ -1993,12 +2257,16 @@ describe('ReactDOMInput', () => {
2257
);
2258
});
2259
1996
- it('should warn if controlled radio switches to uncontrolled with defaultChecked', () => {
2260
+ it('should warn if controlled radio switches to uncontrolled with defaultChecked', async () => {
2261
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1998
- ReactDOM.render(stub, container);
1999
- expect(() =>
2000
- ReactDOM.render(<input type="radio" defaultChecked={true} />, container),
2001
- ).toErrorDev(
2262
+ await act(() => {
2263
+ root.render(stub);
2264
+ });
2265
+ await expect(async () => {
2266
+ await act(() => {
2267
+ root.render(<input type="radio" defaultChecked={true} />);
2268
+ });
2269
+ }).toErrorDev(
2270
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2271
'This is likely caused by the value changing from a defined to ' +
2272
'undefined, which should not happen. ' +
@@ -2008,12 +2276,16 @@ describe('ReactDOMInput', () => {
2276
);
2277
});
2278
2011
- it('should warn if uncontrolled radio (checked is undefined) switches to controlled', () => {
2279
+ it('should warn if uncontrolled radio (checked is undefined) switches to controlled', async () => {
2280
const stub = <input type="radio" />;
2013
- ReactDOM.render(stub, container);
2014
- expect(() =>
2015
- ReactDOM.render(<input type="radio" checked={true} />, container),
2016
- ).toErrorDev(
2281
+ await act(() => {
2282
+ root.render(stub);
2283
+ });
2284
+ await expect(async () => {
2285
+ await act(() => {
2286
+ root.render(<input type="radio" checked={true} />);
2287
+ });
2288
+ }).toErrorDev(
2289
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2290
'This is likely caused by the value changing from undefined to ' +
2291
'a defined value, which should not happen. ' +
@@ -2023,12 +2295,16 @@ describe('ReactDOMInput', () => {
2295
);
2296
});
2297
2026
- it('should warn if uncontrolled radio (checked is null) switches to controlled', () => {
2298
+ it('should warn if uncontrolled radio (checked is null) switches to controlled', async () => {
2299
const stub = <input type="radio" checked={null} />;
2028
- ReactDOM.render(stub, container);
2029
- expect(() =>
2030
- ReactDOM.render(<input type="radio" checked={true} />, container),
2031
- ).toErrorDev(
2300
+ await act(() => {
2301
+ root.render(stub);
2302
+ });
2303
+ await expect(async () => {
2304
+ await act(() => {
2305
+ root.render(<input type="radio" checked={true} />);
2306
+ });
2307
+ }).toErrorDev(
2308
'Warning: A component is changing an uncontrolled input to be controlled. ' +
2309
'This is likely caused by the value changing from undefined to ' +
2310
'a defined value, which should not happen. ' +
@@ -2038,54 +2314,61 @@ describe('ReactDOMInput', () => {
2314
);
2315
});
2316
2041
- it('should not warn if radio value changes but never becomes controlled', () => {
2042
- ReactDOM.render(<input type="radio" value="value" />, container);
2043
- ReactDOM.render(<input type="radio" />, container);
2044
- ReactDOM.render(
2045
- <input type="radio" value="value" defaultChecked={true} />,
2046
- container,
2047
- );
2048
- ReactDOM.render(
2049
- <input type="radio" value="value" onChange={() => null} />,
2050
- container,
2051
- );
2052
- ReactDOM.render(<input type="radio" />, container);
2317
+ it('should not warn if radio value changes but never becomes controlled', async () => {
2318
+ await act(() => {
2319
+ root.render(<input type="radio" value="value" />);
2320
+ });
2321
+ await act(() => {
2322
+ root.render(<input type="radio" />);
2323
+ });
2324
+ await act(() => {
2325
+ root.render(<input type="radio" value="value" defaultChecked={true} />);
2326
+ });
2327
+ await act(() => {
2328
+ root.render(<input type="radio" value="value" onChange={() => null} />);
2329
+ });
2330
+ await act(() => {
2331
+ root.render(<input type="radio" />);
2332
+ });
2333
});
2334
2055
- it('should not warn if radio value changes but never becomes uncontrolled', () => {
2056
- ReactDOM.render(
2057
- <input type="radio" checked={false} onChange={() => null} />,
2058
- container,
2059
- );
2335
+ it('should not warn if radio value changes but never becomes uncontrolled', async () => {
2336
+ await act(() => {
2337
+ root.render(<input type="radio" checked={false} onChange={() => null} />);
2338
+ });
2339
const input = container.querySelector('input');
2340
expect(isCheckedDirty(input)).toBe(true);
2062
- ReactDOM.render(
2063
- <input
2064
- type="radio"
2065
- value="value"
2066
- defaultChecked={true}
2067
- checked={false}
2068
- onChange={() => null}
2069
- />,
2070
- container,
2071
- );
2341
+ await act(() => {
2342
+ root.render(
2343
+ <input
2344
+ type="radio"
2345
+ value="value"
2346
+ defaultChecked={true}
2347
+ checked={false}
2348
+ onChange={() => null}
2349
+ />,
2350
+ );
2351
+ });
2352
expect(isCheckedDirty(input)).toBe(true);
2353
assertInputTrackingIsCurrent(container);
2354
});
2355
2076
- it('should warn if radio checked false changes to become uncontrolled', () => {
2077
- ReactDOM.render(
2078
- <input
2079
- type="radio"
2080
- value="value"
2081
- checked={false}
2082
- onChange={() => null}
2083
- />,
2084
- container,
2085
- );
2086
- expect(() =>
2087
- ReactDOM.render(<input type="radio" value="value" />, container),
2088
- ).toErrorDev(
2356
+ it('should warn if radio checked false changes to become uncontrolled', async () => {
2357
+ await act(() => {
2358
+ root.render(
2359
+ <input
2360
+ type="radio"
2361
+ value="value"
2362
+ checked={false}
2363
+ onChange={() => null}
2364
+ />,
2365
+ );
2366
+ });
2367
+ await expect(async () => {
2368
+ await act(() => {
2369
+ root.render(<input type="radio" value="value" />);
2370
+ });
2371
+ }).toErrorDev(
2372
'Warning: A component is changing a controlled input to be uncontrolled. ' +
2373
'This is likely caused by the value changing from a defined to ' +
2374
'undefined, which should not happen. ' +
@@ -2095,7 +2378,7 @@ describe('ReactDOMInput', () => {
2378
);
2379
});
2380
2098
- it('sets type, step, min, max before value always', () => {
2381
+ it('sets type, step, min, max before value always', async () => {
2382
const log = [];
2383
const originalCreateElement = document.createElement;
2384
spyOnDevAndProd(document, 'createElement').mockImplementation(
@@ -2133,17 +2416,18 @@ describe('ReactDOMInput', () => {
2416
},
2417
);
2418
2136
- ReactDOM.render(
2137
- <input
2138
- value="0"
2139
- onChange={() => {}}
2140
- type="range"
2141
- min="0"
2142
- max="100"
2143
- step="1"
2144
- />,
2145
- container,
2146
- );
2419
+ await act(() => {
2420
+ root.render(
2421
+ <input
2422
+ value="0"
2423
+ onChange={() => {}}
2424
+ type="range"
2425
+ min="0"
2426
+ max="100"
2427
+ step="1"
2428
+ />,
2429
+ );
2430
+ });
2431
2432
expect(log).toEqual([
2433
'set attribute min',
@@ -2154,12 +2438,14 @@ describe('ReactDOMInput', () => {
2438
]);
2439
});
2440
2157
- it('sets value properly with type coming later in props', () => {
2158
- const input = ReactDOM.render(<input value="hi" type="radio" />, container);
2159
- expect(input.value).toBe('hi');
2441
+ it('sets value properly with type coming later in props', async () => {
2442
+ await act(() => {
2443
+ root.render(<input value="hi" type="radio" />);
2444
+ });
2445
+ expect(container.firstChild.value).toBe('hi');
2446
});
2447
2162
- it('does not raise a validation warning when it switches types', () => {
2448
+ it('does not raise a validation warning when it switches types', async () => {
2449
class Input extends React.Component {
2450
state = {type: 'number', value: 1000};
2451
@@ -2169,16 +2455,21 @@ describe('ReactDOMInput', () => {
2455
}
2456
}
2457
2172
- const input = ReactDOM.render(<Input />, container);
2173
- const node = ReactDOM.findDOMNode(input);
2458
+ const ref = React.createRef();
2459
+ await act(() => {
2460
+ root.render(<Input ref={ref} />);
2461
+ });
2462
+ const node = container.firstChild;
2463
2464
// If the value is set before the type, a validation warning will raise and
2465
// the value will not be assigned.
2177
- input.setState({type: 'text', value: 'Test'});
2466
+ await act(() => {
2467
+ ref.current.setState({type: 'text', value: 'Test'});
2468
+ });
2469
expect(node.value).toEqual('Test');
2470
});
2471
2181
- it('resets value of date/time input to fix bugs in iOS Safari', () => {
2472
+ it('resets value of date/time input to fix bugs in iOS Safari', async () => {
2473
function strify(x) {
2474
return JSON.stringify(x, null, 2);
2475
}
@@ -2250,7 +2541,9 @@ describe('ReactDOMInput', () => {
2541
},
2542
);
2543
2253
- ReactDOM.render(<input type="date" defaultValue="1980-01-01" />, container);
2544
+ await act(() => {
2545
+ root.render(<input type="date" defaultValue="1980-01-01" />);
2546
+ });
2547
2548
if (disableInputAttributeSyncing) {
2549
expect(log).toEqual([
@@ -2289,14 +2582,18 @@ describe('ReactDOMInput', () => {
2582
};
2583
}
2584
2292
- it('always sets the attribute when values change on text inputs', function () {
2585
+ it('always sets the attribute when values change on text inputs', async () => {
2586
const Input = getTestInput();
2294
- const stub = ReactDOM.render(<Input type="text" />, container);
2295
- const node = ReactDOM.findDOMNode(stub);
2587
+ await act(() => {
2588
+ root.render(<Input type="text" />);
2589
+ });
2590
+ const node = container.firstChild;
2591
expect(isValueDirty(node)).toBe(false);
2592
2593
setUntrackedValue.call(node, '2');
2299
- dispatchEventOnNode(node, 'input');
2594
+ await act(() => {
2595
+ dispatchEventOnNode(node, 'input');
2596
+ });
2597
2598
expect(isValueDirty(node)).toBe(true);
2599
if (disableInputAttributeSyncing) {
@@ -2306,13 +2603,12 @@ describe('ReactDOMInput', () => {
2603
}
2604
});
2605
2309
- it('does not set the value attribute on number inputs if focused', () => {
2606
+ it('does not set the value attribute on number inputs if focused', async () => {
2607
const Input = getTestInput();
2311
- const stub = ReactDOM.render(
2312
- <Input type="number" value="1" />,
2313
- container,
2314
- );
2315
- const node = ReactDOM.findDOMNode(stub);
2608
+ await act(() => {
2609
+ root.render(<Input type="number" value="1" />);
2610
+ });
2611
+ const node = container.firstChild;
2612
expect(isValueDirty(node)).toBe(true);
2613
2614
node.focus();
@@ -2328,13 +2624,12 @@ describe('ReactDOMInput', () => {
2624
}
2625
});
2626
2331
- it('sets the value attribute on number inputs on blur', () => {
2627
+ it('sets the value attribute on number inputs on blur', async () => {
2628
const Input = getTestInput();
2333
- const stub = ReactDOM.render(
2334
- <Input type="number" value="1" />,
2335
- container,
2336
- );
2337
- const node = ReactDOM.findDOMNode(stub);
2629
+ await act(() => {
2630
+ root.render(<Input type="number" value="1" />);
2631
+ });
2632
+ const node = container.firstChild;
2633
expect(isValueDirty(node)).toBe(true);
2634
2635
node.focus();
@@ -2352,11 +2647,11 @@ describe('ReactDOMInput', () => {
2647
}
2648
});
2649
2355
- it('an uncontrolled number input will not update the value attribute on blur', () => {
2356
- const node = ReactDOM.render(
2357
- <input type="number" defaultValue="1" />,
2358
- container,
2359
- );
2650
+ it('an uncontrolled number input will not update the value attribute on blur', async () => {
2651
+ await act(() => {
2652
+ root.render(<input type="number" defaultValue="1" />);
2653
+ });
2654
+ const node = container.firstChild;
2655
if (disableInputAttributeSyncing) {
2656
expect(isValueDirty(node)).toBe(false);
2657
} else {
@@ -2372,11 +2667,11 @@ describe('ReactDOMInput', () => {
2667
expect(node.getAttribute('value')).toBe('1');
2668
});
2669
2375
- it('an uncontrolled text input will not update the value attribute on blur', () => {
2376
- const node = ReactDOM.render(
2377
- <input type="text" defaultValue="1" />,
2378
- container,
2379
- );
2670
+ it('an uncontrolled text input will not update the value attribute on blur', async () => {
2671
+ await act(() => {
2672
+ root.render(<input type="text" defaultValue="1" />);
2673
+ });
2674
+ const node = container.firstChild;
2675
if (disableInputAttributeSyncing) {
2676
expect(isValueDirty(node)).toBe(false);
2677
} else {
@@ -2396,7 +2691,7 @@ describe('ReactDOMInput', () => {
2691
describe('setting a controlled input to undefined', () => {
2692
let input;
2693
2399
- function renderInputWithStringThenWithUndefined() {
2694
+ async function renderInputWithStringThenWithUndefined() {
2695
let setValueToUndefined;
2696
class Input extends React.Component {
2697
constructor() {
@@ -2414,15 +2709,19 @@ describe('ReactDOMInput', () => {
2709
}
2710
}
2711
2417
- const stub = ReactDOM.render(<Input />, container);
2418
- input = ReactDOM.findDOMNode(stub);
2712
+ await act(() => {
2713
+ root.render(<Input />);
2714
+ });
2715
+ input = container.firstChild;
2716
setUntrackedValue.call(input, 'latest');
2717
dispatchEventOnNode(input, 'input');
2421
- setValueToUndefined();
2718
+ await act(() => {
2719
+ setValueToUndefined();
2720
+ });
2721
}
2722
2424
- it('reverts the value attribute to the initial value', () => {
2425
- expect(renderInputWithStringThenWithUndefined).toErrorDev(
2723
+ it('reverts the value attribute to the initial value', async () => {
2724
+ await expect(renderInputWithStringThenWithUndefined).toErrorDev(
2725
'A component is changing a controlled input to be uncontrolled.',
2726
);
2727
if (disableInputAttributeSyncing) {
@@ -2432,8 +2731,8 @@ describe('ReactDOMInput', () => {
2731
}
2732
});
2733
2435
- it('preserves the value property', () => {
2436
- expect(renderInputWithStringThenWithUndefined).toErrorDev(
2734
+ it('preserves the value property', async () => {
2735
+ await expect(renderInputWithStringThenWithUndefined).toErrorDev(
2736
'A component is changing a controlled input to be uncontrolled.',
2737
);
2738
expect(input.value).toBe('latest');
@@ -2443,7 +2742,7 @@ describe('ReactDOMInput', () => {
2742
describe('setting a controlled input to null', () => {
2743
let input;
2744
2446
- function renderInputWithStringThenWithNull() {
2745
+ async function renderInputWithStringThenWithNull() {
2746
let setValueToNull;
2747
class Input extends React.Component {
2748
constructor() {
@@ -2461,15 +2760,19 @@ describe('ReactDOMInput', () => {
2760
}
2761
}
2762
2464
- const stub = ReactDOM.render(<Input />, container);
2465
- input = ReactDOM.findDOMNode(stub);
2763
+ await act(() => {
2764
+ root.render(<Input />);
2765
+ });
2766
+ input = container.firstChild;
2767
setUntrackedValue.call(input, 'latest');
2768
dispatchEventOnNode(input, 'input');
2468
- setValueToNull();
2769
+ await act(() => {
2770
+ setValueToNull();
2771
+ });
2772
}
2773
2471
- it('reverts the value attribute to the initial value', () => {
2472
- expect(renderInputWithStringThenWithNull).toErrorDev([
2774
+ it('reverts the value attribute to the initial value', async () => {
2775
+ await expect(renderInputWithStringThenWithNull).toErrorDev([
2776
'`value` prop on `input` should not be null. ' +
2777
'Consider using an empty string to clear the component ' +
2778
'or `undefined` for uncontrolled components.',
@@ -2482,8 +2785,8 @@ describe('ReactDOMInput', () => {
2785
}
2786
});
2787
2485
- it('preserves the value property', () => {
2486
- expect(renderInputWithStringThenWithNull).toErrorDev([
2788
+ it('preserves the value property', async () => {
2789
+ await expect(renderInputWithStringThenWithNull).toErrorDev([
2790
'`value` prop on `input` should not be null. ' +
2791
'Consider using an empty string to clear the component ' +
2792
'or `undefined` for uncontrolled components.',
@@ -2494,13 +2797,12 @@ describe('ReactDOMInput', () => {
2797
});
2798
2799
describe('When given a Symbol value', function () {
2497
- it('treats initial Symbol value as an empty string', function () {
2498
- expect(() =>
2499
- ReactDOM.render(
2500
- <input value={Symbol('foobar')} onChange={() => {}} />,
2501
- container,
2502
- ),
2503
- ).toErrorDev('Invalid value for prop `value`');
2800
+ it('treats initial Symbol value as an empty string', async () => {
2801
+ await expect(async () => {
2802
+ await act(() => {
2803
+ root.render(<input value={Symbol('foobar')} onChange={() => {}} />);
2804
+ });
2805
+ }).toErrorDev('Invalid value for prop `value`');
2806
const node = container.firstChild;
2807
2808
expect(node.value).toBe('');
@@ -2511,14 +2813,15 @@ describe('ReactDOMInput', () => {
2813
}
2814
});
2815
2514
- it('treats updated Symbol value as an empty string', function () {
2515
- ReactDOM.render(<input value="foo" onChange={() => {}} />, container);
2516
- expect(() =>
2517
- ReactDOM.render(
2518
- <input value={Symbol('foobar')} onChange={() => {}} />,
2519
- container,
2520
- ),
2521
- ).toErrorDev('Invalid value for prop `value`');
2816
+ it('treats updated Symbol value as an empty string', async () => {
2817
+ await act(() => {
2818
+ root.render(<input value="foo" onChange={() => {}} />);
2819
+ });
2820
+ await expect(async () => {
2821
+ await act(() => {
2822
+ root.render(<input value={Symbol('foobar')} onChange={() => {}} />);
2823
+ });
2824
+ }).toErrorDev('Invalid value for prop `value`');
2825
const node = container.firstChild;
2826
2827
expect(node.value).toBe('');
@@ -2529,8 +2832,10 @@ describe('ReactDOMInput', () => {
2832
}
2833
});
2834
2532
- it('treats initial Symbol defaultValue as an empty string', function () {
2533
- ReactDOM.render(<input defaultValue={Symbol('foobar')} />, container);
2835
+ it('treats initial Symbol defaultValue as an empty string', async () => {
2836
+ await act(() => {
2837
+ root.render(<input defaultValue={Symbol('foobar')} />);
2838
+ });
2839
const node = container.firstChild;
2840
2841
expect(node.value).toBe('');
@@ -2538,9 +2843,13 @@ describe('ReactDOMInput', () => {
2843
// TODO: we should warn here.
2844
});
2845
2541
- it('treats updated Symbol defaultValue as an empty string', function () {
2542
- ReactDOM.render(<input defaultValue="foo" />, container);
2543
- ReactDOM.render(<input defaultValue={Symbol('foobar')} />, container);
2846
+ it('treats updated Symbol defaultValue as an empty string', async () => {
2847
+ await act(() => {
2848
+ root.render(<input defaultValue="foo" />);
2849
+ });
2850
+ await act(() => {
2851
+ root.render(<input defaultValue={Symbol('foobar')} />);
2852
+ });
2853
const node = container.firstChild;
2854
2855
if (disableInputAttributeSyncing) {
@@ -2554,13 +2863,12 @@ describe('ReactDOMInput', () => {
2863
});
2864
2865
describe('When given a function value', function () {
2557
- it('treats initial function value as an empty string', function () {
2558
- expect(() =>
2559
- ReactDOM.render(
2560
- <input value={() => {}} onChange={() => {}} />,
2561
- container,
2562
- ),
2563
- ).toErrorDev('Invalid value for prop `value`');
2866
+ it('treats initial function value as an empty string', async () => {
2867
+ await expect(async () => {
2868
+ await act(() => {
2869
+ root.render(<input value={() => {}} onChange={() => {}} />);
2870
+ });
2871
+ }).toErrorDev('Invalid value for prop `value`');
2872
const node = container.firstChild;
2873
2874
expect(node.value).toBe('');
@@ -2571,14 +2879,15 @@ describe('ReactDOMInput', () => {
2879
}
2880
});
2881
2574
- it('treats updated function value as an empty string', function () {
2575
- ReactDOM.render(<input value="foo" onChange={() => {}} />, container);
2576
- expect(() =>
2577
- ReactDOM.render(
2578
- <input value={() => {}} onChange={() => {}} />,
2579
- container,
2580
- ),
2581
- ).toErrorDev('Invalid value for prop `value`');
2882
+ it('treats updated function value as an empty string', async () => {
2883
+ await act(() => {
2884
+ root.render(<input value="foo" onChange={() => {}} />);
2885
+ });
2886
+ await expect(async () => {
2887
+ await act(() => {
2888
+ root.render(<input value={() => {}} onChange={() => {}} />);
2889
+ });
2890
+ }).toErrorDev('Invalid value for prop `value`');
2891
const node = container.firstChild;
2892
2893
expect(node.value).toBe('');
@@ -2589,8 +2898,10 @@ describe('ReactDOMInput', () => {
2898
}
2899
});
2900
2592
- it('treats initial function defaultValue as an empty string', function () {
2593
- ReactDOM.render(<input defaultValue={() => {}} />, container);
2901
+ it('treats initial function defaultValue as an empty string', async () => {
2902
+ await act(() => {
2903
+ root.render(<input defaultValue={() => {}} />);
2904
+ });
2905
const node = container.firstChild;
2906
2907
expect(node.value).toBe('');
@@ -2598,9 +2909,13 @@ describe('ReactDOMInput', () => {
2909
// TODO: we should warn here.
2910
});
2911
2601
- it('treats updated function defaultValue as an empty string', function () {
2602
- ReactDOM.render(<input defaultValue="foo" />, container);
2603
- ReactDOM.render(<input defaultValue={() => {}} />, container);
2912
+ it('treats updated function defaultValue as an empty string', async () => {
2913
+ await act(() => {
2914
+ root.render(<input defaultValue="foo" />);
2915
+ });
2916
+ await act(() => {
2917
+ root.render(<input defaultValue={() => {}} />);
2918
+ });
2919
const node = container.firstChild;
2920
2921
if (disableInputAttributeSyncing) {
@@ -2619,19 +2934,20 @@ describe('ReactDOMInput', () => {
2934
// Between 16 and 16.2, we assigned a node's value to it's current
2935
// value in order to "dettach" it from defaultValue. This had the unfortunate
2936
// side-effect of assigning value="on" to radio and checkboxes
2622
- it('does not add "on" in absence of value on a checkbox', function () {
2623
- ReactDOM.render(
2624
- <input type="checkbox" defaultChecked={true} />,
2625
- container,
2626
- );
2937
+ it('does not add "on" in absence of value on a checkbox', async () => {
2938
+ await act(() => {
2939
+ root.render(<input type="checkbox" defaultChecked={true} />);
2940
+ });
2941
const node = container.firstChild;
2942
2943
expect(node.value).toBe('on');
2944
expect(node.hasAttribute('value')).toBe(false);
2945
});
2946
2633
- it('does not add "on" in absence of value on a radio', function () {
2634
- ReactDOM.render(<input type="radio" defaultChecked={true} />, container);
2947
+ it('does not add "on" in absence of value on a radio', async () => {
2948
+ await act(() => {
2949
+ root.render(<input type="radio" defaultChecked={true} />);
2950
+ });
2951
const node = container.firstChild;
2952
2953
expect(node.value).toBe('on');
@@ -2639,45 +2955,47 @@ describe('ReactDOMInput', () => {
2955
});
2956
});
2957
2642
- it('should remove previous `defaultValue`', () => {
2643
- const node = ReactDOM.render(
2644
- <input type="text" defaultValue="0" />,
2645
- container,
2646
- );
2958
+ it('should remove previous `defaultValue`', async () => {
2959
+ await act(() => {
2960
+ root.render(<input type="text" defaultValue="0" />);
2961
+ });
2962
+ const node = container.firstChild;
2963
2964
expect(node.value).toBe('0');
2965
expect(node.defaultValue).toBe('0');
2966
2651
- ReactDOM.render(<input type="text" />, container);
2967
+ await act(() => {
2968
+ root.render(<input type="text" />);
2969
+ });
2970
expect(node.defaultValue).toBe('');
2971
});
2972
2655
- it('should treat `defaultValue={null}` as missing', () => {
2656
- const node = ReactDOM.render(
2657
- <input type="text" defaultValue="0" />,
2658
- container,
2659
- );
2973
+ it('should treat `defaultValue={null}` as missing', async () => {
2974
+ await act(() => {
2975
+ root.render(<input type="text" defaultValue="0" />);
2976
+ });
2977
+ const node = container.firstChild;
2978
2979
expect(node.value).toBe('0');
2980
expect(node.defaultValue).toBe('0');
2981
2664
- ReactDOM.render(<input type="text" defaultValue={null} />, container);
2982
+ await act(() => {
2983
+ root.render(<input type="text" defaultValue={null} />);
2984
+ });
2985
expect(node.defaultValue).toBe('');
2986
});
2987
2668
- it('should notice input changes when reverting back to original value', () => {
2988
+ it('should notice input changes when reverting back to original value', async () => {
2989
const log = [];
2990
function onChange(e) {
2991
log.push(e.target.value);
2992
}
2673
- ReactDOM.render(
2674
- <input type="text" value="" onChange={onChange} />,
2675
- container,
2676
- );
2677
- ReactDOM.render(
2678
- <input type="text" value="a" onChange={onChange} />,
2679
- container,
2680
- );
2993
+ await act(() => {
2994
+ root.render(<input type="text" value="" onChange={onChange} />);
2995
+ });
2996
+ await act(() => {
2997
+ root.render(<input type="text" value="a" onChange={onChange} />);
2998
+ });
2999
3000
const node = container.firstChild;
3001
setUntrackedValue.call(node, '');