Use `act()` in ReactFabric tests (#21839)
Timothy Yung committed
Jul 8, 2021 at 15:02 UTC
59d3aca68638319c88d685ce22cac76a03cfe493
1 file changed
+274
-188
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+274
-188
@@ -16,6 +16,7 @@ let createReactNativeComponentClass;
16
let UIManager;
17
let StrictMode;
18
let TextInputState;
19
+let act;
20
21
const SET_NATIVE_PROPS_NOT_SUPPORTED_MESSAGE =
22
'Warning: setNativeProps is not currently supported in Fabric';
@@ -47,6 +48,9 @@ describe('ReactFabric', () => {
48
.ReactNativeViewConfigRegistry.register;
49
TextInputState = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
50
.TextInputState;
51
+
52
+ const ReactTestRenderer = require('react-test-renderer');
53
+ act = ReactTestRenderer.act;
54
});
55
56
it('should be able to create and render a native component', () => {
@@ -55,7 +59,9 @@ describe('ReactFabric', () => {
59
uiViewClassName: 'RCTView',
60
}));
61
58
- ReactFabric.render(<View foo="test" />, 1);
62
+ act(() => {
63
+ ReactFabric.render(<View foo="test" />, 1);
64
+ });
65
expect(nativeFabricUIManager.createNode).toBeCalled();
66
expect(nativeFabricUIManager.appendChild).not.toBeCalled();
67
expect(nativeFabricUIManager.completeRoot).toBeCalled();
@@ -71,11 +77,15 @@ describe('ReactFabric', () => {
77
78
nativeFabricUIManager.createNode.mockReturnValue(firstNode);
79
74
- ReactFabric.render(<View foo="foo" />, 11);
80
+ act(() => {
81
+ ReactFabric.render(<View foo="foo" />, 11);
82
+ });
83
84
expect(nativeFabricUIManager.createNode).toHaveBeenCalledTimes(1);
85
78
- ReactFabric.render(<View foo="bar" />, 11);
86
+ act(() => {
87
+ ReactFabric.render(<View foo="bar" />, 11);
88
+ });
89
90
expect(nativeFabricUIManager.createNode).toHaveBeenCalledTimes(1);
91
expect(nativeFabricUIManager.cloneNodeWithNewProps).toHaveBeenCalledTimes(
@@ -97,7 +107,9 @@ describe('ReactFabric', () => {
107
uiViewClassName: 'RCTText',
108
}));
109
100
- ReactFabric.render(<Text foo="a">1</Text>, 11);
110
+ act(() => {
111
+ ReactFabric.render(<Text foo="a">1</Text>, 11);
112
+ });
113
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
114
expect(nativeFabricUIManager.cloneNodeWithNewChildren).not.toBeCalled();
115
expect(nativeFabricUIManager.cloneNodeWithNewProps).not.toBeCalled();
@@ -106,7 +118,9 @@ describe('ReactFabric', () => {
118
).not.toBeCalled();
119
120
// If no properties have changed, we shouldn't call cloneNode.
109
- ReactFabric.render(<Text foo="a">1</Text>, 11);
121
+ act(() => {
122
+ ReactFabric.render(<Text foo="a">1</Text>, 11);
123
+ });
124
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
125
expect(nativeFabricUIManager.cloneNodeWithNewChildren).not.toBeCalled();
126
expect(nativeFabricUIManager.cloneNodeWithNewProps).not.toBeCalled();
@@ -115,7 +129,9 @@ describe('ReactFabric', () => {
129
).not.toBeCalled();
130
131
// Only call cloneNode for the changed property (and not for text).
118
- ReactFabric.render(<Text foo="b">1</Text>, 11);
132
+ act(() => {
133
+ ReactFabric.render(<Text foo="b">1</Text>, 11);
134
+ });
135
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
136
expect(nativeFabricUIManager.cloneNodeWithNewChildren).not.toBeCalled();
137
expect(nativeFabricUIManager.cloneNodeWithNewProps).toHaveBeenCalledTimes(
@@ -126,7 +142,9 @@ describe('ReactFabric', () => {
142
).not.toBeCalled();
143
144
// Only call cloneNode for the changed text (and no other properties).
129
- ReactFabric.render(<Text foo="b">2</Text>, 11);
145
+ act(() => {
146
+ ReactFabric.render(<Text foo="b">2</Text>, 11);
147
+ });
148
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
149
expect(
150
nativeFabricUIManager.cloneNodeWithNewChildren,
@@ -139,7 +157,9 @@ describe('ReactFabric', () => {
157
).not.toBeCalled();
158
159
// Call cloneNode for both changed text and properties.
142
- ReactFabric.render(<Text foo="c">3</Text>, 11);
160
+ act(() => {
161
+ ReactFabric.render(<Text foo="c">3</Text>, 11);
162
+ });
163
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
164
expect(
165
nativeFabricUIManager.cloneNodeWithNewChildren,
@@ -158,12 +178,14 @@ describe('ReactFabric', () => {
178
uiViewClassName: 'RCTText',
179
}));
180
161
- ReactFabric.render(
162
- <Text foo="a" bar="a">
163
- 1
164
- </Text>,
165
- 11,
166
- );
181
+ act(() => {
182
+ ReactFabric.render(
183
+ <Text foo="a" bar="a">
184
+ 1
185
+ </Text>,
186
+ 11,
187
+ );
188
+ });
189
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
190
expect(nativeFabricUIManager.cloneNodeWithNewChildren).not.toBeCalled();
191
expect(nativeFabricUIManager.cloneNodeWithNewProps).not.toBeCalled();
@@ -171,12 +193,14 @@ describe('ReactFabric', () => {
193
nativeFabricUIManager.cloneNodeWithNewChildrenAndProps,
194
).not.toBeCalled();
195
174
- ReactFabric.render(
175
- <Text foo="a" bar="b">
176
- 1
177
- </Text>,
178
- 11,
179
- );
196
+ act(() => {
197
+ ReactFabric.render(
198
+ <Text foo="a" bar="b">
199
+ 1
200
+ </Text>,
201
+ 11,
202
+ );
203
+ });
204
expect(
205
nativeFabricUIManager.cloneNodeWithNewProps.mock.calls[0][1],
206
).toEqual({
@@ -186,12 +210,14 @@ describe('ReactFabric', () => {
210
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
211
).toMatchSnapshot();
212
189
- ReactFabric.render(
190
- <Text foo="b" bar="b">
191
- 2
192
- </Text>,
193
- 11,
194
- );
213
+ act(() => {
214
+ ReactFabric.render(
215
+ <Text foo="b" bar="b">
216
+ 2
217
+ </Text>,
218
+ 11,
219
+ );
220
+ });
221
expect(
222
nativeFabricUIManager.cloneNodeWithNewChildrenAndProps.mock.calls[0][1],
223
).toEqual({
@@ -211,15 +237,17 @@ describe('ReactFabric', () => {
237
UIManager.updateView.mockReset();
238
239
let viewRef;
214
- ReactFabric.render(
215
- <View
216
- foo="bar"
217
- ref={ref => {
218
- viewRef = ref;
219
- }}
220
- />,
221
- 11,
222
- );
240
+ act(() => {
241
+ ReactFabric.render(
242
+ <View
243
+ foo="bar"
244
+ ref={ref => {
245
+ viewRef = ref;
246
+ }}
247
+ />,
248
+ 11,
249
+ );
250
+ });
251
expect(UIManager.updateView).not.toBeCalled();
252
253
expect(() => {
@@ -247,14 +275,16 @@ describe('ReactFabric', () => {
275
nativeFabricUIManager.dispatchCommand.mockClear();
276
277
let viewRef;
250
- ReactFabric.render(
251
- <View
252
- ref={ref => {
253
- viewRef = ref;
254
- }}
255
- />,
256
- 11,
257
- );
278
+ act(() => {
279
+ ReactFabric.render(
280
+ <View
281
+ ref={ref => {
282
+ viewRef = ref;
283
+ }}
284
+ />,
285
+ 11,
286
+ );
287
+ });
288
289
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
290
ReactFabric.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
@@ -274,14 +304,16 @@ describe('ReactFabric', () => {
304
nativeFabricUIManager.dispatchCommand.mockReset();
305
306
let viewRef;
277
- ReactFabric.render(
278
- <BasicClass
279
- ref={ref => {
280
- viewRef = ref;
281
- }}
282
- />,
283
- 11,
284
- );
307
+ act(() => {
308
+ ReactFabric.render(
309
+ <BasicClass
310
+ ref={ref => {
311
+ viewRef = ref;
312
+ }}
313
+ />,
314
+ 11,
315
+ );
316
+ });
317
318
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
319
expect(() => {
@@ -302,14 +334,16 @@ describe('ReactFabric', () => {
334
nativeFabricUIManager.sendAccessibilityEvent.mockClear();
335
336
let viewRef;
305
- ReactFabric.render(
306
- <View
307
- ref={ref => {
308
- viewRef = ref;
309
- }}
310
- />,
311
- 11,
312
- );
337
+ act(() => {
338
+ ReactFabric.render(
339
+ <View
340
+ ref={ref => {
341
+ viewRef = ref;
342
+ }}
343
+ />,
344
+ 11,
345
+ );
346
+ });
347
348
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
349
ReactFabric.sendAccessibilityEvent(viewRef, 'focus');
@@ -332,14 +366,16 @@ describe('ReactFabric', () => {
366
nativeFabricUIManager.sendAccessibilityEvent.mockReset();
367
368
let viewRef;
335
- ReactFabric.render(
336
- <BasicClass
337
- ref={ref => {
338
- viewRef = ref;
339
- }}
340
- />,
341
- 11,
342
- );
369
+ act(() => {
370
+ ReactFabric.render(
371
+ <BasicClass
372
+ ref={ref => {
373
+ viewRef = ref;
374
+ }}
375
+ />,
376
+ 11,
377
+ );
378
+ });
379
380
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
381
expect(() => {
@@ -360,14 +396,16 @@ describe('ReactFabric', () => {
396
nativeFabricUIManager.measure.mockClear();
397
398
let viewRef;
363
- ReactFabric.render(
364
- <View
365
- ref={ref => {
366
- viewRef = ref;
367
- }}
368
- />,
369
- 11,
370
- );
399
+ act(() => {
400
+ ReactFabric.render(
401
+ <View
402
+ ref={ref => {
403
+ viewRef = ref;
404
+ }}
405
+ />,
406
+ 11,
407
+ );
408
+ });
409
410
expect(nativeFabricUIManager.measure).not.toBeCalled();
411
const successCallback = jest.fn();
@@ -386,14 +424,16 @@ describe('ReactFabric', () => {
424
nativeFabricUIManager.measureInWindow.mockClear();
425
426
let viewRef;
389
- ReactFabric.render(
390
- <View
391
- ref={ref => {
392
- viewRef = ref;
393
- }}
394
- />,
395
- 11,
396
- );
427
+ act(() => {
428
+ ReactFabric.render(
429
+ <View
430
+ ref={ref => {
431
+ viewRef = ref;
432
+ }}
433
+ />,
434
+ 11,
435
+ );
436
+ });
437
438
expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
439
const successCallback = jest.fn();
@@ -413,22 +453,24 @@ describe('ReactFabric', () => {
453
454
let viewRef;
455
let otherRef;
416
- ReactFabric.render(
417
- <View>
418
- <View
419
- foo="bar"
420
- ref={ref => {
421
- viewRef = ref;
422
- }}
423
- />
424
- <View
425
- ref={ref => {
426
- otherRef = ref;
427
- }}
428
- />
429
- </View>,
430
- 11,
431
- );
456
+ act(() => {
457
+ ReactFabric.render(
458
+ <View>
459
+ <View
460
+ foo="bar"
461
+ ref={ref => {
462
+ viewRef = ref;
463
+ }}
464
+ />
465
+ <View
466
+ ref={ref => {
467
+ otherRef = ref;
468
+ }}
469
+ />
470
+ </View>,
471
+ 11,
472
+ );
473
+ });
474
475
expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
476
const successCallback = jest.fn();
@@ -483,12 +525,16 @@ describe('ReactFabric', () => {
525
const before = 'abcdefghijklmnopqrst';
526
const after = 'mxhpgwfralkeoivcstzy';
527
486
- ReactFabric.render(<Component chars={before} />, 11);
528
+ act(() => {
529
+ ReactFabric.render(<Component chars={before} />, 11);
530
+ });
531
expect(
532
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
533
).toMatchSnapshot();
534
491
- ReactFabric.render(<Component chars={after} />, 11);
535
+ act(() => {
536
+ ReactFabric.render(<Component chars={after} />, 11);
537
+ });
538
expect(
539
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
540
).toMatchSnapshot();
@@ -521,12 +567,14 @@ describe('ReactFabric', () => {
567
568
const ref = React.createRef();
569
// Wrap in a host node.
524
- ReactFabric.render(
525
- <View>
526
- <Component ref={ref} />
527
- </View>,
528
- 11,
529
- );
570
+ act(() => {
571
+ ReactFabric.render(
572
+ <View>
573
+ <Component ref={ref} />
574
+ </View>,
575
+ 11,
576
+ );
577
+ });
578
expect(
579
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
580
).toMatchSnapshot();
@@ -552,7 +600,9 @@ describe('ReactFabric', () => {
600
}
601
}
602
555
- ReactFabric.render(<Component />, 11);
603
+ act(() => {
604
+ ReactFabric.render(<Component />, 11);
605
+ });
606
expect(mockArgs.length).toEqual(0);
607
});
608
@@ -572,12 +622,14 @@ describe('ReactFabric', () => {
622
);
623
});
624
575
- ReactFabric.render(
576
- <View foo="a">
577
- <View foo="b" />
578
- </View>,
579
- 22,
580
- );
625
+ act(() => {
626
+ ReactFabric.render(
627
+ <View foo="a">
628
+ <View foo="b" />
629
+ </View>,
630
+ 22,
631
+ );
632
+ });
633
expect(snapshots).toMatchSnapshot();
634
});
635
@@ -595,19 +647,23 @@ describe('ReactFabric', () => {
647
uiViewClassName: 'RCTView',
648
}));
649
598
- ReactFabric.render(
599
- <Text>
600
- <View />
601
- </Text>,
602
- 11,
603
- );
650
+ act(() => {
651
+ ReactFabric.render(
652
+ <Text>
653
+ <View />
654
+ </Text>,
655
+ 11,
656
+ );
657
+ });
658
605
- ReactFabric.render(
606
- <Text>
607
- <Image />
608
- </Text>,
609
- 11,
610
- );
659
+ act(() => {
660
+ ReactFabric.render(
661
+ <Text>
662
+ <Image />
663
+ </Text>,
664
+ 11,
665
+ );
666
+ });
667
});
668
669
it('should throw for text not inside of a <Text> ancestor', () => {
@@ -624,18 +680,22 @@ describe('ReactFabric', () => {
680
uiViewClassName: 'RCTView',
681
}));
682
627
- expect(() => ReactFabric.render(<View>this should warn</View>, 11)).toThrow(
628
- 'Text strings must be rendered within a <Text> component.',
629
- );
683
+ expect(() => {
684
+ act(() => {
685
+ ReactFabric.render(<View>this should warn</View>, 11);
686
+ });
687
+ }).toThrow('Text strings must be rendered within a <Text> component.');
688
631
- expect(() =>
632
- ReactFabric.render(
633
- <Text>
634
- <ScrollView>hi hello hi</ScrollView>
635
- </Text>,
636
- 11,
637
- ),
638
- ).toThrow('Text strings must be rendered within a <Text> component.');
689
+ expect(() => {
690
+ act(() => {
691
+ ReactFabric.render(
692
+ <Text>
693
+ <ScrollView>hi hello hi</ScrollView>
694
+ </Text>,
695
+ 11,
696
+ );
697
+ });
698
+ }).toThrow('Text strings must be rendered within a <Text> component.');
699
});
700
701
it('should not throw for text inside of an indirect <Text> ancestor', () => {
@@ -646,12 +706,14 @@ describe('ReactFabric', () => {
706
707
const Indirection = () => 'Hi';
708
649
- ReactFabric.render(
650
- <Text>
651
- <Indirection />
652
- </Text>,
653
- 11,
654
- );
709
+ act(() => {
710
+ ReactFabric.render(
711
+ <Text>
712
+ <Indirection />
713
+ </Text>,
714
+ 11,
715
+ );
716
+ });
717
});
718
719
it('dispatches events to the last committed props', () => {
@@ -668,7 +730,9 @@ describe('ReactFabric', () => {
730
const touchStart = jest.fn();
731
const touchStart2 = jest.fn();
732
671
- ReactFabric.render(<View onTouchStart={touchStart} />, 11);
733
+ act(() => {
734
+ ReactFabric.render(<View onTouchStart={touchStart} />, 11);
735
+ });
736
737
expect(nativeFabricUIManager.createNode.mock.calls.length).toBe(1);
738
expect(nativeFabricUIManager.registerEventHandler.mock.calls.length).toBe(
@@ -698,7 +762,9 @@ describe('ReactFabric', () => {
762
expect(touchStart).toBeCalled();
763
expect(touchStart2).not.toBeCalled();
764
701
- ReactFabric.render(<View onTouchStart={touchStart2} />, 11);
765
+ act(() => {
766
+ ReactFabric.render(<View onTouchStart={touchStart2} />, 11);
767
+ });
768
769
// Intentionally dispatch to the same instanceHandle again.
770
dispatchEvent(instanceHandle, 'topTouchStart', touchEvent);
@@ -742,33 +808,35 @@ describe('ReactFabric', () => {
808
const ref1 = React.createRef();
809
const ref2 = React.createRef();
810
745
- ReactFabric.render(
746
- <View id="parent">
747
- <View
748
- ref={ref1}
749
- id="one"
750
- onResponderStart={event => {
751
- expect(ref1.current).not.toBeNull();
752
- // Check for referential equality
753
- expect(ref1.current).toBe(event.target);
754
- expect(ref1.current).toBe(event.currentTarget);
755
- }}
756
- onStartShouldSetResponder={() => true}
757
- />
758
- <View
759
- ref={ref2}
760
- id="two"
761
- onResponderStart={event => {
762
- expect(ref2.current).not.toBeNull();
763
- // Check for referential equality
764
- expect(ref2.current).toBe(event.target);
765
- expect(ref2.current).toBe(event.currentTarget);
766
- }}
767
- onStartShouldSetResponder={() => true}
768
- />
769
- </View>,
770
- 1,
771
- );
811
+ act(() => {
812
+ ReactFabric.render(
813
+ <View id="parent">
814
+ <View
815
+ ref={ref1}
816
+ id="one"
817
+ onResponderStart={event => {
818
+ expect(ref1.current).not.toBeNull();
819
+ // Check for referential equality
820
+ expect(ref1.current).toBe(event.target);
821
+ expect(ref1.current).toBe(event.currentTarget);
822
+ }}
823
+ onStartShouldSetResponder={() => true}
824
+ />
825
+ <View
826
+ ref={ref2}
827
+ id="two"
828
+ onResponderStart={event => {
829
+ expect(ref2.current).not.toBeNull();
830
+ // Check for referential equality
831
+ expect(ref2.current).toBe(event.target);
832
+ expect(ref2.current).toBe(event.currentTarget);
833
+ }}
834
+ onStartShouldSetResponder={() => true}
835
+ />
836
+ </View>,
837
+ 1,
838
+ );
839
+ });
840
841
const [
842
dispatchEvent,
@@ -823,7 +891,12 @@ describe('ReactFabric', () => {
891
}
892
}
893
826
- ReactFabric.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
894
+ act(() => {
895
+ ReactFabric.render(
896
+ <ContainsStrictModeChild ref={n => (parent = n)} />,
897
+ 11,
898
+ );
899
+ });
900
901
let match;
902
expect(
@@ -855,12 +928,14 @@ describe('ReactFabric', () => {
928
}
929
}
930
858
- ReactFabric.render(
859
- <StrictMode>
860
- <IsInStrictMode ref={n => (parent = n)} />
861
- </StrictMode>,
862
- 11,
863
- );
931
+ act(() => {
932
+ ReactFabric.render(
933
+ <StrictMode>
934
+ <IsInStrictMode ref={n => (parent = n)} />
935
+ </StrictMode>,
936
+ 11,
937
+ );
938
+ });
939
940
let match;
941
expect(
@@ -896,7 +971,12 @@ describe('ReactFabric', () => {
971
}
972
}
973
899
- ReactFabric.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
974
+ act(() => {
975
+ ReactFabric.render(
976
+ <ContainsStrictModeChild ref={n => (parent = n)} />,
977
+ 11,
978
+ );
979
+ });
980
981
let match;
982
expect(() => (match = ReactFabric.findNodeHandle(parent))).toErrorDev([
@@ -926,12 +1006,14 @@ describe('ReactFabric', () => {
1006
}
1007
}
1008
929
- ReactFabric.render(
930
- <StrictMode>
931
- <IsInStrictMode ref={n => (parent = n)} />
932
- </StrictMode>,
933
- 11,
934
- );
1009
+ act(() => {
1010
+ ReactFabric.render(
1011
+ <StrictMode>
1012
+ <IsInStrictMode ref={n => (parent = n)} />
1013
+ </StrictMode>,
1014
+ 11,
1015
+ );
1016
+ });
1017
1018
let match;
1019
expect(() => (match = ReactFabric.findNodeHandle(parent))).toErrorDev([
@@ -953,7 +1035,9 @@ describe('ReactFabric', () => {
1035
}));
1036
1037
const viewRef = React.createRef();
956
- ReactFabric.render(<View ref={viewRef} />, 11);
1038
+ act(() => {
1039
+ ReactFabric.render(<View ref={viewRef} />, 11);
1040
+ });
1041
1042
expect(TextInputState.blurTextInput).not.toBeCalled();
1043
@@ -970,7 +1054,9 @@ describe('ReactFabric', () => {
1054
}));
1055
1056
const viewRef = React.createRef();
973
- ReactFabric.render(<View ref={viewRef} />, 11);
1057
+ act(() => {
1058
+ ReactFabric.render(<View ref={viewRef} />, 11);
1059
+ });
1060
1061
expect(TextInputState.focusTextInput).not.toBeCalled();
1062