Skip to content

Commit ebf16dd

Browse files
rubennortefacebook-github-bot
authored andcommitted
Improve Fantom documentation in __docs__/README.md (#56660)
Summary: Expand `private/react-native-fantom/__docs__/README.md` so it's the single source of truth for Fantom usage. Added sections: - Updated the Usage example to import `setUpDefaultReactNativeEnvironment` and explicitly warn against `InitializeCore` (which installs LogBox and breaks Fantom's error handling). All real `-itest.js` files use this import. - New `### Conventions` section: `__tests__` placement, `-benchmark-itest.js` suffix, using `Fantom.runTask()` for rendering, the `ensureInstance` helper, component-specific instance types, ref-based element access, testing imperative APIs / method timing / edge cases, `takeMountingManagerLogs` for command verification, and "don't oversimplify assertions" / "avoid trivial tests" guidance. - New `### Assertions` section: prefer `.toEqual()` + inline JSX over `.toMatchSnapshot()`, full examples for `getRenderedOutput().toJSX()` with `includeLayoutMetrics` and the `props` filter, plus an element-level assertion example covering `tagName`, `getBoundingClientRect`, and child structure. - New `### Limitations` section: cannot nest `runTask()`, subset of Jest API, tests must live under `packages/react-native`. - New `#### C++ sampling profiler` subsection under Profiling, documenting `FANTOM_PROFILE_CPP` (parallel to the existing JS profiler section). Pure API references (`setLogBoxCheckEnabled`, `dispatchNativeEvent`, `scheduleTask`, `enqueueNativeEvent`, `runOnUIThread`, `runWorkLoop`, `scrollTo`, `takeJSMemoryHeapSnapshot`, `createRoot` options, etc.) are not duplicated — they continue to live in the inline source docs in `src/index.js`, which the README points to. Changelog: [Internal] Differential Revision: D103217408
1 parent 1181985 commit ebf16dd

1 file changed

Lines changed: 115 additions & 1 deletion

File tree

  • private/react-native-fantom/__docs__

private/react-native-fantom/__docs__/README.md

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ only a subset of Jest's Global API is currently available. For example,
7070
APIs. If you are blocked by the lack of a specific API, please reach out to us.
7171

7272
Most of the interesting APIs are available via the `@react-native/fantom`
73-
package:
73+
package. Test files should also import `setUpDefaultReactNativeEnvironment` at
74+
the top to set up the React Native environment. **Do not import
75+
`InitializeCore`** — it installs LogBox, which interferes with Fantom's error
76+
handling.
7477

7578
```javascript
79+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
7680
import * as Fantom from '@react-native/fantom';
7781

7882
describe('My feature', () => {
@@ -108,6 +112,97 @@ Similar to Jest, you can also run Fantom in watch mode using `--watch`:
108112
yarn fantom <regexForTestFiles> --watch
109113
```
110114

