diff --git a/flow-typed/npm/jest.js b/flow-typed/npm/jest.js
index 3a3c56d5550503..4b4bd7d5dfa1e7 100644
--- a/flow-typed/npm/jest.js
+++ b/flow-typed/npm/jest.js
@@ -853,6 +853,10 @@ type JestObjectType = {
* Returns the number of fake timers still left to run.
*/
getTimerCount(): number,
+ /**
+ * Returns the time in ms of the current clock.
+ */
+ now(): number,
/**
* Set the current system time used by fake timers.
* Simulates a user changing the system clock while your program is running.
diff --git a/packages/react-native/jest/MockNativeMethods.js b/packages/react-native/jest/MockNativeMethods.js
index c0917b7f3a74e1..036d529c0b5ee8 100644
--- a/packages/react-native/jest/MockNativeMethods.js
+++ b/packages/react-native/jest/MockNativeMethods.js
@@ -4,11 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @flow strict
* @format
*/
-'use strict';
-
const MockNativeMethods = {
measure: jest.fn(),
measureInWindow: jest.fn(),
@@ -16,6 +15,13 @@ const MockNativeMethods = {
setNativeProps: jest.fn(),
focus: jest.fn(),
blur: jest.fn(),
+} as {
+ measure: () => void,
+ measureInWindow: () => void,
+ measureLayout: () => void,
+ setNativeProps: () => void,
+ focus: () => void,
+ blur: () => void,
};
-module.exports = MockNativeMethods;
+export default MockNativeMethods;
diff --git a/packages/react-native/jest/RefreshControlMock.js b/packages/react-native/jest/RefreshControlMock.js
index dd86060e7f0364..42111b9cbf4c46 100644
--- a/packages/react-native/jest/RefreshControlMock.js
+++ b/packages/react-native/jest/RefreshControlMock.js
@@ -21,10 +21,12 @@ const RCTRefreshControl: HostComponent<{}> = requireNativeComponent<{}>(
export default class RefreshControlMock extends React.Component<{...}> {
static latestRef: ?RefreshControlMock;
+
+ render(): React.Node {
+ return ;
+ }
+
componentDidMount() {
RefreshControlMock.latestRef = this;
}
- render(): React.MixedElement {
- return ;
- }
}
diff --git a/packages/react-native/jest/assetFileTransformer.js b/packages/react-native/jest/assetFileTransformer.js
index c230a46e64c3be..13ec3e3c528111 100644
--- a/packages/react-native/jest/assetFileTransformer.js
+++ b/packages/react-native/jest/assetFileTransformer.js
@@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @noflow
* @format
*/
diff --git a/packages/react-native/jest/local-setup.js b/packages/react-native/jest/local-setup.js
index dc728555fbc9cd..2d33843fe7b3a1 100644
--- a/packages/react-native/jest/local-setup.js
+++ b/packages/react-native/jest/local-setup.js
@@ -4,24 +4,25 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @flow strict-local
* @format
*/
// Global setup for tests local to the react-native repo. This setup is not
// included in the react-native Jest preset.
-'use strict';
-
-require('./setup');
+import './setup';
const consoleError = console.error;
const consoleWarn = console.warn;
+// $FlowIgnore[cannot-write]
console.error = (...args) => {
consoleError(...args);
throw new Error('console.error() was called (see error above)');
};
+// $FlowIgnore[cannot-write]
console.warn = (...args) => {
consoleWarn(...args);
throw new Error('console.warn() was called (see warning above)');
diff --git a/packages/react-native/jest/mockComponent.js b/packages/react-native/jest/mockComponent.js
index db79932447df27..4b63f8c4786796 100644
--- a/packages/react-native/jest/mockComponent.js
+++ b/packages/react-native/jest/mockComponent.js
@@ -4,37 +4,58 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @flow strict
* @format
*/
-'use strict';
+import * as React from 'react';
+import {createElement} from 'react';
-module.exports = (moduleName, instanceMethods, isESModule) => {
- const RealComponent = isESModule
- ? jest.requireActual(moduleName).default
- : jest.requireActual(moduleName);
- const React = require('react');
+type Modulish = T | $ReadOnly<{default: T}>;
+type ModuleDefault = T['default'];
- const SuperClass =
+type TComponentType = React.ComponentType<$ReadOnly<{children?: React.Node}>>;
+
+export default function mockComponent<
+ TComponentModule: Modulish,
+>(
+ moduleName: string,
+ instanceMethods: ?interface {},
+ isESModule: boolean,
+): typeof isESModule extends true
+ ? ModuleDefault
+ : TComponentModule & typeof instanceMethods {
+ const RealComponent: TComponentType = isESModule
+ ? // $FlowIgnore[prop-missing]
+ jest.requireActual(moduleName).default
+ : // $FlowIgnore[incompatible-type]
+ jest.requireActual(moduleName);
+
+ const SuperClass: typeof React.Component<
+ React.ElementProps,
+ > =
typeof RealComponent === 'function' &&
RealComponent.prototype.constructor instanceof React.Component
? RealComponent
: React.Component;
const name =
- RealComponent.displayName ||
- RealComponent.name ||
- (RealComponent.render // handle React.forwardRef
- ? RealComponent.render.displayName || RealComponent.render.name
- : 'Unknown');
+ RealComponent.displayName ??
+ RealComponent.name ??
+ // $FlowFixMe[prop-missing] - Checking for `forwardRef` values.
+ (RealComponent.render == null
+ ? 'Unknown'
+ : // $FlowFixMe[incompatible-use]
+ RealComponent.render.displayName ?? RealComponent.render.name);
const nameWithoutPrefix = name.replace(/^(RCT|RK)/, '');
const Component = class extends SuperClass {
- static displayName = 'Component';
+ static displayName: ?string = 'Component';
- render() {
- const props = Object.assign({}, RealComponent.defaultProps);
+ render(): React.Node {
+ // $FlowIgnore[prop-missing]
+ const props = {...RealComponent.defaultProps};
if (this.props) {
Object.keys(this.props).forEach(prop => {
@@ -49,7 +70,8 @@ module.exports = (moduleName, instanceMethods, isESModule) => {
});
}
- return React.createElement(nameWithoutPrefix, props, this.props.children);
+ // $FlowIgnore[not-a-function]
+ return createElement(nameWithoutPrefix, props, this.props.children);
}
};
@@ -62,13 +84,16 @@ module.exports = (moduleName, instanceMethods, isESModule) => {
Component.displayName = nameWithoutPrefix;
+ // $FlowIgnore[not-an-object]
Object.keys(RealComponent).forEach(classStatic => {
Component[classStatic] = RealComponent[classStatic];
});
if (instanceMethods != null) {
+ // $FlowIgnore[unsafe-object-assign]
Object.assign(Component.prototype, instanceMethods);
}
+ // $FlowIgnore[incompatible-return]
return Component;
-};
+}
diff --git a/packages/react-native/jest/mockModal.js b/packages/react-native/jest/mockModal.js
index 7bdd85932492d0..1b683831e33d8a 100644
--- a/packages/react-native/jest/mockModal.js
+++ b/packages/react-native/jest/mockModal.js
@@ -4,19 +4,21 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
- * @flow strict-local
+ * @flow strict
* @format
*/
-/* eslint-env jest */
+import * as React from 'react';
-'use strict';
-
-const React = require('react');
-
-function mockModal(BaseComponent: $FlowFixMe) {
- class ModalMock extends BaseComponent {
- render(): React.MixedElement | null {
+export default function mockModal(
+ BaseComponent: React.ComponentType<{children?: React.Node}>,
+): React.ComponentType<{
+ ...React.ElementConfig,
+ visible?: ?boolean,
+}> {
+ // $FlowIgnore[incompatible-use]
+ return class ModalMock extends BaseComponent {
+ render(): React.Node {
if (this.props.visible === false) {
return null;
}
@@ -25,8 +27,5 @@ function mockModal(BaseComponent: $FlowFixMe) {
{this.props.children}
);
}
- }
- return ModalMock;
+ };
}
-
-module.exports = (mockModal: $FlowFixMe);
diff --git a/packages/react-native/jest/mockNativeComponent.js b/packages/react-native/jest/mockNativeComponent.js
index ea5dd406f42db6..0e1d5cdbd90c70 100644
--- a/packages/react-native/jest/mockNativeComponent.js
+++ b/packages/react-native/jest/mockNativeComponent.js
@@ -4,31 +4,38 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @flow strict
* @format
*/
-'use strict';
+import type {HostInstance} from '../src/private/types/HostInstance';
-const React = require('react');
-const {createElement} = require('react');
+import * as React from 'react';
+import {createElement} from 'react';
let nativeTag = 1;
-export default viewName => {
- const Component = class extends React.Component {
- _nativeTag = nativeTag++;
+type MockNativeComponent> =
+ component(ref?: ?React.RefSetter, ...props: TProps);
- render() {
+export default function mockNativeComponent<
+ TProps: $ReadOnly<{children?: React.Node}>,
+>(viewName: string): MockNativeComponent {
+ const Component = class extends React.Component {
+ _nativeTag: number = nativeTag++;
+
+ render(): React.Node {
+ // $FlowIgnore[not-a-function]
return createElement(viewName, this.props, this.props.children);
}
// The methods that exist on host components
- blur = jest.fn();
- focus = jest.fn();
- measure = jest.fn();
- measureInWindow = jest.fn();
- measureLayout = jest.fn();
- setNativeProps = jest.fn();
+ blur: () => void = jest.fn();
+ focus: () => void = jest.fn();
+ measure: () => void = jest.fn();
+ measureInWindow: () => void = jest.fn();
+ measureLayout: () => void = jest.fn();
+ setNativeProps: () => void = jest.fn();
};
if (viewName === 'RCTView') {
@@ -38,4 +45,4 @@ export default viewName => {
}
return Component;
-};
+}
diff --git a/packages/react-native/jest/mockScrollView.js b/packages/react-native/jest/mockScrollView.js
index 027f60eaafc1eb..6b7fbc0da273cd 100644
--- a/packages/react-native/jest/mockScrollView.js
+++ b/packages/react-native/jest/mockScrollView.js
@@ -8,19 +8,24 @@
* @format
*/
-/* eslint-env jest */
+import type {ScrollViewNativeProps} from '../Libraries/Components/ScrollView/ScrollViewNativeComponentType';
-'use strict';
+import View from '../Libraries/Components/View/View';
+import requireNativeComponent from '../Libraries/ReactNative/requireNativeComponent';
+import * as React from 'react';
-const View = require('../Libraries/Components/View/View').default;
-const requireNativeComponent =
- require('../Libraries/ReactNative/requireNativeComponent').default;
-const React = require('react');
-const RCTScrollView: $FlowFixMe = requireNativeComponent('RCTScrollView');
+const RCTScrollView =
+ requireNativeComponent('RCTScrollView');
-function mockScrollView(BaseComponent: $FlowFixMe) {
- class ScrollViewMock extends BaseComponent {
- render(): React.MixedElement {
+export default function mockScrollView(
+ BaseComponent: React.ComponentType<{children?: React.Node}>,
+): React.ComponentType<{
+ ...React.ElementConfig,
+ refreshControl?: ?React.MixedElement,
+}> {
+ // $FlowIgnore[incompatible-use]
+ return class ScrollViewMock extends BaseComponent {
+ render(): React.Node {
return (
{this.props.refreshControl}
@@ -28,8 +33,5 @@ function mockScrollView(BaseComponent: $FlowFixMe) {
);
}
- }
- return ScrollViewMock;
+ };
}
-
-module.exports = (mockScrollView: $FlowFixMe);
diff --git a/packages/react-native/jest/react-native-env.js b/packages/react-native/jest/react-native-env.js
index 494bb884ef4582..f4a3a2ad1c9c26 100644
--- a/packages/react-native/jest/react-native-env.js
+++ b/packages/react-native/jest/react-native-env.js
@@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @noflow
* @format
*/
diff --git a/packages/react-native/jest/renderer.js b/packages/react-native/jest/renderer.js
index 4fb889da3f8c77..7098815ea79b64 100644
--- a/packages/react-native/jest/renderer.js
+++ b/packages/react-native/jest/renderer.js
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
- * @flow
+ * @flow strict
* @format
*/
diff --git a/packages/react-native/jest/resolver.js b/packages/react-native/jest/resolver.js
index 31e3a438764a3f..9148a91fa64f9c 100644
--- a/packages/react-native/jest/resolver.js
+++ b/packages/react-native/jest/resolver.js
@@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @noflow
* @format
*/
diff --git a/packages/react-native/jest/setup.js b/packages/react-native/jest/setup.js
index 5b3bab6d161741..b70fee91eb0a80 100644
--- a/packages/react-native/jest/setup.js
+++ b/packages/react-native/jest/setup.js
@@ -4,21 +4,39 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
+ * @flow strict-local
* @format
*/
-'use strict';
+// NOTE: Ideally, these would use `$Exports`, but Flow is struggling to resolve
+// these module specifiers. Also, these are prefixed with `mock_` to workaround
+// Jest's `babel-plugin-jest-hoist` plugin which validates that mock factories
+// only reference local variables. (It is unaware of generic type annotations.)
+import typeof * as mock_TScrollView from '../Libraries/Components/ScrollView/ScrollView';
+import type {ViewProps as mock_ViewProps} from '../Libraries/Components/View/ViewPropTypes';
+import typeof * as mock_TModal from '../Libraries/Modal/Modal';
+import typeof * as mock_TMockComponent from './mockComponent';
+import typeof * as mock_TMockModal from './mockModal';
+import typeof * as mock_TMockNativeComponent from './mockNativeComponent';
+import typeof * as mock_TMockNativeMethods from './MockNativeMethods';
+import typeof * as mock_TMockScrollView from './mockScrollView';
+import typeof * as mock_TRefreshControlMock from './RefreshControlMock';
global.IS_REACT_ACT_ENVIRONMENT = true;
// Suppress the `react-test-renderer` warnings until New Architecture and legacy
// mode are no longer supported by React Native.
global.IS_REACT_NATIVE_TEST_ENVIRONMENT = true;
-const MockNativeMethods = jest.requireActual('./MockNativeMethods');
-const mockComponent = jest.requireActual('./mockComponent');
+jest.requireActual('@react-native/js-polyfills/error-guard');
-jest.requireActual('@react-native/js-polyfills/error-guard');
+/**
+ * @see https://jestjs.io/docs/jest-object#jestmockmodulename-factory-options
+ */
+function mockESModule(exports: T): {__esModule: true, ...T} {
+ return {__esModule: true, ...exports};
+}
+// $FlowIgnore[cannot-write]
Object.defineProperties(global, {
__DEV__: {
configurable: true,
@@ -29,7 +47,9 @@ Object.defineProperties(global, {
cancelAnimationFrame: {
configurable: true,
enumerable: true,
- value: id => clearTimeout(id),
+ value(id: TimeoutID): void {
+ return clearTimeout(id);
+ },
writable: true,
},
nativeFabricUIManager: {
@@ -42,6 +62,7 @@ Object.defineProperties(global, {
configurable: true,
enumerable: true,
value: {
+ // $FlowIgnore[method-unbinding]
now: jest.fn(Date.now),
},
writable: true,
@@ -49,13 +70,16 @@ Object.defineProperties(global, {
regeneratorRuntime: {
configurable: true,
enumerable: true,
- value: jest.requireActual('regenerator-runtime/runtime'),
+ value: jest.requireActual('regenerator-runtime/runtime'),
writable: true,
},
requestAnimationFrame: {
configurable: true,
enumerable: true,
- value: callback => setTimeout(() => callback(jest.now()), 0),
+ value(callback: number => void): TimeoutID {
+ // $FlowFixMe[prop-missing] - JestObjectType is incomplete.
+ return setTimeout(() => callback(jest.now()), 0);
+ },
writable: true,
},
window: {
@@ -69,142 +93,184 @@ Object.defineProperties(global, {
jest
.mock('../Libraries/Core/InitializeCore', () => {})
.mock('../Libraries/Core/NativeExceptionsManager')
- .mock('../Libraries/ReactNative/UIManager', () => ({
- __esModule: true,
- default: {
- AndroidViewPager: {
- Commands: {
- setPage: jest.fn(),
- setPageWithoutAnimation: jest.fn(),
+ .mock('../Libraries/ReactNative/UIManager', () =>
+ mockESModule({
+ default: {
+ AndroidViewPager: {
+ Commands: {
+ setPage: jest.fn(),
+ setPageWithoutAnimation: jest.fn(),
+ },
},
- },
- blur: jest.fn(),
- createView: jest.fn(),
- customBubblingEventTypes: {},
- customDirectEventTypes: {},
- dispatchViewManagerCommand: jest.fn(),
- focus: jest.fn(),
- getViewManagerConfig: jest.fn(name => {
- if (name === 'AndroidDrawerLayout') {
- return {
- Constants: {
- DrawerPosition: {
- Left: 10,
+ blur: jest.fn(),
+ createView: jest.fn(),
+ customBubblingEventTypes: {},
+ customDirectEventTypes: {},
+ dispatchViewManagerCommand: jest.fn(),
+ focus: jest.fn(),
+ getViewManagerConfig: jest.fn(name => {
+ if (name === 'AndroidDrawerLayout') {
+ return {
+ Constants: {
+ DrawerPosition: {
+ Left: 10,
+ },
},
+ };
+ }
+ }),
+ hasViewManagerConfig: jest.fn(name => {
+ return name === 'AndroidDrawerLayout';
+ }),
+ measure: jest.fn(),
+ manageChildren: jest.fn(),
+ setChildren: jest.fn(),
+ updateView: jest.fn(),
+ AndroidDrawerLayout: {
+ Constants: {
+ DrawerPosition: {
+ Left: 10,
},
- };
- }
- }),
- hasViewManagerConfig: jest.fn(name => {
- return name === 'AndroidDrawerLayout';
- }),
- measure: jest.fn(),
- manageChildren: jest.fn(),
- setChildren: jest.fn(),
- updateView: jest.fn(),
- AndroidDrawerLayout: {
- Constants: {
- DrawerPosition: {
- Left: 10,
},
},
+ AndroidTextInput: {
+ Commands: {},
+ },
+ ScrollView: {
+ Constants: {},
+ },
+ View: {
+ Constants: {},
+ },
},
- AndroidTextInput: {
- Commands: {},
- },
- ScrollView: {
- Constants: {},
- },
- View: {
- Constants: {},
- },
- },
- }))
- .mock('../Libraries/Image/Image', () => ({
- __esModule: true,
- default: mockComponent(
- '../Libraries/Image/Image',
- /* instanceMethods */ null,
- /* isESModule */ true,
- ),
- }))
- .mock('../Libraries/Text/Text', () => ({
- __esModule: true,
- default: mockComponent(
- '../Libraries/Text/Text',
- MockNativeMethods,
- /* isESModule */ true,
- ),
- }))
- .mock('../Libraries/Components/TextInput/TextInput', () => ({
- __esModule: true,
- default: mockComponent(
- '../Libraries/Components/TextInput/TextInput',
- /* instanceMethods */ {
- ...MockNativeMethods,
- isFocused: jest.fn(),
- clear: jest.fn(),
- getNativeRef: jest.fn(),
- },
- /* isESModule */ true,
- ),
- }))
+ }),
+ )
+ .mock('../Libraries/Image/Image', () => {
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+ return mockESModule({
+ default: mockComponent(
+ '../Libraries/Image/Image',
+ /* instanceMethods */ null,
+ /* isESModule */ true,
+ ),
+ });
+ })
+ .mock('../Libraries/Text/Text', () => {
+ const MockNativeMethods = jest.requireActual(
+ './MockNativeMethods',
+ ).default;
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+
+ return mockESModule({
+ default: mockComponent(
+ '../Libraries/Text/Text',
+ MockNativeMethods,
+ /* isESModule */ true,
+ ),
+ });
+ })
+ .mock('../Libraries/Components/TextInput/TextInput', () => {
+ const MockNativeMethods = jest.requireActual(
+ './MockNativeMethods',
+ ).default;
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+
+ return mockESModule({
+ default: mockComponent(
+ '../Libraries/Components/TextInput/TextInput',
+ /* instanceMethods */ {
+ ...MockNativeMethods,
+ isFocused: jest.fn(),
+ clear: jest.fn(),
+ getNativeRef: jest.fn(),
+ },
+ /* isESModule */ true,
+ ),
+ });
+ })
.mock('../Libraries/Modal/Modal', () => {
- const baseComponent = mockComponent(
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+ const mockModal =
+ jest.requireActual('./mockModal').default;
+
+ const baseComponent = mockComponent(
'../Libraries/Modal/Modal',
/* instanceMethods */ null,
/* isESModule */ true,
);
- const mockModal = jest.requireActual('./mockModal');
- return {
- __esModule: true,
+
+ return mockESModule({
default: mockModal(baseComponent),
- };
+ });
})
- .mock('../Libraries/Components/View/View', () => ({
- __esModule: true,
- default: mockComponent(
- '../Libraries/Components/View/View',
- /* instanceMethods */ MockNativeMethods,
- /* isESModule */ true,
- ),
- }))
- .mock('../Libraries/Components/AccessibilityInfo/AccessibilityInfo', () => ({
- __esModule: true,
- default: {
- addEventListener: jest.fn(() => ({
- remove: jest.fn(),
- })),
- announceForAccessibility: jest.fn(),
- announceForAccessibilityWithOptions: jest.fn(),
- isAccessibilityServiceEnabled: jest.fn(() => Promise.resolve(false)),
- isBoldTextEnabled: jest.fn(() => Promise.resolve(false)),
- isGrayscaleEnabled: jest.fn(() => Promise.resolve(false)),
- isInvertColorsEnabled: jest.fn(() => Promise.resolve(false)),
- isReduceMotionEnabled: jest.fn(() => Promise.resolve(false)),
- isHighTextContrastEnabled: jest.fn(() => Promise.resolve(false)),
- isDarkerSystemColorsEnabled: jest.fn(() => Promise.resolve(false)),
- prefersCrossFadeTransitions: jest.fn(() => Promise.resolve(false)),
- isReduceTransparencyEnabled: jest.fn(() => Promise.resolve(false)),
- isScreenReaderEnabled: jest.fn(() => Promise.resolve(false)),
- setAccessibilityFocus: jest.fn(),
- sendAccessibilityEvent: jest.fn(),
- getRecommendedTimeoutMillis: jest.fn(() => Promise.resolve(false)),
- },
- }))
- .mock('../Libraries/Components/Clipboard/Clipboard', () => ({
- __esModule: true,
- default: {
- getString: jest.fn(() => ''),
- setString: jest.fn(),
- },
- }))
- .mock('../Libraries/Components/RefreshControl/RefreshControl', () => ({
- __esModule: true,
- default: jest.requireActual('./RefreshControlMock').default,
- }))
+ .mock('../Libraries/Components/View/View', () => {
+ const MockNativeMethods = jest.requireActual(
+ './MockNativeMethods',
+ ).default;
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+
+ return mockESModule({
+ default: mockComponent(
+ '../Libraries/Components/View/View',
+ /* instanceMethods */ MockNativeMethods,
+ /* isESModule */ true,
+ ),
+ });
+ })
+ .mock('../Libraries/Components/AccessibilityInfo/AccessibilityInfo', () =>
+ mockESModule({
+ default: {
+ addEventListener: jest.fn(() => ({
+ remove: jest.fn(),
+ })),
+ announceForAccessibility: jest.fn(),
+ announceForAccessibilityWithOptions: jest.fn(),
+ isAccessibilityServiceEnabled: jest.fn(() => Promise.resolve(false)),
+ isBoldTextEnabled: jest.fn(() => Promise.resolve(false)),
+ isGrayscaleEnabled: jest.fn(() => Promise.resolve(false)),
+ isInvertColorsEnabled: jest.fn(() => Promise.resolve(false)),
+ isReduceMotionEnabled: jest.fn(() => Promise.resolve(false)),
+ isHighTextContrastEnabled: jest.fn(() => Promise.resolve(false)),
+ isDarkerSystemColorsEnabled: jest.fn(() => Promise.resolve(false)),
+ prefersCrossFadeTransitions: jest.fn(() => Promise.resolve(false)),
+ isReduceTransparencyEnabled: jest.fn(() => Promise.resolve(false)),
+ isScreenReaderEnabled: jest.fn(() => Promise.resolve(false)),
+ setAccessibilityFocus: jest.fn(),
+ sendAccessibilityEvent: jest.fn(),
+ getRecommendedTimeoutMillis: jest.fn(() => Promise.resolve(false)),
+ },
+ }),
+ )
+ .mock('../Libraries/Components/Clipboard/Clipboard', () =>
+ mockESModule({
+ default: {
+ getString: jest.fn(() => ''),
+ setString: jest.fn(),
+ },
+ }),
+ )
+ .mock('../Libraries/Components/RefreshControl/RefreshControl', () =>
+ mockESModule({
+ default: jest.requireActual(
+ './RefreshControlMock',
+ ).default,
+ }),
+ )
.mock('../Libraries/Components/ScrollView/ScrollView', () => {
- const baseComponent = mockComponent(
+ const MockNativeMethods = jest.requireActual(
+ './MockNativeMethods',
+ ).default;
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+ const mockScrollView =
+ jest.requireActual('./mockScrollView').default;
+
+ const baseComponent = mockComponent(
'../Libraries/Components/ScrollView/ScrollView',
{
...MockNativeMethods,
@@ -221,274 +287,298 @@ jest
},
true, // isESModule
);
- const mockScrollView = jest.requireActual('./mockScrollView');
- return {
- __esModule: true,
+
+ return mockESModule({
default: mockScrollView(baseComponent),
- };
+ });
})
- .mock('../Libraries/Components/ActivityIndicator/ActivityIndicator', () => ({
- __esModule: true,
- default: mockComponent(
- '../Libraries/Components/ActivityIndicator/ActivityIndicator',
- null, // instanceMethods
- true, // isESModule
- ),
- }))
- .mock('../Libraries/AppState/AppState', () => ({
- __esModule: true,
- default: {
- addEventListener: jest.fn(() => ({
- remove: jest.fn(),
- })),
- removeEventListener: jest.fn(),
- currentState: jest.fn(),
- },
- }))
- .mock('../Libraries/Linking/Linking', () => ({
- __esModule: true,
- default: {
- openURL: jest.fn(),
- canOpenURL: jest.fn(() => Promise.resolve(true)),
- openSettings: jest.fn(),
- addEventListener: jest.fn(() => ({
- remove: jest.fn(),
- })),
- getInitialURL: jest.fn(() => Promise.resolve()),
- sendIntent: jest.fn(),
- },
- }))
- // Mock modules defined by the native layer (ex: Objective-C, Java)
- .mock('../Libraries/BatchedBridge/NativeModules', () => ({
- __esModule: true,
- default: {
- AlertManager: {
- alertWithArgs: jest.fn(),
+ .mock('../Libraries/Components/ActivityIndicator/ActivityIndicator', () => {
+ const mockComponent =
+ jest.requireActual('./mockComponent').default;
+ return mockESModule({
+ default: mockComponent(
+ '../Libraries/Components/ActivityIndicator/ActivityIndicator',
+ null, // instanceMethods
+ true, // isESModule
+ ),
+ });
+ })
+ .mock('../Libraries/AppState/AppState', () =>
+ mockESModule({
+ default: {
+ addEventListener: jest.fn(() => ({
+ remove: jest.fn(),
+ })),
+ removeEventListener: jest.fn(),
+ currentState: jest.fn(),
},
- AsyncLocalStorage: {
- multiGet: jest.fn((keys, callback) =>
- process.nextTick(() => callback(null, [])),
- ),
- multiSet: jest.fn((entries, callback) =>
- process.nextTick(() => callback(null)),
- ),
- multiRemove: jest.fn((keys, callback) =>
- process.nextTick(() => callback(null)),
- ),
- multiMerge: jest.fn((entries, callback) =>
- process.nextTick(() => callback(null)),
- ),
- clear: jest.fn(callback => process.nextTick(() => callback(null))),
- getAllKeys: jest.fn(callback =>
- process.nextTick(() => callback(null, [])),
- ),
+ }),
+ )
+ .mock('../Libraries/Linking/Linking', () =>
+ mockESModule({
+ default: {
+ openURL: jest.fn(),
+ canOpenURL: jest.fn(() => Promise.resolve(true)),
+ openSettings: jest.fn(),
+ addEventListener: jest.fn(() => ({
+ remove: jest.fn(),
+ })),
+ getInitialURL: jest.fn(() => Promise.resolve()),
+ sendIntent: jest.fn(),
},
- DeviceInfo: {
- getConstants() {
- return {
- Dimensions: {
- window: {
- fontScale: 2,
- height: 1334,
- scale: 2,
- width: 750,
- },
- screen: {
- fontScale: 2,
- height: 1334,
- scale: 2,
- width: 750,
+ }),
+ )
+ // Mock modules defined by the native layer (ex: Objective-C, Java)
+ .mock('../Libraries/BatchedBridge/NativeModules', () =>
+ mockESModule({
+ default: {
+ AlertManager: {
+ alertWithArgs: jest.fn(),
+ },
+ AsyncLocalStorage: {
+ multiGet: jest.fn((keys, callback) =>
+ process.nextTick(() => callback(null, [])),
+ ),
+ multiSet: jest.fn((entries, callback) =>
+ process.nextTick(() => callback(null)),
+ ),
+ multiRemove: jest.fn((keys, callback) =>
+ process.nextTick(() => callback(null)),
+ ),
+ multiMerge: jest.fn((entries, callback) =>
+ process.nextTick(() => callback(null)),
+ ),
+ clear: jest.fn(callback => process.nextTick(() => callback(null))),
+ getAllKeys: jest.fn(callback =>
+ process.nextTick(() => callback(null, [])),
+ ),
+ },
+ DeviceInfo: {
+ getConstants() {
+ return {
+ Dimensions: {
+ window: {
+ fontScale: 2,
+ height: 1334,
+ scale: 2,
+ width: 750,
+ },
+ screen: {
+ fontScale: 2,
+ height: 1334,
+ scale: 2,
+ width: 750,
+ },
},
+ };
+ },
+ },
+ DevSettings: {
+ addMenuItem: jest.fn(),
+ reload: jest.fn(),
+ },
+ ImageLoader: {
+ getSize: jest.fn(url => Promise.resolve([320, 240])),
+ getSizeWithHeaders: jest.fn((url, headers) =>
+ Promise.resolve({height: 222, width: 333}),
+ ),
+ prefetchImage: jest.fn(),
+ prefetchImageWithMetadata: jest.fn(),
+ queryCache: jest.fn(),
+ },
+ ImageViewManager: {
+ getSize: jest.fn((uri, success) =>
+ process.nextTick(() => success(320, 240)),
+ ),
+ prefetchImage: jest.fn(),
+ },
+ KeyboardObserver: {
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+ NativeAnimatedModule: {
+ createAnimatedNode: jest.fn(),
+ updateAnimatedNodeConfig: jest.fn(),
+ getValue: jest.fn(),
+ startListeningToAnimatedNodeValue: jest.fn(),
+ stopListeningToAnimatedNodeValue: jest.fn(),
+ connectAnimatedNodes: jest.fn(),
+ disconnectAnimatedNodes: jest.fn(),
+ startAnimatingNode: jest.fn(
+ (animationId, nodeTag, config, endCallback) => {
+ setTimeout(() => endCallback({finished: true}), 16);
},
- };
+ ),
+ stopAnimation: jest.fn(),
+ setAnimatedNodeValue: jest.fn(),
+ setAnimatedNodeOffset: jest.fn(),
+ flattenAnimatedNodeOffset: jest.fn(),
+ extractAnimatedNodeOffset: jest.fn(),
+ connectAnimatedNodeToView: jest.fn(),
+ disconnectAnimatedNodeFromView: jest.fn(),
+ restoreDefaultValues: jest.fn(),
+ dropAnimatedNode: jest.fn(),
+ addAnimatedEventToView: jest.fn(),
+ removeAnimatedEventFromView: jest.fn(),
+ addListener: jest.fn(),
+ removeListener: jest.fn(),
+ removeListeners: jest.fn(),
},
- },
- DevSettings: {
- addMenuItem: jest.fn(),
- reload: jest.fn(),
- },
- ImageLoader: {
- getSize: jest.fn(url => Promise.resolve([320, 240])),
- getSizeWithHeaders: jest.fn((url, headers) =>
- Promise.resolve({height: 222, width: 333}),
- ),
- prefetchImage: jest.fn(),
- prefetchImageWithMetadata: jest.fn(),
- queryCache: jest.fn(),
- },
- ImageViewManager: {
- getSize: jest.fn((uri, success) =>
- process.nextTick(() => success(320, 240)),
- ),
- prefetchImage: jest.fn(),
- },
- KeyboardObserver: {
- addListener: jest.fn(),
- removeListeners: jest.fn(),
- },
- NativeAnimatedModule: {
- createAnimatedNode: jest.fn(),
- updateAnimatedNodeConfig: jest.fn(),
- getValue: jest.fn(),
- startListeningToAnimatedNodeValue: jest.fn(),
- stopListeningToAnimatedNodeValue: jest.fn(),
- connectAnimatedNodes: jest.fn(),
- disconnectAnimatedNodes: jest.fn(),
- startAnimatingNode: jest.fn(
- (animationId, nodeTag, config, endCallback) => {
- setTimeout(() => endCallback({finished: true}), 16);
+ Networking: {
+ sendRequest: jest.fn(),
+ abortRequest: jest.fn(),
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+ PlatformConstants: {
+ getConstants() {
+ return {
+ reactNativeVersion: {
+ major: 1000,
+ minor: 0,
+ patch: 0,
+ prerelease: undefined,
+ },
+ };
},
- ),
- stopAnimation: jest.fn(),
- setAnimatedNodeValue: jest.fn(),
- setAnimatedNodeOffset: jest.fn(),
- flattenAnimatedNodeOffset: jest.fn(),
- extractAnimatedNodeOffset: jest.fn(),
- connectAnimatedNodeToView: jest.fn(),
- disconnectAnimatedNodeFromView: jest.fn(),
- restoreDefaultValues: jest.fn(),
- dropAnimatedNode: jest.fn(),
- addAnimatedEventToView: jest.fn(),
- removeAnimatedEventFromView: jest.fn(),
- addListener: jest.fn(),
- removeListener: jest.fn(),
- removeListeners: jest.fn(),
- },
- Networking: {
- sendRequest: jest.fn(),
- abortRequest: jest.fn(),
- addListener: jest.fn(),
- removeListeners: jest.fn(),
- },
- PlatformConstants: {
- getConstants() {
- return {
- reactNativeVersion: {
- major: 1000,
- minor: 0,
- patch: 0,
- prerelease: undefined,
- },
- };
},
- },
- PushNotificationManager: {
- presentLocalNotification: jest.fn(),
- scheduleLocalNotification: jest.fn(),
- cancelAllLocalNotifications: jest.fn(),
- removeAllDeliveredNotifications: jest.fn(),
- getDeliveredNotifications: jest.fn(callback =>
- process.nextTick(() => []),
- ),
- removeDeliveredNotifications: jest.fn(),
- setApplicationIconBadgeNumber: jest.fn(),
- getApplicationIconBadgeNumber: jest.fn(callback =>
- process.nextTick(() => callback(0)),
- ),
- cancelLocalNotifications: jest.fn(),
- getScheduledLocalNotifications: jest.fn(callback =>
- process.nextTick(() => callback()),
- ),
- requestPermissions: jest.fn(() =>
- Promise.resolve({alert: true, badge: true, sound: true}),
- ),
- abandonPermissions: jest.fn(),
- checkPermissions: jest.fn(callback =>
- process.nextTick(() =>
- callback({alert: true, badge: true, sound: true}),
+ PushNotificationManager: {
+ presentLocalNotification: jest.fn(),
+ scheduleLocalNotification: jest.fn(),
+ cancelAllLocalNotifications: jest.fn(),
+ removeAllDeliveredNotifications: jest.fn(),
+ getDeliveredNotifications: jest.fn(callback =>
+ process.nextTick(() => []),
),
- ),
- getInitialNotification: jest.fn(() => Promise.resolve(null)),
- addListener: jest.fn(),
- removeListeners: jest.fn(),
- },
- SourceCode: {
- getConstants() {
- return {
- scriptURL: null,
- };
+ removeDeliveredNotifications: jest.fn(),
+ setApplicationIconBadgeNumber: jest.fn(),
+ getApplicationIconBadgeNumber: jest.fn(callback =>
+ process.nextTick(() => callback(0)),
+ ),
+ cancelLocalNotifications: jest.fn(),
+ getScheduledLocalNotifications: jest.fn(callback =>
+ process.nextTick(() => callback()),
+ ),
+ requestPermissions: jest.fn(() =>
+ Promise.resolve({alert: true, badge: true, sound: true}),
+ ),
+ abandonPermissions: jest.fn(),
+ checkPermissions: jest.fn(callback =>
+ process.nextTick(() =>
+ callback({alert: true, badge: true, sound: true}),
+ ),
+ ),
+ getInitialNotification: jest.fn(() => Promise.resolve(null)),
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+ SourceCode: {
+ getConstants() {
+ return {
+ scriptURL: null,
+ };
+ },
+ },
+ StatusBarManager: {
+ setColor: jest.fn(),
+ setStyle: jest.fn(),
+ setHidden: jest.fn(),
+ setNetworkActivityIndicatorVisible: jest.fn(),
+ setBackgroundColor: jest.fn(),
+ setTranslucent: jest.fn(),
+ getConstants: () => ({
+ HEIGHT: 42,
+ }),
+ },
+ Timing: {
+ createTimer: jest.fn(),
+ deleteTimer: jest.fn(),
+ },
+ UIManager: {},
+ BlobModule: {
+ getConstants: () => ({
+ BLOB_URI_SCHEME: 'content',
+ BLOB_URI_HOST: null,
+ }),
+ addNetworkingHandler: jest.fn(),
+ enableBlobSupport: jest.fn(),
+ disableBlobSupport: jest.fn(),
+ createFromParts: jest.fn(),
+ sendBlob: jest.fn(),
+ release: jest.fn(),
+ },
+ WebSocketModule: {
+ connect: jest.fn(),
+ send: jest.fn(),
+ sendBinary: jest.fn(),
+ ping: jest.fn(),
+ close: jest.fn(),
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+ I18nManager: {
+ allowRTL: jest.fn(),
+ forceRTL: jest.fn(),
+ swapLeftAndRightInRTL: jest.fn(),
+ getConstants: () => ({
+ isRTL: false,
+ doLeftAndRightSwapInRTL: true,
+ }),
},
},
- StatusBarManager: {
- setColor: jest.fn(),
- setStyle: jest.fn(),
- setHidden: jest.fn(),
- setNetworkActivityIndicatorVisible: jest.fn(),
- setBackgroundColor: jest.fn(),
- setTranslucent: jest.fn(),
- getConstants: () => ({
- HEIGHT: 42,
- }),
- },
- Timing: {
- createTimer: jest.fn(),
- deleteTimer: jest.fn(),
- },
- UIManager: {},
- BlobModule: {
- getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}),
- addNetworkingHandler: jest.fn(),
- enableBlobSupport: jest.fn(),
- disableBlobSupport: jest.fn(),
- createFromParts: jest.fn(),
- sendBlob: jest.fn(),
- release: jest.fn(),
- },
- WebSocketModule: {
- connect: jest.fn(),
- send: jest.fn(),
- sendBinary: jest.fn(),
- ping: jest.fn(),
- close: jest.fn(),
- addListener: jest.fn(),
- removeListeners: jest.fn(),
- },
- I18nManager: {
- allowRTL: jest.fn(),
- forceRTL: jest.fn(),
- swapLeftAndRightInRTL: jest.fn(),
- getConstants: () => ({
- isRTL: false,
- doLeftAndRightSwapInRTL: true,
- }),
- },
- },
- }))
+ }),
+ )
.mock('../Libraries/NativeComponent/NativeComponentRegistry', () => {
return {
get: jest.fn((name, viewConfigProvider) => {
- return jest.requireActual('./mockNativeComponent').default(name);
+ const mockNativeComponent =
+ jest.requireActual(
+ './mockNativeComponent',
+ ).default;
+ return mockNativeComponent(name);
}),
getWithFallback_DEPRECATED: jest.fn((name, viewConfigProvider) => {
- return jest.requireActual('./mockNativeComponent').default(name);
+ const mockNativeComponent =
+ jest.requireActual(
+ './mockNativeComponent',
+ ).default;
+ return mockNativeComponent(name);
}),
setRuntimeConfigProvider: jest.fn(),
};
})
.mock('../Libraries/ReactNative/requireNativeComponent', () => {
- return jest.requireActual('./mockNativeComponent');
+ const mockNativeComponent = jest.requireActual(
+ './mockNativeComponent',
+ ).default;
+ return mockESModule({
+ default: mockNativeComponent,
+ });
})
- .mock('../Libraries/Vibration/Vibration', () => ({
- __esModule: true,
- default: {
- vibrate: jest.fn(),
- cancel: jest.fn(),
- },
- }))
+ .mock('../Libraries/Vibration/Vibration', () =>
+ mockESModule({
+ default: {
+ vibrate: jest.fn(),
+ cancel: jest.fn(),
+ },
+ }),
+ )
.mock('../Libraries/Components/View/ViewNativeComponent', () => {
const React = require('react');
- const Component = class extends React.Component {
- render() {
- return React.createElement('View', this.props, this.props.children);
+ const {createElement} = React;
+
+ const Component = class extends React.Component {
+ render(): React.Node {
+ // $FlowIgnore[not-a-function]
+ return createElement('View', this.props, this.props.children);
}
};
Component.displayName = 'View';
- return {
- __esModule: true,
+ return mockESModule({
default: Component,
- };
+ });
})
// In tests, we can use the default version instead of the one using
// dependency injection.
@@ -497,7 +587,8 @@ jest
'../Libraries/ReactNative/RendererImplementation',
);
})
- .mock('../Libraries/Utilities/useColorScheme', () => ({
- __esModule: true,
- default: jest.fn().mockReturnValue('light'),
- }));
+ .mock('../Libraries/Utilities/useColorScheme', () =>
+ mockESModule({
+ default: jest.fn().mockReturnValue('light'),
+ }),
+ );