@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/dist/crash-monitor.d.ts +16 -0
- package/dist/crash-monitor.d.ts.map +1 -0
- package/dist/crash-monitor.js +75 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -0
- package/dist/harness.d.ts +13 -1
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js +84 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -7
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +6 -7
- package/src/crash-monitor.ts +109 -0
- package/src/errors.ts +20 -0
- package/src/harness.ts +125 -25
- package/src/index.ts +45 -9
- package/dist/cli-args.test.d.ts +0 -2
- package/dist/cli-args.test.d.ts.map +0 -1
- package/dist/cli-args.test.js +0 -1
- package/dist/event-mapper.d.ts +0 -16
- package/dist/event-mapper.d.ts.map +0 -1
- package/dist/event-mapper.js +0 -120
- package/dist/global-setup.d.ts +0 -3
- package/dist/global-setup.d.ts.map +0 -1
- package/dist/global-setup.js +0 -60
- package/dist/global-teardown.d.ts +0 -3
- package/dist/global-teardown.d.ts.map +0 -1
- package/dist/global-teardown.js +0 -11
- package/dist/harness-reporter.d.ts +0 -8
- package/dist/harness-reporter.d.ts.map +0 -1
- package/dist/harness-reporter.js +0 -12
- package/dist/jest-options.d.ts +0 -2
- package/dist/jest-options.d.ts.map +0 -1
- package/dist/jest-options.js +0 -1
- package/dist/types.d.ts +0 -17
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HarnessPlatformRunner } from '@react-native-harness/platforms';
|
|
2
|
+
import { BridgeServer } from '@react-native-harness/bridge/server';
|
|
3
|
+
export type CrashMonitor = {
|
|
4
|
+
startMonitoring(testFilePath: string): Promise<never>;
|
|
5
|
+
stopMonitoring(): void;
|
|
6
|
+
markIntentionalRestart(): void;
|
|
7
|
+
clearIntentionalRestart(): void;
|
|
8
|
+
dispose(): void;
|
|
9
|
+
};
|
|
10
|
+
export type CrashMonitorOptions = {
|
|
11
|
+
interval: number;
|
|
12
|
+
platformRunner: HarnessPlatformRunner;
|
|
13
|
+
bridgeServer: BridgeServer;
|
|
14
|
+
};
|
|
15
|
+
export declare const createCrashMonitor: ({ interval, platformRunner, bridgeServer, }: CrashMonitorOptions) => CrashMonitor;
|
|
16
|
+
//# sourceMappingURL=crash-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-monitor.d.ts","sourceRoot":"","sources":["../src/crash-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAInE,MAAM,MAAM,YAAY,GAAG;IACzB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,cAAc,IAAI,IAAI,CAAC;IACvB,sBAAsB,IAAI,IAAI,CAAC;IAC/B,uBAAuB,IAAI,IAAI,CAAC;IAChC,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,qBAAqB,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,6CAIhC,mBAAmB,KAAG,YAqFxB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { NativeCrashError } from './errors.js';
|
|
2
|
+
import { logger } from '@react-native-harness/tools';
|
|
3
|
+
export const createCrashMonitor = ({ interval, platformRunner, bridgeServer, }) => {
|
|
4
|
+
let pollingInterval = null;
|
|
5
|
+
let isIntentionalRestart = false;
|
|
6
|
+
let currentTestFilePath = null;
|
|
7
|
+
let rejectFn = null;
|
|
8
|
+
const handleDisconnect = () => {
|
|
9
|
+
// Verify if it's actually a crash by checking if app is still running
|
|
10
|
+
if (!isIntentionalRestart && currentTestFilePath) {
|
|
11
|
+
// Capture the value to avoid it being null when setTimeout callback runs
|
|
12
|
+
const testFilePath = currentTestFilePath;
|
|
13
|
+
logger.debug('Bridge disconnected, checking if app crashed');
|
|
14
|
+
// Use a slight delay to allow the OS to clean up the process
|
|
15
|
+
setTimeout(async () => {
|
|
16
|
+
const isRunning = await platformRunner.isAppRunning();
|
|
17
|
+
if (!isRunning && !isIntentionalRestart && rejectFn) {
|
|
18
|
+
logger.debug(`Native crash detected during: ${testFilePath}`);
|
|
19
|
+
rejectFn(new NativeCrashError(testFilePath));
|
|
20
|
+
}
|
|
21
|
+
}, 100);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const startMonitoring = (testFilePath) => {
|
|
25
|
+
currentTestFilePath = testFilePath;
|
|
26
|
+
return new Promise((_, reject) => {
|
|
27
|
+
rejectFn = reject;
|
|
28
|
+
// Listen for bridge disconnect as early indicator
|
|
29
|
+
bridgeServer.on('disconnect', handleDisconnect);
|
|
30
|
+
// Poll for app running status
|
|
31
|
+
pollingInterval = setInterval(async () => {
|
|
32
|
+
// Skip check during intentional restarts
|
|
33
|
+
if (isIntentionalRestart) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const isRunning = await platformRunner.isAppRunning();
|
|
38
|
+
if (!isRunning && currentTestFilePath) {
|
|
39
|
+
logger.debug(`Native crash detected during: ${currentTestFilePath}`);
|
|
40
|
+
stopMonitoring();
|
|
41
|
+
reject(new NativeCrashError(currentTestFilePath));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
logger.error('Error checking app status:', error);
|
|
46
|
+
}
|
|
47
|
+
}, interval);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
const stopMonitoring = () => {
|
|
51
|
+
if (pollingInterval) {
|
|
52
|
+
clearInterval(pollingInterval);
|
|
53
|
+
pollingInterval = null;
|
|
54
|
+
}
|
|
55
|
+
bridgeServer.off('disconnect', handleDisconnect);
|
|
56
|
+
currentTestFilePath = null;
|
|
57
|
+
rejectFn = null;
|
|
58
|
+
};
|
|
59
|
+
const markIntentionalRestart = () => {
|
|
60
|
+
isIntentionalRestart = true;
|
|
61
|
+
};
|
|
62
|
+
const clearIntentionalRestart = () => {
|
|
63
|
+
isIntentionalRestart = false;
|
|
64
|
+
};
|
|
65
|
+
const dispose = () => {
|
|
66
|
+
stopMonitoring();
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
startMonitoring,
|
|
70
|
+
stopMonitoring,
|
|
71
|
+
markIntentionalRestart,
|
|
72
|
+
clearIntentionalRestart,
|
|
73
|
+
dispose,
|
|
74
|
+
};
|
|
75
|
+
};
|
package/dist/errors.d.ts
CHANGED
|
@@ -9,4 +9,12 @@ export declare class RunnerNotFoundError extends HarnessError {
|
|
|
9
9
|
export declare class InitializationTimeoutError extends HarnessError {
|
|
10
10
|
constructor();
|
|
11
11
|
}
|
|
12
|
+
export declare class MaxAppRestartsError extends HarnessError {
|
|
13
|
+
constructor(attempts: number);
|
|
14
|
+
}
|
|
15
|
+
export declare class NativeCrashError extends HarnessError {
|
|
16
|
+
readonly testFilePath: string;
|
|
17
|
+
readonly lastKnownTest?: string | undefined;
|
|
18
|
+
constructor(testFilePath: string, lastKnownTest?: string | undefined);
|
|
19
|
+
}
|
|
12
20
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,qBAAa,sBAAuB,SAAQ,YAAY;;CAKvD;AAED,qBAAa,mBAAoB,SAAQ,YAAY;aACvB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,0BAA2B,SAAQ,YAAY;;CAK3D"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,qBAAa,sBAAuB,SAAQ,YAAY;;CAKvD;AAED,qBAAa,mBAAoB,SAAQ,YAAY;aACvB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,0BAA2B,SAAQ,YAAY;;CAK3D;AAED,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,QAAQ,EAAE,MAAM;CAO7B;AAED,qBAAa,gBAAiB,SAAQ,YAAY;aAE9B,YAAY,EAAE,MAAM;aACpB,aAAa,CAAC,EAAE,MAAM;gBADtB,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,MAAM,YAAA;CAKzC"}
|
package/dist/errors.js
CHANGED
|
@@ -19,3 +19,20 @@ export class InitializationTimeoutError extends HarnessError {
|
|
|
19
19
|
this.name = 'InitializationTimeoutError';
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
export class MaxAppRestartsError extends HarnessError {
|
|
23
|
+
constructor(attempts) {
|
|
24
|
+
super(`App failed to start after ${attempts} attempts. ` +
|
|
25
|
+
`No bundling activity detected within timeout period.`);
|
|
26
|
+
this.name = 'MaxAppRestartsError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class NativeCrashError extends HarnessError {
|
|
30
|
+
testFilePath;
|
|
31
|
+
lastKnownTest;
|
|
32
|
+
constructor(testFilePath, lastKnownTest) {
|
|
33
|
+
super('The native app crashed during test execution.');
|
|
34
|
+
this.testFilePath = testFilePath;
|
|
35
|
+
this.lastKnownTest = lastKnownTest;
|
|
36
|
+
this.name = 'NativeCrashError';
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/harness.d.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import { BridgeServer } from '@react-native-harness/bridge/server';
|
|
1
2
|
import { BridgeClientFunctions } from '@react-native-harness/bridge';
|
|
2
|
-
import { HarnessPlatform } from '@react-native-harness/platforms';
|
|
3
|
+
import { HarnessPlatform, HarnessPlatformRunner } from '@react-native-harness/platforms';
|
|
4
|
+
import { Reporter } from '@react-native-harness/bundler-metro';
|
|
3
5
|
import { Config as HarnessConfig } from '@react-native-harness/config';
|
|
6
|
+
import { CrashMonitor } from './crash-monitor.js';
|
|
4
7
|
export type Harness = {
|
|
5
8
|
runTests: BridgeClientFunctions['runTests'];
|
|
6
9
|
restart: () => Promise<void>;
|
|
7
10
|
dispose: () => Promise<void>;
|
|
11
|
+
crashMonitor: CrashMonitor;
|
|
8
12
|
};
|
|
13
|
+
export declare const waitForAppReady: (options: {
|
|
14
|
+
metroEvents: Reporter;
|
|
15
|
+
serverBridge: BridgeServer;
|
|
16
|
+
platformInstance: HarnessPlatformRunner;
|
|
17
|
+
bundleStartTimeout: number;
|
|
18
|
+
maxRestarts: number;
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
}) => Promise<void>;
|
|
9
21
|
export declare const getHarness: (config: HarnessConfig, platform: HarnessPlatform, projectRoot: string) => Promise<Harness>;
|
|
10
22
|
//# sourceMappingURL=harness.d.ts.map
|
package/dist/harness.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACb,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,eAAe,EACf,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,QAAQ,EAET,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAsB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEtE,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,SAAS;IAC7C,WAAW,EAAE,QAAQ,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;CACrB,KAAG,OAAO,CAAC,IAAI,CAgFf,CAAC;AA+EF,eAAO,MAAM,UAAU,GACrB,QAAQ,aAAa,EACrB,UAAU,eAAe,EACzB,aAAa,MAAM,KAClB,OAAO,CAAC,OAAO,CAkBjB,CAAC"}
|
package/dist/harness.js
CHANGED
|
@@ -1,8 +1,70 @@
|
|
|
1
|
-
import { getBridgeServer } from '@react-native-harness/bridge/server';
|
|
2
|
-
import { getMetroInstance } from '@react-native-harness/bundler-metro';
|
|
3
|
-
import { InitializationTimeoutError } from './errors.js';
|
|
4
|
-
import
|
|
5
|
-
const
|
|
1
|
+
import { getBridgeServer, } from '@react-native-harness/bridge/server';
|
|
2
|
+
import { getMetroInstance, } from '@react-native-harness/bundler-metro';
|
|
3
|
+
import { InitializationTimeoutError, MaxAppRestartsError } from './errors.js';
|
|
4
|
+
import { createCrashMonitor } from './crash-monitor.js';
|
|
5
|
+
export const waitForAppReady = async (options) => {
|
|
6
|
+
const { metroEvents, serverBridge, platformInstance, bundleStartTimeout, maxRestarts, signal, } = options;
|
|
7
|
+
let restartCount = 0;
|
|
8
|
+
let isBundling = false;
|
|
9
|
+
let bundleTimeoutId = null;
|
|
10
|
+
const clearBundleTimeout = () => {
|
|
11
|
+
if (bundleTimeoutId) {
|
|
12
|
+
clearTimeout(bundleTimeoutId);
|
|
13
|
+
bundleTimeoutId = null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
// Handle abort signal
|
|
18
|
+
signal.addEventListener('abort', () => {
|
|
19
|
+
clearBundleTimeout();
|
|
20
|
+
reject(new DOMException('The operation was aborted', 'AbortError'));
|
|
21
|
+
});
|
|
22
|
+
// Start/restart the bundle timeout
|
|
23
|
+
const startBundleTimeout = () => {
|
|
24
|
+
clearBundleTimeout();
|
|
25
|
+
bundleTimeoutId = setTimeout(() => {
|
|
26
|
+
if (isBundling)
|
|
27
|
+
return; // Don't restart while bundling
|
|
28
|
+
if (restartCount >= maxRestarts) {
|
|
29
|
+
cleanup();
|
|
30
|
+
reject(new MaxAppRestartsError(restartCount + 1));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
restartCount++;
|
|
34
|
+
platformInstance.restartApp().catch(reject);
|
|
35
|
+
startBundleTimeout(); // Reset timer for next attempt
|
|
36
|
+
}, bundleStartTimeout);
|
|
37
|
+
};
|
|
38
|
+
// Metro event listener
|
|
39
|
+
const onMetroEvent = (event) => {
|
|
40
|
+
if (event.type === 'bundle_build_started') {
|
|
41
|
+
isBundling = true;
|
|
42
|
+
clearBundleTimeout(); // Cancel restart timer while bundling
|
|
43
|
+
}
|
|
44
|
+
else if (event.type === 'bundle_build_done' ||
|
|
45
|
+
event.type === 'bundle_build_failed') {
|
|
46
|
+
isBundling = false;
|
|
47
|
+
startBundleTimeout(); // Reset timer after bundle completes
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
// Bridge ready listener
|
|
51
|
+
const onReady = () => {
|
|
52
|
+
cleanup();
|
|
53
|
+
resolve();
|
|
54
|
+
};
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
clearBundleTimeout();
|
|
57
|
+
metroEvents.removeListener(onMetroEvent);
|
|
58
|
+
serverBridge.off('ready', onReady);
|
|
59
|
+
};
|
|
60
|
+
// Setup listeners
|
|
61
|
+
metroEvents.addListener(onMetroEvent);
|
|
62
|
+
serverBridge.once('ready', onReady);
|
|
63
|
+
// Start the app and timeout
|
|
64
|
+
platformInstance.restartApp().catch(reject);
|
|
65
|
+
startBundleTimeout();
|
|
66
|
+
});
|
|
67
|
+
};
|
|
6
68
|
const getHarnessInternal = async (config, platform, projectRoot, signal) => {
|
|
7
69
|
const [metroInstance, platformInstance, serverBridge] = await Promise.all([
|
|
8
70
|
getMetroInstance({ projectRoot, harnessConfig: config }, signal),
|
|
@@ -19,21 +81,22 @@ const getHarnessInternal = async (config, platform, projectRoot, signal) => {
|
|
|
19
81
|
metroInstance.dispose(),
|
|
20
82
|
]);
|
|
21
83
|
};
|
|
84
|
+
const crashMonitor = createCrashMonitor({
|
|
85
|
+
interval: config.crashDetectionInterval,
|
|
86
|
+
platformRunner: platformInstance,
|
|
87
|
+
bridgeServer: serverBridge,
|
|
88
|
+
});
|
|
22
89
|
if (signal.aborted) {
|
|
23
90
|
await dispose();
|
|
24
91
|
throw new DOMException('The operation was aborted', 'AbortError');
|
|
25
92
|
}
|
|
26
93
|
try {
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}), {
|
|
34
|
-
minTimeout: BRIDGE_READY_TIMEOUT,
|
|
35
|
-
maxTimeout: BRIDGE_READY_TIMEOUT,
|
|
36
|
-
retries: Infinity,
|
|
94
|
+
await waitForAppReady({
|
|
95
|
+
metroEvents: metroInstance.events,
|
|
96
|
+
serverBridge,
|
|
97
|
+
platformInstance: platformInstance,
|
|
98
|
+
bundleStartTimeout: config.bundleStartTimeout,
|
|
99
|
+
maxRestarts: config.maxAppRestarts,
|
|
37
100
|
signal,
|
|
38
101
|
});
|
|
39
102
|
}
|
|
@@ -42,7 +105,11 @@ const getHarnessInternal = async (config, platform, projectRoot, signal) => {
|
|
|
42
105
|
throw error;
|
|
43
106
|
}
|
|
44
107
|
const restart = () => new Promise((resolve, reject) => {
|
|
45
|
-
|
|
108
|
+
crashMonitor.markIntentionalRestart();
|
|
109
|
+
serverBridge.once('ready', () => {
|
|
110
|
+
crashMonitor.clearIntentionalRestart();
|
|
111
|
+
resolve();
|
|
112
|
+
});
|
|
46
113
|
platformInstance.restartApp().catch(reject);
|
|
47
114
|
});
|
|
48
115
|
return {
|
|
@@ -55,6 +122,7 @@ const getHarnessInternal = async (config, platform, projectRoot, signal) => {
|
|
|
55
122
|
},
|
|
56
123
|
restart,
|
|
57
124
|
dispose,
|
|
125
|
+
crashMonitor,
|
|
58
126
|
};
|
|
59
127
|
};
|
|
60
128
|
export const getHarness = async (config, platform, projectRoot) => {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAC3B,MAAM,EACN,aAAa,EACb,WAAW,EACX,aAAa,EACb,IAAI,EACJ,iBAAiB,EACjB,WAAW,EACZ,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAC3B,MAAM,EACN,aAAa,EACb,WAAW,EACX,aAAa,EACb,IAAI,EACJ,iBAAiB,EACjB,WAAW,EACZ,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAe5C,MAAM,CAAC,OAAO,OAAO,WAAY,YAAW,2BAA2B;;IACrE,QAAQ,CAAC,QAAQ,QAAQ;gBAIb,YAAY,EAAE,MAAM,CAAC,YAAY;IAIvC,QAAQ,CACZ,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAkCV,oBAAoB,CACxB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,aAAa,GACvB,OAAO,CAAC,IAAI,CAAC;CAkFjB"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { teardown } from './teardown.js';
|
|
|
5
5
|
import { HarnessError } from '@react-native-harness/tools';
|
|
6
6
|
import { getErrorMessage } from './logs.js';
|
|
7
7
|
import { DeviceNotRespondingError } from '@react-native-harness/bridge';
|
|
8
|
+
import { NativeCrashError } from './errors.js';
|
|
8
9
|
class CancelRun extends Error {
|
|
9
10
|
constructor(message) {
|
|
10
11
|
super(message);
|
|
@@ -53,15 +54,45 @@ export default class JestHarness {
|
|
|
53
54
|
await harness.restart();
|
|
54
55
|
}
|
|
55
56
|
isFirstTest = false;
|
|
56
|
-
return onStart(test).then(() =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
return onStart(test).then(async () => {
|
|
58
|
+
if (!harnessConfig.detectNativeCrashes) {
|
|
59
|
+
return runHarnessTestFile({
|
|
60
|
+
testPath: test.path,
|
|
61
|
+
harness,
|
|
62
|
+
globalConfig: this.#globalConfig,
|
|
63
|
+
projectConfig: test.context.config,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Start crash monitoring
|
|
67
|
+
const crashPromise = harness.crashMonitor.startMonitoring(test.path);
|
|
68
|
+
try {
|
|
69
|
+
const result = await Promise.race([
|
|
70
|
+
runHarnessTestFile({
|
|
71
|
+
testPath: test.path,
|
|
72
|
+
harness,
|
|
73
|
+
globalConfig: this.#globalConfig,
|
|
74
|
+
projectConfig: test.context.config,
|
|
75
|
+
}),
|
|
76
|
+
crashPromise,
|
|
77
|
+
]);
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
harness.crashMonitor.stopMonitoring();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
62
84
|
})
|
|
63
85
|
.then((result) => onResult(test, result))
|
|
64
|
-
.catch((err) => {
|
|
86
|
+
.catch(async (err) => {
|
|
87
|
+
if (err instanceof NativeCrashError) {
|
|
88
|
+
onFailure(test, {
|
|
89
|
+
message: err.message,
|
|
90
|
+
stack: '',
|
|
91
|
+
});
|
|
92
|
+
// Restart the app for the next test file
|
|
93
|
+
await harness.restart();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
65
96
|
if (err instanceof DeviceNotRespondingError) {
|
|
66
97
|
onFailure(test, {
|
|
67
98
|
message: err.message,
|