1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
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
-async function mockRenderKeys(keyLists) {
34
- const ReactFabric = require('react-native-renderer/fabric');
35
- const createReactNativeComponentClass =
36
- require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
37
- .ReactNativeViewConfigRegistry.register;
38
- const act = require('internal-test-utils').act;
39
-
40
- const mockContainerTag = 11;
41
- const MockView = createReactNativeComponentClass('RCTMockView', () => ({
42
- validAttributes: {foo: true},
43
- uiViewClassName: 'RCTMockView',
44
- }));
45
-
46
- const result = [];
47
- for (let i = 0; i < keyLists.length; i++) {
48
- const keyList = keyLists[i];
49
- if (Array.isArray(keyList)) {
50
- const refs = keyList.map(key => undefined);
51
- await act(() => {
52
- ReactFabric.render(
53
- <MockView>
54
- {keyList.map((key, index) => (
55
- <MockView
56
- key={key}
57
- ref={ref => {
58
- refs[index] = ref;
59
- }}
60
- />
61
- ))}
62
- </MockView>,
63
- mockContainerTag,
64
- );
65
- });
66
- // Clone `refs` to ignore future passes.
67
- result.push([...refs]);
68
- continue;
69
- }
70
- if (keyList == null) {
71
- await act(() => {
72
- ReactFabric.stopSurface(mockContainerTag);
73
- });
74
- result.push(null);
75
- continue;
76
- }
77
- throw new TypeError(
78
- `Invalid 'keyLists' element of type ${typeof keyList}.`,
79
- );
80
- }
81
-
82
- return result;
83
-}
84
-
85
-describe('blur', () => {
86
- test('blur() invokes TextInputState', async () => {
87
- const {
88
- TextInputState,
89
- } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
90
-
91
- const [[fooRef]] = await mockRenderKeys([['foo']]);
92
-
93
- fooRef.blur();
94
-
95
- expect(TextInputState.blurTextInput.mock.calls).toEqual([[fooRef]]);
96
- });
97
-});
98
-
99
-describe('focus', () => {
100
- test('focus() invokes TextInputState', async () => {
101
- const {
102
- TextInputState,
103
- } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
104
-
105
- const [[fooRef]] = await mockRenderKeys([['foo']]);
106
-
107
- fooRef.focus();
108
-
109
- expect(TextInputState.focusTextInput.mock.calls).toEqual([[fooRef]]);
110
- });
111
-});
112
-
113
-describe('measure', () => {
114
- test('component.measure(...) invokes callback', async () => {
115
- const [[fooRef]] = await mockRenderKeys([['foo']]);
116
-
117
- const callback = jest.fn();
118
- fooRef.measure(callback);
119
-
120
- expect(nativeFabricUIManager.measure).toHaveBeenCalledTimes(1);
121
- expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 0, 0]]);
122
- });
123
-
124
- test('unmounted.measure(...) does nothing', async () => {
125
- const [[fooRef]] = await mockRenderKeys([['foo'], null]);
126
-
127
- const callback = jest.fn();
128
- fooRef.measure(callback);
129
-
130
- expect(nativeFabricUIManager.measure).not.toHaveBeenCalled();
131
- expect(callback).not.toHaveBeenCalled();
132
- });
133
-});
134
-
135
-describe('measureInWindow', () => {
136
- test('component.measureInWindow(...) invokes callback', async () => {
137
- const [[fooRef]] = await mockRenderKeys([['foo']]);
138
-
139
- const callback = jest.fn();
140
- fooRef.measureInWindow(callback);
141
-
142
- expect(nativeFabricUIManager.measureInWindow).toHaveBeenCalledTimes(1);
143
- expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
144
- });
145
-
146
- test('unmounted.measureInWindow(...) does nothing', async () => {
147
- const [[fooRef]] = await mockRenderKeys([['foo'], null]);
148
-
149
- const callback = jest.fn();
150
- fooRef.measureInWindow(callback);
151
-
152
- expect(nativeFabricUIManager.measureInWindow).not.toHaveBeenCalled();
153
- expect(callback).not.toHaveBeenCalled();
154
- });
155
-});
156
-
157
-describe('measureLayout', () => {
158
- test('component.measureLayout(component, ...) invokes callback', async () => {
159
- const [[fooRef, barRef]] = await mockRenderKeys([['foo', 'bar']]);
160
-
161
- const successCallback = jest.fn();
162
- const failureCallback = jest.fn();
163
- fooRef.measureLayout(barRef, successCallback, failureCallback);
164
-
165
- expect(nativeFabricUIManager.measureLayout).toHaveBeenCalledTimes(1);
166
- expect(successCallback.mock.calls).toEqual([[1, 1, 100, 100]]);
167
- });
168
-
169
- test('unmounted.measureLayout(component, ...) does nothing', async () => {
170
- const [[fooRef, barRef]] = await mockRenderKeys([
171
- ['foo', 'bar'],
172
- ['foo', null],
173
- ]);
174
-
175
- const successCallback = jest.fn();
176
- const failureCallback = jest.fn();
177
- fooRef.measureLayout(barRef, successCallback, failureCallback);
178
-
179
- expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
180
- expect(successCallback).not.toHaveBeenCalled();
181
- });
182
-
183
- test('component.measureLayout(unmounted, ...) does nothing', async () => {
184
- const [[fooRef, barRef]] = await mockRenderKeys([
185
- ['foo', 'bar'],
186
- [null, 'bar'],
187
- ]);
188
-
189
- const successCallback = jest.fn();
190
- const failureCallback = jest.fn();
191
- fooRef.measureLayout(barRef, successCallback, failureCallback);
192
-
193
- expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
194
- expect(successCallback).not.toHaveBeenCalled();
195
- });
196
-
197
- test('unmounted.measureLayout(unmounted, ...) does nothing', async () => {
198
- const [[fooRef, barRef]] = await mockRenderKeys([['foo', 'bar'], null]);
199
-
200
- const successCallback = jest.fn();
201
- const failureCallback = jest.fn();
202
- fooRef.measureLayout(barRef, successCallback, failureCallback);
203
-
204
- expect(nativeFabricUIManager.measureLayout).not.toHaveBeenCalled();
205
- expect(successCallback).not.toHaveBeenCalled();
206
- });
207
-});
208
-
209
-describe('unstable_getBoundingClientRect', () => {
210
- test('component.unstable_getBoundingClientRect() returns DOMRect', async () => {
211
- const [[fooRef]] = await mockRenderKeys([['foo']]);
212
-
213
- const rect = fooRef.unstable_getBoundingClientRect();
214
-
215
- expect(nativeFabricUIManager.getBoundingClientRect).toHaveBeenCalledTimes(
216
- 1,
217
- );
218
- expect(rect.toJSON()).toMatchObject({
219
- x: 10,
220
- y: 10,
221
- width: 100,
222
- height: 100,
223
- });
224
- });
225
-
226
- test('unmounted.unstable_getBoundingClientRect() returns empty DOMRect', async () => {
227
- const [[fooRef]] = await mockRenderKeys([['foo'], null]);
228
-
229
- const rect = fooRef.unstable_getBoundingClientRect();
230
-
231
- expect(nativeFabricUIManager.getBoundingClientRect).not.toHaveBeenCalled();
232
- expect(rect.toJSON()).toMatchObject({x: 0, y: 0, width: 0, height: 0});
233
- });
234
-});
235
-
236
-describe('setNativeProps', () => {
237
- test('setNativeProps(...) invokes setNativeProps on Fabric UIManager', async () => {
238
- const {
239
- UIManager,
240
- } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
241
-
242
- const [[fooRef]] = await mockRenderKeys([['foo']]);
243
- fooRef.setNativeProps({foo: 'baz'});
244
-
245
- expect(UIManager.updateView).not.toBeCalled();
246
- expect(nativeFabricUIManager.setNativeProps).toHaveBeenCalledTimes(1);
247
- });
248
-});