diff --git a/packages/bundler-metro/src/factory.ts b/packages/bundler-metro/src/factory.ts index 30915f06..84e23178 100644 --- a/packages/bundler-metro/src/factory.ts +++ b/packages/bundler-metro/src/factory.ts @@ -66,9 +66,16 @@ export const getMetroInstance = async ( .use('/status', getStatusMiddleware(projectRoot)); const ready = waitForBundler(reporter, abortSignal); - const metroBindHost = harnessConfig.host?.trim(); + const metroBindHost = + harnessConfig.host?.trim() ?? + (process.env.CI ? '0.0.0.0' : undefined); + + // In CI, bind to all interfaces to avoid connectivity issues on macOS runners + // where Metro is intermittently unreachable from the iOS simulator when bound + // to localhost only. if (metroBindHost) { - logger.debug(`Binding Metro server to host ${metroBindHost}`); + const source = harnessConfig.host?.trim() ? 'config' : 'CI default'; + logger.debug(`Binding Metro server to host ${metroBindHost} (${source})`); } const maybeServer = await Metro.runServer(config, { diff --git a/website/src/docs/getting-started/configuration.mdx b/website/src/docs/getting-started/configuration.mdx index 2c12a27f..2f8631f8 100644 --- a/website/src/docs/getting-started/configuration.mdx +++ b/website/src/docs/getting-started/configuration.mdx @@ -84,7 +84,7 @@ For Expo projects, the `entryPoint` should be set to the path specified in the ` | `appRegistryComponentName` | **Required.** Name of the component registered with AppRegistry. | | `runners` | **Required.** Array of test runners (at least one required). | | `defaultRunner` | Default runner to use when none specified. | -| `host` | Hostname or IP address to bind the Metro server to (default: Metro default). | +| `host` | Hostname or IP address to bind the Metro server to. Defaults to `0.0.0.0` in CI (`process.env.CI` is set) to avoid connectivity issues on macOS runners where Metro may be unreachable from the iOS simulator when bound to `localhost`. | | `bridgeTimeout` | Bridge timeout in milliseconds (default: `60000`). | | `bundleStartTimeout` | Bundle start timeout in milliseconds (default: `15000`). | | `maxAppRestarts` | Maximum number of app restarts when app fails to report ready (default: `2`). | diff --git a/website/src/docs/guides/ci-cd.md b/website/src/docs/guides/ci-cd.md index 94a77134..7c9d9647 100644 --- a/website/src/docs/guides/ci-cd.md +++ b/website/src/docs/guides/ci-cd.md @@ -225,6 +225,18 @@ If you're using frameworks like **Expo** or **Rock**, you'll benefit from sophis This makes caching much more reliable and reduces the need for manual cache management. +## Metro Networking in CI + +When running in CI (i.e. the `CI` environment variable is set), React Native Harness automatically binds the Metro server to `0.0.0.0` (all network interfaces) instead of the default `localhost`. This works around intermittent connectivity issues on macOS runners where the iOS Simulator cannot reach Metro when it is bound to `localhost` only. + +If you need Metro to bind to a specific interface, set the `host` option in your config — it always takes precedence over the CI default: + +```js +const config = { + host: '192.168.1.100', +}; +``` + ## Adapting for Your Project ### React Native Community CLI Projects