@@ -3,6 +3,10 @@ import { BridgeClientFunctions } from '@react-native-harness/bridge';
33import { HarnessPlatform } from '@react-native-harness/platforms' ;
44import { getMetroInstance } from '@react-native-harness/bundler-metro' ;
55import { InitializationTimeoutError } from './errors.js' ;
6+ import { Config as HarnessConfig } from '@react-native-harness/config' ;
7+ import pRetry from 'p-retry' ;
8+
9+ const BRIDGE_READY_TIMEOUT = 10000 ;
610
711export type Harness = {
812 runTests : BridgeClientFunctions [ 'runTests' ] ;
@@ -11,6 +15,7 @@ export type Harness = {
1115} ;
1216
1317const getHarnessInternal = async (
18+ config : HarnessConfig ,
1419 platform : HarnessPlatform ,
1520 signal : AbortSignal
1621) : Promise < Harness > => {
@@ -19,14 +24,45 @@ const getHarnessInternal = async (
1924 platform . getInstance ( ) ,
2025 getBridgeServer ( {
2126 port : 3001 ,
27+ timeout : config . bridgeTimeout ,
2228 } ) ,
2329 ] ) ;
2430
31+ const dispose = async ( ) => {
32+ await Promise . all ( [
33+ serverBridge . dispose ( ) ,
34+ platformInstance . dispose ( ) ,
35+ metroInstance . dispose ( ) ,
36+ ] ) ;
37+ } ;
38+
2539 if ( signal . aborted ) {
26- metroInstance . dispose ( ) ;
27- platformInstance . dispose ( ) ;
28- serverBridge . dispose ( ) ;
29- signal . throwIfAborted ( ) ;
40+ await dispose ( ) ;
41+
42+ throw new DOMException ( 'The operation was aborted' , 'AbortError' ) ;
43+ }
44+
45+ try {
46+ await pRetry (
47+ ( ) =>
48+ new Promise < void > ( ( resolve , reject ) => {
49+ signal . addEventListener ( 'abort' , ( ) => {
50+ reject ( new DOMException ( 'The operation was aborted' , 'AbortError' ) ) ;
51+ } ) ;
52+
53+ serverBridge . once ( 'ready' , ( ) => resolve ( ) ) ;
54+ platformInstance . restartApp ( ) . catch ( reject ) ;
55+ } ) ,
56+ {
57+ minTimeout : BRIDGE_READY_TIMEOUT ,
58+ maxTimeout : BRIDGE_READY_TIMEOUT ,
59+ retries : Infinity ,
60+ signal,
61+ }
62+ ) ;
63+ } catch ( error ) {
64+ await dispose ( ) ;
65+ throw error ;
3066 }
3167
3268 const restart = ( ) =>
@@ -35,9 +71,6 @@ const getHarnessInternal = async (
3571 platformInstance . restartApp ( ) . catch ( reject ) ;
3672 } ) ;
3773
38- // Wait for the bridge to be ready
39- await restart ( ) ;
40-
4174 return {
4275 runTests : async ( path , options ) => {
4376 const client = serverBridge . rpc . clients . at ( - 1 ) ;
@@ -49,25 +82,18 @@ const getHarnessInternal = async (
4982 return await client . runTests ( path , options ) ;
5083 } ,
5184 restart,
52- dispose : async ( ) => {
53- await Promise . all ( [
54- serverBridge . dispose ( ) ,
55- platformInstance . dispose ( ) ,
56- metroInstance . dispose ( ) ,
57- ] ) ;
58- } ,
85+ dispose,
5986 } ;
6087} ;
6188
6289export const getHarness = async (
63- platform : HarnessPlatform ,
64- timeout : number
90+ config : HarnessConfig ,
91+ platform : HarnessPlatform
6592) : Promise < Harness > => {
66- const abortController = new AbortController ( ) ;
67- const timeoutId = setTimeout ( ( ) => abortController . abort ( ) , timeout ) ;
93+ const abortSignal = AbortSignal . timeout ( config . bridgeTimeout ) ;
94+
6895 try {
69- const harness = await getHarnessInternal ( platform , abortController . signal ) ;
70- clearTimeout ( timeoutId ) ;
96+ const harness = await getHarnessInternal ( config , platform , abortSignal ) ;
7197 return harness ;
7298 } catch ( error ) {
7399 if ( error instanceof DOMException && error . name === 'AbortError' ) {
0 commit comments