Skip to content

RN: Flowify packages/react-native/jest #51652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions flow-typed/npm/jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 9 additions & 3 deletions packages/react-native/jest/MockNativeMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@
* 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(),
measureLayout: jest.fn(),
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;
8 changes: 5 additions & 3 deletions packages/react-native/jest/RefreshControlMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const RCTRefreshControl: HostComponent<{}> = requireNativeComponent<{}>(

export default class RefreshControlMock extends React.Component<{...}> {
static latestRef: ?RefreshControlMock;

render(): React.Node {
return <RCTRefreshControl />;
}

componentDidMount() {
RefreshControlMock.latestRef = this;
}
render(): React.MixedElement {
return <RCTRefreshControl />;
}
}
1 change: 1 addition & 0 deletions packages/react-native/jest/assetFileTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
7 changes: 4 additions & 3 deletions packages/react-native/jest/local-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)');
Expand Down
59 changes: 42 additions & 17 deletions packages/react-native/jest/mockComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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> = T | $ReadOnly<{default: T}>;
type ModuleDefault<T> = T['default'];

const SuperClass =
type TComponentType = React.ComponentType<$ReadOnly<{children?: React.Node}>>;

export default function mockComponent<
TComponentModule: Modulish<TComponentType>,
>(
moduleName: string,
instanceMethods: ?interface {},
isESModule: boolean,
): typeof isESModule extends true
? ModuleDefault<TComponentModule>
: TComponentModule & typeof instanceMethods {
const RealComponent: TComponentType = isESModule
? // $FlowIgnore[prop-missing]
jest.requireActual<TComponentModule>(moduleName).default
: // $FlowIgnore[incompatible-type]
jest.requireActual<TComponentModule>(moduleName);

const SuperClass: typeof React.Component<
React.ElementProps<typeof RealComponent>,
> =
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 => {
Expand All @@ -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);
}
};

Expand All @@ -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;
};
}
25 changes: 12 additions & 13 deletions packages/react-native/jest/mockModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof BaseComponent>,
visible?: ?boolean,
}> {
// $FlowIgnore[incompatible-use]
return class ModalMock extends BaseComponent {
render(): React.Node {
if (this.props.visible === false) {
return null;
}
Expand All @@ -25,8 +27,5 @@ function mockModal(BaseComponent: $FlowFixMe) {
<BaseComponent {...this.props}>{this.props.children}</BaseComponent>
);
}
}
return ModalMock;
};
}

module.exports = (mockModal: $FlowFixMe);
35 changes: 21 additions & 14 deletions packages/react-native/jest/mockNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<TProps: $ReadOnly<{children?: React.Node}>> =
component(ref?: ?React.RefSetter<HostInstance>, ...props: TProps);

render() {
export default function mockNativeComponent<
TProps: $ReadOnly<{children?: React.Node}>,
>(viewName: string): MockNativeComponent<TProps> {
const Component = class extends React.Component<TProps> {
_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') {
Expand All @@ -38,4 +45,4 @@ export default viewName => {
}

return Component;
};
}
30 changes: 16 additions & 14 deletions packages/react-native/jest/mockScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@
* @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<ScrollViewNativeProps>('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<typeof BaseComponent>,
refreshControl?: ?React.MixedElement,
}> {
// $FlowIgnore[incompatible-use]
return class ScrollViewMock extends BaseComponent {
render(): React.Node {
return (
<RCTScrollView {...this.props}>
{this.props.refreshControl}
<View>{this.props.children}</View>
</RCTScrollView>
);
}
}
return ScrollViewMock;
};
}

module.exports = (mockScrollView: $FlowFixMe);
1 change: 1 addition & 0 deletions packages/react-native/jest/react-native-env.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/jest/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
1 change: 1 addition & 0 deletions packages/react-native/jest/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
Loading
Loading