@react-native-harness/jest 1.1.0-rc.4 → 1.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-harness/jest",
3
- "version": "1.1.0-rc.4",
3
+ "version": "1.2.0-rc.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -40,12 +40,12 @@
40
40
  "p-limit": "^7.1.1",
41
41
  "tslib": "^2.3.0",
42
42
  "yargs": "^17.7.2",
43
- "@react-native-harness/bridge": "1.1.0-rc.4",
44
- "@react-native-harness/plugins": "1.1.0-rc.4",
45
- "@react-native-harness/platforms": "1.1.0-rc.4",
46
- "@react-native-harness/tools": "1.1.0-rc.4",
47
- "@react-native-harness/config": "1.1.0-rc.4",
48
- "@react-native-harness/bundler-metro": "1.1.0-rc.4"
43
+ "@react-native-harness/bundler-metro": "1.2.0-rc.1",
44
+ "@react-native-harness/config": "1.2.0-rc.1",
45
+ "@react-native-harness/platforms": "1.2.0-rc.1",
46
+ "@react-native-harness/tools": "1.2.0-rc.1",
47
+ "@react-native-harness/bridge": "1.2.0-rc.1",
48
+ "@react-native-harness/plugins": "1.2.0-rc.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/yargs": "^17.0.32",
@@ -125,7 +125,7 @@ const createReporter = (): Reporter => {
125
125
  };
126
126
 
127
127
  const createMetroInstance = (
128
- overrides: Partial<MetroInstance> = {}
128
+ overrides: Partial<MetroInstance> = {},
129
129
  ): MetroInstance => ({
130
130
  events: createReporter(),
131
131
  httpServer: {} as never,
@@ -163,7 +163,7 @@ const createAppMonitor = (): {
163
163
  };
164
164
 
165
165
  const createPlatformRunner = (
166
- overrides: Partial<HarnessPlatformRunner> = {}
166
+ overrides: Partial<HarnessPlatformRunner> = {},
167
167
  ): HarnessPlatformRunner => ({
168
168
  startApp: vi.fn(async () => undefined),
169
169
  restartApp: vi.fn(async () => undefined),
@@ -175,7 +175,7 @@ const createPlatformRunner = (
175
175
  });
176
176
 
177
177
  const createHarnessConfig = (
178
- overrides: Partial<HarnessConfig> = {}
178
+ overrides: Partial<HarnessConfig> = {},
179
179
  ): HarnessConfig =>
180
180
  ({
181
181
  appRegistryComponentName: 'App',
@@ -196,7 +196,7 @@ const createHarnessConfig = (
196
196
  unstable__skipAlreadyIncludedModules: false,
197
197
  webSocketPort: 3001,
198
198
  ...overrides,
199
- } as HarnessConfig);
199
+ }) as HarnessConfig;
200
200
 
201
201
  beforeEach(() => {
202
202
  vi.clearAllMocks();
@@ -230,7 +230,7 @@ describe('waitForAppReady', () => {
230
230
  emitReady();
231
231
  await readyPromise;
232
232
  options.onAttemptReset?.();
233
- }
233
+ },
234
234
  );
235
235
 
236
236
  await waitForAppReady({
@@ -255,7 +255,7 @@ describe('waitForAppReady', () => {
255
255
  startAttempt: expect.any(Function),
256
256
  waitForReady: expect.any(Function),
257
257
  waitForCrash: expect.any(Function),
258
- })
258
+ }),
259
259
  );
260
260
  expect(crashSupervisor.isReady()).toBe(true);
261
261
 
@@ -276,7 +276,7 @@ describe('waitForAppReady', () => {
276
276
  mocks.waitForMetroBackedAppReady.mockImplementationOnce(
277
277
  async (options: WaitForMetroBackedAppReadyOptions) => {
278
278
  await options.startAttempt();
279
- }
279
+ },
280
280
  );
281
281
 
282
282
  await waitForAppReady({
@@ -324,7 +324,7 @@ describe('getHarness', () => {
324
324
  setTimeout(() => {
325
325
  reject(new DOMException('The operation was aborted', 'AbortError'));
326
326
  }, 20);
327
- })
327
+ }),
328
328
  );
329
329
 
330
330
  const platform: HarnessPlatform = {
@@ -333,7 +333,7 @@ describe('getHarness', () => {
333
333
  name: 'ios',
334
334
  platformId: 'ios',
335
335
  runner: `data:text/javascript,${encodeURIComponent(
336
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
336
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
337
337
  )}`,
338
338
  };
339
339
 
@@ -343,8 +343,8 @@ describe('getHarness', () => {
343
343
  platformReadyTimeout: 10,
344
344
  }),
345
345
  platform,
346
- '/tmp/project'
347
- )
346
+ '/tmp/project',
347
+ ),
348
348
  ).rejects.toBeInstanceOf(PlatformReadyTimeoutError);
349
349
  });
