|
| 1 | + |
| 2 | + |
| 3 | +### Native UI Testing Module for React Native Harness |
| 4 | + |
| 5 | +[![mit licence][license-badge]][license] |
| 6 | +[![npm downloads][npm-downloads-badge]][npm-downloads] |
| 7 | +[![Chat][chat-badge]][chat] |
| 8 | +[![PRs Welcome][prs-welcome-badge]][prs-welcome] |
| 9 | + |
| 10 | +Native UI testing module for React Native Harness that provides view queries and touch simulation capabilities. This module enables finding UI elements and simulating user interactions in your React Native tests. |
| 11 | + |
| 12 | +## Features |
| 13 | + |
| 14 | +- **View Queries**: Find elements by testID or accessibility label |
| 15 | +- **Touch Simulation**: Simulate user presses and text input |
| 16 | +- **Screenshot Capture**: Capture screenshots of the entire screen or specific elements |
| 17 | +- **Debug-Only**: Automatically excluded from release builds, only available in debug builds |
| 18 | + |
| 19 | +## Installation |
| 20 | + |
| 21 | +```bash |
| 22 | +npm install @react-native-harness/ui |
| 23 | +# or |
| 24 | +pnpm add @react-native-harness/ui |
| 25 | +# or |
| 26 | +yarn add @react-native-harness/ui |
| 27 | +``` |
| 28 | + |
| 29 | +## Usage |
| 30 | + |
| 31 | +Import the UI testing utilities in your test files: |
| 32 | + |
| 33 | +```javascript |
| 34 | +import { screen, userEvent } from '@react-native-harness/ui'; |
| 35 | + |
| 36 | +describe('My Component', () => { |
| 37 | + it('should handle user interactions', async () => { |
| 38 | + // Find elements on screen |
| 39 | + const button = await screen.findByTestId('my-button'); |
| 40 | + const input = await screen.findByAccessibilityLabel('Username input'); |
| 41 | + |
| 42 | + // Simulate user interactions |
| 43 | + await userEvent.type(input, 'testuser'); |
| 44 | + await userEvent.press(button); |
| 45 | + |
| 46 | + // Take screenshots for debugging |
| 47 | + const screenshot = await screen.screenshot(); |
| 48 | + }); |
| 49 | +}); |
| 50 | +``` |
| 51 | + |
| 52 | +## API |
| 53 | + |
| 54 | +### `screen` |
| 55 | + |
| 56 | +Provides methods to query and interact with UI elements on screen. |
| 57 | + |
| 58 | +#### `findByTestId(testId: string): Promise<ElementReference>` |
| 59 | + |
| 60 | +Finds an element by its testID (accessibilityIdentifier on iOS, tag on Android). |
| 61 | +Throws an error if no element is found. |
| 62 | + |
| 63 | +#### `findAllByTestId(testId: string): Promise<ElementReference[]>` |
| 64 | + |
| 65 | +Finds all elements by testID. Throws an error if no elements are found. |
| 66 | + |
| 67 | +#### `queryByTestId(testId: string): ElementReference | null` |
| 68 | + |
| 69 | +Queries for an element by testID without throwing. Returns null if not found. |
| 70 | + |
| 71 | +#### `queryAllByTestId(testId: string): ElementReference[]` |
| 72 | + |
| 73 | +Queries for all elements by testID without throwing. Returns an empty array if none found. |
| 74 | + |
| 75 | +#### `findByAccessibilityLabel(label: string): Promise<ElementReference>` |
| 76 | + |
| 77 | +Finds an element by its accessibility label. Throws an error if no element is found. |
| 78 | + |
| 79 | +#### `findAllByAccessibilityLabel(label: string): Promise<ElementReference[]>` |
| 80 | + |
| 81 | +Finds all elements by accessibility label. Throws an error if no elements are found. |
| 82 | + |
| 83 | +#### `queryByAccessibilityLabel(label: string): ElementReference | null` |
| 84 | + |
| 85 | +Queries for an element by accessibility label without throwing. Returns null if not found. |
| 86 | + |
| 87 | +#### `queryAllByAccessibilityLabel(label: string): ElementReference[]` |
| 88 | + |
| 89 | +Queries for all elements by accessibility label without throwing. Returns an empty array if none found. |
| 90 | + |
| 91 | +#### `screenshot(element?: ElementReference): Promise<ScreenshotResult | null>` |
| 92 | + |
| 93 | +Captures a screenshot of the entire app window or a specific element. |
| 94 | +Returns a ScreenshotResult with PNG data, or null if capture fails. |
| 95 | + |
| 96 | +### `userEvent` |
| 97 | + |
| 98 | +Provides methods to simulate user interactions. |
| 99 | + |
| 100 | +#### `press(element: ElementReference): Promise<void>` |
| 101 | + |
| 102 | +Simulates a press on the given element at its center point. |
| 103 | + |
| 104 | +#### `pressAt(x: number, y: number): Promise<void>` |
| 105 | + |
| 106 | +Simulates a press at the specified screen coordinates. |
| 107 | + |
| 108 | +#### `type(element: ElementReference, text: string, options?: TypeOptions): Promise<void>` |
| 109 | + |
| 110 | +Simulates typing text into a text input element. Focuses the element, types each character, and blurs the element. |
| 111 | + |
| 112 | +**TypeOptions:** |
| 113 | +- `skipPress?: boolean` - If true, pressIn and pressOut events will not be triggered |
| 114 | +- `skipBlur?: boolean` - If true, endEditing and blur events will not be triggered |
| 115 | +- `submitEditing?: boolean` - If true, submitEditing event will be triggered after typing |
| 116 | + |
| 117 | +## Types |
| 118 | + |
| 119 | +### `ElementReference` |
| 120 | + |
| 121 | +Represents an element found on screen with its position and dimensions. |
| 122 | + |
| 123 | +```typescript |
| 124 | +type ElementReference = { |
| 125 | + x: number; |
| 126 | + y: number; |
| 127 | + width: number; |
| 128 | + height: number; |
| 129 | + // ... additional view info |
| 130 | +}; |
| 131 | +``` |
| 132 | + |
| 133 | +### `ScreenshotResult` |
| 134 | + |
| 135 | +Screenshot result containing PNG image data. |
| 136 | + |
| 137 | +```typescript |
| 138 | +interface ScreenshotResult { |
| 139 | + data: Uint8Array; // PNG image data |
| 140 | + width: number; // Width in logical pixels |
| 141 | + height: number; // Height in logical pixels |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +## Requirements |
| 146 | + |
| 147 | +- React Native project with React Native Harness configured |
| 148 | +- This module is only available in debug builds and is automatically excluded from release builds |
| 149 | + |
| 150 | +## Made with ❤️ at Callstack |
| 151 | + |
| 152 | +`@react-native-harness/ui` is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack][callstack-readme-with-love] is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi! |
| 153 | + |
| 154 | +Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥 |
| 155 | + |
| 156 | +[callstack-readme-with-love]: https://callstack.com/?utm_source=github.com&utm_medium=referral&utm_campaign=react-native-harness&utm_term=readme-with-love |
| 157 | +[license-badge]: https://img.shields.io/npm/l/@react-native-harness/ui?style=for-the-badge |
| 158 | +[license]: https://github.com/callstackincubator/react-native-harness/blob/main/LICENSE |
| 159 | +[npm-downloads-badge]: https://img.shields.io/npm/dm/@react-native-harness/ui?style=for-the-badge |
| 160 | +[npm-downloads]: https://www.npmjs.com/package/@react-native-harness/ui |
| 161 | +[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge |
| 162 | +[prs-welcome]: ../../CONTRIBUTING.md |
| 163 | +[chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=for-the-badge |
| 164 | +[chat]: https://discord.gg/xgGt7KAjxv |
0 commit comments