@samitouri / QOS-React / commits / 1c8901f750

Convert ReactDOMSelect to createRoot (#28142)

Sebastian Silbermann committed Jan 29, 2024 at 09:10 UTC 1c8901f750fe09396de311e9c9e1e337599b2e9c
1 file changed +932 -582
packages/react-dom/src/__tests__/ReactDOMSelect-test.js
+932 -582
@@ -19,8 +19,9 @@ Element.prototype.setAttribute = function (name, value) {
19 describe('ReactDOMSelect', () => {
20 let React;
21 let ReactDOM;
22 + let ReactDOMClient;
23 let ReactDOMServer;
23 - let ReactTestUtils;
24 + let act;
25
26 const noop = function () {};
27
@@ -28,11 +29,12 @@ describe('ReactDOMSelect', () => {
29 jest.resetModules();
30 React = require('react');
31 ReactDOM = require('react-dom');
32 + ReactDOMClient = require('react-dom/client');
33 ReactDOMServer = require('react-dom/server');
32 - ReactTestUtils = require('react-dom/test-utils');
34 + act = require('internal-test-utils').act;
35 });
36
35 - it('should allow setting `defaultValue`', () => {
37 + it('should allow setting `defaultValue`', async () => {
38 const stub = (
39 <select defaultValue="giraffe">
40 <option value="monkey">A monkey!</option>
@@ -42,27 +44,36 @@ describe('ReactDOMSelect', () => {
44 );
45 const options = stub.props.children;
46 const container = document.createElement('div');
45 - const node = ReactDOM.render(stub, container);
47 + const root = ReactDOMClient.createRoot(container);
48 + await act(() => {
49 + root.render(stub);
50 + });
51 +
52 + const node = container.firstChild;
53
54 expect(node.value).toBe('giraffe');
55
49 - // Changing `defaultValue` should do nothing.
50 - ReactDOM.render(
51 - <select defaultValue="gorilla">{options}</select>,
52 - container,
53 - );
56 + await act(() => {
57 + root.render(<select defaultValue="gorilla">{options}</select>);
58 + });
59 +
60 expect(node.value).toEqual('giraffe');
61 });
62
63 it('should not throw with `defaultValue` and without children', () => {
64 const stub = <select defaultValue="dummy" />;
65
60 - expect(() => {
61 - ReactTestUtils.renderIntoDocument(stub);
66 + expect(async () => {
67 + const container = document.createElement('div');
68 + const root = ReactDOMClient.createRoot(container);
69 +
70 + await act(() => {
71 + root.render(stub);
72 + });
73 }).not.toThrow();
74 });
75
65 - it('should not control when using `defaultValue`', () => {
76 + it('should not control when using `defaultValue`', async () => {
77 const el = (
78 <select defaultValue="giraffe">
79 <option value="monkey">A monkey!</option>
@@ -71,17 +82,26 @@ describe('ReactDOMSelect', () => {
82 </select>
83 );
84 const container = document.createElement('div');
74 - const node = ReactDOM.render(el, container);
85 + const root = ReactDOMClient.createRoot(container);
86 +
87 + await act(() => {
88 + root.render(el);
89 + });
90 +
91 + const node = container.firstChild;
92
93 expect(node.value).toBe('giraffe');
94
95 node.value = 'monkey';
79 - ReactDOM.render(el, container);
96 + await act(() => {
97 + root.render(el);
98 + });
99 +
100 // Uncontrolled selects shouldn't change the value after first mounting
101 expect(node.value).toEqual('monkey');
102 });
103
84 - it('should allow setting `defaultValue` with multiple', () => {
104 + it('should allow setting `defaultValue` with multiple', async () => {
105 const stub = (
106 <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
107 <option value="monkey">A monkey!</option>
@@ -91,26 +111,32 @@ describe('ReactDOMSelect', () => {
111 );
112 const options = stub.props.children;
113 const container = document.createElement('div');
94 - const node = ReactDOM.render(stub, container);
114 + const root = ReactDOMClient.createRoot(container);
115 +
116 + await act(() => {
117 + root.render(stub);
118 + });
119 +
120 + const node = container.firstChild;
121
122 expect(node.options[0].selected).toBe(false); // monkey
123 expect(node.options[1].selected).toBe(true); // giraffe
124 expect(node.options[2].selected).toBe(true); // gorilla
125
100 - // Changing `defaultValue` should do nothing.
101 - ReactDOM.render(
102 - <select multiple={true} defaultValue={['monkey']}>
103 - {options}
104 - </select>,
105 - container,
106 - );
126 + await act(() => {
127 + root.render(
128 + <select multiple={true} defaultValue={['monkey']}>
129 + {options}
130 + </select>,
131 + );
132 + });
133
134 expect(node.options[0].selected).toBe(false); // monkey
135 expect(node.options[1].selected).toBe(true); // giraffe
136 expect(node.options[2].selected).toBe(true); // gorilla
137 });
138
113 - it('should allow setting `value`', () => {
139 + it('should allow setting `value`', async () => {
140 const stub = (
141 <select value="giraffe" onChange={noop}>
142 <option value="monkey">A monkey!</option>
@@ -120,21 +146,28 @@ describe('ReactDOMSelect', () => {
146 );
147 const options = stub.props.children;
148 const container = document.createElement('div');
123 - const node = ReactDOM.render(stub, container);
149 + const root = ReactDOMClient.createRoot(container);
150 +
151 + await act(() => {
152 + root.render(stub);
153 + });
154 +
155 + const node = container.firstChild;
156
157 expect(node.value).toBe('giraffe');
158
127 - // Changing the `value` prop should change the selected option.
128 - ReactDOM.render(
129 - <select value="gorilla" onChange={noop}>
130 - {options}
131 - </select>,
132 - container,
133 - );
159 + await act(() => {
160 + root.render(
161 + <select value="gorilla" onChange={noop}>
162 + {options}
163 + </select>,
164 + );
165 + });
166 +
167 expect(node.value).toEqual('gorilla');
168 });
169
137 - it('should default to the first non-disabled option', () => {
170 + it('should default to the first non-disabled option', async () => {
171 const stub = (
172 <select defaultValue="">
173 <option disabled={true}>Disabled</option>
@@ -144,12 +177,18 @@ describe('ReactDOMSelect', () => {
177 </select>
178 );
179 const container = document.createElement('div');
147 - const node = ReactDOM.render(stub, container);
180 + const root = ReactDOMClient.createRoot(container);
181 +
182 + await act(() => {
183 + root.render(stub);
184 + });
185 +
186 + const node = container.firstChild;
187 expect(node.options[0].selected).toBe(false);
188 expect(node.options[2].selected).toBe(true);
189 });
190
152 - it('should allow setting `value` to __proto__', () => {
191 + it('should allow setting `value` to __proto__', async () => {
192 const stub = (
193 <select value="__proto__" onChange={noop}>
194 <option value="monkey">A monkey!</option>
@@ -159,29 +198,40 @@ describe('ReactDOMSelect', () => {
198 );
199 const options = stub.props.children;
200 const container = document.createElement('div');
162 - const node = ReactDOM.render(stub, container);
201 + const root = ReactDOMClient.createRoot(container);
202 + await act(() => {
203 + root.render(stub);
204 + });
205 +
206 + const node = container.firstChild;
207
208 expect(node.value).toBe('__proto__');
209
166 - // Changing the `value` prop should change the selected option.
167 - ReactDOM.render(
168 - <select value="gorilla" onChange={noop}>
169 - {options}
170 - </select>,
171 - container,
172 - );
210 + await act(() => {
211 + root.render(
212 + <select value="gorilla" onChange={noop}>
213 + {options}
214 + </select>,
215 + );
216 + });
217 +
218 expect(node.value).toEqual('gorilla');
219 });
220
221 it('should not throw with `value` and without children', () => {
222 const stub = <select value="dummy" onChange={noop} />;
223
179 - expect(() => {
180 - ReactTestUtils.renderIntoDocument(stub);
224 + expect(async () => {
225 + const container = document.createElement('div');
226 + const root = ReactDOMClient.createRoot(container);
227 +
228 + await act(() => {
229 + root.render(stub);
230 + });
231 }).not.toThrow();
232 });
233
184 - it('should allow setting `value` with multiple', () => {
234 + it('should allow setting `value` with multiple', async () => {
235 const stub = (
236 <select multiple={true} value={['giraffe', 'gorilla']} onChange={noop}>
237 <option value="monkey">A monkey!</option>
@@ -191,26 +241,32 @@ describe('ReactDOMSelect', () => {
241 );
242 const options = stub.props.children;
243 const container = document.createElement('div');
194 - const node = ReactDOM.render(stub, container);
244 + const root = ReactDOMClient.createRoot(container);
245 +
246 + await act(() => {
247 + root.render(stub);
248 + });
249 +
250 + const node = container.firstChild;
251
252 expect(node.options[0].selected).toBe(false); // monkey
253 expect(node.options[1].selected).toBe(true); // giraffe
254 expect(node.options[2].selected).toBe(true); // gorilla
255
200 - // Changing the `value` prop should change the selected options.
201 - ReactDOM.render(
202 - <select multiple={true} value={['monkey']} onChange={noop}>
203 - {options}
204 - </select>,
205 - container,
206 - );
256 + await act(() => {
257 + root.render(
258 + <select multiple={true} value={['monkey']} onChange={noop}>
259 + {options}
260 + </select>,
261 + );
262 + });
263
264 expect(node.options[0].selected).toBe(true); // monkey
265 expect(node.options[1].selected).toBe(false); // giraffe
266 expect(node.options[2].selected).toBe(false); // gorilla
267 });
268
213 - it('should allow setting `value` to __proto__ with multiple', () => {
269 + it('should allow setting `value` to __proto__ with multiple', async () => {
270 const stub = (
271 <select multiple={true} value={['__proto__', 'gorilla']} onChange={noop}>
272 <option value="monkey">A monkey!</option>
@@ -220,26 +276,31 @@ describe('ReactDOMSelect', () => {
276 );
277 const options = stub.props.children;
278 const container = document.createElement('div');
223 - const node = ReactDOM.render(stub, container);
279 + const root = ReactDOMClient.createRoot(container);
280 + await act(() => {
281 + root.render(stub);
282 + });
283 +
284 + const node = container.firstChild;
285
286 expect(node.options[0].selected).toBe(false); // monkey
287 expect(node.options[1].selected).toBe(true); // __proto__
288 expect(node.options[2].selected).toBe(true); // gorilla
289
229 - // Changing the `value` prop should change the selected options.
230 - ReactDOM.render(
231 - <select multiple={true} value={['monkey']} onChange={noop}>
232 - {options}
233 - </select>,
234 - container,
235 - );
290 + await act(() => {
291 + root.render(
292 + <select multiple={true} value={['monkey']} onChange={noop}>
293 + {options}
294 + </select>,
295 + );
296 + });
297
298 expect(node.options[0].selected).toBe(true); // monkey
299 expect(node.options[1].selected).toBe(false); // __proto__
300 expect(node.options[2].selected).toBe(false); // gorilla
301 });
302
242 - it('should not select other options automatically', () => {
303 + it('should not select other options automatically', async () => {
304 const stub = (
305 <select multiple={true} value={['12']} onChange={noop}>
306 <option value="1">one</option>
@@ -247,33 +308,46 @@ describe('ReactDOMSelect', () => {
308 <option value="12">twelve</option>
309 </select>
310 );
250 - const node = ReactTestUtils.renderIntoDocument(stub);
311 + const container = document.createElement('div');
312 + const root = ReactDOMClient.createRoot(container);
313 +
314 + await act(() => {
315 + root.render(stub);
316 + });
317 +
318 + const node = container.firstChild;
319
320 expect(node.options[0].selected).toBe(false); // one
321 expect(node.options[1].selected).toBe(false); // two
322 expect(node.options[2].selected).toBe(true); // twelve
323 });
324
257 - it('should reset child options selected when they are changed and `value` is set', () => {
325 + it('should reset child options selected when they are changed and `value` is set', async () => {
326 const stub = <select multiple={true} value={['a', 'b']} onChange={noop} />;
327 const container = document.createElement('div');
260 - const node = ReactDOM.render(stub, container);
328 + const root = ReactDOMClient.createRoot(container);
329 + await act(() => {
330 + root.render(stub);
331 + });
332
262 - ReactDOM.render(
263 - <select multiple={true} value={['a', 'b']} onChange={noop}>
264 - <option value="a">a</option>
265 - <option value="b">b</option>
266 - <option value="c">c</option>
267 - </select>,
268 - container,
269 - );
333 + const node = container.firstChild;
334 +
335 + await act(() => {
336 + root.render(
337 + <select multiple={true} value={['a', 'b']} onChange={noop}>
338 + <option value="a">a</option>
339 + <option value="b">b</option>
340 + <option value="c">c</option>
341 + </select>,
342 + );
343 + });
344
345 expect(node.options[0].selected).toBe(true); // a
346 expect(node.options[1].selected).toBe(true); // b
347 expect(node.options[2].selected).toBe(false); // c
348 });
349
276 - it('should allow setting `value` with `objectToString`', () => {
350 + it('should allow setting `value` with `objectToString`', async () => {
351 const objectToString = {
352 animal: 'giraffe',
353 toString: function () {
@@ -289,7 +363,12 @@ describe('ReactDOMSelect', () => {
363 </select>
364 );
365 const container = document.createElement('div');
292 - const node = ReactDOM.render(el, container);
366 + const root = ReactDOMClient.createRoot(container);
367 + await act(() => {
368 + root.render(el);
369 + });
370 +
371 + const node = container.firstChild;
372
373 expect(node.options[0].selected).toBe(false); // monkey
374 expect(node.options[1].selected).toBe(true); // giraffe
@@ -305,14 +384,17 @@ describe('ReactDOMSelect', () => {
384 <option value="gorilla">A gorilla!</option>
385 </select>
386 );
308 - ReactDOM.render(el2, container);
387 +
388 + await act(() => {
389 + root.render(el2);
390 + });
391
392 expect(node.options[0].selected).toBe(true); // monkey
393 expect(node.options[1].selected).toBe(false); // giraffe
394 expect(node.options[2].selected).toBe(false); // gorilla
395 });
396
315 - it('should allow switching to multiple', () => {
397 + it('should allow switching to multiple', async () => {
398 const stub = (
399 <select defaultValue="giraffe">
400 <option value="monkey">A monkey!</option>
@@ -322,26 +404,31 @@ describe('ReactDOMSelect', () => {
404 );
405 const options = stub.props.children;
406 const container = document.createElement('div');
325 - const node = ReactDOM.render(stub, container);
407 + const root = ReactDOMClient.createRoot(container);
408 + await act(() => {
409 + root.render(stub);
410 + });
411 +
412 + const node = container.firstChild;
413
414 expect(node.options[0].selected).toBe(false); // monkey
415 expect(node.options[1].selected).toBe(true); // giraffe
416 expect(node.options[2].selected).toBe(false); // gorilla
417
331 - // When making it multiple, giraffe and gorilla should be selected
332 - ReactDOM.render(
333 - <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
334 - {options}
335 - </select>,
336 - container,
337 - );
418 + await act(() => {
419 + root.render(
420 + <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
421 + {options}
422 + </select>,
423 + );
424 + });
425
426 expect(node.options[0].selected).toBe(false); // monkey
427 expect(node.options[1].selected).toBe(true); // giraffe
428 expect(node.options[2].selected).toBe(true); // gorilla
429 });
430
344 - it('should allow switching from multiple', () => {
431 + it('should allow switching from multiple', async () => {
432 const stub = (
433 <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
434 <option value="monkey">A monkey!</option>
@@ -351,25 +438,27 @@ describe('ReactDOMSelect', () => {
438 );
439 const options = stub.props.children;
440 const container = document.createElement('div');
354 - const node = ReactDOM.render(stub, container);
441 + const root = ReactDOMClient.createRoot(container);
442 + await act(() => {
443 + root.render(stub);
444 + });
445 +
446 + const node = container.firstChild;
447
448 expect(node.options[0].selected).toBe(false); // monkey
449 expect(node.options[1].selected).toBe(true); // giraffe
450 expect(node.options[2].selected).toBe(true); // gorilla
451
360 - // When removing multiple, defaultValue is applied again, being omitted
361 - // means that "monkey" will be selected
362 - ReactDOM.render(
363 - <select defaultValue="gorilla">{options}</select>,
364 - container,
365 - );
452 + await act(() => {
453 + root.render(<select defaultValue="gorilla">{options}</select>);
454 + });
455
456 expect(node.options[0].selected).toBe(false); // monkey
457 expect(node.options[1].selected).toBe(false); // giraffe
458 expect(node.options[2].selected).toBe(true); // gorilla
459 });
460
372 - it('does not select an item when size is initially set to greater than 1', () => {
461 + it('does not select an item when size is initially set to greater than 1', async () => {
462 const stub = (
463 <select size="2">
464 <option value="monkey">A monkey!</option>
@@ -378,7 +467,13 @@ describe('ReactDOMSelect', () => {
467 </select>
468 );
469 const container = document.createElement('div');
381 - const select = ReactDOM.render(stub, container);
470 + const root = ReactDOMClient.createRoot(container);
471 +
472 + await act(() => {
473 + root.render(stub);
474 + });
475 +
476 + const select = container.firstChild;
477
478 expect(select.options[0].selected).toBe(false);
479 expect(select.options[1].selected).toBe(false);
@@ -388,7 +483,7 @@ describe('ReactDOMSelect', () => {
483 expect(select.selectedIndex).toBe(-1);
484 });
485
391 - it('should remember value when switching to uncontrolled', () => {
486 + it('should remember value when switching to uncontrolled', async () => {
487 const stub = (
488 <select value={'giraffe'} onChange={noop}>
489 <option value="monkey">A monkey!</option>
@@ -398,20 +493,27 @@ describe('ReactDOMSelect', () => {
493 );
494 const options = stub.props.children;
495 const container = document.createElement('div');
401 - const node = ReactDOM.render(stub, container);
496 + const root = ReactDOMClient.createRoot(container);
497 + await act(() => {
498 + root.render(stub);
499 + });
500 +
501 + const node = container.firstChild;
502
503 expect(node.options[0].selected).toBe(false); // monkey
504 expect(node.options[1].selected).toBe(true); // giraffe
505 expect(node.options[2].selected).toBe(false); // gorilla
506
407 - ReactDOM.render(<select>{options}</select>, container);
507 + await act(() => {
508 + root.render(<select>{options}</select>);
509 + });
510
511 expect(node.options[0].selected).toBe(false); // monkey
512 expect(node.options[1].selected).toBe(true); // giraffe
513 expect(node.options[2].selected).toBe(false); // gorilla
514 });
515
414 - it('should remember updated value when switching to uncontrolled', () => {
516 + it('should remember updated value when switching to uncontrolled', async () => {
517 const stub = (
518 <select value={'giraffe'} onChange={noop}>
519 <option value="monkey">A monkey!</option>
@@ -421,20 +523,27 @@ describe('ReactDOMSelect', () => {
523 );
524 const options = stub.props.children;
525 const container = document.createElement('div');
424 - const node = ReactDOM.render(stub, container);
526 + const root = ReactDOMClient.createRoot(container);
527 + await act(() => {
528 + root.render(stub);
529 + });
530
426 - ReactDOM.render(
427 - <select value="gorilla" onChange={noop}>
428 - {options}
429 - </select>,
430 - container,
431 - );
531 + const node = container.firstChild;
532 + await act(() => {
533 + root.render(
534 + <select value="gorilla" onChange={noop}>
535 + {options}
536 + </select>,
537 + );
538 + });
539
540 expect(node.options[0].selected).toBe(false); // monkey
541 expect(node.options[1].selected).toBe(false); // giraffe
542 expect(node.options[2].selected).toBe(true); // gorilla
543
437 - ReactDOM.render(<select>{options}</select>, container);
544 + await act(() => {
545 + root.render(<select>{options}</select>);
546 + });
547
548 expect(node.options[0].selected).toBe(false); // monkey
549 expect(node.options[1].selected).toBe(false); // giraffe
@@ -534,64 +643,71 @@ describe('ReactDOMSelect', () => {
643 expect(options[2].selected).toBe(true);
644 });
645
537 - it('should not control defaultValue if re-adding options', () => {
646 + it('should not control defaultValue if re-adding options', async () => {
647 const container = document.createElement('div');
648
540 - const node = ReactDOM.render(
541 - <select multiple={true} defaultValue={['giraffe']}>
542 - <option key="monkey" value="monkey">
543 - A monkey!
544 - </option>
545 - <option key="giraffe" value="giraffe">
546 - A giraffe!
547 - </option>
548 - <option key="gorilla" value="gorilla">
549 - A gorilla!
550 - </option>
551 - </select>,
552 - container,
553 - );
649 + const root = ReactDOMClient.createRoot(container);
650 +
651 + await act(() => {
652 + root.render(
653 + <select multiple={true} defaultValue={['giraffe']}>
654 + <option key="monkey" value="monkey">
655 + A monkey!
656 + </option>
657 + <option key="giraffe" value="giraffe">
658 + A giraffe!
659 + </option>
660 + <option key="gorilla" value="gorilla">
661 + A gorilla!
662 + </option>
663 + </select>,
664 + );
665 + });
666 +
667 + const node = container.firstChild;
668
669 expect(node.options[0].selected).toBe(false); // monkey
670 expect(node.options[1].selected).toBe(true); // giraffe
671 expect(node.options[2].selected).toBe(false); // gorilla
672
559 - ReactDOM.render(
560 - <select multiple={true} defaultValue={['giraffe']}>
561 - <option key="monkey" value="monkey">
562 - A monkey!
563 - </option>
564 - <option key="gorilla" value="gorilla">
565 - A gorilla!
566 - </option>
567 - </select>,
568 - container,
569 - );
673 + await act(() => {
674 + root.render(
675 + <select multiple={true} defaultValue={['giraffe']}>
676 + <option key="monkey" value="monkey">
677 + A monkey!
678 + </option>
679 + <option key="gorilla" value="gorilla">
680 + A gorilla!
681 + </option>
682 + </select>,
683 + );
684 + });
685
686 expect(node.options[0].selected).toBe(false); // monkey
687 expect(node.options[1].selected).toBe(false); // gorilla
688
574 - ReactDOM.render(
575 - <select multiple={true} defaultValue={['giraffe']}>
576 - <option key="monkey" value="monkey">
577 - A monkey!
578 - </option>
579 - <option key="giraffe" value="giraffe">
580 - A giraffe!
581 - </option>
582 - <option key="gorilla" value="gorilla">
583 - A gorilla!
584 - </option>
585 - </select>,
586 - container,
587 - );
689 + await act(() => {
690 + root.render(
691 + <select multiple={true} defaultValue={['giraffe']}>
692 + <option key="monkey" value="monkey">
693 + A monkey!
694 + </option>
695 + <option key="giraffe" value="giraffe">
696 + A giraffe!
697 + </option>
698 + <option key="gorilla" value="gorilla">
699 + A gorilla!
700 + </option>
701 + </select>,
702 + );
703 + });
704
705 expect(node.options[0].selected).toBe(false); // monkey
706 expect(node.options[1].selected).toBe(false); // giraffe
707 expect(node.options[2].selected).toBe(false); // gorilla
708 });
709
594 - it('should support options with dynamic children', () => {
710 + it('should support options with dynamic children', async () => {
711 const container = document.createElement('div');
712
713 let node;
@@ -612,38 +728,51 @@ describe('ReactDOMSelect', () => {
728 );
729 }
730
615 - ReactDOM.render(<App value="monkey" />, container);
731 + const root = ReactDOMClient.createRoot(container);
732 + await act(() => {
733 + root.render(<App value="monkey" />);
734 + });
735 +
736 expect(node.options[0].selected).toBe(true); // monkey
737 expect(node.options[1].selected).toBe(false); // giraffe
738 expect(node.options[2].selected).toBe(false); // gorilla
739
620 - ReactDOM.render(<App value="giraffe" />, container);
740 + await act(() => {
741 + root.render(<App value="giraffe" />);
742 + });
743 +
744 expect(node.options[0].selected).toBe(false); // monkey
745 expect(node.options[1].selected).toBe(true); // giraffe
746 expect(node.options[2].selected).toBe(false); // gorilla
747 });
748
626 - it('should warn if value is null', () => {
627 - expect(() =>
628 - ReactTestUtils.renderIntoDocument(
629 - <select value={null}>
630 - <option value="test" />
631 - </select>,
632 - ),
633 - ).toErrorDev(
749 + it('should warn if value is null', async () => {
750 + const container = document.createElement('div');
751 + const root = ReactDOMClient.createRoot(container);
752 + await expect(async () => {
753 + await act(() => {
754 + root.render(
755 + <select value={null}>
756 + <option value="test" />
757 + </select>,
758 + );
759 + });
760 + }).toErrorDev(
761 '`value` prop on `select` should not be null. ' +
762 'Consider using an empty string to clear the component or `undefined` ' +
763 'for uncontrolled components.',
764 );
765
639 - ReactTestUtils.renderIntoDocument(
640 - <select value={null}>
641 - <option value="test" />
642 - </select>,
643 - );
766 + await act(() => {
767 + root.render(
768 + <select value={null}>
769 + <option value="test" />
770 + </select>,
771 + );
772 + });
773 });
774
646 - it('should warn if selected is set on <option>', () => {
775 + it('should warn if selected is set on <option>', async () => {
776 function App() {
777 return (
778 <select>
@@ -653,36 +782,50 @@ describe('ReactDOMSelect', () => {
782 );
783 }
784
656 - expect(() => ReactTestUtils.renderIntoDocument(<App />)).toErrorDev(
785 + const container = document.createElement('div');
786 + const root = ReactDOMClient.createRoot(container);
787 + await expect(async () => {
788 + await act(() => {
789 + root.render(<App />);
790 + });
791 + }).toErrorDev(
792 'Use the `defaultValue` or `value` props on <select> instead of ' +
793 'setting `selected` on <option>.',
794 );
795
661 - ReactTestUtils.renderIntoDocument(<App />);
796 + await act(() => {
797 + root.render(<App />);
798 + });
799 });
800
664 - it('should warn if value is null and multiple is true', () => {
665 - expect(() =>
666 - ReactTestUtils.renderIntoDocument(
667 - <select value={null} multiple={true}>
668 - <option value="test" />
669 - </select>,
670 - ),
671 - ).toErrorDev(
801 + it('should warn if value is null and multiple is true', async () => {
802 + const container = document.createElement('div');
803 + const root = ReactDOMClient.createRoot(container);
804 + await expect(async () => {
805 + await act(() => {
806 + root.render(
807 + <select value={null} multiple={true}>
808 + <option value="test" />
809 + </select>,
810 + );
811 + });
812 + }).toErrorDev(
813 '`value` prop on `select` should not be null. ' +
814 'Consider using an empty array when `multiple` is ' +
815 'set to `true` to clear the component or `undefined` ' +
816 'for uncontrolled components.',
817 );
818
678 - ReactTestUtils.renderIntoDocument(
679 - <select value={null} multiple={true}>
680 - <option value="test" />
681 - </select>,
682 - );
819 + await act(() => {
820 + root.render(
821 + <select value={null} multiple={true}>
822 + <option value="test" />
823 + </select>,
824 + );
825 + });
826 });
827
685 - it('should refresh state on change', () => {
828 + it('should refresh state on change', async () => {
829 const stub = (
830 <select value="giraffe" onChange={noop}>
831 <option value="monkey">A monkey!</option>
@@ -694,11 +837,19 @@ describe('ReactDOMSelect', () => {
837 document.body.appendChild(container);
838
839 try {
697 - const node = ReactDOM.render(stub, container);
840 + const root = ReactDOMClient.createRoot(container);
841
699 - node.dispatchEvent(
700 - new Event('change', {bubbles: true, cancelable: false}),
701 - );
842 + await act(() => {
843 + root.render(stub);
844 + });
845 +
846 + const node = container.firstChild;
847 +
848 + await act(() => {
849 + node.dispatchEvent(
850 + new Event('change', {bubbles: true, cancelable: false}),
851 + );
852 + });
853
854 expect(node.value).toBe('giraffe');
855 } finally {
@@ -706,16 +857,20 @@ describe('ReactDOMSelect', () => {
857 }
858 });
859
709 - it('should warn if value and defaultValue props are specified', () => {
710 - expect(() =>
711 - ReactTestUtils.renderIntoDocument(
712 - <select value="giraffe" defaultValue="giraffe" readOnly={true}>
713 - <option value="monkey">A monkey!</option>
714 - <option value="giraffe">A giraffe!</option>
715 - <option value="gorilla">A gorilla!</option>
716 - </select>,
717 - ),
718 - ).toErrorDev(
860 + it('should warn if value and defaultValue props are specified', async () => {
861 + const container = document.createElement('div');
862 + const root = ReactDOMClient.createRoot(container);
863 + await expect(async () => {
864 + await act(() => {
865 + root.render(
866 + <select value="giraffe" defaultValue="giraffe" readOnly={true}>
867 + <option value="monkey">A monkey!</option>
868 + <option value="giraffe">A giraffe!</option>
869 + <option value="gorilla">A gorilla!</option>
870 + </select>,
871 + );
872 + });
873 + }).toErrorDev(
874 'Select elements must be either controlled or uncontrolled ' +
875 '(specify either the value prop, or the defaultValue prop, but not ' +
876 'both). Decide between using a controlled or uncontrolled select ' +
@@ -723,28 +878,44 @@ describe('ReactDOMSelect', () => {
878 'https://reactjs.org/link/controlled-components',
879 );
880
726 - ReactTestUtils.renderIntoDocument(
727 - <select value="giraffe" defaultValue="giraffe" readOnly={true}>
728 - <option value="monkey">A monkey!</option>
729 - <option value="giraffe">A giraffe!</option>
730 - <option value="gorilla">A gorilla!</option>
731 - </select>,
732 - );
881 + await act(() => {
882 + root.render(
883 + <select value="giraffe" defaultValue="giraffe" readOnly={true}>
884 + <option value="monkey">A monkey!</option>
885 + <option value="giraffe">A giraffe!</option>
886 + <option value="gorilla">A gorilla!</option>
887 + </select>,
888 + );
889 + });
890 });
891
735 - it('should not warn about missing onChange in uncontrolled textareas', () => {
892 + it('should not warn about missing onChange in uncontrolled textareas', async () => {
893 const container = document.createElement('div');
737 - ReactDOM.render(<select />, container);
738 - ReactDOM.unmountComponentAtNode(container);
739 - ReactDOM.render(<select value={undefined} />, container);
894 + let root = ReactDOMClient.createRoot(container);
895 +
896 + await act(() => {
897 + root.render(<select />);
898 + });
899 +
900 + await act(() => {
901 + root.unmount();
902 + });
903 + root = ReactDOMClient.createRoot(container);
904 +
905 + await act(() => {
906 + root.render(<select value={undefined} />);
907 + });
908 });
909
742 - it('should be able to safely remove select onChange', () => {
743 - function changeView() {
744 - ReactDOM.unmountComponentAtNode(container);
910 + it('should be able to safely remove select onChange', async () => {
911 + const container = document.createElement('div');
912 + const root = ReactDOMClient.createRoot(container);
913 + async function changeView() {
914 + await act(() => {
915 + root.unmount();
916 + });
917 }
918
747 - const container = document.createElement('div');
919 const stub = (
920 <select value="giraffe" onChange={changeView}>
921 <option value="monkey">A monkey!</option>
@@ -752,12 +923,25 @@ describe('ReactDOMSelect', () => {
923 <option value="gorilla">A gorilla!</option>
924 </select>
925 );
755 - const node = ReactDOM.render(stub, container);
926
757 - expect(() => ReactTestUtils.Simulate.change(node)).not.toThrow();
927 + await act(() => {
928 + root.render(stub);
929 + });
930 +
931 + const node = container.firstChild;
932 +
933 + await expect(
934 + act(() => {
935 + node.dispatchEvent(
936 + new Event('change', {bubbles: true, cancelable: false}),
937 + );
938 + }),
939 + ).resolves.not.toThrow();
940 +
941 + expect(container.firstChild).toBe(null);
942 });
943
760 - it('should select grandchild options nested inside an optgroup', () => {
944 + it('should select grandchild options nested inside an optgroup', async () => {
945 const stub = (
946 <select value="b" onChange={noop}>
947 <optgroup label="group">
@@ -768,14 +952,20 @@ describe('ReactDOMSelect', () => {
952 </select>
953 );
954 const container = document.createElement('div');
771 - const node = ReactDOM.render(stub, container);
955 + const root = ReactDOMClient.createRoot(container);
956 +
957 + await act(() => {
958 + root.render(stub);
959 + });
960 +
961 + const node = container.firstChild;
962
963 expect(node.options[0].selected).toBe(false); // a
964 expect(node.options[1].selected).toBe(true); // b
965 expect(node.options[2].selected).toBe(false); // c
966 });
967
778 - it('should allow controlling `value` in a nested render', () => {
968 + it('should allow controlling `value` in a nested legacy render', async () => {
969 let selectNode;
970
971 class Parent extends React.Component {
@@ -839,7 +1029,7 @@ describe('ReactDOMSelect', () => {
1029 document.body.removeChild(container);
1030 });
1031
842 - it('should not select first option by default when multiple is set and no defaultValue is set', () => {
1032 + it('should not select first option by default when multiple is set and no defaultValue is set', async () => {
1033 const stub = (
1034 <select multiple={true} onChange={noop}>
1035 <option value="a">a</option>
@@ -848,7 +1038,13 @@ describe('ReactDOMSelect', () => {
1038 </select>
1039 );
1040 const container = document.createElement('div');
851 - const node = ReactDOM.render(stub, container);
1041 + const root = ReactDOMClient.createRoot(container);
1042 +
1043 + await act(() => {
1044 + root.render(stub);
1045 + });
1046 +
1047 + const node = container.firstChild;
1048
1049 expect(node.options[0].selected).toBe(false); // a
1050 expect(node.options[1].selected).toBe(false); // b
@@ -856,172 +1052,214 @@ describe('ReactDOMSelect', () => {
1052 });
1053
1054 describe('When given a Symbol value', () => {
859 - it('treats initial Symbol value as missing', () => {
860 - let node;
861 -
862 - expect(() => {
863 - node = ReactTestUtils.renderIntoDocument(
864 - <select onChange={noop} value={Symbol('foobar')}>
865 - <option value={Symbol('foobar')}>A Symbol!</option>
866 - <option value="monkey">A monkey!</option>
867 - <option value="giraffe">A giraffe!</option>
868 - </select>,
869 - );
1055 + it('treats initial Symbol value as missing', async () => {
1056 + const container = document.createElement('div');
1057 + const root = ReactDOMClient.createRoot(container);
1058 + await expect(async () => {
1059 + await act(() => {
1060 + root.render(
1061 + <select onChange={noop} value={Symbol('foobar')}>
1062 + <option value={Symbol('foobar')}>A Symbol!</option>
1063 + <option value="monkey">A monkey!</option>
1064 + <option value="giraffe">A giraffe!</option>
1065 + </select>,
1066 + );
1067 + });
1068 }).toErrorDev('Invalid value for prop `value`');
1069
1070 + const node = container.firstChild;
1071 expect(node.value).toBe('A Symbol!');
1072 });
1073
875 - it('treats updated Symbol value as missing', () => {
876 - let node;
1074 + it('treats updated Symbol value as missing', async () => {
1075 + const container = document.createElement('div');
1076 + const root = ReactDOMClient.createRoot(container);
1077 + await expect(async () => {
1078 + await act(() => {
1079 + root.render(
1080 + <select onChange={noop} value="monkey">
1081 + <option value={Symbol('foobar')}>A Symbol!</option>
1082 + <option value="monkey">A monkey!</option>
1083 + <option value="giraffe">A giraffe!</option>
1084 + </select>,
1085 + );
1086 + });
1087 + }).toErrorDev('Invalid value for prop `value`');
1088
878 - expect(() => {
879 - node = ReactTestUtils.renderIntoDocument(
880 - <select onChange={noop} value="monkey">
1089 + let node = container.firstChild;
1090 + expect(node.value).toBe('monkey');
1091 +
1092 + await act(() => {
1093 + root.render(
1094 + <select onChange={noop} value={Symbol('foobar')}>
1095 <option value={Symbol('foobar')}>A Symbol!</option>
1096 <option value="monkey">A monkey!</option>
1097 <option value="giraffe">A giraffe!</option>
1098 </select>,
1099 );
886 - }).toErrorDev('Invalid value for prop `value`');
887 -
888 - expect(node.value).toBe('monkey');
1100 + });
1101
890 - node = ReactTestUtils.renderIntoDocument(
891 - <select onChange={noop} value={Symbol('foobar')}>
892 - <option value={Symbol('foobar')}>A Symbol!</option>
893 - <option value="monkey">A monkey!</option>
894 - <option value="giraffe">A giraffe!</option>
895 - </select>,
896 - );
1102 + node = container.firstChild;
1103
1104 expect(node.value).toBe('A Symbol!');
1105 });
1106
901 - it('treats initial Symbol defaultValue as an empty string', () => {
902 - let node;
903 -
904 - expect(() => {
905 - node = ReactTestUtils.renderIntoDocument(
906 - <select defaultValue={Symbol('foobar')}>
907 - <option value={Symbol('foobar')}>A Symbol!</option>
908 - <option value="monkey">A monkey!</option>
909 - <option value="giraffe">A giraffe!</option>
910 - </select>,
911 - );
1107 + it('treats initial Symbol defaultValue as an empty string', async () => {
1108 + const container = document.createElement('div');
1109 + const root = ReactDOMClient.createRoot(container);
1110 + await expect(async () => {
1111 + await act(() => {
1112 + root.render(
1113 + <select defaultValue={Symbol('foobar')}>
1114 + <option value={Symbol('foobar')}>A Symbol!</option>
1115 + <option value="monkey">A monkey!</option>
1116 + <option value="giraffe">A giraffe!</option>
1117 + </select>,
1118 + );
1119 + });
1120 }).toErrorDev('Invalid value for prop `value`');
1121
1122 + const node = container.firstChild;
1123 expect(node.value).toBe('A Symbol!');
1124 });
1125
917 - it('treats updated Symbol defaultValue as an empty string', () => {
918 - let node;
1126 + it('treats updated Symbol defaultValue as an empty string', async () => {
1127 + let container = document.createElement('div');
1128 + let root = ReactDOMClient.createRoot(container);
1129 + await expect(async () => {
1130 + await act(() => {
1131 + root.render(
1132 + <select defaultValue="monkey">
1133 + <option value={Symbol('foobar')}>A Symbol!</option>
1134 + <option value="monkey">A monkey!</option>
1135 + <option value="giraffe">A giraffe!</option>
1136 + </select>,
1137 + );
1138 + });
1139 + }).toErrorDev('Invalid value for prop `value`');
1140 +
1141 + let node = container.firstChild;
1142 + expect(node.value).toBe('monkey');
1143
920 - expect(() => {
921 - node = ReactTestUtils.renderIntoDocument(
922 - <select defaultValue="monkey">
1144 + container = document.createElement('div');
1145 + root = ReactDOMClient.createRoot(container);
1146 + await act(() => {
1147 + root.render(
1148 + <select defaultValue={Symbol('foobar')}>
1149 <option value={Symbol('foobar')}>A Symbol!</option>
1150 <option value="monkey">A monkey!</option>
1151 <option value="giraffe">A giraffe!</option>
1152 </select>,
1153 );
928 - }).toErrorDev('Invalid value for prop `value`');
929 -
930 - expect(node.value).toBe('monkey');
931 -
932 - node = ReactTestUtils.renderIntoDocument(
933 - <select defaultValue={Symbol('foobar')}>
934 - <option value={Symbol('foobar')}>A Symbol!</option>
935 - <option value="monkey">A monkey!</option>
936 - <option value="giraffe">A giraffe!</option>
937 - </select>,
938 - );
1154 + });
1155
1156 + node = container.firstChild;
1157 expect(node.value).toBe('A Symbol!');
1158 });
1159 });
1160
1161 describe('When given a function value', () => {
945 - it('treats initial function value as missing', () => {
946 - let node;
947 -
948 - expect(() => {
949 - node = ReactTestUtils.renderIntoDocument(
950 - <select onChange={noop} value={() => {}}>
951 - <option value={() => {}}>A function!</option>
952 - <option value="monkey">A monkey!</option>
953 - <option value="giraffe">A giraffe!</option>
954 - </select>,
955 - );
1162 + it('treats initial function value as missing', async () => {
1163 + const container = document.createElement('div');
1164 + const root = ReactDOMClient.createRoot(container);
1165 + await expect(async () => {
1166 + await act(() => {
1167 + root.render(
1168 + <select onChange={noop} value={() => {}}>
1169 + <option value={() => {}}>A function!</option>
1170 + <option value="monkey">A monkey!</option>
1171 + <option value="giraffe">A giraffe!</option>
1172 + </select>,
1173 + );
1174 + });
1175 }).toErrorDev('Invalid value for prop `value`');
1176
1177 + const node = container.firstChild;
1178 expect(node.value).toBe('A function!');
1179 });
1180
961 - it('treats initial function defaultValue as an empty string', () => {
962 - let node;
963 -
964 - expect(() => {
965 - node = ReactTestUtils.renderIntoDocument(
966 - <select defaultValue={() => {}}>
967 - <option value={() => {}}>A function!</option>
968 - <option value="monkey">A monkey!</option>
969 - <option value="giraffe">A giraffe!</option>
970 - </select>,
971 - );
1181 + it('treats initial function defaultValue as an empty string', async () => {
1182 + const container = document.createElement('div');
1183 + const root = ReactDOMClient.createRoot(container);
1184 + await expect(async () => {
1185 + await act(() => {
1186 + root.render(
1187 + <select defaultValue={() => {}}>
1188 + <option value={() => {}}>A function!</option>
1189 + <option value="monkey">A monkey!</option>
1190 + <option value="giraffe">A giraffe!</option>
1191 + </select>,
1192 + );
1193 + });
1194 }).toErrorDev('Invalid value for prop `value`');
1195
1196 + const node = container.firstChild;
1197 expect(node.value).toBe('A function!');
1198 });
1199
977 - it('treats updated function value as an empty string', () => {
978 - let node;
1200 + it('treats updated function value as an empty string', async () => {
1201 + const container = document.createElement('div');
1202 + const root = ReactDOMClient.createRoot(container);
1203 + await expect(async () => {
1204 + await act(() => {
1205 + root.render(
1206 + <select onChange={noop} value="monkey">
1207 + <option value={() => {}}>A function!</option>
1208 + <option value="monkey">A monkey!</option>
1209 + <option value="giraffe">A giraffe!</option>
1210 + </select>,
1211 + );
1212 + });
1213 + }).toErrorDev('Invalid value for prop `value`');
1214
980 - expect(() => {
981 - node = ReactTestUtils.renderIntoDocument(
982 - <select onChange={noop} value="monkey">
1215 + let node = container.firstChild;
1216 + expect(node.value).toBe('monkey');
1217 +
1218 + await act(() => {
1219 + root.render(
1220 + <select onChange={noop} value={() => {}}>
1221 <option value={() => {}}>A function!</option>
1222 <option value="monkey">A monkey!</option>
1223 <option value="giraffe">A giraffe!</option>
1224 </select>,
1225 );
988 - }).toErrorDev('Invalid value for prop `value`');
989 -
990 - expect(node.value).toBe('monkey');
991 -
992 - node = ReactTestUtils.renderIntoDocument(
993 - <select onChange={noop} value={() => {}}>
994 - <option value={() => {}}>A function!</option>
995 - <option value="monkey">A monkey!</option>
996 - <option value="giraffe">A giraffe!</option>
997 - </select>,
998 - );
1226 + });
1227
1228 + node = container.firstChild;
1229 expect(node.value).toBe('A function!');
1230 });
1231
1003 - it('treats updated function defaultValue as an empty string', () => {
1004 - let node;
1232 + it('treats updated function defaultValue as an empty string', async () => {
1233 + let container = document.createElement('div');
1234 + let root = ReactDOMClient.createRoot(container);
1235 + await expect(async () => {
1236 + await act(() => {
1237 + root.render(
1238 + <select defaultValue="monkey">
1239 + <option value={() => {}}>A function!</option>
1240 + <option value="monkey">A monkey!</option>
1241 + <option value="giraffe">A giraffe!</option>
1242 + </select>,
1243 + );
1244 + });
1245 + }).toErrorDev('Invalid value for prop `value`');
1246 +
1247 + let node = container.firstChild;
1248 + expect(node.value).toBe('monkey');
1249
1006 - expect(() => {
1007 - node = ReactTestUtils.renderIntoDocument(
1008 - <select defaultValue="monkey">
1250 + container = document.createElement('div');
1251 + root = ReactDOMClient.createRoot(container);
1252 + await act(() => {
1253 + root.render(
1254 + <select defaultValue={() => {}}>
1255 <option value={() => {}}>A function!</option>
1256 <option value="monkey">A monkey!</option>
1257 <option value="giraffe">A giraffe!</option>
1258 </select>,
1259 );
1014 - }).toErrorDev('Invalid value for prop `value`');
1260 + });
1261
1016 - expect(node.value).toBe('monkey');
1017 -
1018 - node = ReactTestUtils.renderIntoDocument(
1019 - <select defaultValue={() => {}}>
1020 - <option value={() => {}}>A function!</option>
1021 - <option value="monkey">A monkey!</option>
1022 - <option value="giraffe">A giraffe!</option>
1023 - </select>,
1024 - );
1262 + node = container.firstChild;
1263
1264 expect(node.value).toBe('A function!');
1265 });
@@ -1039,316 +1277,416 @@ describe('ReactDOMSelect', () => {
1277 }
1278 }
1279
1042 - it('throws when given a Temporal.PlainDate-like value (select)', () => {
1043 - const test = () => {
1044 - ReactTestUtils.renderIntoDocument(
1045 - <select onChange={noop} value={new TemporalLike()}>
1046 - <option value="2020-01-01">like a Temporal.PlainDate</option>
1047 - <option value="monkey">A monkey!</option>
1048 - <option value="giraffe">A giraffe!</option>
1049 - </select>,
1050 - );
1051 - };
1052 - expect(() =>
1053 - expect(test).toThrowError(new TypeError('prod message')),
1054 - ).toErrorDev(
1280 + it('throws when given a Temporal.PlainDate-like value (select)', async () => {
1281 + const container = document.createElement('div');
1282 + const root = ReactDOMClient.createRoot(container);
1283 + await expect(async () => {
1284 + await expect(
1285 + act(() => {
1286 + root.render(
1287 + <select onChange={noop} value={new TemporalLike()}>
1288 + <option value="2020-01-01">like a Temporal.PlainDate</option>
1289 + <option value="monkey">A monkey!</option>
1290 + <option value="giraffe">A giraffe!</option>
1291 + </select>,
1292 + );
1293 + }),
1294 + ).rejects.toThrowError(new TypeError('prod message'));
1295 + }).toErrorDev([
1296 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1297 ' must be strings, not TemporalLike. ' +
1298 'This value must be coerced to a string before using it here.',
1058 - );
1299 + 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1300 + ' must be strings, not TemporalLike. ' +
1301 + 'This value must be coerced to a string before using it here.',
1302 + ]);
1303 });
1304
1061 - it('throws when given a Temporal.PlainDate-like value (option)', () => {
1062 - const test = () => {
1063 - ReactTestUtils.renderIntoDocument(
1064 - <select onChange={noop} value="2020-01-01">
1065 - <option value={new TemporalLike()}>
1066 - like a Temporal.PlainDate
1067 - </option>
1068 - <option value="monkey">A monkey!</option>
1069 - <option value="giraffe">A giraffe!</option>
1070 - </select>,
1071 - );
1072 - };
1073 - expect(() =>
1074 - expect(test).toThrowError(new TypeError('prod message')),
1075 - ).toErrorDev(
1305 + it('throws when given a Temporal.PlainDate-like value (option)', async () => {
1306 + const container = document.createElement('div');
1307 + const root = ReactDOMClient.createRoot(container);
1308 + await expect(async () => {
1309 + await expect(
1310 + act(() => {
1311 + root.render(
1312 + <select onChange={noop} value="2020-01-01">
1313 + <option value={new TemporalLike()}>
1314 + like a Temporal.PlainDate
1315 + </option>
1316 + <option value="monkey">A monkey!</option>
1317 + <option value="giraffe">A giraffe!</option>
1318 + </select>,
1319 + );
1320 + }),
1321 + ).rejects.toThrowError(new TypeError('prod message'));
1322 + }).toErrorDev([
1323 'The provided `value` attribute is an unsupported type TemporalLike.' +
1324 ' This value must be coerced to a string before using it here.',
1078 - );
1325 + 'The provided `value` attribute is an unsupported type TemporalLike.' +
1326 + ' This value must be coerced to a string before using it here.',
1327 + ]);
1328 });
1329
1081 - it('throws when given a Temporal.PlainDate-like value (both)', () => {
1082 - const test = () => {
1083 - ReactTestUtils.renderIntoDocument(
1084 - <select onChange={noop} value={new TemporalLike()}>
1085 - <option value={new TemporalLike()}>
1086 - like a Temporal.PlainDate
1087 - </option>
1088 - <option value="monkey">A monkey!</option>
1089 - <option value="giraffe">A giraffe!</option>
1090 - </select>,
1091 - );
1092 - };
1093 - expect(() =>
1094 - expect(test).toThrowError(new TypeError('prod message')),
1095 - ).toErrorDev(
1330 + it('throws when given a Temporal.PlainDate-like value (both)', async () => {
1331 + const container = document.createElement('div');
1332 + const root = ReactDOMClient.createRoot(container);
1333 +
1334 + await expect(async () => {
1335 + await expect(
1336 + act(() => {
1337 + root.render(
1338 + <select onChange={noop} value={new TemporalLike()}>
1339 + <option value={new TemporalLike()}>
1340 + like a Temporal.PlainDate
1341 + </option>
1342 + <option value="monkey">A monkey!</option>
1343 + <option value="giraffe">A giraffe!</option>
1344 + </select>,
1345 + );
1346 + }),
1347 + ).rejects.toThrowError(new TypeError('prod message'));
1348 + }).toErrorDev([
1349 'The provided `value` attribute is an unsupported type TemporalLike.' +
1350 ' This value must be coerced to a string before using it here.',
1098 - );
1351 + 'The provided `value` attribute is an unsupported type TemporalLike.' +
1352 + ' This value must be coerced to a string before using it here.',
1353 + ]);
1354 });
1355
1101 - it('throws with updated Temporal.PlainDate-like value (select)', () => {
1102 - ReactTestUtils.renderIntoDocument(
1103 - <select onChange={noop} value="monkey">
1104 - <option value="2020-01-01">like a Temporal.PlainDate</option>
1105 - <option value="monkey">A monkey!</option>
1106 - <option value="giraffe">A giraffe!</option>
1107 - </select>,
1108 - );
1109 - const test = () => {
1110 - ReactTestUtils.renderIntoDocument(
1111 - <select onChange={noop} value={new TemporalLike()}>
1356 + it('throws with updated Temporal.PlainDate-like value (select)', async () => {
1357 + const container = document.createElement('div');
1358 + const root = ReactDOMClient.createRoot(container);
1359 +
1360 + await act(() => {
1361 + root.render(
1362 + <select onChange={noop} value="monkey">
1363 <option value="2020-01-01">like a Temporal.PlainDate</option>
1364 <option value="monkey">A monkey!</option>
1365 <option value="giraffe">A giraffe!</option>
1366 </select>,
1367 );
1117 - };
1118 - expect(() =>
1119 - expect(test).toThrowError(new TypeError('prod message')),
1120 - ).toErrorDev(
1368 + });
1369 +
1370 + await expect(async () => {
1371 + await expect(
1372 + act(() => {
1373 + root.render(
1374 + <select onChange={noop} value={new TemporalLike()}>
1375 + <option value="2020-01-01">like a Temporal.PlainDate</option>
1376 + <option value="monkey">A monkey!</option>
1377 + <option value="giraffe">A giraffe!</option>
1378 + </select>,
1379 + );
1380 + }),
1381 + ).rejects.toThrowError(new TypeError('prod message'));
1382 + }).toErrorDev(
1383 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1384 ' must be strings, not TemporalLike. ' +
1385 'This value must be coerced to a string before using it here.',
1386 );
1387 });
1388
1127 - it('throws with updated Temporal.PlainDate-like value (option)', () => {
1128 - ReactTestUtils.renderIntoDocument(
1129 - <select onChange={noop} value="2020-01-01">
1130 - <option value="donkey">like a Temporal.PlainDate</option>
1131 - <option value="monkey">A monkey!</option>
1132 - <option value="giraffe">A giraffe!</option>
1133 - </select>,
1134 - );
1135 - const test = () => {
1136 - ReactTestUtils.renderIntoDocument(
1389 + it('throws with updated Temporal.PlainDate-like value (option)', async () => {
1390 + const container = document.createElement('div');
1391 + const root = ReactDOMClient.createRoot(container);
1392 +
1393 + await act(() => {
1394 + root.render(
1395 <select onChange={noop} value="2020-01-01">
1138 - <option value={new TemporalLike()}>
1139 - like a Temporal.PlainDate
1140 - </option>
1396 + <option value="donkey">like a Temporal.PlainDate</option>
1397 <option value="monkey">A monkey!</option>
1398 <option value="giraffe">A giraffe!</option>
1399 </select>,
1400 );
1145 - };
1146 - expect(() =>
1147 - expect(test).toThrowError(new TypeError('prod message')),
1148 - ).toErrorDev(
1401 + });
1402 +
1403 + await expect(async () => {
1404 + await expect(
1405 + act(() => {
1406 + root.render(
1407 + <select onChange={noop} value="2020-01-01">
1408 + <option value={new TemporalLike()}>
1409 + like a Temporal.PlainDate
1410 + </option>
1411 + <option value="monkey">A monkey!</option>
1412 + <option value="giraffe">A giraffe!</option>
1413 + </select>,
1414 + );
1415 + }),
1416 + ).rejects.toThrowError(new TypeError('prod message'));
1417 + }).toErrorDev(
1418 'The provided `value` attribute is an unsupported type TemporalLike.' +
1419 ' This value must be coerced to a string before using it here.',
1420 );
1421 });
1422
1154 - it('throws with updated Temporal.PlainDate-like value (both)', () => {
1155 - ReactTestUtils.renderIntoDocument(
1156 - <select onChange={noop} value="donkey">
1157 - <option value="donkey">like a Temporal.PlainDate</option>
1158 - <option value="monkey">A monkey!</option>
1159 - <option value="giraffe">A giraffe!</option>
1160 - </select>,
1161 - );
1162 - const test = () => {
1163 - ReactTestUtils.renderIntoDocument(
1164 - <select onChange={noop} value={new TemporalLike()}>
1165 - <option value={new TemporalLike()}>
1166 - like a Temporal.PlainDate
1167 - </option>
1423 + it('throws with updated Temporal.PlainDate-like value (both)', async () => {
1424 + const container = document.createElement('div');
1425 + const root = ReactDOMClient.createRoot(container);
1426 +
1427 + await act(() => {
1428 + root.render(
1429 + <select onChange={noop} value="donkey">
1430 + <option value="donkey">like a Temporal.PlainDate</option>
1431 <option value="monkey">A monkey!</option>
1432 <option value="giraffe">A giraffe!</option>
1433 </select>,
1434 );
1172 - };
1173 - expect(() =>
1174 - expect(test).toThrowError(new TypeError('prod message')),
1175 - ).toErrorDev(
1435 + });
1436 +
1437 + await expect(async () => {
1438 + await expect(
1439 + act(() => {
1440 + root.render(
1441 + <select onChange={noop} value={new TemporalLike()}>
1442 + <option value={new TemporalLike()}>
1443 + like a Temporal.PlainDate
1444 + </option>
1445 + <option value="monkey">A monkey!</option>
1446 + <option value="giraffe">A giraffe!</option>
1447 + </select>,
1448 + );
1449 + }),
1450 + ).rejects.toThrowError(new TypeError('prod message'));
1451 + }).toErrorDev([
1452 'The provided `value` attribute is an unsupported type TemporalLike.' +
1453 ' This value must be coerced to a string before using it here.',
1178 - );
1454 + 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1455 + ' must be strings, not TemporalLike. ' +
1456 + 'This value must be coerced to a string before using it here.',
1457 + ]);
1458 });
1459
1181 - it('throws when given a Temporal.PlainDate-like defaultValue (select)', () => {
1182 - const test = () => {
1183 - ReactTestUtils.renderIntoDocument(
1184 - <select onChange={noop} defaultValue={new TemporalLike()}>
1185 - <option value="2020-01-01">like a Temporal.PlainDate</option>
1186 - <option value="monkey">A monkey!</option>
1187 - <option value="giraffe">A giraffe!</option>
1188 - </select>,
1189 - );
1190 - };
1191 - expect(() =>
1192 - expect(test).toThrowError(new TypeError('prod message')),
1193 - ).toErrorDev(
1460 + it('throws when given a Temporal.PlainDate-like defaultValue (select)', async () => {
1461 + const container = document.createElement('div');
1462 + const root = ReactDOMClient.createRoot(container);
1463 + await expect(async () => {
1464 + await expect(
1465 + act(() => {
1466 + root.render(
1467 + <select onChange={noop} defaultValue={new TemporalLike()}>
1468 + <option value="2020-01-01">like a Temporal.PlainDate</option>
1469 + <option value="monkey">A monkey!</option>
1470 + <option value="giraffe">A giraffe!</option>
1471 + </select>,
1472 + );
1473 + }),
1474 + ).rejects.toThrowError(new TypeError('prod message'));
1475 + }).toErrorDev([
1476 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1477 ' must be strings, not TemporalLike. ' +
1478 'This value must be coerced to a string before using it here.',
1197 - );
1479 + 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1480 + ' must be strings, not TemporalLike. ' +
1481 + 'This value must be coerced to a string before using it here.',
1482 + ]);
1483 });
1484
1200 - it('throws when given a Temporal.PlainDate-like defaultValue (option)', () => {
1201 - const test = () => {
1202 - ReactTestUtils.renderIntoDocument(
1203 - <select onChange={noop} defaultValue="2020-01-01">
1204 - <option value={new TemporalLike()}>
1205 - like a Temporal.PlainDate
1206 - </option>
1207 - <option value="monkey">A monkey!</option>
1208 - <option value="giraffe">A giraffe!</option>
1209 - </select>,
1210 - );
1211 - };
1212 - expect(() =>
1213 - expect(test).toThrowError(new TypeError('prod message')),
1214 - ).toErrorDev(
1485 + it('throws when given a Temporal.PlainDate-like defaultValue (option)', async () => {
1486 + const container = document.createElement('div');
1487 + const root = ReactDOMClient.createRoot(container);
1488 +
1489 + await expect(async () => {
1490 + await expect(
1491 + act(() => {
1492 + root.render(
1493 + <select onChange={noop} defaultValue="2020-01-01">
1494 + <option value={new TemporalLike()}>
1495 + like a Temporal.PlainDate
1496 + </option>
1497 + <option value="monkey">A monkey!</option>
1498 + <option value="giraffe">A giraffe!</option>
1499 + </select>,
1500 + );
1501 + }),
1502 + ).rejects.toThrowError(new TypeError('prod message'));
1503 + }).toErrorDev([
1504 'The provided `value` attribute is an unsupported type TemporalLike.' +
1505 ' This value must be coerced to a string before using it here.',
1217 - );
1506 + 'The provided `value` attribute is an unsupported type TemporalLike.' +
1507 + ' This value must be coerced to a string before using it here.',
1508 + ]);
1509 });
1510
1220 - it('throws when given a Temporal.PlainDate-like value (both)', () => {
1221 - const test = () => {
1222 - ReactTestUtils.renderIntoDocument(
1223 - <select onChange={noop} defaultValue={new TemporalLike()}>
1224 - <option value={new TemporalLike()}>
1225 - like a Temporal.PlainDate
1226 - </option>
1227 - <option value="monkey">A monkey!</option>
1228 - <option value="giraffe">A giraffe!</option>
1229 - </select>,
1230 - );
1231 - };
1232 - expect(() =>
1233 - expect(test).toThrowError(new TypeError('prod message')),
1234 - ).toErrorDev(
1511 + it('throws when given a Temporal.PlainDate-like value (both)', async () => {
1512 + const container = document.createElement('div');
1513 + const root = ReactDOMClient.createRoot(container);
1514 + await expect(async () => {
1515 + await expect(
1516 + act(() => {
1517 + root.render(
1518 + <select onChange={noop} defaultValue={new TemporalLike()}>
1519 + <option value={new TemporalLike()}>
1520 + like a Temporal.PlainDate
1521 + </option>
1522 + <option value="monkey">A monkey!</option>
1523 + <option value="giraffe">A giraffe!</option>
1524 + </select>,
1525 + );
1526 + }),
1527 + ).rejects.toThrowError(new TypeError('prod message'));
1528 + }).toErrorDev([
1529 'The provided `value` attribute is an unsupported type TemporalLike.' +
1530 ' This value must be coerced to a string before using it here.',
1237 - );
1531 + 'The provided `value` attribute is an unsupported type TemporalLike.' +
1532 + ' This value must be coerced to a string before using it here.',
1533 + ]);
1534 });
1535
1240 - it('throws with updated Temporal.PlainDate-like defaultValue (select)', () => {
1241 - ReactTestUtils.renderIntoDocument(
1242 - <select onChange={noop} defaultValue="monkey">
1243 - <option value="2020-01-01">like a Temporal.PlainDate</option>
1244 - <option value="monkey">A monkey!</option>
1245 - <option value="giraffe">A giraffe!</option>
1246 - </select>,
1247 - );
1248 - const test = () => {
1249 - ReactTestUtils.renderIntoDocument(
1250 - <select onChange={noop} defaultValue={new TemporalLike()}>
1536 + it('throws with updated Temporal.PlainDate-like defaultValue (select)', async () => {
1537 + let container = document.createElement('div');
1538 + let root = ReactDOMClient.createRoot(container);
1539 + await act(() => {
1540 + root.render(
1541 + <select onChange={noop} defaultValue="monkey">
1542 <option value="2020-01-01">like a Temporal.PlainDate</option>
1543 <option value="monkey">A monkey!</option>
1544 <option value="giraffe">A giraffe!</option>
1545 </select>,
1546 );
1256 - };
1257 - expect(() =>
1258 - expect(test).toThrowError(new TypeError('prod message')),
1259 - ).toErrorDev(
1547 + });
1548 +
1549 + container = document.createElement('div');
1550 + root = ReactDOMClient.createRoot(container);
1551 + await expect(async () => {
1552 + await expect(
1553 + act(() => {
1554 + root.render(
1555 + <select onChange={noop} defaultValue={new TemporalLike()}>
1556 + <option value="2020-01-01">like a Temporal.PlainDate</option>
1557 + <option value="monkey">A monkey!</option>
1558 + <option value="giraffe">A giraffe!</option>
1559 + </select>,
1560 + );
1561 + }),
1562 + ).rejects.toThrowError(new TypeError('prod message'));
1563 + }).toErrorDev([
1564 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1565 ' must be strings, not TemporalLike. ' +
1566 'This value must be coerced to a string before using it here.',
1263 - );
1567 + 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
1568 + ' must be strings, not TemporalLike. ' +
1569 + 'This value must be coerced to a string before using it here.',
1570 + ]);
1571 });
1572
1266 - it('throws with updated Temporal.PlainDate-like defaultValue (both)', () => {
1267 - ReactTestUtils.renderIntoDocument(
1268 - <select onChange={noop} defaultValue="monkey">
1269 - <option value="donkey">like a Temporal.PlainDate</option>
1270 - <option value="monkey">A monkey!</option>
1271 - <option value="giraffe">A giraffe!</option>
1272 - </select>,
1273 - );
1274 - const test = () => {
1275 - ReactTestUtils.renderIntoDocument(
1276 - <select onChange={noop} value={new TemporalLike()}>
1277 - <option value={new TemporalLike()}>
1278 - like a Temporal.PlainDate
1279 - </option>
1573 + it('throws with updated Temporal.PlainDate-like defaultValue (both)', async () => {
1574 + let container = document.createElement('div');
1575 + let root = ReactDOMClient.createRoot(container);
1576 +
1577 + await act(() => {
1578 + root.render(
1579 + <select onChange={noop} defaultValue="monkey">
1580 + <option value="donkey">like a Temporal.PlainDate</option>
1581 <option value="monkey">A monkey!</option>
1582 <option value="giraffe">A giraffe!</option>
1583 </select>,
1584 );
1284 - };
1285 - expect(() =>
1286 - expect(test).toThrowError(new TypeError('prod message')),
1287 - ).toErrorDev(
1585 + });
1586 +
1587 + container = document.createElement('div');
1588 + root = ReactDOMClient.createRoot(container);
1589 + await expect(async () => {
1590 + await expect(
1591 + act(() => {
1592 + root.render(
1593 + <select onChange={noop} value={new TemporalLike()}>
1594 + <option value={new TemporalLike()}>
1595 + like a Temporal.PlainDate
1596 + </option>
1597 + <option value="monkey">A monkey!</option>
1598 + <option value="giraffe">A giraffe!</option>
1599 + </select>,
1600 + );
1601 + }),
1602 + ).rejects.toThrowError(new TypeError('prod message'));
1603 + }).toErrorDev([
1604 'The provided `value` attribute is an unsupported type TemporalLike.' +
1605 ' This value must be coerced to a string before using it here.',
1290 - );
1606 + 'The provided `value` attribute is an unsupported type TemporalLike.' +
1607 + ' This value must be coerced to a string before using it here.',
1608 + ]);
1609 });
1610
1293 - it('should not warn about missing onChange if value is not set', () => {
1294 - expect(() => {
1295 - ReactTestUtils.renderIntoDocument(
1296 - <select>
1297 - <option value="monkey">A monkey!</option>
1298 - <option value="giraffe">A giraffe!</option>
1299 - <option value="gorilla">A gorilla!</option>
1300 - </select>,
1301 - );
1302 - }).not.toThrow();
1611 + it('should not warn about missing onChange if value is not set', async () => {
1612 + const container = document.createElement('div');
1613 + const root = ReactDOMClient.createRoot(container);
1614 + await expect(
1615 + act(() => {
1616 + root.render(
1617 + <select>
1618 + <option value="monkey">A monkey!</option>
1619 + <option value="giraffe">A giraffe!</option>
1620 + <option value="gorilla">A gorilla!</option>
1621 + </select>,
1622 + );
1623 + }),
1624 + ).resolves.not.toThrow();
1625 });
1626
1305 - it('should not throw an error about missing onChange if value is undefined', () => {
1306 - expect(() => {
1307 - ReactTestUtils.renderIntoDocument(
1308 - <select value={undefined}>
1309 - <option value="monkey">A monkey!</option>
1310 - <option value="giraffe">A giraffe!</option>
1311 - <option value="gorilla">A gorilla!</option>
1312 - </select>,
1313 - );
1314 - }).not.toThrow();
1627 + it('should not throw an error about missing onChange if value is undefined', async () => {
1628 + const container = document.createElement('div');
1629 + const root = ReactDOMClient.createRoot(container);
1630 + await expect(
1631 + act(() => {
1632 + root.render(
1633 + <select value={undefined}>
1634 + <option value="monkey">A monkey!</option>
1635 + <option value="giraffe">A giraffe!</option>
1636 + <option value="gorilla">A gorilla!</option>
1637 + </select>,
1638 + );
1639 + }),
1640 + ).resolves.not.toThrow();
1641 });
1642
1317 - it('should not warn about missing onChange if onChange is set', () => {
1643 + it('should not warn about missing onChange if onChange is set', async () => {
1644 const change = jest.fn();
1319 - expect(() => {
1320 - ReactTestUtils.renderIntoDocument(
1321 - <select value="monkey" onChange={change}>
1322 - <option value="monkey">A monkey!</option>
1323 - <option value="giraffe">A giraffe!</option>
1324 - <option value="gorilla">A gorilla!</option>
1325 - </select>,
1326 - );
1327 - }).not.toThrow();
1645 + const container = document.createElement('div');
1646 + const root = ReactDOMClient.createRoot(container);
1647 + await expect(
1648 + act(() => {
1649 + root.render(
1650 + <select value="monkey" onChange={change}>
1651 + <option value="monkey">A monkey!</option>
1652 + <option value="giraffe">A giraffe!</option>
1653 + <option value="gorilla">A gorilla!</option>
1654 + </select>,
1655 + );
1656 + }),
1657 + ).resolves.not.toThrow();
1658 });
1659
1330 - it('should not warn about missing onChange if disabled is true', () => {
1331 - expect(() => {
1332 - ReactTestUtils.renderIntoDocument(
1333 - <select value="monkey" disabled={true}>
1334 - <option value="monkey">A monkey!</option>
1335 - <option value="giraffe">A giraffe!</option>
1336 - <option value="gorilla">A gorilla!</option>
1337 - </select>,
1338 - );
1339 - }).not.toThrow();
1660 + it('should not warn about missing onChange if disabled is true', async () => {
1661 + const container = document.createElement('div');
1662 + const root = ReactDOMClient.createRoot(container);
1663 + await expect(
1664 + act(() => {
1665 + root.render(
1666 + <select value="monkey" disabled={true}>
1667 + <option value="monkey">A monkey!</option>
1668 + <option value="giraffe">A giraffe!</option>
1669 + <option value="gorilla">A gorilla!</option>
1670 + </select>,
1671 + );
1672 + }),
1673 + ).resolves.not.toThrow();
1674 });
1675
1342 - it('should warn about missing onChange if value is false', () => {
1343 - expect(() =>
1344 - ReactTestUtils.renderIntoDocument(
1345 - <select value={false}>
1346 - <option value="monkey">A monkey!</option>
1347 - <option value="giraffe">A giraffe!</option>
1348 - <option value="gorilla">A gorilla!</option>
1349 - </select>,
1350 - ),
1351 - ).toErrorDev(
1676 + it('should warn about missing onChange if value is false', async () => {
1677 + const container = document.createElement('div');
1678 + const root = ReactDOMClient.createRoot(container);
1679 + await expect(async () => {
1680 + await act(() => {
1681 + root.render(
1682 + <select value={false}>
1683 + <option value="monkey">A monkey!</option>
1684 + <option value="giraffe">A giraffe!</option>
1685 + <option value="gorilla">A gorilla!</option>
1686 + </select>,
1687 + );
1688 + });
1689 + }).toErrorDev(
1690 'Warning: You provided a `value` prop to a form ' +
1691 'field without an `onChange` handler. This will render a read-only ' +
1692 'field. If the field should be mutable use `defaultValue`. ' +
@@ -1356,16 +1694,20 @@ describe('ReactDOMSelect', () => {
1694 );
1695 });
1696
1359 - it('should warn about missing onChange if value is 0', () => {
1360 - expect(() =>
1361 - ReactTestUtils.renderIntoDocument(
1362 - <select value={0}>
1363 - <option value="monkey">A monkey!</option>
1364 - <option value="giraffe">A giraffe!</option>
1365 - <option value="gorilla">A gorilla!</option>
1366 - </select>,
1367 - ),
1368 - ).toErrorDev(
1697 + it('should warn about missing onChange if value is 0', async () => {
1698 + const container = document.createElement('div');
1699 + const root = ReactDOMClient.createRoot(container);
1700 + await expect(async () => {
1701 + await act(() => {
1702 + root.render(
1703 + <select value={0}>
1704 + <option value="monkey">A monkey!</option>
1705 + <option value="giraffe">A giraffe!</option>
1706 + <option value="gorilla">A gorilla!</option>
1707 + </select>,
1708 + );
1709 + });
1710 + }).toErrorDev(
1711 'Warning: You provided a `value` prop to a form ' +
1712 'field without an `onChange` handler. This will render a read-only ' +
1713 'field. If the field should be mutable use `defaultValue`. ' +
@@ -1373,16 +1715,20 @@ describe('ReactDOMSelect', () => {
1715 );
1716 });
1717
1376 - it('should warn about missing onChange if value is "0"', () => {
1377 - expect(() =>
1378 - ReactTestUtils.renderIntoDocument(
1379 - <select value="0">
1380 - <option value="monkey">A monkey!</option>
1381 - <option value="giraffe">A giraffe!</option>
1382 - <option value="gorilla">A gorilla!</option>
1383 - </select>,
1384 - ),
1385 - ).toErrorDev(
1718 + it('should warn about missing onChange if value is "0"', async () => {
1719 + const container = document.createElement('div');
1720 + const root = ReactDOMClient.createRoot(container);
1721 + await expect(async () => {
1722 + await act(() => {
1723 + root.render(
1724 + <select value="0">
1725 + <option value="monkey">A monkey!</option>
1726 + <option value="giraffe">A giraffe!</option>
1727 + <option value="gorilla">A gorilla!</option>
1728 + </select>,
1729 + );
1730 + });
1731 + }).toErrorDev(
1732 'Warning: You provided a `value` prop to a form ' +
1733 'field without an `onChange` handler. This will render a read-only ' +
1734 'field. If the field should be mutable use `defaultValue`. ' +
@@ -1390,16 +1736,20 @@ describe('ReactDOMSelect', () => {
1736 );
1737 });
1738
1393 - it('should warn about missing onChange if value is ""', () => {
1394 - expect(() =>
1395 - ReactTestUtils.renderIntoDocument(
1396 - <select value="">
1397 - <option value="monkey">A monkey!</option>
1398 - <option value="giraffe">A giraffe!</option>
1399 - <option value="gorilla">A gorilla!</option>
1400 - </select>,
1401 - ),
1402 - ).toErrorDev(
1739 + it('should warn about missing onChange if value is ""', async () => {
1740 + const container = document.createElement('div');
1741 + const root = ReactDOMClient.createRoot(container);
1742 + await expect(async () => {
1743 + await act(() => {
1744 + root.render(
1745 + <select value="">
1746 + <option value="monkey">A monkey!</option>
1747 + <option value="giraffe">A giraffe!</option>
1748 + <option value="gorilla">A gorilla!</option>
1749 + </select>,
1750 + );
1751 + });
1752 + }).toErrorDev(
1753 'Warning: You provided a `value` prop to a form ' +
1754 'field without an `onChange` handler. This will render a read-only ' +
1755 'field. If the field should be mutable use `defaultValue`. ' +