@react-native-harness/jest 1.0.0-alpha.20 → 1.0.0-alpha.21

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.0.0-alpha.20",
3
+ "version": "1.0.0-alpha.21",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -38,14 +38,13 @@
38
38
  "jest-message-util": "^30.2.0",
39
39
  "jest-util": "^30.2.0",
40
40
  "p-limit": "^7.1.1",
41
- "p-retry": "^7.1.0",
42
41
  "tslib": "^2.3.0",
43
42
  "yargs": "^17.7.2",
44
- "@react-native-harness/bundler-metro": "1.0.0-alpha.20",
45
- "@react-native-harness/config": "1.0.0-alpha.20",
46
- "@react-native-harness/platforms": "1.0.0-alpha.20",
47
- "@react-native-harness/tools": "1.0.0-alpha.20",
48
- "@react-native-harness/bridge": "1.0.0-alpha.20"
43
+ "@react-native-harness/bridge": "1.0.0-alpha.21",
44
+ "@react-native-harness/bundler-metro": "1.0.0-alpha.21",
45
+ "@react-native-harness/config": "1.0.0-alpha.21",
46
+ "@react-native-harness/platforms": "1.0.0-alpha.21",
47
+ "@react-native-harness/tools": "1.0.0-alpha.21"
49
48
  },
50
49
  "devDependencies": {
51
50
  "@types/yargs": "^17.0.32",
@@ -0,0 +1,109 @@
1
+ import { HarnessPlatformRunner } from '@react-native-harness/platforms';
2
+ import { BridgeServer } from '@react-native-harness/bridge/server';
3
+ import { NativeCrashError } from './errors.js';
4
+ import { logger } from '@react-native-harness/tools';
5
+
6
+ export type CrashMonitor = {
7
+ startMonitoring(testFilePath: string): Promise<never>;
8
+ stopMonitoring(): void;
9
+ markIntentionalRestart(): void;
10
+ clearIntentionalRestart(): void;
11
+ dispose(): void;
12
+ };
13
+
14
+ export type CrashMonitorOptions = {
15
+ interval: number;
16
+ platformRunner: HarnessPlatformRunner;
17
+ bridgeServer: BridgeServer;
18
+ };
19
+
20
+ export const createCrashMonitor = ({
21
+ interval,
22
+ platformRunner,
23
+ bridgeServer,
24
+ }: CrashMonitorOptions): CrashMonitor => {
25
+ let pollingInterval: NodeJS.Timeout | null = null;
26
+ let isIntentionalRestart = false;
27
+ let currentTestFilePath: string | null = null;
28
+ let rejectFn: ((error: NativeCrashError) => void) | null = null;
29
+
30
+ const handleDisconnect = () => {
31
+ // Verify if it's actually a crash by checking if app is still running
32
+ if (!isIntentionalRestart && currentTestFilePath) {
33
+ // Capture the value to avoid it being null when setTimeout callback runs
34
+ const testFilePath = currentTestFilePath;
35
+ logger.debug('Bridge disconnected, checking if app crashed');
36
+ // Use a slight delay to allow the OS to clean up the process
37
+ setTimeout(async () => {
38
+ const isRunning = await platformRunner.isAppRunning();
39
+ if (!isRunning && !isIntentionalRestart && rejectFn) {
40
+ logger.debug(`Native crash detected during: ${testFilePath}`);
41
+ rejectFn(new NativeCrashError(testFilePath));
42
+ }
43
+ }, 100);
44
+ }
45
+ };
46
+
47
+ const startMonitoring = (testFilePath: string): Promise<never> => {
48
+ currentTestFilePath = testFilePath;
49
+
50
+ return new Promise<never>((_, reject) => {
51
+ rejectFn = reject;
52
+
53
+ // Listen for bridge disconnect as early indicator
54
+ bridgeServer.on('disconnect', handleDisconnect);
55
+
56
+ // Poll for app running status
57
+ pollingInterval = setInterval(async () => {
58
+ // Skip check during intentional restarts
59
+ if (isIntentionalRestart) {
60
+ return;
61
+ }
62
+
63
+ try {
64
+ const isRunning = await platformRunner.isAppRunning();
65
+
66
+ if (!isRunning && currentTestFilePath) {
67
+ logger.debug(
68
+ `Native crash detected during: ${currentTestFilePath}`
69
+ );
70
+ stopMonitoring();
71
+ reject(new NativeCrashError(currentTestFilePath));
72
+ }
73
+ } catch (error) {
74
+ logger.error('Error checking app status:', error);
75
+ }
76
+ }, interval);
77
+ });
78
+ };
79
+
80
+ const stopMonitoring = () => {
81
+ if (pollingInterval) {
82
+ clearInterval(pollingInterval);
83
+ pollingInterval = null;
84
+ }
85
+ bridgeServer.off('disconnect', handleDisconnect);
86
+ currentTestFilePath = null;
87
+ rejectFn = null;
88
+ };
89
+
90
+ const markIntentionalRestart = () => {
91
+ isIntentionalRestart = true;
92
+ };
93
+
94
+ const clearIntentionalRestart = () => {
95
+ isIntentionalRestart = false;
96
+ };
97
+
98
+ const dispose = () => {
99
+ stopMonitoring();
100
+ };
101
+
102
+ return {
103
+ startMonitoring,
104
+ stopMonitoring,
105
+ markIntentionalRestart,
106
+ clearIntentionalRestart,
107
+ dispose,
108
+ };
109
+ };
package/src/errors.ts CHANGED
@@ -20,3 +20,23 @@ export class InitializationTimeoutError extends HarnessError {
20
20
  this.name = 'InitializationTimeoutError';
21
21
  }
22
22
  }
