@office-iss/react-native-win32 0.0.0-canary.256 → 0.0.0-canary.257

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.flowconfig +1 -1
  2. package/CHANGELOG.json +40 -1
  3. package/CHANGELOG.md +20 -8
  4. package/Libraries/Core/ReactNativeVersion.js +1 -1
  5. package/Libraries/Core/setUpTimers.js +19 -0
  6. package/Libraries/LogBox/Data/LogBoxData.js +39 -4
  7. package/Libraries/LogBox/Data/LogBoxLog.js +5 -2
  8. package/Libraries/LogBox/Data/parseLogBoxLog.js +22 -1
  9. package/Libraries/LogBox/LogBox.js +29 -12
  10. package/Libraries/LogBox/LogBoxNotificationContainer.js +4 -0
  11. package/Libraries/LogBox/UI/LogBoxInspector.js +8 -70
  12. package/Libraries/LogBox/UI/LogBoxInspectorBody.js +87 -0
  13. package/Libraries/LogBox/UI/LogBoxInspectorFooter.js +6 -42
  14. package/Libraries/LogBox/UI/LogBoxInspectorFooterButton.js +58 -0
  15. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +5 -66
  16. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +7 -72
  17. package/Libraries/LogBox/UI/LogBoxInspectorHeaderButton.js +76 -0
  18. package/Libraries/LogBox/UI/LogBoxNotification.js +13 -152
  19. package/Libraries/LogBox/UI/LogBoxNotificationCountBadge.js +63 -0
  20. package/Libraries/LogBox/UI/LogBoxNotificationDismissButton.js +67 -0
  21. package/Libraries/LogBox/UI/LogBoxNotificationMessage.js +57 -0
  22. package/Libraries/Renderer/implementations/ReactFabric-dev.js +15690 -26405
  23. package/Libraries/Renderer/implementations/ReactFabric-prod.js +2675 -1630
  24. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +2945 -1682
  25. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +16141 -27018
  26. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +2723 -1666
  27. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +2984 -1737
  28. package/Libraries/Share/Share.d.ts +16 -10
  29. package/Libraries/Share/Share.js +14 -15
  30. package/Libraries/Text/Text.js +25 -20
  31. package/Libraries/Text/Text.win32.js +25 -20
  32. package/Libraries/Text/TextNativeComponent.js +1 -1
  33. package/Libraries/Text/TextNativeComponent.win32.js +1 -1
  34. package/Libraries/Text/TextOptimized.js +538 -0
  35. package/Libraries/Utilities/ReactNativeTestTools.js +7 -24
  36. package/Libraries/__tests__/ButtonWin32-test.js +7 -6
  37. package/Libraries/promiseRejectionTrackingOptions.js +1 -0
  38. package/jest/renderer.js +25 -14
  39. package/jest/setup.js +5 -0
  40. package/overrides.json +5 -5
  41. package/package.json +19 -19
  42. package/src/private/specs/modules/NativeDevSettings.js +1 -0
  43. package/src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks.js +34 -0
