@samitouri / QOS-React / commits / 2314227de5

Convert ReactTestUtils to createRoot (#28446)

it'll be removed soon anyway but until then let's unblock moving legacy APIs behind a flag.

Sebastian Silbermann committed Feb 26, 2024 at 21:54 UTC 2314227de55b23e5819f7b96443693df16b5e911
1 file changed +142 -59
packages/react-dom/src/__tests__/ReactTestUtils-test.js
+142 -59
@@ -9,8 +9,9 @@
9
10 'use strict';
11
12 +import {act} from 'internal-test-utils';
13 import * as React from 'react';
13 -import * as ReactDOM from 'react-dom';
14 +import * as ReactDOMClient from 'react-dom/client';
15 import * as ReactDOMServer from 'react-dom/server';
16 import * as ReactTestUtils from 'react-dom/test-utils';
17
@@ -30,7 +31,7 @@ describe('ReactTestUtils', () => {
31 expect(Object.keys(ReactTestUtils.Simulate).sort()).toMatchSnapshot();
32 });
33
33 - it('gives Jest mocks a passthrough implementation with mockComponent()', () => {
34 + it('gives Jest mocks a passthrough implementation with mockComponent()', async () => {
35 class MockedComponent extends React.Component {
36 render() {
37 throw new Error('Should not get here.');
@@ -51,11 +52,15 @@ describe('ReactTestUtils', () => {
52 ReactTestUtils.mockComponent(MockedComponent);
53
54 const container = document.createElement('div');
54 - ReactDOM.render(<MockedComponent>Hello</MockedComponent>, container);
55 + const root = ReactDOMClient.createRoot(container);
56 + await act(() => {
57 + root.render(<MockedComponent>Hello</MockedComponent>);
58 + });
59 +
60 expect(container.textContent).toBe('Hello');
61 });
62
58 - it('can scryRenderedComponentsWithType', () => {
63 + it('can scryRenderedComponentsWithType', async () => {
64 class Child extends React.Component {
65 render() {
66 return null;
@@ -70,7 +75,12 @@ describe('ReactTestUtils', () => {
75 );
76 }
77 }
73 - const renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
78 + const container = document.createElement('div');
79 + const root = ReactDOMClient.createRoot(container);
80 + let renderedComponent;
81 + await act(() => {
82 + root.render(<Wrapper ref={current => (renderedComponent = current)} />);
83 + });
84 const scryResults = ReactTestUtils.scryRenderedComponentsWithType(
85 renderedComponent,
86 Child,
@@ -78,7 +88,7 @@ describe('ReactTestUtils', () => {
88 expect(scryResults.length).toBe(1);
89 });
90
81 - it('can scryRenderedDOMComponentsWithClass with TextComponent', () => {
91 + it('can scryRenderedDOMComponentsWithClass with TextComponent', async () => {
92 class Wrapper extends React.Component {
93 render() {
94 return (
@@ -89,7 +99,12 @@ describe('ReactTestUtils', () => {
99 }
100 }
101
92 - const renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
102 + const container = document.createElement('div');
103 + const root = ReactDOMClient.createRoot(container);
104 + let renderedComponent;
105 + await act(() => {
106 + root.render(<Wrapper ref={current => (renderedComponent = current)} />);
107 + });
108 const scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass(
109 renderedComponent,
110 'NonExistentClass',
@@ -97,7 +112,7 @@ describe('ReactTestUtils', () => {
112 expect(scryResults.length).toBe(0);
113 });
114
100 - it('can scryRenderedDOMComponentsWithClass with className contains \\n', () => {
115 + it('can scryRenderedDOMComponentsWithClass with className contains \\n', async () => {
116 class Wrapper extends React.Component {
117 render() {
118 return (
@@ -108,7 +123,12 @@ describe('ReactTestUtils', () => {
123 }
124 }
125
111 - const renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
126 + const container = document.createElement('div');
127 + const root = ReactDOMClient.createRoot(container);
128 + let renderedComponent;
129 + await act(() => {
130 + root.render(<Wrapper ref={current => (renderedComponent = current)} />);
131 + });
132 const scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass(
133 renderedComponent,
134 'x',
@@ -116,7 +136,7 @@ describe('ReactTestUtils', () => {
136 expect(scryResults.length).toBe(1);
137 });
138
119 - it('can scryRenderedDOMComponentsWithClass with multiple classes', () => {
139 + it('can scryRenderedDOMComponentsWithClass with multiple classes', async () => {
140 class Wrapper extends React.Component {
141 render() {
142 return (
@@ -127,7 +147,12 @@ describe('ReactTestUtils', () => {
147 }
148 }
149
130 - const renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
150 + const container = document.createElement('div');
151 + const root = ReactDOMClient.createRoot(container);
152 + let renderedComponent;
153 + await act(() => {
154 + root.render(<Wrapper ref={current => (renderedComponent = current)} />);
155 + });
156 const scryResults1 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
157 renderedComponent,
158 'x y',
@@ -162,7 +187,7 @@ describe('ReactTestUtils', () => {
187 expect(scryResults5.length).toBe(0);
188 });
189
165 - it('traverses children in the correct order', () => {
190 + it('traverses children in the correct order', async () => {
191 class Wrapper extends React.Component {
192 render() {
193 return <div>{this.props.children}</div>;
@@ -170,25 +195,29 @@ describe('ReactTestUtils', () => {
195 }
196
197 const container = document.createElement('div');
173 - ReactDOM.render(
174 - <Wrapper>
175 - {null}
176 - <div>purple</div>
177 - </Wrapper>,
178 - container,
179 - );
180 - const tree = ReactDOM.render(
181 - <Wrapper>
182 - <div>orange</div>
183 - <div>purple</div>
184 - </Wrapper>,
185 - container,
186 - );
198 + const root = ReactDOMClient.createRoot(container);
199 + await act(() => {
200 + root.render(
201 + <Wrapper>
202 + {null}
203 + <div>purple</div>
204 + </Wrapper>,
205 + );
206 + });
207 + let tree;
208 + await act(() => {
209 + root.render(
210 + <Wrapper ref={current => (tree = current)}>
211 + <div>orange</div>
212 + <div>purple</div>
213 + </Wrapper>,
214 + );
215 + });
216
217 const log = [];
218 ReactTestUtils.findAllInRenderedTree(tree, function (child) {
219 if (ReactTestUtils.isDOMComponent(child)) {
191 - log.push(ReactDOM.findDOMNode(child).textContent);
220 + log.push(child.textContent);
221 }
222 });
223
@@ -196,7 +225,7 @@ describe('ReactTestUtils', () => {
225 expect(log).toEqual(['orangepurple', 'orange', 'purple']);
226 });
227
199 - it('should support injected wrapper components as DOM components', () => {
228 + it('should support injected wrapper components as DOM components', async () => {
229 const injectedDOMComponents = [
230 'button',
231 'form',
@@ -208,13 +237,22 @@ describe('ReactTestUtils', () => {
237 'textarea',
238 ];
239
211 - injectedDOMComponents.forEach(function (type) {
212 - const testComponent = ReactTestUtils.renderIntoDocument(
213 - React.createElement(type),
214 - );
240 + // eslint-disable-next-line no-for-of-loops/no-for-of-loops
241 + for (const type of injectedDOMComponents) {
242 + const container = document.createElement('div');
243 + const root = ReactDOMClient.createRoot(container);
244 + let testComponent;
245 + await act(() => {
246 + root.render(
247 + React.createElement(type, {
248 + ref: current => (testComponent = current),
249 + }),
250 + );
251 + });
252 +
253 expect(testComponent.tagName).toBe(type.toUpperCase());
254 expect(ReactTestUtils.isDOMComponent(testComponent)).toBe(true);
217 - });
255 + }
256
257 // Full-page components (html, head, body) can't be rendered into a div
258 // directly...
@@ -237,7 +275,13 @@ describe('ReactTestUtils', () => {
275
276 const markup = ReactDOMServer.renderToString(<Root />);
277 const testDocument = getTestDocument(markup);
240 - const component = ReactDOM.hydrate(<Root />, testDocument);
278 + let component;
279 + await act(() => {
280 + ReactDOMClient.hydrateRoot(
281 + testDocument,
282 + <Root ref={current => (component = current)} />,
283 + );
284 + });
285
286 expect(component.htmlRef.current.tagName).toBe('HTML');
287 expect(component.headRef.current.tagName).toBe('HEAD');
@@ -247,7 +291,7 @@ describe('ReactTestUtils', () => {
291 expect(ReactTestUtils.isDOMComponent(component.bodyRef.current)).toBe(true);
292 });
293
250 - it('can scry with stateless components involved', () => {
294 + it('can scry with stateless components involved', async () => {
295 const Function = () => (
296 <div>
297 <hr />
@@ -265,7 +309,13 @@ describe('ReactTestUtils', () => {
309 }
310 }
311
268 - const inst = ReactTestUtils.renderIntoDocument(<SomeComponent />);
312 + const container = document.createElement('div');
313 + const root = ReactDOMClient.createRoot(container);
314 + let inst;
315 + await act(() => {
316 + root.render(<SomeComponent ref={current => (inst = current)} />);
317 + });
318 +
319 const hrs = ReactTestUtils.scryRenderedDOMComponentsWithTag(inst, 'hr');
320 expect(hrs.length).toBe(2);
321 });
@@ -327,7 +377,7 @@ describe('ReactTestUtils', () => {
377 });
378
379 describe('Simulate', () => {
330 - it('should change the value of an input field', () => {
380 + it('should change the value of an input field', async () => {
381 const obj = {
382 handler: function (e) {
383 e.persist();
@@ -335,10 +385,11 @@ describe('ReactTestUtils', () => {
385 };
386 spyOnDevAndProd(obj, 'handler');
387 const container = document.createElement('div');
338 - const node = ReactDOM.render(
339 - <input type="text" onChange={obj.handler} />,
340 - container,
341 - );
388 + const root = ReactDOMClient.createRoot(container);
389 + await act(() => {
390 + root.render(<input type="text" onChange={obj.handler} />);
391 + });
392 + const node = container.firstChild;
393
394 node.value = 'giraffe';
395 ReactTestUtils.Simulate.change(node);
@@ -348,7 +399,7 @@ describe('ReactTestUtils', () => {
399 );
400 });
401
351 - it('should change the value of an input field in a component', () => {
402 + it('should change the value of an input field in a component', async () => {
403 class SomeComponent extends React.Component {
404 inputRef = React.createRef();
405 render() {
@@ -371,10 +422,16 @@ describe('ReactTestUtils', () => {
422 };
423 spyOnDevAndProd(obj, 'handler');
424 const container = document.createElement('div');
374 - const instance = ReactDOM.render(
375 - <SomeComponent handleChange={obj.handler} />,
376 - container,
377 - );
425 + const root = ReactDOMClient.createRoot(container);
426 + let instance;
427 + await act(() => {
428 + root.render(
429 + <SomeComponent
430 + handleChange={obj.handler}
431 + ref={current => (instance = current)}
432 + />,
433 + );
434 + });
435
436 const node = instance.inputRef.current;
437 node.value = 'zebra';
@@ -385,27 +442,33 @@ describe('ReactTestUtils', () => {
442 );
443 });
444
388 - it('should not warn when used with extra properties', () => {
445 + it('should not warn when used with extra properties', async () => {
446 const CLIENT_X = 100;
447
448 class Component extends React.Component {
449 + childRef = React.createRef();
450 handleClick = e => {
451 expect(e.clientX).toBe(CLIENT_X);
452 };
453
454 render() {
397 - return <div onClick={this.handleClick} />;
455 + return <div onClick={this.handleClick} ref={this.childRef} />;
456 }
457 }
458
459 const element = document.createElement('div');
402 - const instance = ReactDOM.render(<Component />, element);
403 - ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance), {
460 + const root = ReactDOMClient.createRoot(element);
461 + let instance;
462 + await act(() => {
463 + root.render(<Component ref={current => (instance = current)} />);
464 + });
465 +
466 + ReactTestUtils.Simulate.click(instance.childRef.current, {
467 clientX: CLIENT_X,
468 });
469 });
470
408 - it('should set the type of the event', () => {
471 + it('should set the type of the event', async () => {
472 let event;
473 const stub = jest.fn().mockImplementation(e => {
474 e.persist();
@@ -413,8 +476,11 @@ describe('ReactTestUtils', () => {
476 });
477
478 const container = document.createElement('div');
416 - const instance = ReactDOM.render(<div onKeyDown={stub} />, container);
417 - const node = ReactDOM.findDOMNode(instance);
479 + const root = ReactDOMClient.createRoot(container);
480 + let node;
481 + await act(() => {
482 + root.render(<div onKeyDown={stub} ref={current => (node = current)} />);
483 + });
484
485 ReactTestUtils.Simulate.keyDown(node);
486
@@ -422,7 +488,7 @@ describe('ReactTestUtils', () => {
488 expect(event.nativeEvent.type).toBe('keydown');
489 });
490
425 - it('should work with renderIntoDocument', () => {
491 + it('should work with renderIntoDocument', async () => {
492 const onChange = jest.fn();
493
494 class MyComponent extends React.Component {
@@ -435,7 +501,13 @@ describe('ReactTestUtils', () => {
501 }
502 }
503
438 - const instance = ReactTestUtils.renderIntoDocument(<MyComponent />);
504 + const container = document.createElement('div');
505 + const root = ReactDOMClient.createRoot(container);
506 + let instance;
507 + await act(() => {
508 + root.render(<MyComponent ref={current => (instance = current)} />);
509 + });
510 +
511 const input = ReactTestUtils.findRenderedDOMComponentWithTag(
512 instance,
513 'input',
@@ -449,7 +521,7 @@ describe('ReactTestUtils', () => {
521 });
522 });
523
452 - it('should call setState callback with no arguments', () => {
524 + it('should call setState callback with no arguments', async () => {
525 let mockArgs;
526 class Component extends React.Component {
527 componentDidMount() {
@@ -460,17 +532,28 @@ describe('ReactTestUtils', () => {
532 }
533 }
534
463 - ReactTestUtils.renderIntoDocument(<Component />);
535 + const container = document.createElement('div');
536 + const root = ReactDOMClient.createRoot(container);
537 + await act(() => {
538 + root.render(<Component />);
539 + });
540 +
541 expect(mockArgs.length).toEqual(0);
542 });
466 - it('should find rendered component with type in document', () => {
543 + it('should find rendered component with type in document', async () => {
544 class MyComponent extends React.Component {
545 render() {
546 return true;
547 }
548 }
549
473 - const instance = ReactTestUtils.renderIntoDocument(<MyComponent />);
550 + const container = document.createElement('div');
551 + const root = ReactDOMClient.createRoot(container);
552 + let instance;
553 + await act(() => {
554 + root.render(<MyComponent ref={current => (instance = current)} />);
555 + });
556 +
557 const renderedComponentType = ReactTestUtils.findRenderedComponentWithType(
558 instance,
559 MyComponent,