-
Notifications
You must be signed in to change notification settings - Fork 274
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
315afca
commit c47220b
Showing
8 changed files
with
147 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import * as React from 'react'; | ||
import { Text, View } from 'react-native'; | ||
|
||
import { render, screen } from '..'; | ||
import { getEventHandler } from '../event-handler'; | ||
|
||
test('getEventHandler strict mode', () => { | ||
const onPress = jest.fn(); | ||
const testOnlyOnPress = jest.fn(); | ||
|
||
render( | ||
<View> | ||
<Text testID="regular" onPress={onPress} /> | ||
{/* @ts-expect-error Intentionally passing such props */} | ||
<View testID="testOnly" testOnly_onPress={testOnlyOnPress} /> | ||
{/* @ts-expect-error Intentionally passing such props */} | ||
<View testID="both" onPress={onPress} testOnly_onPress={testOnlyOnPress} /> | ||
</View>, | ||
); | ||
|
||
const regular = screen.getByTestId('regular'); | ||
const testOnly = screen.getByTestId('testOnly'); | ||
const both = screen.getByTestId('both'); | ||
|
||
expect(getEventHandler(regular, 'press')).toBe(onPress); | ||
expect(getEventHandler(testOnly, 'press')).toBe(testOnlyOnPress); | ||
expect(getEventHandler(both, 'press')).toBe(onPress); | ||
|
||
expect(getEventHandler(regular, 'onPress')).toBe(undefined); | ||
expect(getEventHandler(testOnly, 'onPress')).toBe(undefined); | ||
expect(getEventHandler(both, 'onPress')).toBe(undefined); | ||
}); | ||
|
||
test('getEventHandler loose mode', () => { | ||
const onPress = jest.fn(); | ||
const testOnlyOnPress = jest.fn(); | ||
|
||
render( | ||
<View> | ||
<Text testID="regular" onPress={onPress} /> | ||
{/* @ts-expect-error Intentionally passing such props */} | ||
<View testID="testOnly" testOnly_onPress={testOnlyOnPress} /> | ||
{/* @ts-expect-error Intentionally passing such props */} | ||
<View testID="both" onPress={onPress} testOnly_onPress={testOnlyOnPress} /> | ||
</View>, | ||
); | ||
|
||
const regular = screen.getByTestId('regular'); | ||
const testOnly = screen.getByTestId('testOnly'); | ||
const both = screen.getByTestId('both'); | ||
|
||
expect(getEventHandler(regular, 'press', { loose: true })).toBe(onPress); | ||
expect(getEventHandler(testOnly, 'press', { loose: true })).toBe(testOnlyOnPress); | ||
expect(getEventHandler(both, 'press', { loose: true })).toBe(onPress); | ||
|
||
expect(getEventHandler(regular, 'onPress', { loose: true })).toBe(onPress); | ||
expect(getEventHandler(testOnly, 'onPress', { loose: true })).toBe(testOnlyOnPress); | ||
expect(getEventHandler(both, 'onPress', { loose: true })).toBe(onPress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import type { ReactTestInstance } from 'react-test-renderer'; | ||
|
||
export type EventHandlerOptions = { | ||
/** Include check for event handler named without adding `on*` prefix. */ | ||
loose?: boolean; | ||
}; | ||
|
||
export function getEventHandler( | ||
element: ReactTestInstance, | ||
eventName: string, | ||
options?: EventHandlerOptions, | ||
) { | ||
const handlerName = getEventHandlerName(eventName); | ||
if (typeof element.props[handlerName] === 'function') { | ||
return element.props[handlerName]; | ||
} | ||
|
||
if (options?.loose && typeof element.props[eventName] === 'function') { | ||
return element.props[eventName]; | ||
} | ||
|
||
if (typeof element.props[`testOnly_${handlerName}`] === 'function') { | ||
return element.props[`testOnly_${handlerName}`]; | ||
} | ||
|
||
if (options?.loose && typeof element.props[`testOnly_${eventName}`] === 'function') { | ||
return element.props[`testOnly_${eventName}`]; | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
export function getEventHandlerName(eventName: string) { | ||
return `on${capitalizeFirstLetter(eventName)}`; | ||
} | ||
|
||
function capitalizeFirstLetter(str: string) { | ||
return str.charAt(0).toUpperCase() + str.slice(1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
["testing-env", "understanding-act"] | ||
["testing-env", "understanding-act", "third-party-integration"] |
39 changes: 39 additions & 0 deletions
39
website/docs/13.x/docs/advanced/third-party-integration.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Third-Party Library Integration | ||
|
||
The React Native Testing Library is designed to simulate the core behaviors of React Native. However, it does not replicate the internal logic of third-party libraries. This guide explains how to integrate your library with RNTL. | ||
|
||
## Handling Events in Third-Party Libraries | ||
|
||
RNTL provides two subsystems to simulate events: | ||
|
||
- **Fire Event**: A lightweight simulation system that can trigger event handlers defined on both host and composite components. | ||
- **User Event**: A more realistic interaction simulation system that can trigger event handlers defined only on host components. | ||
|
||
In many third-party libraries, event handling involves native code, which means RNTL cannot fully simulate the event flow, as it runs only JavaScript code. To address this limitation, you can use `testOnly_on*` props on host components to expose custom events to RNTL’s event subsystems. Both subsystems will first attempt to locate the standard `on*` event handlers; if these are not available, they fall back to the `testOnly_on*` handlers. | ||
|
||
### Example: React Native Gesture Handler | ||
|
||
React Native Gesture Handler (RNGH) provides a composite [Pressable](https://docs.swmansion.com/react-native-gesture-handler/docs/components/pressable/) component with `onPress*` props. These event handlers are not exposed on the rendered host views; instead, they are invoked via RNGH’s internal event flow, which involves native modules. As a result, they are not accessible to RNTL’s event subsystems. | ||
|
||
To enable RNTL to interact with RNGH’s `Pressable` component, the library exposes `testOnly_onPress*` props on the `NativeButton` host component rendered by `Pressable`. This adjustment allows RNTL to simulate interactions during testing. | ||
|
||
```tsx title="Simplified RNGH Pressable component" | ||
function Pressable({ onPress, onPressIn, onPressOut, onLongPress, ... }) { | ||
|
||
// Component logic... | ||
|
||
const isTestEnv = process.env.NODE_ENV === 'test'; | ||
|
||
return ( | ||
<GestureDetector gesture={gesture}> | ||
<NativeButton | ||
/* Other props... */ | ||
testOnly_onPress={isTestEnv ? onPress : undefined} | ||
testOnly_onPressIn={isTestEnv ? onPressIn : undefined} | ||
testOnly_onPressOut={isTestEnv ? onPressOut : undefined} | ||
testOnly_onLongPress={isTestEnv ? onLongPress : undefined} | ||
/> | ||
</GestureDetector> | ||
); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters