Skip to content
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

Add testing-library compatibility props #3357

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

latekvo
Copy link
Contributor

@latekvo latekvo commented Jan 27, 2025

Description

This PR adds 3 props to the Pressable used for compatibility with react-native-testing-library

Full discussion: callstack/react-native-testing-library#1738

Test plan

* Used for testing-library compatibility, not passed to the native component.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
testOnly_onPress?: Function | null;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of argument should be passed to testOnly_onPress?

Copy link
Contributor Author

@latekvo latekvo Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testOnly_onPress will currently always be of type ((event: PressableEvent) => void) | null, but this may change if more of our components will implement testOnly_onPress.

I've made it of type Function, because RawButtonProps usage is not specific to Pressable.

Link to type definitions: (link)
Extract from type definitions:

export type InnerPressableEvent = {
  changedTouches: InnerPressableEvent[];
  identifier: number;
  locationX: number;
  locationY: number;
  pageX: number;
  pageY: number;
  target: number;
  timestamp: number;
  touches: InnerPressableEvent[];
  force?: number;
};

export type PressableEvent = { nativeEvent: InnerPressableEvent };

export interface PressableProps
  extends AccessibilityProps,
    Omit<ViewProps, 'children' | 'style' | 'hitSlop'> {

  [...]

  onPress?: null | ((event: PressableEvent) => void);
  onPressIn?: null | ((event: PressableEvent) => void);
  onPressOut?: null | ((event: PressableEvent) => void);

  [...]
}

@@ -380,6 +380,8 @@ export default function Pressable(props: PressableProps) {
? children({ pressed: pressedState })
: children;

const inJestEnv = typeof jest !== 'undefined';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should use process.env.NODE_ENV === 'test'; as more typical option for checking test env.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e51fdcd

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have isJest function (defined here). Can't we use that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NODE_ENV === 'test' also works with Mocha and Jasmine, while isJest which uses JEST_WORKER_ID only works with Jest. I think it'd actually be worth changing isJest function to the implementation present in this PR.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future RNTL would like to support other test runners, like vitest or bun. If you hardcode to Jest instead of testing, this would break in such case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case why don't we change isJestEnv implementation instead of adding new check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the isJestEnv implementation can be changed, mentioned this in #3357 (comment) as well.
Done in f13e7b0

Copy link

@mdjastrzebski mdjastrzebski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good, I've left some recommended tweaks

@latekvo
Copy link
Contributor Author

latekvo commented Jan 27, 2025

Note on c63a561 - I tried using ReturnType<typeof setTimeout>, manually creating globals.d.ts type resolutions, and finding ways of giving one of the typing libraries higher priority. Unfortunately none of these methods worked for all instances of conflicting types, with node types always overwriting react-native types.

@latekvo latekvo marked this pull request as ready for review January 27, 2025 17:40
@latekvo latekvo requested review from j-piasecki and m-bert January 27, 2025 17:47
@@ -380,6 +380,10 @@ 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';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this

export function isJestEnv(): 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;
}
?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned here: #3357 (comment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THis would tie the implementation only to Jest test runner. In case of user using other test runners Mocha, Vitest, Bun (not all of these are supported by RNTL atm) this props will not be set. The process.env.NODE_ENV === 'test'; should support all test runners.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4d942e8

@mdjastrzebski
Copy link

@latekvo could you also expose onLongPress in a similar way?

@mdjastrzebski
Copy link

I've implemented RNTL counterpart here: callstack/react-native-testing-library#1741

Comment on lines 394 to 396
testOnly_onPress={isTestEnv() ? onPress : undefined}
testOnly_onPressIn={isTestEnv() ? onPressIn : undefined}
testOnly_onPressOut={isTestEnv() ? onPressOut : undefined}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do something similar to Reanimated, i.e. call this only once and store result in constant

const IS_TEST_ENV = isTestEnv()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though about that, but isTestEnv() is just a property read, and both notations are just as readable, so i don't think there's a point in caching the value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it calls hasProperty and then compares values, so it's more than just property read. While it's not crucial in test environment, I think it is better to memoize this value.

Copy link
Contributor Author

@latekvo latekvo Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, done in 7a31f5e and 4ec26c4

@latekvo
Copy link
Contributor Author

latekvo commented Jan 28, 2025

@latekvo could you also expose onLongPress in a similar way?

@mdjastrzebski sure, done in 6184078

Copy link

@mdjastrzebski mdjastrzebski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🙌

@latekvo latekvo requested a review from m-bert January 30, 2025 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RNGH::Pressable won't work the same as RN::Pressable when using Testing Library
4 participants