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
});