Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58631
Fantom's CI retries use Jest's `--onlyFailures` mode. Jest 29's default sequencer caches suite-level runtime errors as passing because they contain no failed test cases, so retries select no suites.
See https://github.com/react/react-native/actions/runs/35630015753/job/106440689782?pr=58624 of an example of this, where retries didn't actually do anything
Add a Fantom-specific sequencer that marks runtime-error suites as failed only for cache bookkeeping. This preserves the original test reporting while ensuring targeted retries rerun the crashed suite.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D121063351
fbshipit-source-id: e24737cc247ea0e11aa04dac74d557a3f41f9db6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58605
Use global DOM APIs, supported React Native entry points, and package-relative implementation imports throughout Fantom. Use the renderer-only private interface for the existing public-instance conversion helpers instead of importing Node internals.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D120717572
fbshipit-source-id: 1aae11b7b9434c783d42ca289e2c6edd17aa887c
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58573
Migrate the remaining Flow-visible deep imports in React Native tests. Use public DOM globals where their types are sufficient, and use relative imports for implementation-specific helpers, observer types, and native specs that are not publicly exported.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D120537585
fbshipit-source-id: ea494dd65c68cbd556ec31bea58aee22e5cc06b3
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58569
Replace Fantom test imports of internal Event, EventTarget, AbortController, and feature flag modules with supported exports and global DOM APIs. Add the missing static Event phase constants to the DOM Flow declarations so constructor constants remain typed, and route trusted-event coverage through `dispatchNativeEvent`.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D120528709
fbshipit-source-id: 9d991904dbe1f4cb061a9629026a6fc3cbc3dd16
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58567
Replace eligible React Native deep imports in Fantom tests with package exports, Fantom APIs, DOM globals, and types derived from exported symbols. Keep implementation-specific imports where the public surface does not expose equivalent behavior or compatible Flow types.
Changelog: [Internal]
___
Reviewed By: cipolleschi
Differential Revision: D120517166
fbshipit-source-id: 6ba6ec2c6159cca6309f558ccf478c49220e85fc
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58554
Generate component descriptor headers through the public <React/ComponentRegistry.h> umbrella instead of directly including ComponentDescriptorProviderRegistry.h. Refresh codegen snapshots and the checked-in popup-menu binding, and export the ComponentRegistry dependency needed by that public generated header.
Changelog:
[Internal].
Reviewed By: cipolleschi
Differential Revision: D120317127
fbshipit-source-id: fedea53bbe65e22ae53ed00a7fde787b2581bfab
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58468
Reformat the Kotlin and Kotlin Gradle sources with the npm-backed ktfmt 0.59.0 command after Arcanist formatting has been disabled for OSS-exported sources.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119504762
fbshipit-source-id: 8a594f04ad72bd2d42baa49e578a4b0fa926b6bf
Summary:
> Stack 3/3 — parent: `feat/LayoutEventEmitter`. Review the two parents first.
Implements the [`ResizeObserver`](https://drafts.csswg.org/resize-observer/) Web API for the New Architecture, behind the `enableResizeObserverByDefault` flag (off by default).
The motivation is Web compatibility, and it's more capable than `onLayout`: callers pick which box to observe (`content-box`, `border-box`, `device-pixel-content-box`) and the sizes for those boxes are delivered in the notification.
The design is as follows: JS `ResizeObserver`/`ResizeObserverEntry`/`ResizeObserverSize` on top of a manager singleton and the `NativeResizeObserver` TurboModule, using the same notify + `takeRecords` pull model. In C++, `ResizeObserverManager` collects observed targets whose layout changed at commit time (via `shadowTreeDidCommit`) and then computes and delivers observations in the event loop's "update the rendering" step (`RuntimeSchedulerResizeObserverDelegate::runResizeObservations`), as the spec requires. Requires bridgeless + the modern event loop; the legacy scheduler gets a no-op delegate.
`runResizeObservations` implements the spec's depth-increasing gather/broadcast loop: each round gathers observations deeper than the shallowest target delivered in the previous round, so a callback that synchronously resizes or observes a shallower node is still delivered within the same tick.
Known deviations from the spec (each pinned by a test):
- Resizes triggered from a callback via a React state update are delivered on the next tick rather than within the current loop, because RN has no synchronous re-layout. Callbacks that resize or `observe()` synchronously do run further rounds in the same tick, and report `ResizeObserver loop completed with undelivered notifications` when an observation is left undelivered.
- The loop carries a hard cap of 100 iterations on top of the spec's depth rule. Reaching the cap reports the loop error and stops, so a pathological callback degrades to a log line instead of a frozen app.
- Re-observing a target with the same box is a no-op and does not re-deliver. This matches browsers, not the literal `observe()` algorithm.
- Callback order across observers follows first-`observe()` order rather than construction order.
## Changelog:
[INTERNAL] [ADDED] - Add the `ResizeObserver` API, behind the `enableResizeObserverByDefault` feature flag
Pull Request resolved: https://github.com/react/react-native/pull/57723
Test Plan:
- Fantom `ResizeObserver-itest.js` covers many test scenarios.
- rn-tester has `ResizeObserver` examples (box sizes, text, visibility); verified initial, resize, and animation-driven delivery there.
- `RuntimeSchedulerTest.cpp` new test scenarios for update rendering loop.
Reviewed By: christophpurrer
Differential Revision: D114045415
Pulled By: javache
fbshipit-source-id: a561d5321ba45adb35f46ffb0cf26ad78eb3bae6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57936
`react/cxxstableapi` is a header-only module — the stable API guards are pure
preprocessor headers with no compilable source. Under `use_frameworks!`,
CocoaPods emits a `PBXAggregateTarget` for a pod with no compilable sources, and
an aggregate target produces no `.framework`, so pods depending on
`React-cxxstableapi` cannot resolve the guard headers.
Add an anchor translation unit so the pod has one source and CocoaPods emits a
real framework target instead, and widen the podspec's build-from-source glob to
pick it up. The prebuilt glob stays headers-only, since prebuilt pods do not
generate frameworks. This mirrors the existing `CSSDummy.cpp` anchor for the
header-only `React-renderercss` pod.
Also register `react/cxxstableapi` as a subdirectory of the Fantom tester CMake
build so the guard headers resolve there.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D115859623
fbshipit-source-id: 47e63560e1478ad507d1f28f053b925438232ea4
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57783
# Changelog: [Internal]
Adds the `enableConditionalUseWarning` dynamic React feature flag, which the React renderer reads from `ReactNativeInternalFeatureFlags`. The flag gates the new warning for conditional use of `use()` based on cache state: https://react.dev/warnings/conditional-use-of-use
This is a dev-only warning, I don't see any reasons to control this via gk.
Reviewed By: antonk52
Differential Revision: D114407789
fbshipit-source-id: d63dd09180e6560a82d178610c7ae24b9e31b65e
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57611
Directly follows D112733139 (Metro).
**Motivation**
- New Node builtins are *only* available under the prefix (e.g. `node:sqlite`), as this allows Node to introduce them without ecosystem-breaking changes, so this is the direction of travel and the only choice that'll allow consistency.
- Encouraging them and grouping them separately makes it easier to reason about a module's 3rd party dependencies.
Changelog: [Internal]
Reviewed By: robhogan
Differential Revision: D112803684
fbshipit-source-id: 40668d746a7151b3aa4800ff8af997902a18d198
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57587
Adds rethrow in catch blocks when `startJSSamplingProfiler()` fails, preventing the `finally` block from attempting to stop a profiler that was never started.
Changelog: [Internal]
Reviewed By: thegreatercurve
Differential Revision: D112405579
fbshipit-source-id: 4b1cc6746d8ba29df99be57e583ee06ac742c12c
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57486
`prettier --list-different` (run via `yarn format-check`) flagged the react-native-fantom `__docs__/README.md` as unformatted. Re-wrap the two affected prose lines to prettier's print width so the docs pass the formatting check.
No content changes; formatting only.
Changelog: [Internal]
___
Differential Revision: D111041556
fbshipit-source-id: cab15f502e941d908503e0873fe8cba12b48686f
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57467
Adds a convention to the Fantom README recommending that tests exercise React Native through its public API (importing from `react-native`) whenever possible, rather than reaching into internal modules. Exercising the public surface also drives the underlying native (Fabric/TurboModules) code, so tests stay close to real usage and are more resilient to internal refactors.
Changelog:
[Internal]
Reviewed By: christophpurrer
Differential Revision: D110918650
fbshipit-source-id: b19dc4b4a380030196a4e83890aae6720a64c77f
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57443
The Fantom REPL (`yarn fantom-cli`) crashed on startup with `TypeError: Cannot read properties of undefined (reading 'loadConfig')`. `metro` is a CommonJS module that only provides named exports, so the default import `import Metro from 'metro'` resolves to `undefined` under the Babel interop used to run the REPL, and any access such as `Metro.loadConfig` throws.
Switch to a namespace import (`import * as Metro from 'metro'`), matching how metro is already imported in the Fantom global setup.
Changelog: [Internal]
___
Reviewed By: javache
Differential Revision: D110754395
fbshipit-source-id: f1c7c415f96a6adeb6dde12919983aa9a5a819a4
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57401
The `FANTOM_ENABLE_CPP_DEBUGGING` environment variable was kept only as a legacy alias for `FANTOM_DEBUG_CPP`. Remove it from Fantom so `FANTOM_DEBUG_CPP` is the single supported way to enable the C++ debugger.
Changelog: [Internal]
Reviewed By: sammy-SC
Differential Revision: D110324557
fbshipit-source-id: 2cbde4736137db792b8b99d1806c146e3094ca4b
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57387
Adds `yarn fantom-cli`, an interactive REPL that evaluates JavaScript against the same native tester binary and Hermes runtime that Fantom tests run in. State persists across lines, input goes through Metro/Babel (so `import`, JSX and Flow all work), and the environment is set up the same way tests set it up — `React`, `ReactNative` and the `Fantom` API are available globally, so you can render surfaces and drive them interactively from the prompt.
The native tester gains an `--interactive` mode that loads a warm-up bundle without running tests and then evaluates length-prefixed snippets read from stdin, reporting results, console output and errors back as newline-delimited JSON. A Node driver hosts a Metro server, builds the warm-up bundle, spawns the binary, and bridges each line of input into the live runtime (top-level declarations persist across evaluations).
Features:
- Console-style output: results are printed with an inspector similar to the Chrome DevTools / Node.js consoles (nested objects/arrays up to a depth limit, quoted strings, functions/classes, `Map`/`Set`/`RegExp`/`Date`/`Error`, class instances, circular references, multi-line wrapping), colorized by type when stdout is a terminal. Inspecting a property never aborts the result or leaks into later evaluations: a property whose getter fails renders as `[Thrown: <error>]`, including getters that fail asynchronously through the runtime's global error handler (e.g. accessing a `react-native` export backed by a TurboModule that isn't registered).
- Autocompletion: pressing Tab completes global identifiers, in-scope bindings and object properties (property names are listed without invoking getters).
- Node-like CLI: with no arguments it starts the REPL; `-e <code>` evaluates a snippet and exits; a filename runs that script and exits. In the non-interactive modes the value of a trailing expression is not printed (use `console.log`) and a thrown error exits with a non-zero status code.
Also documents the REPL in the Fantom README.
Changelog: [Internal]
Reviewed By: javache, sammy-SC
Differential Revision: D110187712
fbshipit-source-id: 3e76c498ae04b8b1ce9e0e27e5ce6b6a0cd11e09
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57378
Refactor Metro imports to:
- Remove use of deprecated default object export, prefer named/namespace exports.
- Prefer imports from `metro`, remove public dependencies on `metro-core` and `metro-config` from `react-native/community-cli-plugin`.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D110177050
fbshipit-source-id: f21a561d40d13f354bc56cdc50d6e6d6843877cc
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57358
The `enableEagerAlternateStateNodeCleanup` flag is no longer read by the renderer, so the feature-flag definition and the two prelude overrides that forced it on become dead code.
[Internal]
Reviewed By: lenaic
Differential Revision: D110043719
fbshipit-source-id: 24a7e2b85ec60da1cb1855f444bba5e1e6fc4288
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57274
Fantom could not deterministically fire delayed JS timers: the timer registry it used scheduled timers on a real background thread with real wall-clock delays, so `setTimeout(fn, 100)`/`setInterval` callbacks never fired within a synchronous test. This adds a mockable timer registry and a public Fantom API to control it from JS, similar to `installHighResTimeStampMock`.
- New `Fantom.installTimerMock()` returns a controller with `advanceTimersByTime(ms)`, `runAllTimers()`, `getPendingTimerCount()`, and `uninstall()` (jest fake-timer style). While installed, `setTimeout`/`setInterval` callbacks only fire when the virtual clock is advanced.
- New deterministic `FantomTimerRegistry` (no background thread) keyed off a virtual clock, injected via a new optional `platformTimerRegistryFactory` seam on `ReactInstanceConfig` (the default registry is unchanged for all other consumers).
- `PlatformTimerRegistry` gains a virtual `setTimerManager` (default no-op) so the registry can be wired polymorphically.
- Control flows from JS through new `NativeFantom` methods, the same way the high-res timestamp mock works.
Default (non-mock) behavior is preserved: zero-delay `setTimeout` still fires on the next work loop, and existing tests are unaffected.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D109017304
fbshipit-source-id: 8afe6fb2a39f470ae293038f6592c46535442dc2
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57272
Fantom integration tests declared with `fantom_mode dev` rely on debug-only native APIs (e.g. timer mocking via `installHighResTimeStampMock`) that are only compiled when the native tester is built in debug mode.
Under some build configurations the active platform pins the core build mode to optimized, so the preprocessor flag that gates those debug-only APIs is not defined and the tester is compiled in optimized mode. As a result, dev-mode tests that depend on those APIs throw at runtime (e.g. "Mocking timers is not supported in optimized builds").
A previous attempt stacked a build-mode constraint on the Hermes build mode setting, which the native preprocessor flags never read, so it had no effect. Stack the constraint on the core build mode setting that actually gates the flag instead, so the tester is compiled in the test's intended dev/opt mode.
Changelog: [Internal]
Reviewed By: ellemac123
Differential Revision: D109014401
fbshipit-source-id: a04d75d299e3d2a0d1ccabcc2629833ac7a9dbd6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57226
This removes the experimental `enableImageRequestDowngradingForNonVisibleImages` feature flag and backs out the behavior it gated. When enabled, `ImageShadowNode` downgraded image requests to prefetch priority for images that layout determined did not intersect the viewport — threading an `ImageRequestPriority` through `ImageRequestParams` and the Apple image managers, and propagating per-node viewport frames during Yoga layout via `experimental_layoutOrigin`/`experimental_layoutFrame` on `LayoutContext`.
The flag defaulted to off and was never enabled in a release, and the gated behavior did not deliver the expected improvement, so the feature is removed entirely: `<Image>` once again always requests at immediate priority. This deletes the feature flag, the `ImageRequestPriority` enum and the `ImageRequestParams::priority` field, the priority parameter on `RCTImageManager`/`RCTSyncImageManager`/`RCTImageManagerProtocol`, the `experimental_layout*` `LayoutContext` fields and their Yoga propagation, the iOS request-priority debug overlay, and the associated Fantom test scaffolding. The generated feature-flag sources and the C++ API snapshots are regenerated accordingly.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D108411690
fbshipit-source-id: 1538ec699ed2857f3d3154d666fac43a1dc64cd1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57034
With D107165685, it should work this time.
Changelog: [Internal]
Reviewed By: gkz
Differential Revision: D107111468
fbshipit-source-id: 326b2911088d7c87c3564a578125eeaab9d0b8cc
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56998
Reverts the recent Flow syntax codemods applied across `packages/`, `private/`, and `scripts/` in react-native-github. Specifically restores the previous form for:
- `+T` / `+Instance` style variance annotations on generic type parameters that had been converted to the newer `out T` / `in T` keyword form.
- `+field:` covariant object/interface properties that had been converted to the `readonly field:` modifier form.
- `+[K in keyof T]:` mapped-type covariance that had been converted to `readonly [K in keyof T]:`.
These are purely Flow type-annotation changes with no runtime behavior impact, restoring the form that the rest of the toolchain (in particular Fantom) already supports.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D106813102
fbshipit-source-id: 6bf915d530e130eba9c9d96a2b6c3dc8853594d1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56990
Adds a new `Fantom.getHostPlatform()` API that returns the host
operating system where the Fantom test runner is running (e.g. 'linux',
'macos', 'windows', 'android'). This is different from React Native's
`Platform.OS`, which always reflects the React Native target platform
being tested.
The value is determined by the Node.js Jest runner (via
`process.platform`) and baked into the JS bundle through the existing
`setConstants(...)` pipeline, so no native changes are needed.
- Add `HostPlatform` type and `hostPlatform` field to
`FantomRuntimeConstants`.
- Populate `hostPlatform` from the host platform in the entrypoint
template (maps darwin -> macos, win32 -> windows, etc.).
- Expose `getHostPlatform()` from the public Fantom API.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D106669673
fbshipit-source-id: 6948e0c1eb0075131211d8c5099da96a87306b0a
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56976
changelog: [internal]
Use Fabric layout data to classify image shadow nodes as visible or offscreen on Apple platforms. Offscreen image requests now use `ImageRequestPriority::Prefetch`, which is bridged to the existing `RCTImageLoaderPriorityPrefetch` API, while visible images stay at `Immediate`. The new React Native feature flag defaults to `false` until app-specific gating wires it up.
Reviewed By: javache
Differential Revision: D106074485
fbshipit-source-id: 80ece75cf0d639be1fdbfdd5f19b838b7b64aba6
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56660
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]
Reviewed By: mdvacca, cipolleschi
Differential Revision: D103217408
fbshipit-source-id: ff01523682961914d795ef400954bcb3ded19dc1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56527
Removed parameter names from unused parameters in StubWebSocketClient stub implementation to fix clang-diagnostic-unused-parameter warnings. This stub class implements IWebSocketClient interface with empty method bodies, so all parameters were unused.
Changelog: [Internal]
Reviewed By: philIip
Differential Revision: D101110612
fbshipit-source-id: 859d7e630b6f0fd1836c5706a81f05ffd72471f7
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56541
The Fantom test runner spawns native `fantom-tester` binaries built in
either dev or opt mode based on each test's `fantom_mode` pragma. When
collecting C++ code coverage of the tester binary, however, the build
may switch to a coverage-instrumented build configuration that does not
define `REACT_NATIVE_DEBUG`.
That breaks dev-mode tests that rely on debug-only native APIs. For
example, `installHighResTimeStampMock` in
`private/react-native-fantom/tester/src/NativeFantom.cpp` is gated on
`#ifdef REACT_NATIVE_DEBUG` and throws "Mocking timers is not supported
in optimized builds" otherwise. Tests like `LongTasksAPI-itest.js` (no
`fantom_mode` pragma → defaults to dev) fail in CI coverage runs with
that error.
When invoking buck with coverage enabled, layer the `hermes_build_mode`
constraint on top of the build platform so `rn_build_mode()` (in
`tools/build_defs/oss/rn_defs.bzl`) picks up the right value and adds
`-DREACT_NATIVE_DEBUG` for dev tests.
Reviewed By: fkgozali
Differential Revision: D101832028
fbshipit-source-id: cfb5269dea846f41d9d1f9af1c5ff8bd5828085c
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56538
The Fantom Jest `globalSetup` builds the `fantom-tester` native binaries
upfront, using `globalConfig.collectCoverage` to decide whether to build
the `-coverage` flavor.
However, `runner/coverageUtils.js`'s `shouldCollectCoverage()` returns
`false` for some tests even when `globalConfig.collectCoverage` is true:
- All benchmarks (filename matches `*Benchmark-itest.*`)
- Tests with the `fantom_disable_coverage` pragma
In CI coverage runs, those tests resolve their tester binary path with
`enableCoverage=false` (e.g. `fantom-tester-statichermesstable-opt`),
but `globalSetup` only built the `-coverage` variants, so spawn fails
with `ENOENT` and the test fails with an empty stdout/stderr and exit
code `-2`.
When `enableCoverage` is true, also build the non-coverage tester
variants so coverage-opt-out tests can find their binary.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D101819861
fbshipit-source-id: e82f7c8c548c9477d214e9265c813bf9b54ab141
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56531
Add a section to the Fantom `__docs__/README.md` that recommends running the full suite locally with `FANTOM_FORCE_CI_MODE=1`. In CI mode, `globalSetup` pre-builds the entire `(hermesVariant × enableOptimized)` binary matrix once up-front and per-test buck2 invocations are skipped, which eliminates buck2 daemon contention from the worker pool — a common source of sporadic build failures when many workers race to build different binary variants at the same time.
CI environments (`SANDCASTLE`, `GITHUB_ACTIONS`) already auto-detect this mode; this just documents it for local use.
Changelog: [Internal]
Reviewed By: andrewdacenko
Differential Revision: D101795648
fbshipit-source-id: 984bc8bfd034347b5aee0ff438b037e5eb9d41a8
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56530
Each Fantom test writes a unique `\-<test>.js` entrypoint into
`.out/js-builds/` and then asks Metro to bundle it. Metro's file watcher
(metro-file-map's `FallbackWatcher` on Linux, debounced 100 ms) does not
always observe the new entrypoint by the time the HTTP request arrives,
especially when multiple workers are writing entrypoints concurrently.
The previous retry logic was too narrow:
- Only HTTP 404 was treated as retryable. Metro returns 404 only when the
entry file path itself can't be resolved; an unresolved transitive
dep (e.g. `setUpDefaultReactNativeEnvironment`) returns HTTP 500 with
`{type: 'UnableToResolveError'}` — we'd throw immediately on that.
- Only 3 attempts with a flat 500 ms wait (~1 s total), which is not
enough on a busy host with 8 workers writing entrypoints at once.
This results in ~30 spurious "Failed to request bundle from Metro: Unable
to resolve module ..." failures per run.
Refactor `createBundle` into a focused `fetchBundleWithRetry` helper that:
- Parses Metro's JSON error envelope (`{type, message, ...}` from
`formatBundlingError`) once per response and uses `type` to decide
whether to retry. Retries on HTTP 404, on HTTP 500 with
`UnableToResolveError` or `ResourceNotFoundError`, and on transient
`fetch` network errors. All other failures (transform errors, syntax
errors, real config issues) throw immediately so we don't waste seconds
on them.
- Uses exponential backoff (100 ms → 200 → 400 → 800 → 1.6 s, capped at
2 s) with up to 10 attempts (~11 s total worst case).
- Surfaces a clean error message (parsed from the JSON envelope) when
retries are exhausted.
Changelog: [Internal]
Reviewed By: andrewdacenko
Differential Revision: D101791796
fbshipit-source-id: 805ef9bc6e58fce7c1dc10d0cbbb7fdfa1fa24a5
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56529
Fantom runs every test through a single shared Metro server (started in
`globalSetup`). Jest's default `maxWorkers` is `numCpus - 1`, so on a
high-core box (e.g. 176 CPUs) ~175 workers fire bundle requests at Metro
concurrently. Each in-flight request makes Metro materialize a full
dependency `Graph` (transformed modules, source maps, inverse-deps,
file-watcher subscription), which is hundreds of MB.
The per-test `DELETE` eviction added in D101652820 only releases that
memory after the bundle response completes, so the simultaneous in-flight
set still blows past the previous Node `--max-old-space-size=8192` ceiling
in `scripts/fantom.sh` — the Metro process aborts with
`FATAL ERROR: Ineffective mark-compacts near heap limit` after just a
handful of test suites.
Two coordinated changes that balance throughput and safety:
- `scripts/fantom.sh`: bump the Node heap from 8 GB to 16 GB so we have
headroom over the observed steady-state peak.
- `private/react-native-fantom/config/jest.config.js`: cap `maxWorkers`
at `min(numCpus - 1, 16)`. With 8 workers the heap peaked at ~3 GB
(~400 MB / worker), so 16 workers fits comfortably under a 16 GB cap
with ~40% headroom.
This is intentionally a balance rather than a hard worker cap — bumping
the heap alone would still leave 100+ in-flight graphs racing GC, and
capping workers alone leaves throughput on the table on big machines.
Changelog: [Internal]
Reviewed By: andrewdacenko
Differential Revision: D101791795
fbshipit-source-id: 035c7235c32303f7b7f1eb05698b2a5cba90edc9
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56513
Changelog: [internal]
Fantom previously did not propagate errors thrown inside `runTask` callbacks
(or microtasks queued by them) to Jest, so failing assertions inside tasks
were silently swallowed and only logged via `console.error`. Tests had to
work around this with manual `try`/`catch` blocks and a couple of
`it.skip`s with TODOs.
This installs a Fantom-specific global error handler (via `ErrorUtils.setGlobalHandler`)
that captures the first error reported during the current work loop into
`pendingError`. After `flushMessageQueue()` returns, `runWorkLoop()`
re-throws the captured error so it becomes observable as a Jest failure.
Only the first error in a work loop is re-thrown (subsequent ones are
typically follow-on noise), and `pendingError` is cleared at the start of
each work loop so errors captured during module setup do not spuriously
fail later loops. The post-loop `runLogBoxCheck()` continues to take
precedence, since LogBox diagnostics are more actionable.
With this in place:
- The 'should throw when running a task inside another task' test can use
`expect(...).toThrow(...)` directly instead of manual try/catch.
- The two previously-skipped tests for re-throwing errors from tasks and
microtasks are now enabled.
NOTE: this will cause some tests to start failing, but they're legit failures
Reviewed By: javache
Differential Revision: D101647822
fbshipit-source-id: b9cba056d46cc94a4f6dad5e3665266df62a0211
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56464
Changelog: [internal]
Moved the CI validation checks for `debugCpp` and `profileCpp` from the `run()` function in `tester.js` to `validateEnvironmentVariables()` in `EnvironmentOptions.js`, alongside the existing CI/OSS validation for memory instrumentation.
This centralizes all environment option validation in one place, so invalid configurations are caught early during environment setup rather than at tester execution time.
Reviewed By: javache
Differential Revision: D101159820
fbshipit-source-id: 1e488db6e9de3eb3bac840c4931bb1536f8b5efb
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56435
Avoid printing the result summary table when benchmarks are executed in
test mode. In test mode, benchmarks run only a single iteration with no
warmup, so the timing results are not meaningful for comparison.
The per-suite results table (console.table) was already skipped in test
mode, but the benchmark result was still reported to the runner, which
could cause the cross-variant comparison table to be printed with
meaningless data. This change skips the reportBenchmarkResult call
entirely when running in test mode.
Changelog: [Internal]
Reviewed By: lenaic
Differential Revision: D100795458
fbshipit-source-id: 910f0aa5615ea07fd19b3703a2774e13b4531743
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56401
Add `pushAnimationMutations(Callback)` to the AnimationBackend as a targeted alternative to `trigger()`.
The existing `trigger()` method has two problems:
1. **Blast radius**: It calls `onAnimationFrame()` which invokes ALL registered callbacks. When one animation frontend (e.g. Animated) calls `trigger()` in response to an event, every other frontend (e.g. Reanimated) also spins up unnecessarily.
2. **Broken timestamp on iOS**: `trigger()` uses `std::chrono::steady_clock` which on iOS maps to a different kernel clock than what `CADisplayLink` uses for vsync timestamps. These clocks have different baselines and can diverge over time (e.g. after device sleep), causing animations to see time jumps.
`pushAnimationMutations(Callback)` fixes both issues:
- Executes only the provided callback, not all registered ones
- Uses `AnimationChoreographer::now()` which delegates to `HighResTimeStamp`, providing a timestamp from the same clock as the vsync path on each platform
Also refactors `onAnimationFrame` to use `unpackMutations`/`applySurfaceUpdates` helpers, avoiding intermediate vector/set merging when accumulating mutations from multiple callbacks.
## Changelog:
[General][Added] - Add pushAnimationMutations to AnimationBackend for targeted event-driven animation updates
Reviewed By: zeyap
Differential Revision: D100164749
fbshipit-source-id: 53d36ed316614baa835707a45361ae8f3b828d26
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56418
Changelog: [internal]
D92150163 excluded benchmark tests by default when running `yarn fantom` without `--benchmarks`. This was incorrect because it means benchmarks could silently break without being caught.
This changes the behavior so:
1. By default (without `--benchmarks`), benchmarks run in test mode (single iteration for correctness only), ensuring they do not break.
2. With `--benchmarks`, benchmarks run in full benchmark mode (multiple iterations for performance measurement).
Also renames `FANTOM_FORCE_TEST_MODE` to `FANTOM_RUN_BENCHMARKS` and `forceTestModeForBenchmarks` to `runBenchmarks` to better reflect the intent (opt-in to full benchmarks rather than opt-in to test mode).
Reviewed By: sammy-SC
Differential Revision: D100464314
fbshipit-source-id: 822cc5a25f0cdddf035616fdddf8619d27ef436a