23
+
24
+ export class MaxAppRestartsError extends HarnessError {
25
+ constructor(attempts: number) {
26
+ super(
27
+ `App failed to start after ${attempts} attempts. ` +
28
+ `No bundling activity detected within timeout period.`
29
+ );
30
+ this.name = 'MaxAppRestartsError';
31
+ }
32
+ }
33
+
34
+ export class NativeCrashError extends HarnessError {
35
+ constructor(
36
+ public readonly testFilePath: string,
37
+ public readonly lastKnownTest?: string
38
+ ) {
39
+ super('The native app crashed during test execution.');
40
+ this.name = 'NativeCrashError';
41
+ }
42
+ }
package/src/harness.ts CHANGED
@@ -1,17 +1,115 @@
1
- import { getBridgeServer } from '@react-native-harness/bridge/server';
1
+ import {
2
+ getBridgeServer,
3
+ BridgeServer,
4
+ } from '@react-native-harness/bridge/server';
2
5
  import { BridgeClientFunctions } from '@react-native-harness/bridge';
3
- import { HarnessPlatform } from '@react-native-harness/platforms';
4
- import { getMetroInstance } from '@react-native-harness/bundler-metro';
5
- import { InitializationTimeoutError } from './errors.js';
6
+ import {
7
+ HarnessPlatform,
8
+ HarnessPlatformRunner,
9
+ } from '@react-native-harness/platforms';
10
+ import {
11
+ getMetroInstance,
12
+ Reporter,
13
+ ReportableEvent,
14
+ } from '@react-native-harness/bundler-metro';
15
+ import { InitializationTimeoutError, MaxAppRestartsError } from './errors.js';
6
16
  import { Config as HarnessConfig } from '@react-native-harness/config';
7
- import pRetry from 'p-retry';
8
-
9
- const BRIDGE_READY_TIMEOUT = 10000;
17
+ import { createCrashMonitor, CrashMonitor } from './crash-monitor.js';
10
18
 
