From 122d977ae5521ccc38821ab4e190605a8a9454cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Mon, 27 Jan 2025 16:24:02 +0100 Subject: [PATCH 01/10] add testOnly onPressX props to Pressable --- src/components/GestureButtonsProps.ts | 18 ++++++++++++++++++ src/components/Pressable/Pressable.tsx | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/GestureButtonsProps.ts b/src/components/GestureButtonsProps.ts index e5075a17da..b86881408f 100644 --- a/src/components/GestureButtonsProps.ts +++ b/src/components/GestureButtonsProps.ts @@ -50,6 +50,24 @@ export interface RawButtonProps * Style object, use it to set additional styles. */ style?: StyleProp; + + /** + * Used for testing-library compatibility, not passed to the native component. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + testOnly_onPress?: Function | null; + + /** + * Used for testing-library compatibility, not passed to the native component. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + testOnly_onPressIn?: Function | null; + + /** + * Used for testing-library compatibility, not passed to the native component. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + testOnly_onPressOut?: Function | null; } interface ButtonWithRefProps { innerRef?: React.ForwardedRef>; diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index 9223a18cc1..1adc0088a2 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -380,6 +380,8 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; + const inJestEnv = typeof jest !== 'undefined'; + return ( + style={[pointerStyle, styleProp]} + testOnly_onPress={inJestEnv ? onPress : undefined} + testOnly_onPressIn={inJestEnv ? onPressIn : undefined} + testOnly_onPressOut={inJestEnv ? onPressOut : undefined}> {childrenProp} {__DEV__ ? ( From e51fdcd44bd18e52d79843266f18c07312dea4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Mon, 27 Jan 2025 17:37:34 +0100 Subject: [PATCH 02/10] update test env detection --- src/components/Pressable/Pressable.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index 1adc0088a2..d15b3da39f 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -380,7 +380,7 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; - const inJestEnv = typeof jest !== 'undefined'; + const inTestEnv = process.env.NODE_ENV === 'test'; return ( @@ -393,9 +393,9 @@ export default function Pressable(props: PressableProps) { rippleColor={processColor(android_ripple?.color ?? defaultRippleColor)} rippleRadius={android_ripple?.radius ?? undefined} style={[pointerStyle, styleProp]} - testOnly_onPress={inJestEnv ? onPress : undefined} - testOnly_onPressIn={inJestEnv ? onPressIn : undefined} - testOnly_onPressOut={inJestEnv ? onPressOut : undefined}> + testOnly_onPress={inTestEnv ? onPress : undefined} + testOnly_onPressIn={inTestEnv ? onPressIn : undefined} + testOnly_onPressOut={inTestEnv ? onPressOut : undefined}> {childrenProp} {__DEV__ ? ( From 930dabce9f0ab11144ea1d29618c9925ba29641f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Mon, 27 Jan 2025 17:45:54 +0100 Subject: [PATCH 03/10] add node type defs --- package.json | 1 + tsconfig.json | 2 +- yarn.lock | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0cff2ec210..f65299021d 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@types/hoist-non-react-statics": "^3.3.1", "@types/invariant": "^2.2.37", "@types/jest": "^27.0.3", + "@types/node": "^22.10.10", "@types/react": "^18.2.6", "@types/react-test-renderer": "^17.0.0", "@typescript-eslint/eslint-plugin": "^4.33.0", diff --git a/tsconfig.json b/tsconfig.json index 5a6772d936..207a0d4dc2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "esModuleInterop": true, "jsx": "react-native", "lib": ["esnext", "dom"], - "types": ["jest"], + "types": ["jest", "node"], "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, diff --git a/yarn.lock b/yarn.lock index f4d3e299ab..c396619bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4225,6 +4225,13 @@ version "14.0.24" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.24.tgz#b0f86f58564fa02a28b68f8b55d4cdec42e3b9d6" +"@types/node@^22.10.10": + version "22.10.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.10.tgz#85fe89f8bf459dc57dfef1689bd5b52ad1af07e6" + integrity sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww== + dependencies: + undici-types "~6.20.0" + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -11622,6 +11629,11 @@ unc-path-regex@^0.1.2: resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" From c63a561547acbf8ec715b036091b5e504b02d33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Mon, 27 Jan 2025 18:37:22 +0100 Subject: [PATCH 04/10] ignore type error --- package.json | 1 - src/components/Pressable/Pressable.tsx | 2 ++ tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f65299021d..0cff2ec210 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "@types/hoist-non-react-statics": "^3.3.1", "@types/invariant": "^2.2.37", "@types/jest": "^27.0.3", - "@types/node": "^22.10.10", "@types/react": "^18.2.6", "@types/react-test-renderer": "^17.0.0", "@typescript-eslint/eslint-plugin": "^4.33.0", diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index d15b3da39f..e0d90bd2ff 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -380,6 +380,8 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; + // @ts-ignore Adding type definitions for @types/node causes multiple conflicts with react-native/types, + // and as far as i know, there is no simple way of automatically resolving them. const inTestEnv = process.env.NODE_ENV === 'test'; return ( diff --git a/tsconfig.json b/tsconfig.json index 207a0d4dc2..5a6772d936 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "esModuleInterop": true, "jsx": "react-native", "lib": ["esnext", "dom"], - "types": ["jest", "node"], + "types": ["jest"], "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, From 556f8f2d4d728aa13c40e1fbae55396f41d52803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Mon, 27 Jan 2025 18:40:38 +0100 Subject: [PATCH 05/10] (amend) update yarn.lock --- yarn.lock | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index c396619bb0..f4d3e299ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4225,13 +4225,6 @@ version "14.0.24" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.24.tgz#b0f86f58564fa02a28b68f8b55d4cdec42e3b9d6" -"@types/node@^22.10.10": - version "22.10.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.10.tgz#85fe89f8bf459dc57dfef1689bd5b52ad1af07e6" - integrity sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww== - dependencies: - undici-types "~6.20.0" - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -11629,11 +11622,6 @@ unc-path-regex@^0.1.2: resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" From f13e7b041070a03a0a97e241cadb979f1eba75a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 28 Jan 2025 16:36:44 +0100 Subject: [PATCH 06/10] change jest check to general test check --- src/handlers/createHandler.tsx | 6 +++--- src/handlers/gestures/GestureDetector/index.tsx | 4 ++-- src/handlers/gestures/GestureDetector/utils.ts | 4 ++-- src/handlers/handlersRegistry.ts | 6 +++--- src/utils.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/handlers/createHandler.tsx b/src/handlers/createHandler.tsx index 371d632514..06b269c7d7 100644 --- a/src/handlers/createHandler.tsx +++ b/src/handlers/createHandler.tsx @@ -19,7 +19,7 @@ import { import { filterConfig, scheduleFlushOperations } from './utils'; import findNodeHandle from '../findNodeHandle'; import { ValueOf } from '../typeUtils'; -import { deepEqual, isFabric, isJestEnv, tagMessage } from '../utils'; +import { deepEqual, isFabric, isTestEnv, tagMessage } from '../utils'; import { ActionType } from '../ActionType'; import { PressabilityDebugView } from './PressabilityDebugView'; import GestureHandlerRootViewContext from '../GestureHandlerRootViewContext'; @@ -428,7 +428,7 @@ export default function createHandler< } render() { - if (__DEV__ && !this.context && !isJestEnv() && Platform.OS !== 'web') { + if (__DEV__ && !this.context && !isTestEnv() && Platform.OS !== 'web') { throw new Error( name + ' must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/installation for more details.' @@ -539,7 +539,7 @@ export default function createHandler< { ref: this.refHandler, collapsable: false, - ...(isJestEnv() + ...(isTestEnv() ? { handlerType: name, handlerTag: this.handlerTag, diff --git a/src/handlers/gestures/GestureDetector/index.tsx b/src/handlers/gestures/GestureDetector/index.tsx index dac3e49495..71f9dd2948 100644 --- a/src/handlers/gestures/GestureDetector/index.tsx +++ b/src/handlers/gestures/GestureDetector/index.tsx @@ -11,7 +11,7 @@ import findNodeHandle from '../../../findNodeHandle'; import { GestureType } from '../gesture'; import { UserSelect, TouchAction } from '../../gestureHandlerCommon'; import { ComposedGesture } from '../gestureComposition'; -import { isJestEnv } from '../../../utils'; +import { isTestEnv } from '../../../utils'; import GestureHandlerRootViewContext from '../../../GestureHandlerRootViewContext'; import { AttachedGestureState, GestureDetectorState } from './types'; @@ -94,7 +94,7 @@ interface GestureDetectorProps { */ export const GestureDetector = (props: GestureDetectorProps) => { const rootViewContext = useContext(GestureHandlerRootViewContext); - if (__DEV__ && !rootViewContext && !isJestEnv() && Platform.OS !== 'web') { + if (__DEV__ && !rootViewContext && !isTestEnv() && Platform.OS !== 'web') { throw new Error( 'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/installation for more details.' ); diff --git a/src/handlers/gestures/GestureDetector/utils.ts b/src/handlers/gestures/GestureDetector/utils.ts index 3d3d79ed70..784eb297ae 100644 --- a/src/handlers/gestures/GestureDetector/utils.ts +++ b/src/handlers/gestures/GestureDetector/utils.ts @@ -1,6 +1,6 @@ import { Platform } from 'react-native'; -import { isJestEnv, tagMessage } from '../../../utils'; +import { isTestEnv, tagMessage } from '../../../utils'; import { GestureRef, BaseGesture, GestureType } from '../gesture'; import { flingGestureHandlerProps } from '../../FlingGestureHandler'; @@ -100,7 +100,7 @@ export function checkGestureCallbacksForWorklets(gesture: GestureType) { const areAllNotWorklets = !areSomeWorklets && areSomeNotWorklets; // If none of the callbacks are worklets and the gesture is not explicitly marked with // `.runOnJS(true)` show a warning - if (areAllNotWorklets && !isJestEnv()) { + if (areAllNotWorklets && !isTestEnv()) { console.warn( tagMessage( `None of the callbacks in the gesture are worklets. If you wish to run them on the JS thread use '.runOnJS(true)' modifier on the gesture to make this explicit. Otherwise, mark the callbacks as 'worklet' to run them on the UI thread.` diff --git a/src/handlers/handlersRegistry.ts b/src/handlers/handlersRegistry.ts index 3a19447edf..f070fc94b2 100644 --- a/src/handlers/handlersRegistry.ts +++ b/src/handlers/handlersRegistry.ts @@ -1,4 +1,4 @@ -import { isJestEnv } from '../utils'; +import { isTestEnv } from '../utils'; import { GestureType } from './gestures/gesture'; import { GestureEvent, HandlerStateChangeEvent } from './gestureHandlerCommon'; @@ -13,7 +13,7 @@ export function registerHandler( testID?: string ) { gestures.set(handlerTag, handler); - if (isJestEnv() && testID) { + if (isTestEnv() && testID) { testIDs.set(testID, handlerTag); } } @@ -27,7 +27,7 @@ export function registerOldGestureHandler( export function unregisterHandler(handlerTag: number, testID?: string) { gestures.delete(handlerTag); - if (isJestEnv() && testID) { + if (isTestEnv() && testID) { testIDs.delete(testID); } } diff --git a/src/utils.ts b/src/utils.ts index 8d7284a443..727fcb4937 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -34,9 +34,9 @@ export function hasProperty(object: object, key: string) { return Object.prototype.hasOwnProperty.call(object, key); } -export function isJestEnv(): boolean { +export function isTestEnv(): boolean { // @ts-ignore Do not use `@types/node` because it will prioritise Node types over RN types which breaks the types (ex. setTimeout) in React Native projects. - return hasProperty(global, 'process') && !!process.env.JEST_WORKER_ID; + return hasProperty(global, 'process') && process.env.NODE_ENV === 'test'; } export function tagMessage(msg: string) { From 4d942e8d200aff9b35c0d866d5addb04a54480be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 28 Jan 2025 16:37:12 +0100 Subject: [PATCH 07/10] use isTestEnv in pressable --- src/components/Pressable/Pressable.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index e0d90bd2ff..f62f5252b0 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -20,7 +20,7 @@ import { } from './utils'; import { PressabilityDebugView } from '../../handlers/PressabilityDebugView'; import { GestureTouchEvent } from '../../handlers/gestureHandlerCommon'; -import { INT32_MAX } from '../../utils'; +import { INT32_MAX, isTestEnv } from '../../utils'; const DEFAULT_LONG_PRESS_DURATION = 500; @@ -380,10 +380,6 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; - // @ts-ignore Adding type definitions for @types/node causes multiple conflicts with react-native/types, - // and as far as i know, there is no simple way of automatically resolving them. - const inTestEnv = process.env.NODE_ENV === 'test'; - return ( + testOnly_onPress={isTestEnv() ? onPress : undefined} + testOnly_onPressIn={isTestEnv() ? onPressIn : undefined} + testOnly_onPressOut={isTestEnv() ? onPressOut : undefined}> {childrenProp} {__DEV__ ? ( From 7a31f5ec2a42aa51ab2d4fa3f9744f5361b020d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 28 Jan 2025 17:23:38 +0100 Subject: [PATCH 08/10] memo isTestEnv --- src/components/Pressable/Pressable.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index f62f5252b0..5ac8ded5f9 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -380,6 +380,8 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; + const IS_TEST_ENV = useMemo(() => isTestEnv(), []); + return ( + testOnly_onPress={IS_TEST_ENV ? onPress : undefined} + testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined} + testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}> {childrenProp} {__DEV__ ? ( From 618407816e8ef604597be3b706e9c72125a27891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 28 Jan 2025 17:31:26 +0100 Subject: [PATCH 09/10] expose onLongPress --- src/components/GestureButtonsProps.ts | 6 ++++++ src/components/Pressable/Pressable.tsx | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/GestureButtonsProps.ts b/src/components/GestureButtonsProps.ts index b86881408f..dabf62d5f1 100644 --- a/src/components/GestureButtonsProps.ts +++ b/src/components/GestureButtonsProps.ts @@ -68,6 +68,12 @@ export interface RawButtonProps */ // eslint-disable-next-line @typescript-eslint/ban-types testOnly_onPressOut?: Function | null; + + /** + * Used for testing-library compatibility, not passed to the native component. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + testOnly_onLongPress?: Function | null; } interface ButtonWithRefProps { innerRef?: React.ForwardedRef>; diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index 5ac8ded5f9..d91af0d20a 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -395,7 +395,8 @@ export default function Pressable(props: PressableProps) { style={[pointerStyle, styleProp]} testOnly_onPress={IS_TEST_ENV ? onPress : undefined} testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined} - testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}> + testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined} + testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}> {childrenProp} {__DEV__ ? ( From 4ec26c48e0e9d77a8e41a8683e7d8455b1f95ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Tue, 28 Jan 2025 17:44:15 +0100 Subject: [PATCH 10/10] cache IS_TEST_ENV outside of Pressable --- src/components/Pressable/Pressable.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Pressable/Pressable.tsx b/src/components/Pressable/Pressable.tsx index d91af0d20a..3781afb9f6 100644 --- a/src/components/Pressable/Pressable.tsx +++ b/src/components/Pressable/Pressable.tsx @@ -23,6 +23,7 @@ import { GestureTouchEvent } from '../../handlers/gestureHandlerCommon'; import { INT32_MAX, isTestEnv } from '../../utils'; const DEFAULT_LONG_PRESS_DURATION = 500; +const IS_TEST_ENV = isTestEnv(); export default function Pressable(props: PressableProps) { const { @@ -380,8 +381,6 @@ export default function Pressable(props: PressableProps) { ? children({ pressed: pressedState }) : children; - const IS_TEST_ENV = useMemo(() => isTestEnv(), []); - return (