350
350
 
@@ -372,14 +372,14 @@ describe('getHarness', () => {
372
372
  name: 'ios',
373
373
  platformId: 'ios',
374
374
  runner: `data:text/javascript,${encodeURIComponent(
375
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
375
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
376
376
  )}`,
377
377
  };
378
378
 
379
379
  const harness = await getHarness(
380
380
  createHarnessConfig(),
381
381
  platform,
382
- '/tmp/project'
382
+ '/tmp/project',
383
383
  );
384
384
 
385
385
  expect(runner).toHaveBeenCalledWith(
@@ -389,7 +389,7 @@ describe('getHarness', () => {
389
389
  }),
390
390
  expect.objectContaining({
391
391
  signal: expect.any(AbortSignal),
392
- })
392
+ }),
393
393
  );
394
394
 
395
395
  await harness.dispose();
@@ -422,14 +422,14 @@ describe('getHarness', () => {
422
422
  name: 'android',
423
423
  platformId: 'android',
424
424
  runner: `data:text/javascript,${encodeURIComponent(
425
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
425
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
426
426
  )}`,
427
427
  };
428
428
 
429
429
  const harness = await getHarness(
430
430
  createHarnessConfig(),
431
431
  platform,
432
- '/tmp/project'
432
+ '/tmp/project',
433
433
  );
434
434
 
435
435
  expect(harness.config.metroPort).toBe(8082);
@@ -439,7 +439,7 @@ describe('getHarness', () => {
439
439
  metroPort: 8082,
440
440
  }),
441
441
  }),
442
- expect.any(AbortSignal)
442
+ expect.any(AbortSignal),
443
443
  );
444
444
  expect(runner).toHaveBeenCalledWith(
445
445
  platform.config,
@@ -448,7 +448,7 @@ describe('getHarness', () => {
448
448
  }),
449
449
  expect.objectContaining({
450
450
  signal: expect.any(AbortSignal),
451
- })
451
+ }),
452
452
  );
453
453
  expect(mocks.logMetroPortFallback).toHaveBeenCalledWith(8081, 8082);
454
454
 