@@ -0,0 +1,538 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ import type {PressEvent} from '../Types/CoreEventTypes';
12
+ import type {NativeTextProps} from './TextNativeComponent';
13
+ import type {PressRetentionOffset, TextProps} from './TextProps';
14
+
15
+ import * as PressabilityDebug from '../Pressability/PressabilityDebug';
16
+ import usePressability from '../Pressability/usePressability';
17
+ import flattenStyle from '../StyleSheet/flattenStyle';
18
+ import processColor from '../StyleSheet/processColor';
19
+ import Platform from '../Utilities/Platform';
20
+ import TextAncestor from './TextAncestor';
21
+ import {NativeText, NativeVirtualText} from './TextNativeComponent';
22
+ import * as React from 'react';
23
+ import {useContext, useMemo, useState} from 'react';
24
+
25
+ type TextForwardRef = React.ElementRef<
26
+ typeof NativeText | typeof NativeVirtualText,
27
+ >;
28
+
29
+ /**
30
+ * Text is the fundamental component for displaying text.
31
+ *
32
+ * @see https://reactnative.dev/docs/text
33
+ *
34
+ * NOTE: This file is a short term fork of `Text` for the purpose of performance
35
+ * testing. Any changes to either this component or `Text` should be avoided
36
+ * while this file exists.
37
+ *
38
+ * Specific differences from `Text`:
39
+ * - Lazy init Pressability via a nested component
40
+ * - Skip children context wrapper when safe.
41
+ * - Move props destructuring to function param.
42
+ */
43
+ const TextOptimized: React.AbstractComponent<TextProps, TextForwardRef> =
44
+ React.forwardRef(
45
+ (
46
+ {
47
+ accessible,
48
+ accessibilityLabel,
49
+ accessibilityState,
50
+ allowFontScaling,
51
+ 'aria-busy': ariaBusy,
52
+ 'aria-checked': ariaChecked,
53
+ 'aria-disabled': ariaDisabled,
54
+ 'aria-expanded': ariaExpanded,
55
+ 'aria-label': ariaLabel,
56
+ 'aria-selected': ariaSelected,
57
+ children,
58
+ ellipsizeMode,
59
+ disabled,
60
+ id,
61
+ nativeID,
62
+ numberOfLines,
63
+ onLongPress,
64
+ onPress,
65
+ onPressIn,
66
+ onPressOut,
67
+ onResponderGrant,
68
+ onResponderMove,
69
+ onResponderRelease,
70
+ onResponderTerminate,
71
+ onResponderTerminationRequest,
72
+ onStartShouldSetResponder,
73
+ pressRetentionOffset,
74
+ selectable,
75
+ selectionColor,
76
+ suppressHighlighting,
77
+ style,
78
+ ...restProps
79
+ }: TextProps,
80
+ forwardedRef,
81
+ ) => {
82
+ const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
83
+
84
+ let _accessibilityState: ?TextProps['accessibilityState'] =
85
+ accessibilityState;
86
+ if (
87
+ ariaBusy != null ||
88
+ ariaChecked != null ||
89
+ ariaDisabled != null ||
90
+ ariaExpanded != null ||
91
+ ariaSelected != null
92
+ ) {
93
+ if (_accessibilityState != null) {
94
+ _accessibilityState = {
95
+ busy: ariaBusy ?? _accessibilityState.busy,
96
+ checked: ariaChecked ?? _accessibilityState.checked,
97
+ disabled: ariaDisabled ?? _accessibilityState.disabled,
98
+ expanded: ariaExpanded ?? _accessibilityState.expanded,
99
+ selected: ariaSelected ?? _accessibilityState.selected,
100
+ };
101
+ } else {
102
+ _accessibilityState = {
103
+ busy: ariaBusy,
104
+ checked: ariaChecked,
105
+ disabled: ariaDisabled,
106
+ expanded: ariaExpanded,
107
+ selected: ariaSelected,
108
+ };
109
+ }
110
+ }
111
+
112
+ const _accessibilityStateDisabled = _accessibilityState?.disabled;
113
+ const _disabled = disabled ?? _accessibilityStateDisabled;
114
+
115
+ const isPressable =
116
+ (onPress != null ||
117
+ onLongPress != null ||
118
+ onStartShouldSetResponder != null) &&
119
+ _disabled !== true;
120
+
121
+ // TODO: Move this processing to the view configuration.
122
+ const _selectionColor =
123
+ selectionColor == null ? null : processColor(selectionColor);
124
+
125
+ let _style = style;
126
+ if (__DEV__) {
127
+ if (PressabilityDebug.isEnabled() && onPress != null) {
128
+ _style = [style, {color: 'magenta'}];
129
+ }
130
+ }
131
+
132
+ let _numberOfLines = numberOfLines;
133
+ if (_numberOfLines != null && !(_numberOfLines >= 0)) {
134
+ if (__DEV__) {
135
+ console.error(
136
+ `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
137
+ );
138
+ }
139
+ _numberOfLines = 0;
140
+ }
141
+
142
+ let _selectable = selectable;
143
+
144
+ const processedStyle = flattenStyle(_style);
145
+ if (processedStyle != null) {
146
+ if (typeof processedStyle.fontWeight === 'number') {
147
+ // $FlowFixMe[cannot-write]
148
+ processedStyle.fontWeight = processedStyle.fontWeight.toString();
149
+ }
150
+
151
+ if (processedStyle.userSelect != null) {
152
+ _selectable = userSelectToSelectableMap[processedStyle.userSelect];
153
+ // $FlowFixMe[cannot-write]
154
+ delete processedStyle.userSelect;
155
+ }
156
+
157
+ if (processedStyle.verticalAlign != null) {
158
+ // $FlowFixMe[cannot-write]
159
+ processedStyle.textAlignVertical =
160
+ verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
161
+ // $FlowFixMe[cannot-write]
162
+ delete processedStyle.verticalAlign;
163
+ }
164
+ }
165
+
166
+ const _nativeID = id ?? nativeID;
167
+
168
+ const hasTextAncestor = useContext(TextAncestor);
169
+ if (hasTextAncestor) {
170
+ if (isPressable) {
171
+ return (
172
+ <NativePressableVirtualText
173
+ ref={forwardedRef}
174
+ textProps={{
175
+ ...restProps,
176
+ accessibilityLabel: _accessibilityLabel,
177
+ accessibilityState: _accessibilityState,
178
+ nativeID: _nativeID,
179
+ numberOfLines: _numberOfLines,
180
+ selectable: _selectable,
181
+ selectionColor: _selectionColor,
182
+ style: processedStyle,
183
+ disabled: disabled,
184
+ children,
185
+ }}
186
+ textPressabilityProps={{
187
+ onLongPress,
188
+ onPress,
189
+ onPressIn,
190
+ onPressOut,
191
+ onResponderGrant,
192
+ onResponderMove,
193
+ onResponderRelease,
194
+ onResponderTerminate,
195
+ onResponderTerminationRequest,
196
+ onStartShouldSetResponder,
197
+ pressRetentionOffset,
198
+ suppressHighlighting,
199
+ }}
200
+ />
201
+ );
202
+ }
203
+
204
+ return (
205
+ <NativeVirtualText
206
+ {...restProps}
207
+ accessibilityLabel={_accessibilityLabel}
208
+ accessibilityState={_accessibilityState}
209
+ isHighlighted={false}
210
+ isPressable={false}
211
+ nativeID={_nativeID}
212
+ numberOfLines={_numberOfLines}
213
+ ref={forwardedRef}
214
+ selectable={_selectable}
215
+ selectionColor={_selectionColor}
216
+ style={processedStyle}
217
+ disabled={disabled}>
218
+ {children}
219
+ </NativeVirtualText>
220
+ );
221
+ }
222
+
223
+ // If the disabled prop and accessibilityState.disabled are out of sync but not both in
224
+ // falsy states we need to update the accessibilityState object to use the disabled prop.
225
+ if (
226
+ _disabled !== _accessibilityStateDisabled &&
227
+ ((_disabled != null && _disabled !== false) ||
228
+ (_accessibilityStateDisabled != null &&
229
+ _accessibilityStateDisabled !== false))
230
+ ) {
231
+ _accessibilityState = {..._accessibilityState, disabled: _disabled};
232
+ }
233
+
234
+ const _accessible = Platform.select({
235
+ ios: accessible !== false,
236
+ android:
237
+ accessible == null
238
+ ? onPress != null || onLongPress != null
239
+ : accessible,
240
+ default: accessible,
241
+ });
242
+
243
+ let nativeText = null;
244
+ if (isPressable) {
245
+ nativeText = (
246
+ <NativePressableText
247
+ ref={forwardedRef}
248
+ textProps={{
249
+ ...restProps,
250
+ accessibilityLabel: _accessibilityLabel,
251
+ accessibilityState: _accessibilityState,
252
+ accessible: _accessible,
253
+ allowFontScaling: allowFontScaling !== false,
254
+ disabled: _disabled,
255
+ ellipsizeMode: ellipsizeMode ?? 'tail',
256
+ nativeID: _nativeID,
257
+ numberOfLines: _numberOfLines,
258
+ selectable: _selectable,
259
+ selectionColor: _selectionColor,
260
+ style: processedStyle,
261
+ children,
262
+ }}
263
+ textPressabilityProps={{
264
+ onLongPress,
265
+ onPress,
266
+ onPressIn,
267
+ onPressOut,
268
+ onResponderGrant,
269
+ onResponderMove,
270
+ onResponderRelease,
271
+ onResponderTerminate,
272
+ onResponderTerminationRequest,
273
+ onStartShouldSetResponder,
274
+ pressRetentionOffset,
275
+ suppressHighlighting,
276
+ }}
277
+ />
278
+ );
279
+ } else {
280
+ nativeText = (
281
+ <NativeText
282
+ {...restProps}
283
+ accessibilityLabel={_accessibilityLabel}
284
+ accessibilityState={_accessibilityState}
285
+ accessible={_accessible}
286
+ allowFontScaling={allowFontScaling !== false}
287
+ disabled={_disabled}
288
+ ellipsizeMode={ellipsizeMode ?? 'tail'}
289
+ isHighlighted={false}
290
+ nativeID={_nativeID}
291
+ numberOfLines={_numberOfLines}
292
+ ref={forwardedRef}
293
+ selectable={_selectable}
294
+ selectionColor={_selectionColor}
295
+ style={processedStyle}>
296
+ {children}
297
+ </NativeText>
298
+ );
299
+ }
300
+
301
+ if (children == null) {
302
+ return nativeText;
303
+ }
304
+
305
+ // If the children do not contain a JSX element it would not be possible to have a
306
+ // nested `Text` component so we can skip adding the `TextAncestor` context wrapper
307
+ // which has a performance overhead. Since we do this for performance reasons we need
308
+ // to keep the check simple to avoid regressing overall perf. For this reason the
309
+ // `children.length` constant is set to `3`, this should be a reasonable tradeoff
310
+ // to capture the majority of `Text` uses but also not make this check too expensive.
311
+ if (Array.isArray(children) && children.length <= 3) {
312
+ let hasNonTextChild = false;
313
+ for (let child of children) {
314
+ if (child != null && typeof child === 'object') {
315
+ hasNonTextChild = true;
316
+ break;
317
+ }
318
+ }
319
+ if (!hasNonTextChild) {
320
+ return nativeText;
321
+ }
322
+ } else if (typeof children !== 'object') {
323
+ return nativeText;
324
+ }
325
+
326
+ return (
327
+ <TextAncestor.Provider value={true}>{nativeText}</TextAncestor.Provider>
328
+ );
329
+ },
330
+ );
331
+
332
+ TextOptimized.displayName = 'TextOptimized';
333
+
334
+ type TextPressabilityProps = $ReadOnly<{
335
+ onLongPress?: ?(event: PressEvent) => mixed,
336
+ onPress?: ?(event: PressEvent) => mixed,
337
+ onPressIn?: ?(event: PressEvent) => mixed,
338
+ onPressOut?: ?(event: PressEvent) => mixed,
339
+ onResponderGrant?: ?(event: PressEvent) => void,
340
+ onResponderMove?: ?(event: PressEvent) => void,
341
+ onResponderRelease?: ?(event: PressEvent) => void,
342
+ onResponderTerminate?: ?(event: PressEvent) => void,
343
+ onResponderTerminationRequest?: ?() => boolean,
344
+ onStartShouldSetResponder?: ?() => boolean,
345
+ pressRetentionOffset?: ?PressRetentionOffset,
346
+ suppressHighlighting?: ?boolean,
347
+ }>;
348
+
349
+ /**
350
+ * Hook that handles setting up Pressability of Text components.
351
+ *
352
+ * NOTE: This hook is relatively expensive so it should only be used absolutely necessary.
353
+ */
354
+ function useTextPressability({
355
+ onLongPress,
356
+ onPress,
357
+ onPressIn,
358
+ onPressOut,
359
+ onResponderGrant,
360
+ onResponderMove,
361
+ onResponderRelease,
362
+ onResponderTerminate,
363
+ onResponderTerminationRequest,
364
+ onStartShouldSetResponder,
365
+ pressRetentionOffset,
366
+ suppressHighlighting,
367
+ }: TextPressabilityProps) {
368
+ const [isHighlighted, setHighlighted] = useState(false);
369
+
370
+ // Setup pressability config and wrap callbacks needs to track the highlight state.
371
+ const config = useMemo(() => {
372
+ let _onPressIn = onPressIn;
373
+ let _onPressOut = onPressOut;
374
+
375
+ // Updating isHighlighted causes unnecessary re-renders for platforms that don't use it
376
+ // in the best case, and cause issues with text selection in the worst case. Forcing
377
+ // the isHighlighted prop to false on all platforms except iOS.
378
+ if (Platform.OS === 'ios') {
379
+ _onPressIn = (event: PressEvent) => {
380
+ setHighlighted(suppressHighlighting == null || !suppressHighlighting);
381
+ onPressIn?.(event);
382
+ };
383
+
384
+ _onPressOut = (event: PressEvent) => {
385
+ setHighlighted(false);
386
+ onPressOut?.(event);
387
+ };
388
+ }
389
+
390
+ return {
391
+ disabled: false,
392
+ pressRectOffset: pressRetentionOffset,
393
+ onLongPress,
394
+ onPress,
395
+ onPressIn: _onPressIn,
396
+ onPressOut: _onPressOut,
397
+ };
398
+ }, [
399
+ pressRetentionOffset,
400
+ onLongPress,
401
+ onPress,
402
+ onPressIn,
403
+ onPressOut,
404
+ suppressHighlighting,
405
+ ]);
406
+
407
+ // Init the pressability class
408
+ const eventHandlers = usePressability(config);
409
+
410
+ // Create NativeText event handlers which proxy events to pressability
411
+ const eventHandlersForText = useMemo(
412
+ () =>
413
+ eventHandlers == null
414
+ ? null
415
+ : {
416
+ onResponderGrant(event: PressEvent) {
417
+ eventHandlers.onResponderGrant(event);
418
+ if (onResponderGrant != null) {
419
+ onResponderGrant(event);
420
+ }
421
+ },
422
+ onResponderMove(event: PressEvent) {
423
+ eventHandlers.onResponderMove(event);
424
+ if (onResponderMove != null) {
425
+ onResponderMove(event);
426
+ }
427
+ },
428
+ onResponderRelease(event: PressEvent) {
429
+ eventHandlers.onResponderRelease(event);
430
+ if (onResponderRelease != null) {
431
+ onResponderRelease(event);
432
+ }
433
+ },
434
+ onResponderTerminate(event: PressEvent) {
435
+ eventHandlers.onResponderTerminate(event);
436
+ if (onResponderTerminate != null) {
437
+ onResponderTerminate(event);
438
+ }
439
+ },
440
+ onClick: eventHandlers.onClick,
441
+ onResponderTerminationRequest:
442
+ onResponderTerminationRequest != null
443
+ ? onResponderTerminationRequest
444
+ : eventHandlers.onResponderTerminationRequest,
445
+ onStartShouldSetResponder:
446
+ onStartShouldSetResponder != null
447
+ ? onStartShouldSetResponder
448
+ : eventHandlers.onStartShouldSetResponder,
449
+ },
450
+ [
451
+ eventHandlers,
452
+ onResponderGrant,
453
+ onResponderMove,
454
+ onResponderRelease,
455
+ onResponderTerminate,
456
+ onResponderTerminationRequest,
457
+ onStartShouldSetResponder,
458
+ ],
459
+ );
460
+
461
+ // Return the highlight state and NativeText event handlers
462
+ return useMemo(
463
+ () => [isHighlighted, eventHandlersForText],
464
+ [isHighlighted, eventHandlersForText],
465
+ );
466
+ }
467
+
468
+ type NativePressableTextProps = $ReadOnly<{
469
+ textProps: NativeTextProps,
470
+ textPressabilityProps: TextPressabilityProps,
471
+ }>;
472
+
473
+ /**
474
+ * Wrap the NativeVirtualText component and initialize pressability.
475
+ *
476
+ * This logic is split out from the main Text component to enable the more
477
+ * expensive pressability logic to be only initialized when needed.
478
+ */
479
+ const NativePressableVirtualText: React.AbstractComponent<
480
+ NativePressableTextProps,
481
+ TextForwardRef,
482
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
483
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
484
+ textPressabilityProps,
485
+ );
486
+
487
+ return (
488
+ <NativeVirtualText
489
+ {...textProps}
490
+ {...eventHandlersForText}
491
+ isHighlighted={isHighlighted}
492
+ isPressable={true}
493
+ ref={forwardedRef}
494
+ />
495
+ );
496
+ });
497
+
498
+ /**
499
+ * Wrap the NativeText component and initialize pressability.
500
+ *
501
+ * This logic is split out from the main Text component to enable the more
502
+ * expensive pressability logic to be only initialized when needed.
503
+ */
504
+ const NativePressableText: React.AbstractComponent<
505
+ NativePressableTextProps,
506
+ TextForwardRef,
507
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
508
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
509
+ textPressabilityProps,
510
+ );
511
+
512
+ return (
513
+ <NativeText
514
+ {...textProps}
515
+ {...eventHandlersForText}
516
+ isHighlighted={isHighlighted}
517
+ isPressable={true}
518
+ ref={forwardedRef}
519
+ />
520
+ );
521
+ });
522
+
523
+ const userSelectToSelectableMap = {
524
+ auto: true,
525
+ text: true,
526
+ none: false,
527
+ contain: true,
528
+ all: true,
529
+ };
530
+
531
+ const verticalAlignToTextAlignVerticalMap = {
532
+ auto: 'auto',
533
+ top: 'top',
534
+ bottom: 'bottom',
535
+ middle: 'center',
536
+ };
537
+
538
+ module.exports = TextOptimized;
@@ -20,14 +20,8 @@ const View = require('../Components/View/View');
20
20
  const Text = require('../Text/Text');
21
21
  const {VirtualizedList} = require('@react-native/virtualized-lists');
22
22
  const React = require('react');
23
- const ShallowRenderer = require('react-shallow-renderer');
24
23
  const ReactTestRenderer = require('react-test-renderer');
25
24
 
26
- /* $FlowFixMe[not-a-function] (>=0.125.1 site=react_native_fb) This comment
27
- * suppresses an error found when Flow v0.125.1 was deployed. To see the error,
28
- * delete this comment and run Flow. */
29
- // $FlowFixMe[invalid-constructor]
30
- const shallowRenderer = new ShallowRenderer();
31
25
  export type ReactTestInstance = $PropertyType<ReactTestRendererType, 'root'>;
32
26
  export type Predicate = (node: ReactTestInstance) => boolean;
33
27
  /* $FlowFixMe[value-as-type] (>=0.125.1 site=react_native_fb) This comment
@@ -119,7 +113,7 @@ function expectNoConsoleError() {
119
113
  });
120
114
  }
121
115
 
122
- function expectRendersMatchingSnapshot(
116
+ async function expectRendersMatchingSnapshot(
123
117
  name: string,
124
118
  ComponentProvider: () => React.Element<any>,
125
119
  unmockComponent: () => mixed,
@@ -128,7 +122,9 @@ function expectRendersMatchingSnapshot(
128
122
 
129
123
  jest.resetAllMocks();
130
124
 
131
- instance = ReactTestRenderer.create(<ComponentProvider />);
125
+ await ReactTestRenderer.act(() => {
126
+ instance = ReactTestRenderer.create(<ComponentProvider />);
127
+ });
132
128
  expect(instance).toMatchSnapshot(
133
129
  'should deep render when mocked (please verify output manually)',
134
130
  );
@@ -136,22 +132,9 @@ function expectRendersMatchingSnapshot(
136
132
  jest.resetAllMocks();
137
133
  unmockComponent();
138
134
 
139
- instance = shallowRenderer.render(<ComponentProvider />);
140
- expect(instance).toMatchSnapshot(
141
- `should shallow render as <${name} /> when not mocked`,
142
- );
143
-
144
- jest.resetAllMocks();
145
-
146
- instance = shallowRenderer.render(<ComponentProvider />);
147
- expect(instance).toMatchSnapshot(
148
- `should shallow render as <${name} /> when mocked`,
149
- );
150
-
151
- jest.resetAllMocks();
152
- unmockComponent();
153
-
154
- instance = ReactTestRenderer.create(<ComponentProvider />);
135
+ await ReactTestRenderer.act(() => {
136
+ instance = ReactTestRenderer.create(<ComponentProvider />);
137
+ });
155
138
  expect(instance).toMatchSnapshot(
156
139
  'should deep render when not mocked (please verify output manually)',
157
140
  );
@@ -2,15 +2,16 @@
2
2
  'use strict';
3
3
 
4
4
  const React = require('react');
5
- const ReactTestRenderer = require('react-test-renderer');
5
+ const renderer = require('react-native/jest/renderer');
6
6
 
7
7
  const {ButtonWin32} = require('@office-iss/react-native-win32');
8
8
 
9
9
  describe('ButtonWin32', () => {
10
- it('renders native component', () => {
11
- const component = ReactTestRenderer.create(
12
- <ButtonWin32/>
13
- );
14
- expect(component).toMatchSnapshot();
10
+ it('renders native component', async () => {
11
+ expect(
12
+ await renderer.create(
13
+ <ButtonWin32/>,
14
+ ),
15
+ ).toMatchSnapshot();
15
16
  });
16
17
  });
@@ -52,6 +52,7 @@ let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
52
52
  substitutions: [],
53
53
  },
54
54
  componentStack: [],
55
+ componentStackType: null,
55
56
  stack,
56
57
  category: 'possible_unhandled_promise_rejection',
57
58
  });
package/jest/renderer.js CHANGED
@@ -9,22 +9,33 @@
9
9
  * @oncall react_native
10
10
  */
11
11
 
12
+ import type {ReactTestRenderer} from 'react-test-renderer';
13
+
14
+ import nullthrows from 'nullthrows';
12
15
  import * as React from 'react';
13
- import ShallowRenderer from 'react-shallow-renderer';
14
16
  import TestRenderer from 'react-test-renderer';
15
17
 
16
- const renderer = new ShallowRenderer();
17
-
18
- export const shallow = (Component: React.Element<any>): any => {
19
- const Wrapper = (): React.Element<any> => Component;
20
-
21
- return renderer.render(<Wrapper />);
22
- };
18
+ export async function create(
19
+ Component: React.Element<any>,
20
+ ): Promise<ReactTestRenderer> {
21
+ let component;
22
+ await TestRenderer.act(async () => {
23
+ component = TestRenderer.create(Component);
24
+ });
25
+ return nullthrows(component);
26
+ }
23
27
 
24
- export const shallowRender = (Component: React.Element<any>): any => {
25
- return renderer.render(Component);
26
- };
28
+ export async function unmount(testRenderer: ReactTestRenderer) {
29
+ await TestRenderer.act(async () => {
30
+ testRenderer.unmount();
31
+ });
32
+ }
27
33
 
28
- export const create = (Component: React.Element<any>): any => {
29
- return TestRenderer.create(Component);
30
- };
34
+ export async function update(
35
+ testRenderer: ReactTestRenderer,
36
+ element: React.Element<any>,
37
+ ) {
38
+ await TestRenderer.act(async () => {
39
+ testRenderer.update(element);
40
+ });
41
+ }
package/jest/setup.js CHANGED
@@ -9,6 +9,11 @@
9
9
 
10
10
  'use strict';
11
11
 
12
+ global.IS_REACT_ACT_ENVIRONMENT = true;
13
+ // Suppress the `react-test-renderer` warnings until New Architecture and legacy
14
+ // mode are no longer supported by React Native.
15
+ global.IS_REACT_NATIVE_TEST_ENVIRONMENT = true;
16
+
12
17
  const MockNativeMethods = jest.requireActual('./MockNativeMethods');
13
18
  const mockComponent = jest.requireActual('./mockComponent');
14
19