@samitouri / QOS-React-2 / commits / 6c64428d90

Convert ChangeEventPlugin to createRoot (#28090)

Sebastian Silbermann committed Jan 26, 2024 at 10:20 UTC 6c64428d904f8339cddaa0f4850cba89acabe0bb
1 file changed +134 -80
packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js
+134 -80
@@ -83,7 +83,7 @@ describe('ChangeEventPlugin', () => {
83 // keep track of the "current" value and only fire events when it changes.
84 // See https://github.com/facebook/react/pull/5746.
85
86 - it('should consider initial text value to be current', () => {
86 + it('should consider initial text value to be current', async () => {
87 let called = 0;
88
89 function cb(e) {
@@ -91,10 +91,12 @@ describe('ChangeEventPlugin', () => {
91 expect(e.type).toBe('change');
92 }
93
94 - const node = ReactDOM.render(
95 - <input type="text" onChange={cb} defaultValue="foo" />,
96 - container,
97 - );
94 + const root = ReactDOMClient.createRoot(container);
95 + await act(() => {
96 + root.render(<input type="text" onChange={cb} defaultValue="foo" />);
97 + });
98 +
99 + const node = container.firstChild;
100 node.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
101 node.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
102
@@ -102,7 +104,7 @@ describe('ChangeEventPlugin', () => {
104 expect(called).toBe(0);
105 });
106
105 - it('should consider initial text value to be current (capture)', () => {
107 + it('should consider initial text value to be current (capture)', async () => {
108 let called = 0;
109
110 function cb(e) {
@@ -110,10 +112,14 @@ describe('ChangeEventPlugin', () => {
112 expect(e.type).toBe('change');
113 }
114
113 - const node = ReactDOM.render(
114 - <input type="text" onChangeCapture={cb} defaultValue="foo" />,
115 - container,
116 - );
115 + const root = ReactDOMClient.createRoot(container);
116 + await act(() => {
117 + root.render(
118 + <input type="text" onChangeCapture={cb} defaultValue="foo" />,
119 + );
120 + });
121 +
122 + const node = container.firstChild;
123 node.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
124 node.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
125
@@ -121,7 +127,7 @@ describe('ChangeEventPlugin', () => {
127 expect(called).toBe(0);
128 });
129
124 - it('should not invoke a change event for textarea same value', () => {
130 + it('should not invoke a change event for textarea same value', async () => {
131 let called = 0;
132
133 function cb(e) {
@@ -129,17 +135,19 @@ describe('ChangeEventPlugin', () => {
135 expect(e.type).toBe('change');
136 }
137
132 - const node = ReactDOM.render(
133 - <textarea onChange={cb} defaultValue="initial" />,
134 - container,
135 - );
138 + const root = ReactDOMClient.createRoot(container);
139 + await act(() => {
140 + root.render(<textarea onChange={cb} defaultValue="initial" />);
141 + });
142 +
143 + const node = container.firstChild;
144 node.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
145 node.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
146 // There should be no React change events because the value stayed the same.
147 expect(called).toBe(0);
148 });
149
142 - it('should not invoke a change event for textarea same value (capture)', () => {
150 + it('should not invoke a change event for textarea same value (capture)', async () => {
151 let called = 0;
152
153 function cb(e) {
@@ -147,17 +155,19 @@ describe('ChangeEventPlugin', () => {
155 expect(e.type).toBe('change');
156 }
157
150 - const node = ReactDOM.render(
151 - <textarea onChangeCapture={cb} defaultValue="initial" />,
152 - container,
153 - );
158 + const root = ReactDOMClient.createRoot(container);
159 + await act(() => {
160 + root.render(<textarea onChangeCapture={cb} defaultValue="initial" />);
161 + });
162 +
163 + const node = container.firstChild;
164 node.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
165 node.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
166 // There should be no React change events because the value stayed the same.
167 expect(called).toBe(0);
168 });
169
160 - it('should consider initial checkbox checked=true to be current', () => {
170 + it('should consider initial checkbox checked=true to be current', async () => {
171 let called = 0;
172
173 function cb(e) {
@@ -165,10 +175,14 @@ describe('ChangeEventPlugin', () => {
175 expect(e.type).toBe('change');
176 }
177
168 - const node = ReactDOM.render(
169 - <input type="checkbox" onChange={cb} defaultChecked={true} />,
170 - container,
171 - );
178 + const root = ReactDOMClient.createRoot(container);
179 + await act(() => {
180 + root.render(
181 + <input type="checkbox" onChange={cb} defaultChecked={true} />,
182 + );
183 + });
184 +
185 + const node = container.firstChild;
186
187 // Secretly, set `checked` to false, so that dispatching the `click` will
188 // make it `true` again. Thus, at the time of the event, React should not
@@ -181,7 +195,7 @@ describe('ChangeEventPlugin', () => {
195 expect(called).toBe(0);
196 });
197
184 - it('should consider initial checkbox checked=false to be current', () => {
198 + it('should consider initial checkbox checked=false to be current', async () => {
199 let called = 0;
200
201 function cb(e) {
@@ -189,10 +203,14 @@ describe('ChangeEventPlugin', () => {
203 expect(e.type).toBe('change');
204 }
205
192 - const node = ReactDOM.render(
193 - <input type="checkbox" onChange={cb} defaultChecked={false} />,
194 - container,
195 - );
206 + const root = ReactDOMClient.createRoot(container);
207 + await act(() => {
208 + root.render(
209 + <input type="checkbox" onChange={cb} defaultChecked={false} />,
210 + );
211 + });
212 +
213 + const node = container.firstChild;
214
215 // Secretly, set `checked` to true, so that dispatching the `click` will
216 // make it `false` again. Thus, at the time of the event, React should not
@@ -205,7 +223,7 @@ describe('ChangeEventPlugin', () => {
223 expect(called).toBe(0);
224 });
225
208 - it('should fire change for checkbox input', () => {
226 + it('should fire change for checkbox input', async () => {
227 let called = 0;
228
229 function cb(e) {
@@ -213,10 +231,12 @@ describe('ChangeEventPlugin', () => {
231 expect(e.type).toBe('change');
232 }
233
216 - const node = ReactDOM.render(
217 - <input type="checkbox" onChange={cb} />,
218 - container,
219 - );
234 + const root = ReactDOMClient.createRoot(container);
235 + await act(() => {
236 + root.render(<input type="checkbox" onChange={cb} />);
237 + });
238 +
239 + const node = container.firstChild;
240
241 expect(node.checked).toBe(false);
242 node.dispatchEvent(
@@ -235,7 +255,7 @@ describe('ChangeEventPlugin', () => {
255 expect(called).toBe(2);
256 });
257
238 - it('should not fire change setting the value programmatically', () => {
258 + it('should not fire change setting the value programmatically', async () => {
259 let called = 0;
260
261 function cb(e) {
@@ -243,10 +263,12 @@ describe('ChangeEventPlugin', () => {
263 expect(e.type).toBe('change');
264 }
265
246 - const input = ReactDOM.render(
247 - <input type="text" defaultValue="foo" onChange={cb} />,
248 - container,
249 - );
266 + const root = ReactDOMClient.createRoot(container);
267 + await act(() => {
268 + root.render(<input type="text" defaultValue="foo" onChange={cb} />);
269 + });
270 +
271 + const input = container.firstChild;
272
273 // Set it programmatically.
274 input.value = 'bar';
@@ -271,7 +293,7 @@ describe('ChangeEventPlugin', () => {
293 expect(called).toBe(1);
294 });
295
274 - it('should not distinguish equal string and number values', () => {
296 + it('should not distinguish equal string and number values', async () => {
297 let called = 0;
298
299 function cb(e) {
@@ -279,10 +301,12 @@ describe('ChangeEventPlugin', () => {
301 expect(e.type).toBe('change');
302 }
303
282 - const input = ReactDOM.render(
283 - <input type="text" defaultValue="42" onChange={cb} />,
284 - container,
285 - );
304 + const root = ReactDOMClient.createRoot(container);
305 + await act(() => {
306 + root.render(<input type="text" defaultValue="42" onChange={cb} />);
307 + });
308 +
309 + const input = container.firstChild;
310
311 // When we set `value` as a property, React updates the "current" value
312 // that it tracks internally. The "current" value is later used to determine
@@ -296,7 +320,7 @@ describe('ChangeEventPlugin', () => {
320 });
321
322 // See a similar input test above for a detailed description of why.
299 - it('should not fire change when setting checked programmatically', () => {
323 + it('should not fire change when setting checked programmatically', async () => {
324 let called = 0;
325
326 function cb(e) {
@@ -304,10 +328,14 @@ describe('ChangeEventPlugin', () => {
328 expect(e.type).toBe('change');
329 }
330
307 - const input = ReactDOM.render(
308 - <input type="checkbox" onChange={cb} defaultChecked={false} />,
309 - container,
310 - );
331 + const root = ReactDOMClient.createRoot(container);
332 + await act(() => {
333 + root.render(
334 + <input type="checkbox" onChange={cb} defaultChecked={false} />,
335 + );
336 + });
337 +
338 + const input = container.firstChild;
339
340 // Set the value, updating the "current" value that React tracks to true.
341 input.checked = true;
@@ -326,13 +354,20 @@ describe('ChangeEventPlugin', () => {
354 expect(called).toBe(1);
355 });
356
329 - it('should unmount', () => {
330 - const input = ReactDOM.render(<input />, container);
357 + it('should unmount', async () => {
358 + const root = ReactDOMClient.createRoot(container);
359 + await act(() => {
360 + root.render(<input />);
361 + });
362 +
363 + const input = container.firstChild;
364
332 - ReactDOM.unmountComponentAtNode(container);
365 + await act(() => {
366 + root.unmount();
367 + });
368 });
369
335 - it('should only fire change for checked radio button once', () => {
370 + it('should only fire change for checked radio button once', async () => {
371 let called = 0;
372
373 function cb(e) {
@@ -340,10 +375,12 @@ describe('ChangeEventPlugin', () => {
375 expect(e.type).toBe('change');
376 }
377
343 - const input = ReactDOM.render(
344 - <input type="radio" onChange={cb} />,
345 - container,
346 - );
378 + const root = ReactDOMClient.createRoot(container);
379 + await act(() => {
380 + root.render(<input type="radio" onChange={cb} />);
381 + });
382 +
383 + const input = container.firstChild;
384
385 setUntrackedChecked.call(input, true);
386 input.dispatchEvent(new Event('click', {bubbles: true, cancelable: true}));
@@ -351,7 +388,7 @@ describe('ChangeEventPlugin', () => {
388 expect(called).toBe(1);
389 });
390
354 - it('should track radio button cousins in a group', () => {
391 + it('should track radio button cousins in a group', async () => {
392 let called1 = 0;
393 let called2 = 0;
394
@@ -365,13 +402,17 @@ describe('ChangeEventPlugin', () => {
402 expect(e.type).toBe('change');
403 }
404
368 - const div = ReactDOM.render(
369 - <div>
370 - <input type="radio" name="group" onChange={cb1} />
371 - <input type="radio" name="group" onChange={cb2} />
372 - </div>,
373 - container,
374 - );
405 + const root = ReactDOMClient.createRoot(container);
406 + await act(() => {
407 + root.render(
408 + <div>
409 + <input type="radio" name="group" onChange={cb1} />
410 + <input type="radio" name="group" onChange={cb2} />
411 + </div>,
412 + );
413 + });
414 +
415 + const div = container.firstChild;
416 const option1 = div.childNodes[0];
417 const option2 = div.childNodes[1];
418
@@ -455,7 +496,7 @@ describe('ChangeEventPlugin', () => {
496 });
497 });
498
458 - it('should listen for both change and input events when supported', () => {
499 + it('should listen for both change and input events when supported', async () => {
500 let called = 0;
501
502 function cb(e) {
@@ -463,10 +504,12 @@ describe('ChangeEventPlugin', () => {
504 expect(e.type).toBe('change');
505 }
506
466 - const input = ReactDOM.render(
467 - <input type="range" onChange={cb} />,
468 - container,
469 - );
507 + const root = ReactDOMClient.createRoot(container);
508 + await act(() => {
509 + root.render(<input type="range" onChange={cb} />);
510 + });
511 +
512 + const input = container.firstChild;
513
514 setUntrackedValue.call(input, 10);
515 input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
@@ -477,7 +520,7 @@ describe('ChangeEventPlugin', () => {
520 expect(called).toBe(2);
521 });
522
480 - it('should only fire events when the value changes for range inputs', () => {
523 + it('should only fire events when the value changes for range inputs', async () => {
524 let called = 0;
525
526 function cb(e) {
@@ -485,10 +528,12 @@ describe('ChangeEventPlugin', () => {
528 expect(e.type).toBe('change');
529 }
530
488 - const input = ReactDOM.render(
489 - <input type="range" onChange={cb} />,
490 - container,
491 - );
531 + const root = ReactDOMClient.createRoot(container);
532 + await act(() => {
533 + root.render(<input type="range" onChange={cb} />);
534 + });
535 +
536 + const input = container.firstChild;
537 setUntrackedValue.call(input, '40');
538 input.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
539 input.dispatchEvent(new Event('change', {bubbles: true, cancelable: true}));
@@ -500,7 +545,7 @@ describe('ChangeEventPlugin', () => {
545 expect(called).toBe(2);
546 });
547
503 - it('does not crash for nodes with custom value property', () => {
548 + it('does not crash for nodes with custom value property', async () => {
549 let originalCreateElement;
550 // https://github.com/facebook/react/issues/10196
551 try {
@@ -514,16 +559,25 @@ describe('ChangeEventPlugin', () => {
559 return node;
560 };
561 const div = document.createElement('div');
562 + const root = ReactDOMClient.createRoot(div);
563 // Mount
518 - const node = ReactDOM.render(<input type="text" />, div);
564 + await act(() => {
565 + root.render(<input type="text" />);
566 + });
567 + const node = div.firstChild;
568 // Update
520 - ReactDOM.render(<input type="text" />, div);
569 + await act(() => {
570 + root.render(<input type="text" />);
571 + });
572 +
573 // Change
574 node.dispatchEvent(
575 new Event('change', {bubbles: true, cancelable: true}),
576 );
577 // Unmount
526 - ReactDOM.unmountComponentAtNode(div);
578 + await act(() => {
579 + root.unmount();
580 + });
581 } finally {
582 document.createElement = originalCreateElement;
583 }