Skip to content

Commit 8d152d9

Browse files
committed
chore: update lockfile
2 parents c95fc46 + d50c3e7 commit 8d152d9

33 files changed

Lines changed: 1291 additions & 190 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@react-native-harness/jest': patch
3+
'@react-native-harness/platform-android': patch
4+
'@react-native-harness/platform-apple': patch
5+
---
6+
7+
Adds support for configuring the Metro port in Harness, including CLI overrides via `--metroPort`. Harness now also restores Android and iOS simulator Metro connection settings on cleanup so normal dev-mode launches keep working after a test run.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
__default__: patch
3+
---
4+
5+
Harness now restores app startup stall recovery for RN-ready launches, including restart-between-files. Apps are retried when startup stalls without a crash, while confirmed native crashes still fail immediately with crash diagnostics.

actions/android/action.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ inputs:
2222
required: false
2323
type: string
2424
default: ''
25+
cacheAvd:
26+
description: Whether to cache the AVD
27+
required: false
28+
type: boolean
29+
default: 'true'
2530
runs:
2631
using: 'composite'
2732
steps:
@@ -68,6 +73,7 @@ runs:
6873
sudo udevadm trigger --name-match=kvm
6974
ls /dev/kvm
7075
- name: Compute AVD cache key
76+
if: ${{ fromJSON(inputs.cacheAvd) }}
7177
id: avd-key
7278
shell: bash
7379
run: |
@@ -78,6 +84,7 @@ runs:
7884
CACHE_KEY="avd-$ARCH-$AVD_CONFIG_HASH"
7985
echo "key=$CACHE_KEY" >> $GITHUB_OUTPUT
8086
- name: Restore AVD cache
87+
if: ${{ fromJSON(inputs.cacheAvd) }}
8188
uses: actions/cache/restore@v4
8289
id: avd-cache
8390
with:
@@ -86,7 +93,7 @@ runs:
8693
~/.android/adb*
8794
key: ${{ steps.avd-key.outputs.key }}
8895
- name: Create AVD and generate snapshot for caching
89-
if: steps.avd-cache.outputs.cache-hit != 'true'
96+
if: ${{ fromJSON(inputs.cacheAvd) && steps.avd-cache.outputs.cache-hit != 'true' }}
9097
uses: reactivecircus/android-emulator-runner@v2
9198
with:
9299
api-level: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.apiLevel }}
@@ -100,7 +107,7 @@ runs:
100107
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
101108
script: echo "Generated AVD snapshot for caching."
102109
- name: Save AVD cache
103-
if: steps.avd-cache.outputs.cache-hit != 'true'
110+
if: ${{ fromJSON(inputs.cacheAvd) && steps.avd-cache.outputs.cache-hit != 'true' }}
104111
uses: actions/cache/save@v4
105112
with:
106113
path: |

