@samitouri / QOS-React-1 / commits / 7ab84fb116

Remove usage of ReactTestUtils from ReactFunctionComponent (#28331)

Sebastian Silbermann committed Feb 20, 2024 at 16:50 UTC 7ab84fb1168d14b895fc9569b6b6899a10bfdc78
1 file changed +139 -65
packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
+139 -65
@@ -12,7 +12,6 @@
12 let PropTypes;
13 let React;
14 let ReactDOMClient;
15 -let ReactTestUtils;
15 let act;
16
17 function FunctionComponent(props) {
@@ -26,7 +25,6 @@ describe('ReactFunctionComponent', () => {
25 React = require('react');
26 ReactDOMClient = require('react-dom/client');
27 act = require('internal-test-utils').act;
29 - ReactTestUtils = require('react-dom/test-utils');
28 });
29
30 it('should render stateless component', async () => {
@@ -161,25 +159,33 @@ describe('ReactFunctionComponent', () => {
159 );
160 });
161
164 - it('should not throw when stateless component returns undefined', () => {
162 + it('should not throw when stateless component returns undefined', async () => {
163 function NotAComponent() {}
166 - expect(function () {
167 - ReactTestUtils.renderIntoDocument(
168 - <div>
169 - <NotAComponent />
170 - </div>,
171 - );
172 - }).not.toThrowError();
164 + const container = document.createElement('div');
165 + const root = ReactDOMClient.createRoot(container);
166 + await expect(
167 + act(() => {
168 + root.render(
169 + <div>
170 + <NotAComponent />
171 + </div>,
172 + );
173 + }),
174 + ).resolves.not.toThrowError();
175 });
176
175 - it('should throw on string refs in pure functions', () => {
177 + it('should throw on string refs in pure functions', async () => {
178 function Child() {
179 return <div ref="me" />;
180 }
181
180 - expect(function () {
181 - ReactTestUtils.renderIntoDocument(<Child test="test" />);
182 - }).toThrowError(
182 + const container = document.createElement('div');
183 + const root = ReactDOMClient.createRoot(container);
184 + await expect(
185 + act(() => {
186 + root.render(<Child test="test" />);
187 + }),
188 + ).rejects.toThrowError(
189 __DEV__
190 ? 'Function components cannot have string refs. We recommend using useRef() instead.'
191 : // It happens because we don't save _owner in production for
@@ -193,7 +199,7 @@ describe('ReactFunctionComponent', () => {
199 );
200 });
201
196 - it('should warn when given a string ref', () => {
202 + it('should warn when given a string ref', async () => {
203 function Indirection(props) {
204 return <div>{props.children}</div>;
205 }
@@ -208,9 +214,13 @@ describe('ReactFunctionComponent', () => {
214 }
215 }
216
211 - expect(() =>
212 - ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />),
213 - ).toErrorDev(
217 + await expect(async () => {
218 + const container = document.createElement('div');
219 + const root = ReactDOMClient.createRoot(container);
220 + await act(() => {
221 + root.render(<ParentUsingStringRef />);
222 + });
223 + }).toErrorDev(
224 'Warning: Function components cannot be given refs. ' +
225 'Attempts to access this ref will fail. ' +
226 'Did you mean to use React.forwardRef()?\n\n' +
@@ -223,32 +233,36 @@ describe('ReactFunctionComponent', () => {
233 );
234
235 // No additional warnings should be logged
226 - ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />);
236 + const container = document.createElement('div');
237 + const root = ReactDOMClient.createRoot(container);
238 + await act(() => {
239 + root.render(<ParentUsingStringRef />);
240 + });
241 });
242
229 - it('should warn when given a function ref', () => {
243 + it('should warn when given a function ref and ignore them', async () => {
244 function Indirection(props) {
245 return <div>{props.children}</div>;
246 }
247
248 + const ref = jest.fn();
249 class ParentUsingFunctionRef extends React.Component {
250 render() {
251 return (
252 <Indirection>
238 - <FunctionComponent
239 - name="A"
240 - ref={arg => {
241 - expect(arg).toBe(null);
242 - }}
243 - />
253 + <FunctionComponent name="A" ref={ref} />
254 </Indirection>
255 );
256 }
257 }
258
249 - expect(() =>
250 - ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />),
251 - ).toErrorDev(
259 + await expect(async () => {
260 + const container = document.createElement('div');
261 + const root = ReactDOMClient.createRoot(container);
262 + await act(() => {
263 + root.render(<ParentUsingFunctionRef />);
264 + });
265 + }).toErrorDev(
266 'Warning: Function components cannot be given refs. ' +
267 'Attempts to access this ref will fail. ' +
268 'Did you mean to use React.forwardRef()?\n\n' +
@@ -259,12 +273,17 @@ describe('ReactFunctionComponent', () => {
273 ' in Indirection (at **)\n' +
274 ' in ParentUsingFunctionRef (at **)',
275 );
276 + expect(ref).not.toHaveBeenCalled();
277
278 // No additional warnings should be logged
264 - ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />);
279 + const container = document.createElement('div');
280 + const root = ReactDOMClient.createRoot(container);
281 + await act(() => {
282 + root.render(<ParentUsingFunctionRef />);
283 + });
284 });
285
267 - it('deduplicates ref warnings based on element or owner', () => {
286 + it('deduplicates ref warnings based on element or owner', async () => {
287 // When owner uses JSX, we can use exact line location to dedupe warnings
288 class AnonymousParentUsingJSX extends React.Component {
289 render() {
@@ -274,15 +293,24 @@ describe('ReactFunctionComponent', () => {
293
294 let instance1;
295
277 - expect(() => {
278 - instance1 = ReactTestUtils.renderIntoDocument(
279 - <AnonymousParentUsingJSX />,
280 - );
296 + await expect(async () => {
297 + const container = document.createElement('div');
298 + const root = ReactDOMClient.createRoot(container);
299 +
300 + await act(() => {
301 + root.render(
302 + <AnonymousParentUsingJSX ref={current => (instance1 = current)} />,
303 + );
304 + });
305 }).toErrorDev('Warning: Function components cannot be given refs.');
306 // Should be deduped (offending element is on the same line):
307 instance1.forceUpdate();
308 // Should also be deduped (offending element is on the same line):
285 - ReactTestUtils.renderIntoDocument(<AnonymousParentUsingJSX />);
309 + let container = document.createElement('div');
310 + let root = ReactDOMClient.createRoot(container);
311 + await act(() => {
312 + root.render(<AnonymousParentUsingJSX />);
313 + });
314
315 // When owner doesn't use JSX, and is anonymous, we warn once per internal instance.
316 class AnonymousParentNotUsingJSX extends React.Component {
@@ -295,15 +323,23 @@ describe('ReactFunctionComponent', () => {
323 }
324
325 let instance2;
298 - expect(() => {
299 - instance2 = ReactTestUtils.renderIntoDocument(
300 - <AnonymousParentNotUsingJSX />,
301 - );
326 + await expect(async () => {
327 + container = document.createElement('div');
328 + root = ReactDOMClient.createRoot(container);
329 + await act(() => {
330 + root.render(
331 + <AnonymousParentNotUsingJSX ref={current => (instance2 = current)} />,
332 + );
333 + });
334 }).toErrorDev('Warning: Function components cannot be given refs.');
335 // Should be deduped (same internal instance, no additional warnings)
336 instance2.forceUpdate();
337 // Could not be differentiated (since owner is anonymous and no source location)
306 - ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
338 + container = document.createElement('div');
339 + root = ReactDOMClient.createRoot(container);
340 + await act(() => {
341 + root.render(<AnonymousParentNotUsingJSX />);
342 + });
343
344 // When owner doesn't use JSX, but is named, we warn once per owner name
345 class NamedParentNotUsingJSX extends React.Component {
@@ -315,19 +351,29 @@ describe('ReactFunctionComponent', () => {
351 }
352 }
353 let instance3;
318 - expect(() => {
319 - instance3 = ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
354 + await expect(async () => {
355 + container = document.createElement('div');
356 + root = ReactDOMClient.createRoot(container);
357 + await act(() => {
358 + root.render(
359 + <NamedParentNotUsingJSX ref={current => (instance3 = current)} />,
360 + );
361 + });
362 }).toErrorDev('Warning: Function components cannot be given refs.');
363 // Should be deduped (same owner name, no additional warnings):
364 instance3.forceUpdate();
365 // Should also be deduped (same owner name, no additional warnings):
324 - ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
366 + container = document.createElement('div');
367 + root = ReactDOMClient.createRoot(container);
368 + await act(() => {
369 + root.render(<NamedParentNotUsingJSX />);
370 + });
371 });
372
373 // This guards against a regression caused by clearing the current debug fiber.
374 // https://github.com/facebook/react/issues/10831
375 // @gate !disableLegacyContext || !__DEV__
330 - it('should warn when giving a function ref with context', () => {
376 + it('should warn when giving a function ref with context', async () => {
377 function Child() {
378 return null;
379 }
@@ -349,7 +395,13 @@ describe('ReactFunctionComponent', () => {
395 }
396 }
397
352 - expect(() => ReactTestUtils.renderIntoDocument(<Parent />)).toErrorDev(
398 + await expect(async () => {
399 + const container = document.createElement('div');
400 + const root = ReactDOMClient.createRoot(container);
401 + await act(() => {
402 + root.render(<Parent />);
403 + });
404 + }).toErrorDev(
405 'Warning: Function components cannot be given refs. ' +
406 'Attempts to access this ref will fail. ' +
407 'Did you mean to use React.forwardRef()?\n\n' +
@@ -360,21 +412,18 @@ describe('ReactFunctionComponent', () => {
412 );
413 });
414
363 - it('should provide a null ref', () => {
364 - function Child() {
365 - return <div />;
366 - }
367 -
368 - const comp = ReactTestUtils.renderIntoDocument(<Child />);
369 - expect(comp).toBe(null);
370 - });
371 -
372 - it('should use correct name in key warning', () => {
415 + it('should use correct name in key warning', async () => {
416 function Child() {
417 return <div>{[<span />]}</div>;
418 }
419
377 - expect(() => ReactTestUtils.renderIntoDocument(<Child />)).toErrorDev(
420 + await expect(async () => {
421 + const container = document.createElement('div');
422 + const root = ReactDOMClient.createRoot(container);
423 + await act(() => {
424 + root.render(<Child />);
425 + });
426 + }).toErrorDev(
427 'Each child in a list should have a unique "key" prop.\n\n' +
428 'Check the render method of `Child`.',
429 );
@@ -382,14 +431,21 @@ describe('ReactFunctionComponent', () => {
431
432 // TODO: change this test after we deprecate default props support
433 // for function components
385 - it('should support default props and prop types', () => {
434 + it('should support default props and prop types', async () => {
435 function Child(props) {
436 return <div>{props.test}</div>;
437 }
438 Child.defaultProps = {test: 2};
439 Child.propTypes = {test: PropTypes.string};
440
392 - expect(() => ReactTestUtils.renderIntoDocument(<Child />)).toErrorDev([
441 + await expect(async () => {
442 + const container = document.createElement('div');
443 + const root = ReactDOMClient.createRoot(container);
444 +
445 + await act(() => {
446 + root.render(<Child />);
447 + });
448 + }).toErrorDev([
449 'Warning: Child: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
450 'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
451 'supplied to `Child`, expected `string`.\n' +
@@ -427,7 +483,7 @@ describe('ReactFunctionComponent', () => {
483 expect(el.textContent).toBe('en');
484 });
485
430 - it('should work with arrow functions', () => {
486 + it('should work with arrow functions', async () => {
487 let Child = function () {
488 return <div />;
489 };
@@ -435,20 +491,38 @@ describe('ReactFunctionComponent', () => {
491 // arrow function.
492 Child = Child.bind(this);
493
438 - expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
494 + await expect(async () => {
495 + const container = document.createElement('div');
496 + const root = ReactDOMClient.createRoot(container);
497 + await act(() => {
498 + root.render(<Child />);
499 + });
500 + }).not.toThrow();
501 });
502
441 - it('should allow simple functions to return null', () => {
503 + it('should allow simple functions to return null', async () => {
504 const Child = function () {
505 return null;
506 };
445 - expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
507 + await expect(async () => {
508 + const container = document.createElement('div');
509 + const root = ReactDOMClient.createRoot(container);
510 + await act(() => {
511 + root.render(<Child />);
512 + });
513 + }).not.toThrow();
514 });
515
448 - it('should allow simple functions to return false', () => {
516 + it('should allow simple functions to return false', async () => {
517 function Child() {
518 return false;
519 }
452 - expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
520 + const container = document.createElement('div');
521 + const root = ReactDOMClient.createRoot(container);
522 + await expect(
523 + act(() => {
524 + root.render(<Child />);
525 + }),
526 + ).resolves.not.toThrow();
527 });
528 });