@@ -467,7 +467,7 @@ describe('getHarness', () => {
467
467
  };
468
468
 
469
469
  await expect(
470
- getHarness(createHarnessConfig(), platform, '/tmp/project')
470
+ getHarness(createHarnessConfig(), platform, '/tmp/project'),
471
471
  ).rejects.toBeInstanceOf(MetroPortRangeExhaustedError);
472
472
 
473
473
  expect(mocks.getBridgeServer).not.toHaveBeenCalled();
@@ -496,14 +496,14 @@ describe('getHarness', () => {
496
496
  name: 'legacy-ios',
497
497
  platformId: 'ios',
498
498
  runner: `data:text/javascript,${encodeURIComponent(
499
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
499
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
500
500
  )}`,
501
501
  };
502
502
 
503
503
  const harness = await getHarness(
504
504
  createHarnessConfig(),
505
505
  platform,
506
- '/tmp/project'
506
+ '/tmp/project',
507
507
  );
508
508
 
509
509
  await harness.dispose();
@@ -527,7 +527,7 @@ describe('getHarness', () => {
527
527
  const readyPromise = options.waitForReady(new AbortController().signal);
528
528
  emitReady();
529
529
  await readyPromise;
530
- }
530
+ },
531
531
  );
532
532
 
533
533
  (
@@ -547,7 +547,7 @@ describe('getHarness', () => {
547
547
  name: 'ios',
548
548
  platformId: 'ios',
549
549
  runner: `data:text/javascript,${encodeURIComponent(
550
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
550
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
551
551
  )}`,
552
552
  getResourceLockKey: () => 'ios:simulator:iPhone 17 Pro:26.2',
553
553
  };
@@ -557,7 +557,7 @@ describe('getHarness', () => {
557
557
  bridgeTimeout: 1,
558
558
  }),
559
559
  platform,
560
- '/tmp/project'
560
+ '/tmp/project',
561
561
  );
562
562
 
563
563
  await harness.ensureAppReady('/tmp/example.harness.ts');
@@ -593,7 +593,7 @@ describe('getHarness', () => {
593
593
  const readyPromise = options.waitForReady(new AbortController().signal);
594
594
  emitReady();
595
595
  await readyPromise;
596
- }
596
+ },
597
597
  );
598
598
 
599
599
  (
@@ -613,7 +613,7 @@ describe('getHarness', () => {
613
613
  name: 'ios',
614
614
  platformId: 'ios',
615
615
  runner: `data:text/javascript,${encodeURIComponent(
616
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
616
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
617
617
  )}`,
618
618
  getResourceLockKey: () => 'ios:simulator:iPhone 17 Pro:26.2',
619
619
  };
@@ -621,13 +621,13 @@ describe('getHarness', () => {
621
621
  const harness = await getHarness(
622
622
  createHarnessConfig(),
623
623
  platform,
624
- '/tmp/project'
624
+ '/tmp/project',
625
625
  );
626
626
 
627
627
  expect(mocks.getBridgeServer).toHaveBeenCalledWith(
628
628
  expect.objectContaining({
629
629
  noServer: true,
630
- })
630
+ }),
631
631
  );
632
632
  expect(mocks.getMetroInstance).toHaveBeenCalledWith(
633
633
  expect.objectContaining({
@@ -635,7 +635,7 @@ describe('getHarness', () => {
635
635
  [HARNESS_BRIDGE_PATH]: serverBridge.ws,
636
636
  },
637
637
  }),
638
- expect.any(AbortSignal)
638
+ expect.any(AbortSignal),
639
639
  );
640
640
  await harness.restart('/tmp/restart.harness.ts');
641
641
 
@@ -691,7 +691,7 @@ describe('plugins', () => {
691
691
  ctx.appLaunchOptions == null
692
692
  ? 'no-launch-options'
693
693
  : 'launch-options'
694
- }`
694
+ }`,
695
695
  );
696
696
  },
697
697
  beforeRun: (ctx) => {
@@ -700,24 +700,24 @@ describe('plugins', () => {
700
700
  ctx.appLaunchOptions == null
701
701
  ? 'no-launch-options'
702
702
  : 'launch-options'
703
- }`
703
+ }`,
704
704
  );
705
705
  },
706
706
  afterRun: (ctx) => {
707
707
  observedHooks.push(
708
- `afterRun:${ctx.state.creationCount}:${ctx.reason}`
708
+ `afterRun:${ctx.state.creationCount}:${ctx.reason}`,
709
709
  );
710
710
  },
711
711
  beforeDispose: (ctx) => {
712
712
  observedHooks.push(
713
- `beforeDispose:${ctx.state.creationCount}:${ctx.reason}`
713
+ `beforeDispose:${ctx.state.creationCount}:${ctx.reason}`,
714
714
  );
715
715
  },
716
716
  },
717
717
  runtime: {
718
718
  ready: (ctx) => {
719
719
  observedHooks.push(
720
- `runtime.ready:${ctx.runId}:${ctx.device.platform}`
720
+ `runtime.ready:${ctx.runId}:${ctx.device.platform}`,
721
721
  );
722
722
  },
723
723
  disconnected: (ctx) => {
@@ -743,7 +743,7 @@ describe('plugins', () => {
743
743
  name: 'ios',
744
744
  platformId: 'ios',
745
745
  runner: `data:text/javascript,${encodeURIComponent(
746
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
746
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
747
747
  )}`,
748
748
  getResourceLockKey: () => 'ios:simulator:iPhone 17 Pro:26.2',
749
749
  };
@@ -753,7 +753,7 @@ describe('plugins', () => {
753
753
  plugins: [plugin],
754
754
  }),
755
755
  platform,
756
- '/tmp/project'
756
+ '/tmp/project',
757
757
  );
758
758
 
759
759
  harness.setRunState({
@@ -791,6 +791,59 @@ describe('plugins', () => {
791
791
  ]);
792
792
  });
793
793
 
794
+ it('disposes lifecycle hooks and platform resources only once', async () => {
795
+ const { serverBridge } = createBridgeServer();
796
+ const platformInstance = createPlatformRunner();
797
+ const observedHooks: string[] = [];
798
+
799
+ mocks.getBridgeServer.mockResolvedValue(serverBridge);
800
+ mocks.getMetroInstance.mockResolvedValue(createMetroInstance());
801
+
802
+ (
803
+ globalThis as typeof globalThis & {
804
+ __HARNESS_PLATFORM_RUNNER__?: (...args: unknown[]) => Promise<unknown>;
805
+ }
806
+ ).__HARNESS_PLATFORM_RUNNER__ = vi.fn(async () => platformInstance);
807
+
808
+ const plugin = definePlugin({
809
+ name: 'dispose-plugin',
810
+ hooks: {
811
+ harness: {
812
+ afterRun: () => {
813
+ observedHooks.push('afterRun');
814
+ },
815
+ beforeDispose: () => {
816
+ observedHooks.push('beforeDispose');
817
+ },
818
+ },
819
+ },
820
+ });
821
+
822
+ const platform: HarnessPlatform = {
823
+ config: {},
824
+ name: 'ios',
825
+ platformId: 'ios',
826
+ runner: `data:text/javascript,${encodeURIComponent(
827
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
828
+ )}`,
829
+ getResourceLockKey: () => 'ios:simulator:iPhone 17 Pro:26.2',
830
+ };
831
+
832
+ const harness = await getHarness(
833
+ createHarnessConfig({
834
+ plugins: [plugin],
835
+ }),
836
+ platform,
837
+ '/tmp/project',
838
+ );
839
+
840
+ await harness.dispose();
841
+ await harness.dispose();
842
+
843
+ expect(observedHooks).toEqual(['afterRun', 'beforeDispose']);
844
+ expect(platformInstance.dispose).toHaveBeenCalledTimes(1);
845
+ });
846
+
794
847
  it('waits in queue before starting Metro and releases the lock on dispose', async () => {
795
848
  const resourceKey = 'ios:simulator:iPhone 17 Pro:26.2';
796
849
  const firstPlatformRunner = createPlatformRunner();
@@ -828,7 +881,7 @@ describe('plugins', () => {
828
881
  name: 'ios',
829
882
  platformId: 'ios',
830
883
  runner: `data:text/javascript,${encodeURIComponent(
831
- 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);'
884
+ 'export default (...args) => globalThis.__HARNESS_PLATFORM_RUNNER__(...args);',
832
885
  )}`,
833
886
  getResourceLockKey: () => resourceKey,
834
887
  };
@@ -836,13 +889,13 @@ describe('plugins', () => {
836
889
  const firstHarness = await getHarness(
837
890
  createHarnessConfig(),
838
891
  platform,
839
- '/tmp/project'
892
+ '/tmp/project',
840
893
  );
841
894
 
842
895
  const secondHarnessPromise = getHarness(
843
896
  createHarnessConfig(),
844
897
  platform,
845
- '/tmp/project'
898
+ '/tmp/project',
846
899
  );
847
900
 
848
901
  await new Promise((resolve) => setTimeout(resolve, 1100));
@@ -864,7 +917,7 @@ describe('plugins', () => {
864
917
  describe('StartupStallError', () => {
865
918
  it('includes the configured timeout and attempt count', () => {
866
919
  expect(new StartupStallError(1_500, 4).message).toBe(
867
- 'The app did not request its Metro bundle after 4 launch attempts within 1500ms. Last Metro status: unknown.'
920
+ 'The app did not request its Metro bundle after 4 launch attempts within 1500ms. Last Metro status: unknown.',
868
921
  );
869
922
  });
870
923
  });
package/src/harness.ts CHANGED
@@ -78,7 +78,7 @@ export type Harness = {
78
78
  config: HarnessConfig;
79
79
  runTests: (
80
80
  path: string,
81
- options: HarnessRunTestsOptions
81
+ options: HarnessRunTestsOptions,
82
82
  ) => Promise<TestSuiteResult>;
83
83
  ensureAppReady: (testFilePath: string) => Promise<void>;
84
84
  restart: (testFilePath?: string) => Promise<void>;
@@ -92,7 +92,7 @@ export type Harness = {
92
92
  export const maybeLogMetroCacheReuse = (
93
93
  config: HarnessConfig,
94
94
  platform: HarnessPlatform,
95
- projectRoot: string
95
+ projectRoot: string,
96
96
  ): void => {
97
97
  if (config.unstable__enableMetroCache && isMetroCacheReusable(projectRoot)) {
98
98
  logMetroCacheReused(platform);
@@ -116,7 +116,7 @@ const waitForAbort = (signal: AbortSignal): Promise<never> => {
116
116
  () => {
117
117
  reject(signal.reason ?? createAbortError());
118
118
  },
119
- { once: true }
119
+ { once: true },
120
120
  );
121
121
  });
122
122
  };
@@ -239,7 +239,7 @@ const getHarnessInternal = async (
239
239
  config: HarnessConfig,
240
240
  platform: HarnessPlatform,
241
241
  projectRoot: string,
242
- signal: AbortSignal
242
+ signal: AbortSignal,
243
243
  ): Promise<Harness> => {
244
244
  const context: HarnessContext = {
245
245
  platform,
@@ -247,7 +247,7 @@ const getHarnessInternal = async (
247
247
  harnessLogger.debug(
248
248
  'creating Harness internals for runner=%s platform=%s',
249
249
  platform.name,
250
- platform.platformId
250
+ platform.platformId,
251
251
  );
252
252
  const resourceLockKey = await (platform.getResourceLockKey?.() ??
253
253
  getDefaultResourceLockKey(platform));
@@ -261,7 +261,7 @@ const getHarnessInternal = async (
261
261
  harnessLogger.debug(
262
262
  'waiting in queue for runner=%s key=%s',
263
263
  platform.name,
264
- resourceLockKey
264
+ resourceLockKey,
265
265
  );
266
266
  },
267
267
  onStillWaiting: (elapsedMs) => {
@@ -275,7 +275,7 @@ const getHarnessInternal = async (
275
275
  'still waiting in queue for runner=%s key=%s elapsedMs=%d',
276
276
  platform.name,
277
277
  resourceLockKey,
278
- elapsedMs
278
+ elapsedMs,
279
279
  );
280
280
  },
281
281
  });
@@ -285,7 +285,7 @@ const getHarnessInternal = async (
285
285
  harnessLogger.debug(
286
286
  'resource lock acquired for runner=%s key=%s',
287
287
  platform.name,
288
- resourceLockKey
288
+ resourceLockKey,
289
289
  );
290
290
  try {
291
291
  const {
@@ -322,7 +322,6 @@ const getHarnessInternal = async (
322
322
  let activeTestFilePath: string | undefined;
323
323
  const pendingHookPromises = new Set<Promise<void>>();
324
324
  let pendingHookError: unknown;
325
-
326
325
  const getCurrentRunId = () => currentRun?.runId;
327
326
  const toRelativeTestFilePath = (testFilePath?: string) =>
328
327
  testFilePath == null
@@ -358,7 +357,7 @@ const getHarnessInternal = async (
358
357
  object,
359
358
  HarnessConfig,
360
359
  HarnessPlatform
361
- >
360
+ >,
362
361
  >(
363
362
  name: TName,
364
363
  payload: Omit<
@@ -373,7 +372,7 @@ const getHarnessInternal = async (
373
372
  | 'timestamp'
374
373
  | 'abortSignal'
375
374
  | 'meta'
376
- >
375
+ >,
377
376
  ) => {
378
377
  trackHook(pluginManager.callHook(name, payload));
379
378
  };
@@ -384,11 +383,11 @@ const getHarnessInternal = async (
384
383
  context,
385
384
  });
386
385
  harnessLogger.debug(
387
- 'starting Metro, platform runner, and bridge initialization'
386
+ 'starting Metro, platform runner, and bridge initialization',
388
387
  );
389
388
  harnessLogger.debug(
390
389
  'bridge server initialized on Metro websocket path %s',
391
- HARNESS_BRIDGE_PATH
390
+ HARNESS_BRIDGE_PATH,
392
391
  );
393
392
  const [metroInstance, platformInstance] = await (async () => {
394
393
  try {
@@ -402,7 +401,7 @@ const getHarnessInternal = async (
402
401
  serverBridge.ws as unknown as MetroWebSocketEndpoint,
403
402
  },
404
403
  },
405
- signal
404
+ signal,
406
405
  ).then((instance) => {
407
406
  harnessLogger.debug('Metro initialized');
408
407
  return instance;
@@ -415,7 +414,7 @@ const getHarnessInternal = async (
415
414
  .then((module) =>
416
415
  module.default(platform.config, runtimeConfig, {
417
416
  signal,
418
- } satisfies HarnessPlatformInitOptions)
417
+ } satisfies HarnessPlatformInitOptions),
419
418
  )
420
419
  .then((instance) => {
421
420
  harnessLogger.debug('platform runner initialized');
@@ -650,7 +649,10 @@ const getHarnessInternal = async (
650
649
  harnessLogger.debug('client log forwarding enabled');
651
650
  }
652
651
 
653
- const dispose = async (reason: 'normal' | 'abort' | 'error' = 'normal') => {
652
+ let disposePromise: Promise<void> | null = null;
653
+ const disposeOnce = async (
654
+ reason: 'normal' | 'abort' | 'error' = 'normal'
655
+ ) => {
654
656
  harnessLogger.debug('disposing Harness (reason=%s)', reason);
655
657
  let hookError: unknown;
656
658
 
@@ -709,6 +711,10 @@ const getHarnessInternal = async (
709
711
  throw cleanupError;
710
712
  }
711
713
  };
714
+ const dispose = (reason: 'normal' | 'abort' | 'error' = 'normal') => {
715
+ disposePromise ??= disposeOnce(reason);
716
+ return disposePromise;
717
+ };
712
718
 
713
719
  if (signal.aborted) {
714
720
  await dispose('abort');
@@ -737,7 +743,7 @@ const getHarnessInternal = async (
737
743
  await dispose(
738
744
  error instanceof DOMException && error.name === 'AbortError'
739
745
  ? 'abort'
740
- : 'error'
746
+ : 'error',
741
747
  );
742
748
  throw error;
743
749
  }
@@ -758,7 +764,7 @@ const getHarnessInternal = async (
758
764
 
759
765
  crashSupervisor.reset();
760
766
  harnessLogger.debug(
761
- 'app not ready, waiting for launch and runtime readiness'
767
+ 'app not ready, waiting for launch and runtime readiness',
762
768
  );
763
769
  await waitForAppReady({
764
770
  metroInstance,
@@ -783,7 +789,7 @@ const getHarnessInternal = async (
783
789
  harnessLogger.debug(
784
790
  'restarting app (testFile=%s mode=%s)',
785
791
  testFilePath ?? 'n/a',
786
- testFilePath ? 'stop-and-ensure-ready' : 'direct-restart'
792
+ testFilePath ? 'stop-and-ensure-ready' : 'direct-restart',
787
793
  );
788
794
 
789
795
  if (testFilePath) {
@@ -848,17 +854,17 @@ const getHarnessInternal = async (
848
854
  export const getHarness = async (
849
855
  config: HarnessConfig,
850
856
  platform: HarnessPlatform,
851
- projectRoot: string
857
+ projectRoot: string,
852
858
  ): Promise<Harness> => {
853
859
  harnessLogger.debug(
854
860
  'creating Harness with platform ready timeout %dms',
855
- config.platformReadyTimeout
861
+ config.platformReadyTimeout,
856
862
  );
857
863
 
858
864
  return await getHarnessInternal(
859
865
  config,
860
866
  platform,
861
867
  projectRoot,
862
- new AbortController().signal
868
+ new AbortController().signal,
863
869
  );
864
870
  };