actions/shared/index.cjs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4209,6 +4209,7 @@ var coerce = {
42094209
var NEVER = INVALID;
42104210

42114211
// ../config/dist/types.js
4212+
var DEFAULT_METRO_PORT = 8081;
42124213
var RunnerSchema = external_exports.object({
42134214
name: external_exports.string().min(1, "Runner name is required").regex(/^[a-zA-Z0-9._-]+$/, "Runner name can only contain alphanumeric characters, dots, underscores, and hyphens"),
42144215
config: external_exports.record(external_exports.any()),
@@ -4221,12 +4222,11 @@ var ConfigSchema = external_exports.object({
42214222
runners: external_exports.array(RunnerSchema).min(1, "At least one runner is required"),
42224223
defaultRunner: external_exports.string().optional(),
42234224
host: external_exports.string().min(1, "Host is required").optional(),
4225+
metroPort: external_exports.number().int("Metro port must be an integer").min(1, "Metro port must be at least 1").max(65535, "Metro port must be at most 65535").optional().default(DEFAULT_METRO_PORT),
42244226
webSocketPort: external_exports.number().optional().default(3001),
42254227
bridgeTimeout: external_exports.number().min(1e3, "Bridge timeout must be at least 1 second").default(6e4),
4226-
/** @deprecated Removed in favor of crash supervisor. Accepted for backwards compatibility. */
4227-
bundleStartTimeout: external_exports.number().optional(),
4228-
/** @deprecated Removed in favor of crash supervisor. Accepted for backwards compatibility. */
4229-
maxAppRestarts: external_exports.number().optional(),
4228+
bundleStartTimeout: external_exports.number().min(1e3, "Bundle start timeout must be at least 1 second").default(15e3),
4229+
maxAppRestarts: external_exports.number().min(0, "Max app restarts must be at least 0").default(2),
42304230
resetEnvironmentBetweenTestFiles: external_exports.boolean().optional().default(true),
42314231
unstable__skipAlreadyIncludedModules: external_exports.boolean().optional().default(false),
42324232
unstable__enableMetroCache: external_exports.boolean().optional().default(false),
@@ -4413,20 +4413,6 @@ var import_node_path5 = __toESM(require("path"), 1);
44134413
var import_node_fs5 = __toESM(require("fs"), 1);
44144414
var import_node_module2 = require("module");
44154415
var import_meta = {};
4416-
var DEPRECATED_PROPERTIES = {
4417-
bundleStartTimeout: '"bundleStartTimeout" is no longer used and can be removed from your config. Startup crash detection is now handled automatically by the crash supervisor.',
4418-
maxAppRestarts: '"maxAppRestarts" is no longer used and can be removed from your config. Startup crash detection is now handled automatically by the crash supervisor.'
4419-
};
4420-
var warnDeprecatedProperties = (rawConfig) => {
4421-
if (typeof rawConfig !== "object" || rawConfig === null) {
4422-
return;
4423-
}
4424-
for (const [key, message] of Object.entries(DEPRECATED_PROPERTIES)) {
4425-
if (key in rawConfig) {
4426-
console.warn(`[react-native-harness] Deprecation warning: ${message}`);
4427-
}
4428-
}
4429-
};
44304416
var extensions = [".js", ".mjs", ".cjs", ".json"];
44314417
var importUp = async (dir, name) => {
44324418
const filePath = import_node_path5.default.join(dir, name);
@@ -4445,7 +4431,6 @@ var importUp = async (dir, name) => {
44454431
throw new ConfigLoadError(filePathWithExt, error instanceof Error ? error : void 0);
44464432
}
44474433
try {
4448-
warnDeprecatedProperties(rawConfig);
44494434
const config = ConfigSchema.parse(rawConfig);
44504435
return { config, filePathWithExt, configDir: dir };
44514436
} catch (error) {

packages/bundler-metro/src/constants.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/bundler-metro/src/factory.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import connect from 'connect';
55
import nocache from 'nocache';
66
import { isPortAvailable, getMetroPackage } from './utils.js';
77
import { MetroPortUnavailableError } from './errors.js';
8-
import { METRO_PORT } from './constants.js';
98
import type { MetroInstance, MetroOptions } from './types.js';
109
import {
1110
type Reporter,
@@ -41,18 +40,19 @@ export const getMetroInstance = async (
4140
abortSignal: AbortSignal
4241
): Promise<MetroInstance> => {
4342
const { projectRoot, harnessConfig } = options;
44-
const isDefaultPortAvailable = await isPortAvailable(METRO_PORT);
43+
const metroPort = harnessConfig.metroPort;
44+
const isMetroPortAvailable = await isPortAvailable(metroPort);
4545

46-
if (!isDefaultPortAvailable) {
47-
throw new MetroPortUnavailableError(METRO_PORT);
46+
if (!isMetroPortAvailable) {
47+
throw new MetroPortUnavailableError(metroPort);
4848
}
4949

5050
const Metro = getMetroPackage(projectRoot);
5151

5252
process.env.RN_HARNESS = 'true';
5353

5454
const projectMetroConfig = await Metro.loadConfig({
55-
port: METRO_PORT,
55+
port: metroPort,
5656
projectRoot,
5757
});
5858
const config = await withRnHarness(projectMetroConfig, true)();
@@ -62,7 +62,7 @@ export const getMetroInstance = async (
6262

6363
const middleware = connect()
6464
.use(nocache())
65-
.use('/', getExpoMiddleware(projectRoot, harnessConfig.entryPoint))
65+
.use('/', getExpoMiddleware(projectRoot, harnessConfig))
6666
.use('/status', getStatusMiddleware(projectRoot));
6767

6868
const ready = waitForBundler(reporter, abortSignal);

packages/bundler-metro/src/middlewares/expo-middleware.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import type { IncomingMessage, ServerResponse } from 'node:http';
22
import type { NextFunction } from 'connect';
3+
import type { Config as HarnessConfig } from '@react-native-harness/config';
34
import crypto from 'node:crypto';
45
import { getResolvedEntryPointWithoutExtension } from '../entry-point-utils.js';
56

67
export const getExpoMiddleware =
7-
(projectRoot: string, entryPoint: string) =>
8+
(projectRoot: string, harnessConfig: HarnessConfig) =>
89
(req: IncomingMessage, res: ServerResponse, next: NextFunction) => {
910
if (req.url !== '/') {
1011
next();
@@ -14,7 +15,7 @@ export const getExpoMiddleware =
1415
const platform = req.headers['expo-platform'] as string;
1516
const resolvedEntryPoint = getResolvedEntryPointWithoutExtension(
1617
projectRoot,
17-
entryPoint
18+
harnessConfig.entryPoint
1819
);
1920

2021
const manifestJson = JSON.stringify({
@@ -24,7 +25,7 @@ export const getExpoMiddleware =
2425
launchAsset: {
2526
key: 'bundle',
2627
contentType: 'application/javascript',
27-
url: `http://localhost:8081/${resolvedEntryPoint}.bundle?platform=${platform}&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=1&transform.routerRoot=app&transform.reactCompiler=true&unstable_transformProfile=hermes-stable`,
28+
url: `http://localhost:${harnessConfig.metroPort}/${resolvedEntryPoint}.bundle?platform=${platform}&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=1&transform.routerRoot=app&transform.reactCompiler=true&unstable_transformProfile=hermes-stable`,
2829
},
2930
assets: [],
3031
metadata: {},
@@ -35,7 +36,7 @@ export const getExpoMiddleware =
3536
version: '1.0.0',
3637
},
3738
expoGo: {
38-
debuggerHost: 'localhost:8081',
39+
debuggerHost: `localhost:${harnessConfig.metroPort}`,
3940
developer: {
4041
tool: 'expo-cli',
4142
projectRoot,

packages/bundler-metro/src/prewarm.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { METRO_PORT } from './constants.js';
21
import { getResolvedEntryPointWithoutExtension } from './entry-point-utils.js';
32

43
type PrewarmOptions = {
54
projectRoot: string;
65
entryPoint: string;
6+
port: number;
77
platform: string;
88
dev: boolean;
99
minify: boolean;
@@ -13,7 +13,8 @@ type PrewarmOptions = {
1313
export const prewarmMetroBundle = async (
1414
options: PrewarmOptions
1515
): Promise<void> => {
16-
const { projectRoot, entryPoint, platform, dev, minify, signal } = options;
16+
const { projectRoot, entryPoint, port, platform, dev, minify, signal } =
17+
options;
1718
const resolvedEntryPoint = getResolvedEntryPointWithoutExtension(
1819
projectRoot,
1920
entryPoint
@@ -23,7 +24,7 @@ export const prewarmMetroBundle = async (
2324
dev: String(dev),
2425
minify: String(minify),
2526
});
26-
const url = `http://localhost:${METRO_PORT}/${resolvedEntryPoint}.bundle?${searchParams.toString()}`;
27+
const url = `http://localhost:${port}/${resolvedEntryPoint}.bundle?${searchParams.toString()}`;
2728

2829
const response = await fetch(url, { signal });
2930

packages/config/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export { getConfig } from './reader.js';
22
export type { Config } from './types.js';
3+
export { ConfigSchema, DEFAULT_METRO_PORT } from './types.js';
34
export {
45
ConfigValidationError,
56
ConfigNotFoundError,

packages/config/src/reader.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,6 @@ import fs from 'node:fs';
99
import { createRequire } from 'node:module';
1010
import { ZodError } from 'zod';
1111

12-
const DEPRECATED_PROPERTIES: Record<string, string> = {
13-
bundleStartTimeout:
14-
'"bundleStartTimeout" is no longer used and can be removed from your config. Startup crash detection is now handled automatically by the crash supervisor.',
15-
maxAppRestarts:
16-
'"maxAppRestarts" is no longer used and can be removed from your config. Startup crash detection is now handled automatically by the crash supervisor.',
17-
};
18-
19-
const warnDeprecatedProperties = (rawConfig: unknown) => {
20-
if (typeof rawConfig !== 'object' || rawConfig === null) {
21-
return;
22-
}
23-
24-
for (const [key, message] of Object.entries(DEPRECATED_PROPERTIES)) {
25-
if (key in rawConfig) {
26-
console.warn(`[react-native-harness] Deprecation warning: ${message}`);
27-
}
28-
}
29-
};
30-
3112
const extensions = ['.js', '.mjs', '.cjs', '.json'];
3213

3314
const importUp = async (
@@ -62,7 +43,6 @@ const importUp = async (
6243
}
6344

6445
try {
65-
warnDeprecatedProperties(rawConfig);
6646
const config = ConfigSchema.parse(rawConfig);
6747
return { config, filePathWithExt, configDir: dir };
6848
} catch (error) {

0 commit comments

Comments
 (0)