115+
### Conventions
116+
117+
- Place test files in `__tests__` directories alongside the code being tested.
118+
- Benchmark tests use the `-benchmark-itest.js` suffix.
119+
- Use `Fantom.runTask()` to render and run synchronous operations; it ensures
120+
the React work is flushed before assertions.
121+
- Access elements through refs and use the
122+
[`ensureInstance`](../../../packages/react-native/src/private/__tests__/utilities/ensureInstance.js)
123+
helper for type-safe access to the underlying instance:
124+
125+
```javascript
126+
import ensureInstance from 'react-native/src/private/__tests__/utilities/ensureInstance';
127+
128+
const element = ensureInstance(elementRef.current, ReactNativeElement);
129+
```
130+
131+
- Prefer component-specific instance types (`TextInputInstance`,
132+
`ScrollViewInstance`, etc.) over the generic `HostInstance` when available.
133+
- For components with imperative APIs (`focus`, `blur`, `clear`, etc.), test:
134+
- Each method's behaviour and edge cases (e.g. `blur` when not focused).
135+
- Method timing — that it works when called from refs, `useLayoutEffect`, and
136+
`useEffect`.
137+
- Verify that native commands are dispatched with
138+
`root.takeMountingManagerLogs()`.
139+
- Don't write tests with only trivial assertions like
140+
`expect(element).toBeDefined()` when more complex behaviour is under test.
141+
When a test fails, understand what should render rather than weakening the
142+
assertion to make it pass.
143+
144+
### Assertions
145+
146+
Prefer evaluating rendered output inline with `.toEqual()` and inline JSX over
147+
`.toMatchSnapshot()` or weak numeric assertions like
148+
`element.childNodes.length`.
149+
150+
```javascript
151+
// Get JSX representation
152+
expect(root.getRenderedOutput().toJSX()).toEqual(
153+
<rn-view width="100" height="50" />,
154+
);
155+
156+
// Include layout metrics
157+
expect(root.getRenderedOutput({includeLayoutMetrics: true}).toJSX()).toEqual(
158+
<rn-view
159+
layoutMetrics-frame="{x:0,y:0,width:100,height:50}"
160+
layoutMetrics-displayType="Flex"
161+
/>,
162+
);
163+
164+
// Filter to specific props for minimal assertions
165+
expect(root.getRenderedOutput({props: ['backgroundColor']}).toJSX()).toEqual(
166+
<rn-view backgroundColor="rgba(255, 0, 0, 1)" />,
167+
);
168+
```
169+
170+
For element-level assertions, get a typed reference and inspect tag names,
171+
layout metrics, or children:
172+
173+
```javascript
174+
const elementRef = createRef<HostInstance>();
175+
176+
Fantom.runTask(() => {
177+
root.render(
178+
<View ref={elementRef}>
179+
<Text>the quick brown fox</Text>
180+
</View>,
181+
);
182+
});
183+
184+
const element = ensureInstance(elementRef.current, ReactNativeElement);
185+
expect(element.tagName).toBe('RN:View');
186+
187+
const bounds = element.getBoundingClientRect();
188+
expect(bounds.width).toBe(100);
189+
expect(bounds.height).toBe(50);
190+
191+
expect(root.getRenderedOutput().toJSX()).toEqual(
192+
<rn-view>
193+
<rn-paragraph>the quick brown fox</rn-paragraph>
194+
</rn-view>,
195+
);
196+
```
197+
198+
### Limitations
199+
200+
- `Fantom.runTask()` calls cannot be nested — doing so will throw.
201+
- Only a subset of Jest's Global API is available (e.g. `test.each` is not
202+
implemented). Reach out if you're blocked by a specific missing API.
203+
- Tests must live within `packages/react-native`; Fantom is not currently
204+
intended for application-specific code.
205+
111206
### Test configuration
112207

113208
You can configure certain aspects of the test execution using pragmas in the
@@ -303,6 +398,25 @@ memory heap and print a message indicating where it was saved. E.g.:
303398
You can have multiple calls to `Fantom.takeJSMemoryHeapSnapshot()` in your test,
304399
and each one will create a different file.
305400

401+
#### C++ sampling profiler
402+
403+
You can automatically record C++ sampling profiler traces (with DWARF call
404+
graphs) by wrapping the Fantom tester binary with Linux `perf record`. Run your
405+
fantom test with the flag `FANTOM_PROFILE_CPP`:
406+
407+
```shell
408+
FANTOM_PROFILE_CPP=1 yarn fantom <regexForTestFiles>
409+
```
410+
411+
Output is saved to `.out/cpp-traces/perf-<timestamp>.data`. Analyze it with:
412+
413+
```shell
414+
perf report -i .out/cpp-traces/perf-<timestamp>.data
415+
```
416+
417+
This is not available on CI (the runner will throw an error if attempted) and
418+
requires `perf` to be installed on the host.
419+
306420
### Running the full suite locally
307421

308422
When running the entire suite locally, set `FANTOM_FORCE_CI_MODE=1`:

0 commit comments

Comments
 (0)