|
| 1 | +# Test Environment & Lifecycle |
| 2 | + |
| 3 | +Understanding the execution lifecycle of React Native Harness is key to configuring complex test suites and ensuring test isolation. |
| 4 | + |
| 5 | +## Execution Lifecycle |
| 6 | + |
| 7 | +When you run `react-native-harness`, the following process occurs for each test file: |
| 8 | + |
| 9 | +1. **Node.js Setup**: The CLI loads your configuration and prepares the Metro bundler. |
| 10 | +2. **App Preparation**: The target app is launched or brought to the foreground on the device. |
| 11 | +3. **Harness Initialization**: The native bridge is established. |
| 12 | +4. **`setupFiles`**: Global setup files are evaluated in the app environment. |
| 13 | +5. **Test Collection**: The test file is evaluated to build a structure of `describe` and `it` blocks. |
| 14 | + - **`setupFilesAfterEnv`**: These files are evaluated *during* this phase. |
| 15 | +6. **Execution**: Tests are run serially on the device. |
| 16 | +7. **Teardown**: Results are sent back to the CLI, and the environment is cleaned up. |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Setup Files |
| 21 | + |
| 22 | +Harness supports two types of setup files, configured in your `jest.harness.config.mjs`. |
| 23 | + |
| 24 | +### `setupFiles` |
| 25 | +Executed **before** the testing environment is initialized. |
| 26 | +- **Context**: Runs in the app's JavaScript environment, but *before* the Test Runner has initialized the test framework (Jest). |
| 27 | +- **Limitations**: `describe`, `it`, `expect`, and `beforeEach` are **not available**. |
| 28 | +- **Use Case**: Polyfilling global APIs that the environment or third-party libraries expect to exist immediately upon import. |
| 29 | + |
| 30 | +```javascript |
| 31 | +// jest.setup.js |
| 32 | +// Polyfill URL for React Native |
| 33 | +import 'react-native-url-polyfill/auto'; |
| 34 | + |
| 35 | +// Polyfill TextEncoder |
| 36 | +import { TextEncoder, TextDecoder } from 'text-encoding'; |
| 37 | +global.TextEncoder = TextEncoder; |
| 38 | +global.TextDecoder = TextDecoder; |
| 39 | +``` |
| 40 | + |
| 41 | +### `setupFilesAfterEnv` |
| 42 | +Executed **after** the testing environment is initialized, but before the test file itself. |
| 43 | +- **Context**: Runs immediately before the test file is executed. The test framework is fully loaded. |
| 44 | +- **Capabilities**: Full access to `describe`, `it`, `expect`, `beforeEach`, and Harness APIs like `mock`, `spyOn`, `clearAllMocks`, etc. |
| 45 | +- **Use Case**: Configuring global mocks, custom matchers, or global setup/teardown hooks. |
| 46 | + |
| 47 | +```javascript |
| 48 | +// jest.setupAfterEnv.js |
| 49 | +import { beforeEach, afterEach, clearAllMocks, mock } from 'react-native-harness'; |
| 50 | + |
| 51 | +// Global cleanup |
| 52 | +afterEach(() => { |
| 53 | + clearAllMocks(); |
| 54 | +}); |
| 55 | + |
| 56 | +// Mock a global library that is used in many tests |
| 57 | +mock('react-native-safe-area-context', () => ({ |
| 58 | + useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 }), |
| 59 | +})); |
| 60 | +``` |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Isolation and Persistence |
| 65 | + |
| 66 | +### Environment Reset |
| 67 | +By default, Harness ensures test isolation by resetting the environment between test files. |
| 68 | + |
| 69 | +- **`resetEnvironmentBetweenTestFiles`**: (Default: `true`) When enabled, the app is fully restarted between different test files. This prevents state leakage (like singleton native modules or global variables) from affecting subsequent tests. |
| 70 | + |
| 71 | +### Native Module Mocking |
| 72 | +Mocks created via `mock()` are tied to the module cache. Use `resetModules()` in an `afterEach` hook to ensure mocks don't leak between individual tests within the same file. |
| 73 | + |
| 74 | +--- |
| 75 | + |
| 76 | +## Native Crash Detection |
| 77 | + |
| 78 | +Testing native modules often involves calling code that might cause the host application to crash. Standard test runners often hang or report a generic "Device disconnected" error in these cases. |
| 79 | + |
| 80 | +Harness includes a built-in **Native Crash Monitor**: |
| 81 | + |
| 82 | +- **`detectNativeCrashes`**: (Default: `true`) When enabled, Harness actively monitors the native process. If the app crashes, Harness catches the failure, reports a `NativeCrashError` for the current test, and automatically restarts the app to continue with the remaining test files. |
| 83 | +- **`crashDetectionInterval`**: (Default: `500ms`) How often the CLI polls the device to ensure the app is still alive. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## Forwarding Client Logs |
| 88 | + |
| 89 | +To aid in debugging, you can forward all `console` output from the device to your terminal. |
| 90 | + |
| 91 | +```javascript title="rn-harness.config.mjs" |
| 92 | +export default { |
| 93 | + // ... |
| 94 | + forwardClientLogs: true, |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +When enabled, logs from the device appear in your terminal with indicators: |
| 99 | +- ` LOG ` - `console.log` |
| 100 | +- ` WARN ` - `console.warn` |
| 101 | +- ` ERROR ` - `console.error` |
0 commit comments