diff --git a/.nx/version-plans/version-plan-1766951346332.md b/.nx/version-plans/version-plan-1766951346332.md new file mode 100644 index 0000000..f5e1957 --- /dev/null +++ b/.nx/version-plans/version-plan-1766951346332.md @@ -0,0 +1,5 @@ +--- +__default__: prerelease +--- + +Added `webSocketPort` option to `rn-harness.config` (default 3001). This allows configuring the Bridge Server port, enabling usage of custom ports without rebuilding the application. \ No newline at end of file diff --git a/apps/playground/rn-harness.config.mjs b/apps/playground/rn-harness.config.mjs index 335a2a2..0c49b64 100644 --- a/apps/playground/rn-harness.config.mjs +++ b/apps/playground/rn-harness.config.mjs @@ -51,6 +51,7 @@ const config = { ], defaultRunner: 'android', bridgeTimeout: 120000, + webSocketPort: 3002, resetEnvironmentBetweenTestFiles: true, unstable__skipAlreadyIncludedModules: false, diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts index 26547eb..272a4b4 100644 --- a/packages/config/src/types.ts +++ b/packages/config/src/types.ts @@ -8,6 +8,7 @@ export const ConfigSchema = z .min(1, 'App registry component name is required'), runners: z.array(z.any()).min(1, 'At least one runner is required'), defaultRunner: z.string().optional(), + webSocketPort: z.number().optional().default(3001), bridgeTimeout: z .number() .min(1000, 'Bridge timeout must be at least 1 second') diff --git a/packages/jest/src/harness.ts b/packages/jest/src/harness.ts index 235751e..db2a6f4 100644 --- a/packages/jest/src/harness.ts +++ b/packages/jest/src/harness.ts @@ -22,9 +22,11 @@ const getHarnessInternal = async ( ): Promise => { const [metroInstance, platformInstance, serverBridge] = await Promise.all([ getMetroInstance({ projectRoot, harnessConfig: config }, signal), - import(platform.runner).then((module) => module.default(platform.config)), + import(platform.runner).then((module) => + module.default(platform.config, config) + ), getBridgeServer({ - port: 3001, + port: config.webSocketPort, timeout: config.bridgeTimeout, }), ]); diff --git a/packages/metro/src/manifest.ts b/packages/metro/src/manifest.ts index 42c87ba..5c32141 100644 --- a/packages/metro/src/manifest.ts +++ b/packages/metro/src/manifest.ts @@ -3,7 +3,10 @@ import fs from 'node:fs'; import { Config as HarnessConfig } from '@react-native-harness/config'; const getManifestContent = (harnessConfig: HarnessConfig): string => { - return `global.RN_HARNESS = { appRegistryComponentName: '${harnessConfig.appRegistryComponentName}' };`; + return `global.RN_HARNESS = { + appRegistryComponentName: '${harnessConfig.appRegistryComponentName}', + webSocketPort: ${harnessConfig.webSocketPort} + };`; }; export const getHarnessManifest = (harnessConfig: HarnessConfig): string => { diff --git a/packages/platform-android/package.json b/packages/platform-android/package.json index c573249..3dac4f3 100644 --- a/packages/platform-android/package.json +++ b/packages/platform-android/package.json @@ -18,6 +18,7 @@ "dependencies": { "@react-native-harness/platforms": "workspace:*", "@react-native-harness/tools": "workspace:*", + "@react-native-harness/config": "workspace:*", "zod": "^3.25.67", "tslib": "^2.3.0" }, diff --git a/packages/platform-android/src/adb.ts b/packages/platform-android/src/adb.ts index 1a04bcc..4b9e6f1 100644 --- a/packages/platform-android/src/adb.ts +++ b/packages/platform-android/src/adb.ts @@ -18,9 +18,10 @@ export const isAppInstalled = async ( export const reversePort = async ( adbId: string, - port: number + port: number, + hostPort: number = port ): Promise => { - await spawn('adb', ['-s', adbId, 'reverse', `tcp:${port}`, `tcp:${port}`]); + await spawn('adb', ['-s', adbId, 'reverse', `tcp:${port}`, `tcp:${hostPort}`]); }; export const stopApp = async ( diff --git a/packages/platform-android/src/runner.ts b/packages/platform-android/src/runner.ts index 4b4775e..419c109 100644 --- a/packages/platform-android/src/runner.ts +++ b/packages/platform-android/src/runner.ts @@ -3,6 +3,7 @@ import { AppNotInstalledError, HarnessPlatformRunner, } from '@react-native-harness/platforms'; +import { Config } from '@react-native-harness/config'; import { AndroidPlatformConfigSchema, type AndroidPlatformConfig, @@ -12,7 +13,8 @@ import * as adb from './adb.js'; import { getDeviceName } from './utils.js'; const getAndroidRunner = async ( - config: AndroidPlatformConfig + config: AndroidPlatformConfig, + harnessConfig: Config ): Promise => { const parsedConfig = AndroidPlatformConfigSchema.parse(config); const adbId = await getAdbId(parsedConfig.device); @@ -33,7 +35,7 @@ const getAndroidRunner = async ( await Promise.all([ adb.reversePort(adbId, 8081), adb.reversePort(adbId, 8080), - adb.reversePort(adbId, 3001), + adb.reversePort(adbId, harnessConfig.webSocketPort), ]); return { diff --git a/packages/runtime/src/client/getWSServer.ts b/packages/runtime/src/client/getWSServer.ts index d81baf9..8cf0a2f 100644 --- a/packages/runtime/src/client/getWSServer.ts +++ b/packages/runtime/src/client/getWSServer.ts @@ -4,6 +4,7 @@ import { WS_SERVER_PORT } from '../constants.js'; export const getWSServer = (): string => { const devServerUrl = getDevServerUrl(); const hostname = devServerUrl.split('://')[1].split(':')[0]; + const port = global.RN_HARNESS?.webSocketPort || WS_SERVER_PORT; - return `ws://${hostname}:${WS_SERVER_PORT}`; + return `ws://${hostname}:${port}`; }; diff --git a/packages/runtime/src/globals.ts b/packages/runtime/src/globals.ts index cad4a8a..71d11a8 100644 --- a/packages/runtime/src/globals.ts +++ b/packages/runtime/src/globals.ts @@ -1,5 +1,6 @@ export type HarnessGlobal = { appRegistryComponentName: string; + webSocketPort?: number; }; declare global { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4dc3a35..7c031f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -352,6 +352,9 @@ importers: packages/platform-android: dependencies: + '@react-native-harness/config': + specifier: workspace:* + version: link:../config '@react-native-harness/platforms': specifier: workspace:* version: link:../platforms