@samitouri / QOS-React / commits / 4cc8ec64c2

Separate unit tests for ReactFabricHostComponent (#21969)

Timothy Yung committed Jul 26, 2021 at 23:45 UTC 4cc8ec64c2c853146f35ee3c7d072fe23847a006
2 files changed +220 -354
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
-354
@@ -13,14 +13,9 @@
13 let React;
14 let ReactFabric;
15 let createReactNativeComponentClass;
16 -let UIManager;
16 let StrictMode;
18 -let TextInputState;
17 let act;
18
21 -const SET_NATIVE_PROPS_NOT_SUPPORTED_MESSAGE =
22 - 'Warning: setNativeProps is not currently supported in Fabric';
23 -
19 const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT =
20 "Warning: dispatchCommand was called with a ref that isn't a " +
21 'native component. Use React.forwardRef to get access to the underlying native component';
@@ -42,12 +37,8 @@ describe('ReactFabric', () => {
37 React = require('react');
38 StrictMode = React.StrictMode;
39 ReactFabric = require('react-native-renderer/fabric');
45 - UIManager = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
46 - .UIManager;
40 createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
41 .ReactNativeViewConfigRegistry.register;
49 - TextInputState = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
50 - .TextInputState;
42
43 act = require('jest-react').act;
44 });
@@ -227,44 +218,6 @@ describe('ReactFabric', () => {
218 ).toMatchSnapshot();
219 });
220
230 - it('should not call UIManager.updateView from ref.setNativeProps', () => {
231 - const View = createReactNativeComponentClass('RCTView', () => ({
232 - validAttributes: {foo: true},
233 - uiViewClassName: 'RCTView',
234 - }));
235 -
236 - UIManager.updateView.mockReset();
237 -
238 - let viewRef;
239 - act(() => {
240 - ReactFabric.render(
241 - <View
242 - foo="bar"
243 - ref={ref => {
244 - viewRef = ref;
245 - }}
246 - />,
247 - 11,
248 - );
249 - });
250 - expect(UIManager.updateView).not.toBeCalled();
251 -
252 - expect(() => {
253 - viewRef.setNativeProps({});
254 - }).toErrorDev([SET_NATIVE_PROPS_NOT_SUPPORTED_MESSAGE], {
255 - withoutStack: true,
256 - });
257 -
258 - expect(UIManager.updateView).not.toBeCalled();
259 -
260 - expect(() => {
261 - viewRef.setNativeProps({foo: 'baz'});
262 - }).toErrorDev([SET_NATIVE_PROPS_NOT_SUPPORTED_MESSAGE], {
263 - withoutStack: true,
264 - });
265 - expect(UIManager.updateView).not.toBeCalled();
266 - });
267 -
221 it('should call dispatchCommand for native refs', () => {
222 const View = createReactNativeComponentClass('RCTView', () => ({
223 validAttributes: {foo: true},
@@ -386,275 +339,6 @@ describe('ReactFabric', () => {
339 expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
340 });
341
389 - it('should call FabricUIManager.measure on ref.measure', () => {
390 - const View = createReactNativeComponentClass('RCTView', () => ({
391 - validAttributes: {foo: true},
392 - uiViewClassName: 'RCTView',
393 - }));
394 -
395 - nativeFabricUIManager.measure.mockClear();
396 -
397 - let viewRef;
398 - act(() => {
399 - ReactFabric.render(
400 - <View
401 - ref={ref => {
402 - viewRef = ref;
403 - }}
404 - />,
405 - 11,
406 - );
407 - });
408 -
409 - expect(nativeFabricUIManager.measure).not.toBeCalled();
410 - const successCallback = jest.fn();
411 - viewRef.measure(successCallback);
412 - expect(nativeFabricUIManager.measure).toHaveBeenCalledTimes(1);
413 - expect(successCallback).toHaveBeenCalledTimes(1);
414 - expect(successCallback).toHaveBeenCalledWith(10, 10, 100, 100, 0, 0);
415 - });
416 -
417 - it('should no-op if calling measure on unmounted refs', () => {
418 - const View = createReactNativeComponentClass('RCTView', () => ({
419 - validAttributes: {foo: true},
420 - uiViewClassName: 'RCTView',
421 - }));
422 -
423 - nativeFabricUIManager.measure.mockClear();
424 -
425 - let viewRef;
426 - act(() => {
427 - ReactFabric.render(
428 - <View
429 - ref={ref => {
430 - viewRef = ref;
431 - }}
432 - />,
433 - 11,
434 - );
435 - });
436 - const dangerouslyRetainedViewRef = viewRef;
437 - act(() => {
438 - ReactFabric.stopSurface(11);
439 - });
440 -
441 - expect(nativeFabricUIManager.measure).not.toBeCalled();
442 - const successCallback = jest.fn();
443 - dangerouslyRetainedViewRef.measure(successCallback);
444 - expect(nativeFabricUIManager.measure).not.toBeCalled();
445 - expect(successCallback).not.toBeCalled();
446 - });
447 -
448 - it('should call FabricUIManager.measureInWindow on ref.measureInWindow', () => {
449 - const View = createReactNativeComponentClass('RCTView', () => ({
450 - validAttributes: {foo: true},
451 - uiViewClassName: 'RCTView',
452 - }));
453 -
454 - nativeFabricUIManager.measureInWindow.mockClear();
455 -
456 - let viewRef;
457 - act(() => {
458 - ReactFabric.render(
459 - <View
460 - ref={ref => {
461 - viewRef = ref;
462 - }}
463 - />,
464 - 11,
465 - );
466 - });
467 -
468 - expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
469 - const successCallback = jest.fn();
470 - viewRef.measureInWindow(successCallback);
471 - expect(nativeFabricUIManager.measureInWindow).toHaveBeenCalledTimes(1);
472 - expect(successCallback).toHaveBeenCalledTimes(1);
473 - expect(successCallback).toHaveBeenCalledWith(10, 10, 100, 100);
474 - });
475 -
476 - it('should no-op if calling measureInWindow on unmounted refs', () => {
477 - const View = createReactNativeComponentClass('RCTView', () => ({
478 - validAttributes: {foo: true},
479 - uiViewClassName: 'RCTView',
480 - }));
481 -
482 - nativeFabricUIManager.measureInWindow.mockClear();
483 -
484 - let viewRef;
485 - act(() => {
486 - ReactFabric.render(
487 - <View
488 - ref={ref => {
489 - viewRef = ref;
490 - }}
491 - />,
492 - 11,
493 - );
494 - });
495 - const dangerouslyRetainedViewRef = viewRef;
496 - act(() => {
497 - ReactFabric.stopSurface(11);
498 - });
499 -
500 - expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
501 - const successCallback = jest.fn();
502 - dangerouslyRetainedViewRef.measureInWindow(successCallback);
503 - expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
504 - expect(successCallback).not.toBeCalled();
505 - });
506 -
507 - it('should support ref in ref.measureLayout', () => {
508 - const View = createReactNativeComponentClass('RCTView', () => ({
509 - validAttributes: {foo: true},
510 - uiViewClassName: 'RCTView',
511 - }));
512 -
513 - nativeFabricUIManager.measureLayout.mockClear();
514 -
515 - let viewRef;
516 - let otherRef;
517 - act(() => {
518 - ReactFabric.render(
519 - <View>
520 - <View
521 - foo="bar"
522 - ref={ref => {
523 - viewRef = ref;
524 - }}
525 - />
526 - <View
527 - ref={ref => {
528 - otherRef = ref;
529 - }}
530 - />
531 - </View>,
532 - 11,
533 - );
534 - });
535 -
536 - expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
537 - const successCallback = jest.fn();
538 - const failureCallback = jest.fn();
539 - viewRef.measureLayout(otherRef, successCallback, failureCallback);
540 - expect(nativeFabricUIManager.measureLayout).toHaveBeenCalledTimes(1);
541 - expect(successCallback).toHaveBeenCalledTimes(1);
542 - expect(successCallback).toHaveBeenCalledWith(1, 1, 100, 100);
543 - });
544 -
545 - it('should no-op if calling measureLayout on unmounted "from" ref', () => {
546 - const View = createReactNativeComponentClass('RCTView', () => ({
547 - validAttributes: {foo: true},
548 - uiViewClassName: 'RCTView',
549 - }));
550 -
551 - nativeFabricUIManager.measureLayout.mockClear();
552 -
553 - let viewRef;
554 - let otherRef;
555 - act(() => {
556 - ReactFabric.render(
557 - <View>
558 - <View
559 - foo="bar"
560 - ref={ref => {
561 - viewRef = ref;
562 - }}
563 - />
564 - <View
565 - ref={ref => {
566 - otherRef = ref;
567 - }}
568 - />
569 - </View>,
570 - 11,
571 - );
572 - });
573 - const dangerouslyRetainedOtherRef = otherRef;
574 - act(() => {
575 - ReactFabric.render(
576 - <View>
577 - <View
578 - foo="bar"
579 - ref={ref => {
580 - viewRef = ref;
581 - }}
582 - />
583 - {null}
584 - </View>,
585 - 11,
586 - );
587 - });
588 -
589 - expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
590 - const successCallback = jest.fn();
591 - const failureCallback = jest.fn();
592 - viewRef.measureLayout(
593 - dangerouslyRetainedOtherRef,
594 - successCallback,
595 - failureCallback,
596 - );
597 - expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
598 - expect(successCallback).not.toBeCalled();
599 - expect(failureCallback).not.toBeCalled();
600 - });
601 -
602 - it('should no-op if calling measureLayout on unmounted "to" ref', () => {
603 - const View = createReactNativeComponentClass('RCTView', () => ({
604 - validAttributes: {foo: true},
605 - uiViewClassName: 'RCTView',
606 - }));
607 -
608 - nativeFabricUIManager.measureLayout.mockClear();
609 -
610 - let viewRef;
611 - let otherRef;
612 - act(() => {
613 - ReactFabric.render(
614 - <View>
615 - <View
616 - foo="bar"
617 - ref={ref => {
618 - viewRef = ref;
619 - }}
620 - />
621 - <View
622 - ref={ref => {
623 - otherRef = ref;
624 - }}
625 - />
626 - </View>,
627 - 11,
628 - );
629 - });
630 - const dangerouslyRetainedViewRef = viewRef;
631 - act(() => {
632 - ReactFabric.render(
633 - <View>
634 - {null}
635 - <View
636 - ref={ref => {
637 - otherRef = ref;
638 - }}
639 - />
640 - </View>,
641 - 11,
642 - );
643 - });
644 -
645 - expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
646 - const successCallback = jest.fn();
647 - const failureCallback = jest.fn();
648 - dangerouslyRetainedViewRef.measureLayout(
649 - otherRef,
650 - successCallback,
651 - failureCallback,
652 - );
653 - expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
654 - expect(successCallback).not.toBeCalled();
655 - expect(failureCallback).not.toBeCalled();
656 - });
657 -
342 it('returns the correct instance and calls it in the callback', () => {
343 const View = createReactNativeComponentClass('RCTView', () => ({
344 validAttributes: {foo: true},
@@ -1202,44 +886,6 @@ describe('ReactFabric', () => {
886 expect(match).toBe(child._nativeTag);
887 });
888
1205 - it('blur on host component calls TextInputState', () => {
1206 - const View = createReactNativeComponentClass('RCTView', () => ({
1207 - validAttributes: {foo: true},
1208 - uiViewClassName: 'RCTView',
1209 - }));
1210 -
1211 - const viewRef = React.createRef();
1212 - act(() => {
1213 - ReactFabric.render(<View ref={viewRef} />, 11);
1214 - });
1215 -
1216 - expect(TextInputState.blurTextInput).not.toBeCalled();
1217 -
1218 - viewRef.current.blur();
1219 -
1220 - expect(TextInputState.blurTextInput).toHaveBeenCalledTimes(1);
1221 - expect(TextInputState.blurTextInput).toHaveBeenCalledWith(viewRef.current);
1222 - });
1223 -
1224 - it('focus on host component calls TextInputState', () => {
1225 - const View = createReactNativeComponentClass('RCTView', () => ({
1226 - validAttributes: {foo: true},
1227 - uiViewClassName: 'RCTView',
1228 - }));
1229 -
1230 - const viewRef = React.createRef();
1231 - act(() => {
1232 - ReactFabric.render(<View ref={viewRef} />, 11);
1233 - });
1234 -
1235 - expect(TextInputState.focusTextInput).not.toBeCalled();
1236 -
1237 - viewRef.current.focus();
1238 -
1239 - expect(TextInputState.focusTextInput).toHaveBeenCalledTimes(1);
1240 - expect(TextInputState.focusTextInput).toHaveBeenCalledWith(viewRef.current);
1241 - });
1242 -
889 it('should no-op if calling sendAccessibilityEvent on unmounted refs', () => {
890 const View = createReactNativeComponentClass('RCTView', () => ({
891 validAttributes: {foo: true},
packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js new
+220
@@ -0,0 +1,220 @@
1 +/**
2 + * (c) Facebook, Inc. and its affiliates. Confidential and proprietary.
3 + *
4 + * @emails react-core
5 + * @jest-environment node
6 + */
7 +
8 +'use strict';
9 +
10 +import * as React from 'react';
11 +
12 +beforeEach(() => {
13 + jest.resetModules();
14 + jest.restoreAllMocks();
15 +
16 + require('react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager');
17 +});
18 +
19 +/**
20 + * Renders a sequence of mock views as dictated by `keyLists`. The `keyLists`
21 + * argument is an array of arrays which determines the number of render passes,
22 + * how many views will be rendered in each pass, and what the keys are for each
23 + * of the views.
24 + *
25 + * If an element in `keyLists` is null, the entire root will be unmounted.
26 + *
27 + * The return value is an array of arrays with the resulting refs from rendering
28 + * each corresponding array of keys.
29 + *
30 + * If the corresponding array of keys is null, the returned element at that
31 + * index will also be null.
32 + */
33 +function mockRenderKeys(keyLists) {
34 + const ReactFabric = require('react-native-renderer/fabric');
35 + const createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
36 + .ReactNativeViewConfigRegistry.register;
37 + const {act} = require('jest-react');
38 +
39 + const mockContainerTag = 11;
40 + const MockView = createReactNativeComponentClass('RCTMockView', () => ({
41 + validAttributes: {},
42 + uiViewClassName: 'RCTMockView',
43 + }));
44 +
45 + return keyLists.map(keyList => {
46 + if (Array.isArray(keyList)) {
47 + const refs = keyList.map(key => undefined);
48 + act(() => {
49 + ReactFabric.render(
50 + <MockView>
51 + {keyList.map((key, index) => (
52 + <MockView
53 + key={key}
54 + ref={ref => {
55 + refs[index] = ref;
56 + }}
57 + />
58 + ))}
59 + </MockView>,
60 + mockContainerTag,
61 + );
62 + });
63 + // Clone `refs` to ignore future passes.
64 + return [...refs];
65 + }
66 + if (keyList == null) {
67 + act(() => {
68 + ReactFabric.stopSurface(mockContainerTag);
69 + });
70 + return null;
71 + }
72 + throw new TypeError(
73 + `Invalid 'keyLists' element of type ${typeof keyList}.`,
74 + );
75 + });
76 +}
77 +
78 +describe('blur', () => {
79 + test('blur() invokes TextInputState', () => {
80 + const {
81 + TextInputState,
82 + } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
83 +
84 + const [[fooRef]] = mockRenderKeys([['foo']]);
85 +
86 + fooRef.blur();
87 +
88 + expect(TextInputState.blurTextInput.mock.calls).toEqual([[fooRef]]);
89 + });
90 +});
91 +
92 +describe('focus', () => {
93 + test('focus() invokes TextInputState', () => {
94 + const {
95 + TextInputState,
96 + } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
97 +
98 + const [[fooRef]] = mockRenderKeys([['foo']]);
99 +
100 + fooRef.focus();
101 +
102 + expect(TextInputState.focusTextInput.mock.calls).toEqual([[fooRef]]);
103 + });
104 +});
105 +
106 +describe('measure', () => {
107 + test('component.measure(...) invokes callback', () => {
108 + const [[fooRef]] = mockRenderKeys([['foo']]);
109 +
110 + const callback = jest.fn();
111 + fooRef.measure(callback);
112 +
113 + expect(nativeFabricUIManager.measure).toHaveBeenCalledTimes(1);
114 + expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 0, 0]]);
115 + });
116 +
117 + test('unmounted.measure(...) does nothing', () => {
118 + const [[fooRef]] = mockRenderKeys([['foo'], null]);
119 +
120 + const callback = jest.fn();
121 + fooRef.measure(callback);
122 +
123 + expect(nativeFabricUIManager.measure).not.toHaveBeenCalled();
124 + expect(callback).not.toHaveBeenCalled();
125 + });
126 +});
127 +
128 +describe('measureInWindow', () => {
129 + test('component.measureInWindow(...) invokes callback', () => {
130 + const [[fooRef]] = mockRenderKeys([['foo']]);
131 +
132 + const callback = jest.fn();
133 + fooRef.measureInWindow(callback);
134 +
135 + expect(nativeFabricUIManager.measureInWindow).toHaveBeenCalledTimes(1);
136 + expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
137 + });
138 +
139 + test('unmounted.measureInWindow(...) does nothing', () => {
140 + const [[fooRef]] = mockRenderKeys([['foo'], null]);
141 +
142 + const callback = jest.fn();
143 + fooRef.measureInWindow(callback);
144 +
145 + expect(nativeFabricUIManager.measureInWindow).not.toHaveBeenCalled();
146 + expect(callback).not.toHaveBeenCalled();
147 + });
148 +});
149 +
150 +describe('measureLayout', () => {
151 + test('component.measureLayout(component, ...) invokes callback', () => {
152 + const [[fooRef, barRef]] = mockRenderKeys([['foo', 'bar']]);
153 +
154 + const successCallback = jest.fn();
155 + const failureCallback = jest.fn();
156 + fooRef.measureLayout(barRef, successCallback, failureCallback);
157 +
158 + expect(nativeFabricUIManager.measureLayout).toHaveBeenCalledTimes(1);
159 + expect(successCallback.mock.calls).toEqual([[1, 1, 100, 100]]);
160 + });
161 +
162 + test('unmounted.measureLayout(component, ...) does nothing', () => {
163 + const [[fooRef, barRef]] = mockRenderKeys([
164 + ['foo', 'bar'],
165 + ['foo', null],
166 + ]);
167 +
168 + const successCallback = jest.fn();
169 + const failureCallback = jest.fn();
170 + fooRef.measureLayout(barRef, successCallback, failureCallback);
171 +
172 + expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
173 + expect(successCallback).not.toHaveBeenCalled();
174 + });
175 +
176 + test('component.measureLayout(unmounted, ...) does nothing', () => {
177 + const [[fooRef, barRef]] = mockRenderKeys([
178 + ['foo', 'bar'],
179 + [null, 'bar'],
180 + ]);
181 +
182 + const successCallback = jest.fn();
183 + const failureCallback = jest.fn();
184 + fooRef.measureLayout(barRef, successCallback, failureCallback);
185 +
186 + expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
187 + expect(successCallback).not.toHaveBeenCalled();
188 + });
189 +
190 + test('unmounted.measureLayout(unmounted, ...) does nothing', () => {
191 + const [[fooRef, barRef]] = mockRenderKeys([['foo', 'bar'], null]);
192 +
193 + const successCallback = jest.fn();
194 + const failureCallback = jest.fn();
195 + fooRef.measureLayout(barRef, successCallback, failureCallback);
196 +
197 + expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
198 + expect(successCallback).not.toHaveBeenCalled();
199 + });
200 +});
201 +
202 +describe('setNativeProps', () => {
203 + test('setNativeProps(...) emits a warning', () => {
204 + const {
205 + UIManager,
206 + } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
207 +
208 + const [[fooRef]] = mockRenderKeys([['foo']]);
209 +
210 + expect(() => {
211 + fooRef.setNativeProps({});
212 + }).toErrorDev(
213 + ['Warning: setNativeProps is not currently supported in Fabric'],
214 + {
215 + withoutStack: true,
216 + },
217 + );
218 + expect(UIManager.updateView).not.toBeCalled();
219 + });
220 +});