Skip to content

Commit 4d2be2b

Browse files
committed
docs: revise the contents
1 parent 3edd100 commit 4d2be2b

15 files changed

Lines changed: 526 additions & 450 deletions

File tree

website/src/docs/_meta.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"name": "getting-started",
55
"label": "Getting Started"
66
},
7+
{
8+
"type": "dir",
9+
"name": "platforms",
10+
"label": "Platforms"
11+
},
712
{
813
"type": "dir",
914
"name": "api",
@@ -19,4 +24,4 @@
1924
"name": "feature-comparison",
2025
"label": "Feature Comparison"
2126
}
22-
]
27+
]

website/src/docs/api/_meta.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,15 @@
2323
"type": "file",
2424
"name": "rendering-components",
2525
"label": "Rendering Components"
26+
},
27+
{
28+
"type": "file",
29+
"name": "test-environment",
30+
"label": "Test Environment & Lifecycle"
31+
},
32+
{
33+
"type": "file",
34+
"name": "cli",
35+
"label": "CLI Reference"
2636
}
2737
]

website/src/docs/api/cli.mdx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# CLI Reference
2+
3+
The `react-native-harness` command is a powerful wrapper around the Jest CLI. It provides seamless integration with native environments while maintaining the familiar Jest developer experience.
4+
5+
## Commands
6+
7+
### `init`
8+
9+
Runs the interactive setup wizard to configure React Native Harness in your project.
10+
11+
```bash
12+
npx react-native-harness init
13+
```
14+
15+
The wizard will help you:
16+
- Detect your project type (Expo or React Native CLI).
17+
- Install required platform packages.
18+
- Configure Android, iOS, or Web runners.
19+
- Generate configuration files (`rn-harness.config.mjs` and `jest.harness.config.mjs`).
20+
21+
### `(default)`
22+
23+
Runs tests using the Harness test runner.
24+
25+
```bash
26+
npx react-native-harness [test-file-pattern] [options]
27+
```
28+
29+
## Options
30+
31+
### Harness Specific Flags
32+
33+
| Flag | Description |
34+
| :--- | :--- |
35+
| `--harnessRunner <name>` | Specify which runner from your `rn-harness.config.mjs` to use. **Note:** Only one runner can be specified per command execution. |
36+
| `--config, -c <path>` | Path to your Harness Jest configuration (defaults to `jest.harness.config.mjs`). |
37+
38+
### Running on Multiple Platforms
39+
40+
Harness executes tests on a single runner at a time to ensure isolated and reliable reporting. To run tests on multiple platforms (e.g., both iOS and Android in CI), you must execute the command separately for each runner:
41+
42+
```bash
43+
# Run Android tests
44+
npx react-native-harness --harnessRunner android
45+
46+
# Run iOS tests
47+
npx react-native-harness --harnessRunner ios
48+
```
49+
50+
### Supported Jest Flags
51+
52+
React Native Harness supports the most commonly used Jest flags:
53+
54+
- `--watch`: Watch files for changes and rerun tests related to changed files.
55+
- `--coverage`: Indicates that test coverage information should be collected and reported in the output.
56+
- `--testNamePattern, -t`: Run only tests with a name that matches the regex.
57+
- `--testPathPattern`: A regexp string that is matched against all tests paths before executing the test.
58+
- `--verbose`: Display individual test results with the test suite hierarchy.
59+
60+
## Restrictions and Limitations
61+
62+
To ensure stability and compatibility with real native devices, React Native Harness **disables** or **restricts** certain standard Jest CLI options.
63+
64+
### Forced Serial Execution
65+
66+
Harness executes tests **serially** (one at a time) on the target device to prevent native resource conflicts (like multiple tests trying to access the camera or filesystem simultaneously).
67+
68+
The following Jest flags are **ignored or disabled**:
69+
- `--maxWorkers`
70+
- `--runInBand` (Implicitly always true)
71+
- `--maxConcurrency`
72+
- `--shard`
73+
74+
### Restricted Configuration Overrides
75+
76+
Harness manages the test environment, transformation, and module resolution internally to ensure tests can be bundled by Metro and run on-device.
77+
78+
The following Jest configuration flags are **disabled**:
79+
- `--runner` / `--testRunner`
80+
- `--testEnvironment`
81+
- `--preset`
82+
- `--transform` / `--transformIgnorePatterns`
83+
- `--resolver`
84+
- `--globals`
85+
86+
### Snapshot Management
87+
88+
Snapshot testing for UI is handled via the separate `@react-native-harness/ui` package and the `toMatchImageSnapshot` matcher. Standard Jest snapshot flags like `--updateSnapshot` (`-u`) are currently not supported for native image snapshots.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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`

website/src/docs/getting-started/_meta.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
"name": "problem-statement",
1010
"label": "Problem Statement"
1111
},
12+
{
13+
"type": "file",
14+
"name": "architecture",
15+
"label": "Architecture"
16+
},
1217
{
1318
"type": "file",
1419
"name": "quick-start",
@@ -24,4 +29,4 @@
2429
"name": "prior-art",
2530
"label": "Prior Art"
2631
}
27-
]
32+
]
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Architecture
2+
3+
React Native Harness is designed to bridge the gap between Node.js-based test runners (like Jest) and the native environment of mobile devices. Understanding how it works demystifies the "magic" and helps you configure it effectively.
4+
5+
## High-Level Overview
6+
7+
At its core, React Native Harness operates by replacing your application's standard Metro bundle with a specialized **Test Bundle**. This bundle contains the Harness Test Runner, which executes tests directly on the device.
8+
9+
The architecture consists of three main components:
10+
11+
1. **Harness CLI (Node.js)**: Orchestrates the test run, manages the device, and reports results.
12+
2. **Metro Bundler**: Serves the Test Bundle to the device.
13+
3. **Harness Native Runner (Device)**: A lightweight runtime injected into your app that executes tests and communicates with the CLI.
14+
15+
## How It Works
16+
17+
### 1. The Test Bundle
18+
When you run `react-native-harness`, the CLI instructs Metro to bundle a special entry point instead of your app's `index.js`. This initial bundle contains:
19+
* The Harness Test Runner.
20+
* Your app's native modules (since the native binary is unchanged).
21+
22+
Note that **test files are not included in this initial bundle**. This keeps the initial load fast and allows Harness to manage test isolation and execution dynamically.
23+
24+
### 2. Device Injection
25+
Harness does **not** modify your native code (`.ipa` or `.apk`). Instead, it relies on the standard React Native development mechanism:
26+
1. The CLI launches your existing Debug app on the simulator/emulator.
27+
2. The app connects to Metro to download the JavaScript bundle.
28+
3. Metro serves the **Test Bundle** (the runner).
29+
4. The app loads the bundle, and instead of rendering your `App.tsx`, it starts the Harness Test Runner.
30+
31+
### 3. The Bridge (WebSocket)
32+
Once the Test Runner starts on the device, it establishes a WebSocket connection back to the Harness CLI on your computer (default port `3001`). This bridge is used for:
33+
* **Control**: The CLI tells the device which tests to run.
34+
* **Reporting**: The device sends assertions, failures, and logs back to the CLI.
35+
* **Lifecycle**: The CLI monitors the device for crashes or timeouts.
36+
37+
### 4. Test Execution
38+
Tests are executed **serially** on the device:
39+
1. The **CLI** sends a command to the **Runtime** (on the device) to run a specific test file.
40+
2. The **Runtime** requests **Metro** to bundle that specific test file.
41+
3. The **Runtime** downloads and evaluates the bundled test file.
42+
4. Tests are executed using the Jest-compatible `describe`/`it` API.
43+
5. Results are sent back to the **CLI**.
44+
45+
## Key Takeaways
46+
47+
* **No Native Changes**: You don't need to change your `AppDelegate` or `MainActivity` to use Harness. It works entirely through JavaScript bundle swapping.
48+
* **Single Runtime**: Tests run in the same JS thread as your app would, ensuring accurate behavior for native module calls.
49+
* **Debug Builds**: Harness requires a Debug build of your app to load the bundle from Metro. It cannot run on Release builds (which have the bundle pre-packaged).

0 commit comments

Comments
 (0)