11
19
  export type Harness = {
12
20
  runTests: BridgeClientFunctions['runTests'];
13
21
  restart: () => Promise<void>;
14
22
  dispose: () => Promise<void>;
23
+ crashMonitor: CrashMonitor;
24
+ };
25
+
26
+ export const waitForAppReady = async (options: {
27
+ metroEvents: Reporter;
28
+ serverBridge: BridgeServer;
29
+ platformInstance: HarnessPlatformRunner;
30
+ bundleStartTimeout: number;
31
+ maxRestarts: number;
32
+ signal: AbortSignal;
33
+ }): Promise<void> => {
34
+ const {
35
+ metroEvents,
36
+ serverBridge,
37
+ platformInstance,
38
+ bundleStartTimeout,
39
+ maxRestarts,
40
+ signal,
41
+ } = options;
42
+
43
+ let restartCount = 0;
44
+ let isBundling = false;
45
+ let bundleTimeoutId: NodeJS.Timeout | null = null;
46
+
47
+ const clearBundleTimeout = () => {
48
+ if (bundleTimeoutId) {
49
+ clearTimeout(bundleTimeoutId);
50
+ bundleTimeoutId = null;
51
+ }
52
+ };
53
+
54
+ return new Promise<void>((resolve, reject) => {
55
+ // Handle abort signal
56
+ signal.addEventListener('abort', () => {
57
+ clearBundleTimeout();
58
+ reject(new DOMException('The operation was aborted', 'AbortError'));
59
+ });
60
+
61
+ // Start/restart the bundle timeout
62
+ const startBundleTimeout = () => {
63
+ clearBundleTimeout();
64
+ bundleTimeoutId = setTimeout(() => {
65
+ if (isBundling) return; // Don't restart while bundling
66
+
67
+ if (restartCount >= maxRestarts) {
68
+ cleanup();
69
+ reject(new MaxAppRestartsError(restartCount + 1));
70
+ return;
71
+ }
72
+
73
+ restartCount++;
74
+ platformInstance.restartApp().catch(reject);
75
+ startBundleTimeout(); // Reset timer for next attempt
76
+ }, bundleStartTimeout);
77
+ };
78
+
79
+ // Metro event listener
80
+ const onMetroEvent = (event: ReportableEvent) => {
81
+ if (event.type === 'bundle_build_started') {
82
+ isBundling = true;
83
+ clearBundleTimeout(); // Cancel restart timer while bundling
84
+ } else if (
85
+ event.type === 'bundle_build_done' ||
86
+ event.type === 'bundle_build_failed'
87
+ ) {
88
+ isBundling = false;
89
+ startBundleTimeout(); // Reset timer after bundle completes
90
+ }
91
+ };
92
+
93
+ // Bridge ready listener
94
+ const onReady = () => {
95
+ cleanup();
96
+ resolve();
97
+ };
98
+
99
+ const cleanup = () => {
100
+ clearBundleTimeout();
101
+ metroEvents.removeListener(onMetroEvent);
102
+ serverBridge.off('ready', onReady);
103
+ };
104
+
105
+ // Setup listeners
106
+ metroEvents.addListener(onMetroEvent);
107
+ serverBridge.once('ready', onReady);
108
+
109
+ // Start the app and timeout
110
+ platformInstance.restartApp().catch(reject);
111
+ startBundleTimeout();
112
+ });
15
113
  };
16
114
 
17
115
  const getHarnessInternal = async (
@@ -39,6 +137,12 @@ const getHarnessInternal = async (
39
137
  ]);
40
138
  };
41
139
 
140
+ const crashMonitor = createCrashMonitor({
141
+ interval: config.crashDetectionInterval,
142
+ platformRunner: platformInstance,
143
+ bridgeServer: serverBridge,
144
+ });
145
+
42
146
  if (signal.aborted) {
43
147
  await dispose();
44
148
 
@@ -46,23 +150,14 @@ const getHarnessInternal = async (
46
150
  }
47
151
 
48
152
  try {
49
- await pRetry(
50
- () =>
51
- new Promise<void>((resolve, reject) => {
52
- signal.addEventListener('abort', () => {
53
- reject(new DOMException('The operation was aborted', 'AbortError'));
54
- });
55
-
56
- serverBridge.once('ready', () => resolve());
57
- platformInstance.restartApp().catch(reject);
58
- }),
59
- {
60
- minTimeout: BRIDGE_READY_TIMEOUT,
61
- maxTimeout: BRIDGE_READY_TIMEOUT,
62
- retries: Infinity,
63
- signal,
64
- }
65
- );
153
+ await waitForAppReady({
154
+ metroEvents: metroInstance.events,
155
+ serverBridge,
156
+ platformInstance: platformInstance as HarnessPlatformRunner,
157
+ bundleStartTimeout: config.bundleStartTimeout,
158
+ maxRestarts: config.maxAppRestarts,
159
+ signal,
160
+ });
66
161
  } catch (error) {
67
162
  await dispose();
68
163
  throw error;
@@ -70,7 +165,11 @@ const getHarnessInternal = async (
70
165
 
71
166
  const restart = () =>
72
167
  new Promise<void>((resolve, reject) => {
73
- serverBridge.once('ready', () => resolve());
168
+ crashMonitor.markIntentionalRestart();
169
+ serverBridge.once('ready', () => {
170
+ crashMonitor.clearIntentionalRestart();
171
+ resolve();
172
+ });
74
173
  platformInstance.restartApp().catch(reject);
75
174
  });
76
175
 
@@ -86,6 +185,7 @@ const getHarnessInternal = async (
86
185
  },
87
186
  restart,
88
187
  dispose,
188
+ crashMonitor,
89
189
  };
90
190
  };
91
191
 
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ import { teardown } from './teardown.js';
17
17
  import { HarnessError } from '@react-native-harness/tools';
18
18
  import { getErrorMessage } from './logs.js';
19
19
  import { DeviceNotRespondingError } from '@react-native-harness/bridge';
20
+ import { NativeCrashError } from './errors.js';
20
21
 
21
22
  class CancelRun extends Error {
22
23
  constructor(message?: string) {
@@ -104,17 +105,52 @@ export default class JestHarness implements CallbackTestRunnerInterface {
104
105
  }
105
106
  isFirstTest = false;
106
107
 
107
- return onStart(test).then(() =>
108
- runHarnessTestFile({
109
- testPath: test.path,
110
- harness,
111
- globalConfig: this.#globalConfig,
112
- projectConfig: test.context.config,
113
- })
114
- );
108
+ return onStart(test).then(async () => {
109
+ if (!harnessConfig.detectNativeCrashes) {
110
+ return runHarnessTestFile({
111
+ testPath: test.path,
112
+ harness,
113
+ globalConfig: this.#globalConfig,
114
+ projectConfig: test.context.config,
115
+ });
116
+ }
117
+
118
+ // Start crash monitoring
119
+ const crashPromise = harness.crashMonitor.startMonitoring(
120
+ test.path
121
+ );
122
+
123
+ try {
124
+ const result = await Promise.race([
125
+ runHarnessTestFile({
126
+ testPath: test.path,
127
+ harness,
128
+ globalConfig: this.#globalConfig,
129
+ projectConfig: test.context.config,
130
+ }),
131
+ crashPromise,
132
+ ]);
133
+
134
+ return result;
135
+ } finally {
136
+ harness.crashMonitor.stopMonitoring();
137
+ }
138
+ });
115
139
  })
116
140
  .then((result) => onResult(test, result))
117
- .catch((err) => {
141
+ .catch(async (err) => {
142
+ if (err instanceof NativeCrashError) {
143
+ onFailure(test, {
144
+ message: err.message,
145
+ stack: '',
146
+ });
147
+
148
+ // Restart the app for the next test file
149
+ await harness.restart();
150
+
151
+ return;
152
+ }
153
+
118
154
  if (err instanceof DeviceNotRespondingError) {
119
155
  onFailure(test, {
120
156
  message: err.message,
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cli-args.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-args.test.d.ts","sourceRoot":"","sources":["../src/cli-args.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- export {};
@@ -1,16 +0,0 @@
1
- import type { TestEvents } from '@jest/test-result';
2
- import type { Test } from 'jest-runner';
3
- import type { BridgeEvents } from '@react-native-harness/bridge';
4
- import type { TestCaseResult } from '@jest/test-result';
5
- export type EventMapperState = {
6
- currentTest?: Test;
7
- suiteHierarchy: string[];
8
- testResults: Map<string, TestCaseResult>;
9
- fileStartTime: number;
10
- };
11
- export type HarnessEventMapper = {
12
- handleBridgeEvent: (event: BridgeEvents, test: Test) => void;
13
- reset: () => void;
14
- };
15
- export declare const getHarnessEventMapper: (emit: <T extends keyof TestEvents>(eventName: T, eventData: TestEvents[T]) => void) => HarnessEventMapper;
16
- //# sourceMappingURL=event-mapper.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-mapper.d.ts","sourceRoot":"","sources":["../src/event-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EASV,YAAY,EACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iBAAiB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7D,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,CAAC,CAAC,SAAS,MAAM,UAAU,EAC/B,SAAS,EAAE,CAAC,EACZ,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,KACrB,IAAI,KACR,kBA8JF,CAAC"}
@@ -1,120 +0,0 @@
1
- export const getHarnessEventMapper = (emit) => {
2
- const state = {
3
- suiteHierarchy: [],
4
- testResults: new Map(),
5
- fileStartTime: 0,
6
- };
7
- const handleBridgeEvent = (event, test) => {
8
- // Filter to only process test runner events
9
- if (event.type.startsWith('test-') ||
10
- event.type.startsWith('suite-') ||
11
- event.type.startsWith('file-')) {
12
- switch (event.type) {
13
- case 'file-started':
14
- handleFileStarted(event, test);
15
- break;
16
- case 'file-finished':
17
- handleFileFinished(event, test);
18
- break;
19
- case 'suite-started':
20
- handleSuiteStarted(event);
21
- break;
22
- case 'suite-finished':
23
- handleSuiteFinished(event);
24
- break;
25
- case 'test-started':
26
- handleTestStarted(event, test);
27
- break;
28
- case 'test-finished':
29
- handleTestFinished(event, test);
30
- break;
31
- }
32
- }
33
- };
34
- const handleFileStarted = (event, test) => {
35
- state.currentTest = test;
36
- state.fileStartTime = Date.now();
37
- state.suiteHierarchy = [];
38
- state.testResults.clear();
39
- // Don't emit test-file-start here - that should be handled by the Jest runner
40
- // when it actually starts running the test file
41
- };
42
- const handleFileFinished = (_event, _test) => {
43
- // File finished - all test results should already be emitted
44
- // The final TestResult will be handled by the runHarnessTestFile function
45
- };
46
- const handleSuiteStarted = (event) => {
47
- state.suiteHierarchy.push(event.name);
48
- };
49
- const handleSuiteFinished = (event) => {
50
- // Remove the suite from hierarchy when it finishes
51
- const index = state.suiteHierarchy.lastIndexOf(event.name);
52
- if (index !== -1) {
53
- state.suiteHierarchy.splice(index, 1);
54
- }
55
- };
56
- const handleTestStarted = (event, test) => {
57
- const testCaseStartInfo = {
58
- ancestorTitles: [...state.suiteHierarchy],
59
- fullName: `${state.suiteHierarchy.join(' ')} ${event.name}`.trim(),
60
- title: event.name,
61
- mode: 'skip', // Default mode, will be updated based on test status
62
- };
63
- emit('test-case-start', [test.path, testCaseStartInfo]);
64
- };
65
- const handleTestFinished = (event, test) => {
66
- const testCaseResult = {
67
- ancestorTitles: [...state.suiteHierarchy],
68
- duration: event.duration,
69
- failureDetails: [],
70
- failureMessages: event.error ? [formatError(event.error)] : [],
71
- fullName: `${state.suiteHierarchy.join(' ')} ${event.name}`.trim(),
72
- numPassingAsserts: event.status === 'passed' ? 1 : 0,
73
- status: mapStatus(event.status),
74
- title: event.name,
75
- startedAt: Date.now() - event.duration,
76
- };
77
- state.testResults.set(event.name, testCaseResult);
78
- emit('test-case-result', [test.path, testCaseResult]);
79
- };
80
- const mapStatus = (status) => {
81
- return status;
82
- };
83
- const formatError = (error) => {
84
- let errorMessage = `${error.name}: ${error.message}`;
85
- if (error.codeFrame) {
86
- errorMessage += '\n\n' + formatCodeFrame(error.codeFrame);
87
- }
88
- return errorMessage;
89
- };
90
- const formatCodeFrame = (codeFrame) => {
91
- const lines = codeFrame.content.split('\n');
92
- const lineNumber = codeFrame.location?.row || 1;
93
- const column = codeFrame.location?.column || 1;
94
- let formatted = `\n${codeFrame.fileName}:${lineNumber}:${column}\n`;
95
- // Add context lines around the error
96
- const startLine = Math.max(0, lineNumber - 3);
97
- const endLine = Math.min(lines.length, lineNumber + 2);
98
- for (let i = startLine; i < endLine; i++) {
99
- const lineNum = i + 1;
100
- const line = lines[i];
101
- const isErrorLine = lineNum === lineNumber;
102
- formatted += `${lineNum.toString().padStart(3)} | ${line}\n`;
103
- if (isErrorLine && column > 0) {
104
- const pointer = ' '.repeat(column + 5) + '^';
105
- formatted += pointer + '\n';
106
- }
107
- }
108
- return formatted;
109
- };
110
- const reset = () => {
111
- state.suiteHierarchy = [];
112
- state.testResults.clear();
113
- state.fileStartTime = 0;
114
- state.currentTest = undefined;
115
- };
116
- return {
117
- handleBridgeEvent,
118
- reset,
119
- };
120
- };
@@ -1,3 +0,0 @@
1
- import type { Config as JestConfig } from 'jest-runner';
2
- export default function (globalConfig: JestConfig.GlobalConfig): Promise<void>;
3
- //# sourceMappingURL=global-setup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"global-setup.d.ts","sourceRoot":"","sources":["../src/global-setup.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AA4CxD,yBAA+B,YAAY,EAAE,UAAU,CAAC,YAAY,iBA4CnE"}
@@ -1,60 +0,0 @@
1
- import { getConfig, } from '@react-native-harness/config';
2
- import { getHarness as getHarnessExternal, NoRunnerSpecifiedError, RunnerNotFoundError, } from '@react-native-harness/cli/external';
3
- import { preRunMessage } from 'jest-util';
4
- import { getAdditionalCliArgs } from './cli-args.js';
5
- import { logTestEnvironmentReady, logTestRunHeader } from './logs.js';
6
- const getHarnessConfig = async (globalConfig) => {
7
- const projectRoot = globalConfig.rootDir;
8
- const { config: harnessConfig } = await getConfig(projectRoot);
9
- return harnessConfig;
10
- };
11
- const getHarnessRunner = (config, cliArgs) => {
12
- const selectedRunnerName = cliArgs.harnessRunner ?? config.defaultRunner;
13
- if (!selectedRunnerName) {
14
- throw new NoRunnerSpecifiedError(config.runners);
15
- }
16
- const runner = config.runners.find((runner) => runner.name === selectedRunnerName);
17
- if (!runner) {
18
- throw new RunnerNotFoundError(selectedRunnerName, config.runners);
19
- }
20
- return runner;
21
- };
22
- const getHarness = async (runner) => {
23
- return await getHarnessExternal(runner);
24
- };
25
- export default async function (globalConfig) {
26
- preRunMessage.remove(process.stderr);
27
- const harnessConfig = global.HARNESS_CONFIG ?? (await getHarnessConfig(globalConfig));
28
- const isWatchMode = globalConfig.watch || globalConfig.watchAll;
29
- if (global.HARNESS) {
30
- // Do not setup again if HARNESS is already initialized
31
- // This is useful when running tests in watch mode
32
- if (harnessConfig.resetEnvironmentBetweenTestFiles) {
33
- // In watch mode, we want to restart the environment before each test run
34
- await new Promise((resolve) => {
35
- global.HARNESS.bridge.once('ready', resolve);
36
- global.HARNESS.environment.restart();
37
- });
38
- }
39
- return;
40
- }
41
- if (isWatchMode) {
42
- // In watch mode, we want to dispose the Harness when the process exits.
43
- process.on('exit', async () => {
44
- await global.HARNESS.bridge.dispose();
45
- await global.HARNESS.environment.dispose();
46
- });
47
- }
48
- const cliArgs = getAdditionalCliArgs();
49
- const selectedRunner = getHarnessRunner(harnessConfig, cliArgs);
50
- if (globalConfig.collectCoverage) {
51
- // This is going to be used by @react-native-harness/babel-preset
52
- // to enable instrumentation of test files.
53
- process.env.RN_HARNESS_COLLECT_COVERAGE = 'true';
54
- }
55
- logTestRunHeader(selectedRunner);
56
- const harness = await getHarness(selectedRunner);
57
- logTestEnvironmentReady(selectedRunner);
58
- global.HARNESS_CONFIG = harnessConfig;
59
- global.HARNESS = harness;
60
- }
@@ -1,3 +0,0 @@
1
- import type { Config as JestConfig } from 'jest-runner';
2
- export default function (globalConfig: JestConfig.GlobalConfig): Promise<void>;
3
- //# sourceMappingURL=global-teardown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"global-teardown.d.ts","sourceRoot":"","sources":["../src/global-teardown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAExD,yBAA+B,YAAY,EAAE,UAAU,CAAC,YAAY,iBAYnE"}
@@ -1,11 +0,0 @@
1
- export default async function (globalConfig) {
2
- const isWatchMode = globalConfig.watch || globalConfig.watchAll;
3
- if (isWatchMode) {
4
- // In watch mode, we don't want to dispose the Harness.
5
- return;
6
- }
7
- if (global.HARNESS) {
8
- await global.HARNESS.bridge.dispose();
9
- await global.HARNESS.environment.dispose();
10
- }
11
- }
@@ -1,8 +0,0 @@
1
- import { BaseReporter } from '@jest/reporters';
2
- import { Config } from '@jest/types';
3
- export default class HarnessReporter extends BaseReporter {
4
- #private;
5
- constructor(globalConfig: Config.GlobalConfig);
6
- onRunStart(): void;
7
- }
8
- //# sourceMappingURL=harness-reporter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"harness-reporter.d.ts","sourceRoot":"","sources":["../src/harness-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,YAAY;;gBAE3C,YAAY,EAAE,MAAM,CAAC,YAAY;IAKpC,UAAU,IAAI,IAAI;CAM5B"}