@react-native-harness/jest 1.4.0-rc.1 → 1.4.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/dist/crash-monitor.d.ts +7 -0
- package/dist/crash-monitor.d.ts.map +1 -1
- package/dist/crash-monitor.js +19 -0
- package/dist/diagnostics/derivers.d.ts +24 -0
- package/dist/diagnostics/derivers.d.ts.map +1 -0
- package/dist/diagnostics/derivers.js +146 -0
- package/dist/diagnostics/index.d.ts +3 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +2 -0
- package/dist/diagnostics/report.d.ts +7 -0
- package/dist/diagnostics/report.d.ts.map +1 -0
- package/dist/diagnostics/report.js +84 -0
- package/dist/environment-reset.d.ts +51 -0
- package/dist/environment-reset.d.ts.map +1 -0
- package/dist/environment-reset.js +83 -0
- package/dist/execute-run.d.ts.map +1 -1
- package/dist/execute-run.js +121 -69
- package/dist/format-harness-error.d.ts +5 -0
- package/dist/format-harness-error.d.ts.map +1 -0
- package/dist/format-harness-error.js +43 -0
- package/dist/harness-session.d.ts +26 -1
- package/dist/harness-session.d.ts.map +1 -1
- package/dist/harness-session.js +260 -87
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +21 -4
- package/package.json +8 -7
- package/src/crash-monitor.ts +28 -0
- package/src/diagnostics/derivers.ts +170 -0
- package/src/diagnostics/index.ts +2 -0
- package/src/diagnostics/report.ts +124 -0
- package/src/environment-reset.ts +138 -0
- package/src/execute-run.ts +136 -77
- package/src/format-harness-error.ts +73 -0
- package/src/harness-session.ts +369 -131
- package/src/run.ts +23 -4
- package/tsconfig.json +3 -0
- package/tsconfig.lib.json +3 -0
- package/dist/__tests__/bridge.test.d.ts +0 -2
- package/dist/__tests__/bridge.test.d.ts.map +0 -1
- package/dist/__tests__/bridge.test.js +0 -163
- package/dist/__tests__/client-log-handler.test.d.ts +0 -2
- package/dist/__tests__/client-log-handler.test.d.ts.map +0 -1
- package/dist/__tests__/client-log-handler.test.js +0 -306
- package/dist/__tests__/crash-monitor.test.d.ts +0 -2
- package/dist/__tests__/crash-monitor.test.d.ts.map +0 -1
- package/dist/__tests__/crash-monitor.test.js +0 -166
- package/dist/__tests__/crash-supervisor.test.d.ts +0 -2
- package/dist/__tests__/crash-supervisor.test.d.ts.map +0 -1
- package/dist/__tests__/crash-supervisor.test.js +0 -151
- package/dist/__tests__/errors.test.d.ts +0 -2
- package/dist/__tests__/errors.test.d.ts.map +0 -1
- package/dist/__tests__/errors.test.js +0 -98
- package/dist/__tests__/execute-run.test.d.ts +0 -2
- package/dist/__tests__/execute-run.test.d.ts.map +0 -1
- package/dist/__tests__/execute-run.test.js +0 -393
- package/dist/__tests__/fixtures/mock-platform-runner.d.ts +0 -7
- package/dist/__tests__/fixtures/mock-platform-runner.d.ts.map +0 -1
- package/dist/__tests__/fixtures/mock-platform-runner.js +0 -6
- package/dist/__tests__/harness-cache.test.d.ts +0 -2
- package/dist/__tests__/harness-cache.test.d.ts.map +0 -1
- package/dist/__tests__/harness-cache.test.js +0 -51
- package/dist/__tests__/harness-session.test.d.ts +0 -2
- package/dist/__tests__/harness-session.test.d.ts.map +0 -1
- package/dist/__tests__/harness-session.test.js +0 -74
- package/dist/__tests__/harness.test.d.ts +0 -2
- package/dist/__tests__/harness.test.d.ts.map +0 -1
- package/dist/__tests__/harness.test.js +0 -636
- package/dist/__tests__/hook-queue.test.d.ts +0 -2
- package/dist/__tests__/hook-queue.test.d.ts.map +0 -1
- package/dist/__tests__/hook-queue.test.js +0 -56
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -148
- package/dist/__tests__/metro-port.test.d.ts +0 -2
- package/dist/__tests__/metro-port.test.d.ts.map +0 -1
- package/dist/__tests__/metro-port.test.js +0 -52
- package/dist/__tests__/resource-lock.test.d.ts +0 -2
- package/dist/__tests__/resource-lock.test.d.ts.map +0 -1
- package/dist/__tests__/resource-lock.test.js +0 -138
- package/dist/__tests__/test-file-platform-filter.test.d.ts +0 -2
- package/dist/__tests__/test-file-platform-filter.test.d.ts.map +0 -1
- package/dist/__tests__/test-file-platform-filter.test.js +0 -47
- 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/tsconfig.lib.tsbuildinfo +0 -1
- package/src/__tests__/bridge.test.ts +0 -219
- package/src/__tests__/client-log-handler.test.ts +0 -364
- package/src/__tests__/crash-monitor.test.ts +0 -239
- package/src/__tests__/errors.test.ts +0 -157
- package/src/__tests__/execute-run.test.ts +0 -526
- package/src/__tests__/harness-session.test.ts +0 -93
- package/src/__tests__/hook-queue.test.ts +0 -77
- package/src/__tests__/index.test.ts +0 -219
- package/src/__tests__/metro-port.test.ts +0 -61
- package/src/__tests__/resource-lock.test.ts +0 -179
- package/src/__tests__/test-file-platform-filter.test.ts +0 -83
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { createCrashMonitor, CrashWatchCancelledError, } from '../crash-monitor.js';
|
|
4
|
-
import { NativeCrashError, RuntimeDisconnectError } from '../errors.js';
|
|
5
|
-
const noop = () => undefined;
|
|
6
|
-
const waitForClassification = () => new Promise((resolve) => setTimeout(resolve, 1600));
|
|
7
|
-
const createAppSessionMock = (initialState = { status: 'running' }, logs = [], getCrashDetails) => {
|
|
8
|
-
let state = initialState;
|
|
9
|
-
let listener = null;
|
|
10
|
-
const session = {
|
|
11
|
-
dispose: vi.fn(async () => undefined),
|
|
12
|
-
getState: vi.fn(async () => state),
|
|
13
|
-
getLogs: vi.fn(() => logs),
|
|
14
|
-
addListener: vi.fn((l) => {
|
|
15
|
-
listener = l;
|
|
16
|
-
}),
|
|
17
|
-
removeListener: vi.fn((l) => {
|
|
18
|
-
if (listener === l)
|
|
19
|
-
listener = null;
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
if (getCrashDetails) {
|
|
23
|
-
session.getCrashDetails = getCrashDetails;
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
session,
|
|
27
|
-
setState: (nextState) => {
|
|
28
|
-
state = nextState;
|
|
29
|
-
},
|
|
30
|
-
emit: (event) => listener?.(event),
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
describe('createCrashMonitor', () => {
|
|
34
|
-
it('starts not alive and becomes alive when an app session is attached', () => {
|
|
35
|
-
const cm = createCrashMonitor();
|
|
36
|
-
const { session } = createAppSessionMock();
|
|
37
|
-
expect(cm.isAlive()).toBe(false);
|
|
38
|
-
cm.setAppSession(session);
|
|
39
|
-
expect(cm.isAlive()).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
it('rejects a watch with NativeCrashError when the app session exits', async () => {
|
|
42
|
-
const { session, emit } = createAppSessionMock({
|
|
43
|
-
status: 'exited',
|
|
44
|
-
occurredAt: Date.now(),
|
|
45
|
-
reason: 'observed-exit',
|
|
46
|
-
});
|
|
47
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
48
|
-
const watch = cm.watch('/test/example.ts', 'execution');
|
|
49
|
-
watch.promise.catch(noop);
|
|
50
|
-
emit({ type: 'app_exited' });
|
|
51
|
-
const error = await watch.promise.catch((err) => err);
|
|
52
|
-
expect(error).toBeInstanceOf(NativeCrashError);
|
|
53
|
-
expect(error.testFilePath).toBe('/test/example.ts');
|
|
54
|
-
expect(error.details.phase).toBe('execution');
|
|
55
|
-
expect(cm.isAlive()).toBe(false);
|
|
56
|
-
});
|
|
57
|
-
it('classifies bridge disconnect plus exited app as NativeCrashError', async () => {
|
|
58
|
-
const { session, setState } = createAppSessionMock();
|
|
59
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
60
|
-
const watch = cm.watch('test.ts', 'execution');
|
|
61
|
-
watch.promise.catch(noop);
|
|
62
|
-
cm.handleBridgeDisconnect();
|
|
63
|
-
setState({
|
|
64
|
-
status: 'exited',
|
|
65
|
-
occurredAt: Date.now(),
|
|
66
|
-
reason: 'process-gone',
|
|
67
|
-
});
|
|
68
|
-
await expect(watch.promise).rejects.toBeInstanceOf(NativeCrashError);
|
|
69
|
-
});
|
|
70
|
-
it('classifies bridge disconnect plus running app as RuntimeDisconnectError', async () => {
|
|
71
|
-
const { session } = createAppSessionMock({ status: 'running' });
|
|
72
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
73
|
-
const watch = cm.watch('test.ts', 'execution');
|
|
74
|
-
watch.promise.catch(noop);
|
|
75
|
-
cm.handleBridgeDisconnect();
|
|
76
|
-
await expect(watch.promise).rejects.toBeInstanceOf(RuntimeDisconnectError);
|
|
77
|
-
});
|
|
78
|
-
it('attaches matching session log evidence to native crash details', async () => {
|
|
79
|
-
const occurredAt = Date.now();
|
|
80
|
-
const logs = [
|
|
81
|
-
{ line: 'ordinary app log', occurredAt },
|
|
82
|
-
{ line: 'MyApp[123] fatal error: boom', occurredAt },
|
|
83
|
-
];
|
|
84
|
-
const { session, setState } = createAppSessionMock({ status: 'running' }, logs);
|
|
85
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
86
|
-
const watch = cm.watch('test.ts', 'execution');
|
|
87
|
-
watch.promise.catch(noop);
|
|
88
|
-
cm.handleBridgeDisconnect();
|
|
89
|
-
setState({ status: 'exited', occurredAt, reason: 'process-gone' });
|
|
90
|
-
const error = await watch.promise.catch((err) => err);
|
|
91
|
-
expect(error).toBeInstanceOf(NativeCrashError);
|
|
92
|
-
expect(error.details.rawLines).toEqual(['MyApp[123] fatal error: boom']);
|
|
93
|
-
});
|
|
94
|
-
it('asks the app session to extract native crash details for the current test', async () => {
|
|
95
|
-
const occurredAt = Date.now();
|
|
96
|
-
const getCrashDetails = vi.fn(async () => ({
|
|
97
|
-
artifactType: 'logcat',
|
|
98
|
-
artifactPath: '/tmp/.harness/crash-reports/crash-logcat.txt',
|
|
99
|
-
processName: 'com.harnessplayground',
|
|
100
|
-
pid: 7777,
|
|
101
|
-
}));
|
|
102
|
-
const { session, setState } = createAppSessionMock({ status: 'running' }, [], getCrashDetails);
|
|
103
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
104
|
-
const watch = cm.watch('/test/example.ts', 'execution');
|
|
105
|
-
watch.promise.catch(noop);
|
|
106
|
-
cm.handleBridgeDisconnect();
|
|
107
|
-
setState({
|
|
108
|
-
status: 'exited',
|
|
109
|
-
occurredAt,
|
|
110
|
-
pid: 7777,
|
|
111
|
-
reason: 'process-gone',
|
|
112
|
-
});
|
|
113
|
-
const error = await watch.promise.catch((err) => err);
|
|
114
|
-
expect(getCrashDetails).toHaveBeenCalledWith({
|
|
115
|
-
occurredAt: expect.any(Number),
|
|
116
|
-
pid: 7777,
|
|
117
|
-
processName: undefined,
|
|
118
|
-
testFilePath: '/test/example.ts',
|
|
119
|
-
});
|
|
120
|
-
expect(error.details.artifactPath).toBe('/tmp/.harness/crash-reports/crash-logcat.txt');
|
|
121
|
-
expect(error.message).toContain(`Harness extracted the crash log: ${path.relative(process.cwd(), '/tmp/.harness/crash-reports/crash-logcat.txt')}`);
|
|
122
|
-
});
|
|
123
|
-
it('falls back to log details when native crash extraction fails', async () => {
|
|
124
|
-
const occurredAt = Date.now();
|
|
125
|
-
const getCrashDetails = vi.fn(async () => {
|
|
126
|
-
throw new Error('copy failed');
|
|
127
|
-
});
|
|
128
|
-
const { session, setState } = createAppSessionMock({ status: 'running' }, [{ line: 'MyApp[123] fatal error: boom', occurredAt }], getCrashDetails);
|
|
129
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
130
|
-
const watch = cm.watch('/test/example.ts', 'execution');
|
|
131
|
-
watch.promise.catch(noop);
|
|
132
|
-
cm.handleBridgeDisconnect();
|
|
133
|
-
setState({ status: 'exited', occurredAt, reason: 'process-gone' });
|
|
134
|
-
const error = await watch.promise.catch((err) => err);
|
|
135
|
-
expect(error.details.rawLines).toEqual(['MyApp[123] fatal error: boom']);
|
|
136
|
-
expect(error.message).toContain("Harness couldn't extract the crash log.");
|
|
137
|
-
});
|
|
138
|
-
it('settles the promise with CrashWatchCancelledError on cancel()', async () => {
|
|
139
|
-
const cm = createCrashMonitor();
|
|
140
|
-
const watch = cm.watch('test.ts', 'execution');
|
|
141
|
-
watch.cancel();
|
|
142
|
-
await expect(watch.promise).rejects.toBeInstanceOf(CrashWatchCancelledError);
|
|
143
|
-
});
|
|
144
|
-
it('ignores session events while stopped', async () => {
|
|
145
|
-
const { session, emit } = createAppSessionMock({
|
|
146
|
-
status: 'exited',
|
|
147
|
-
occurredAt: Date.now(),
|
|
148
|
-
});
|
|
149
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
150
|
-
await cm.stop();
|
|
151
|
-
const watch = cm.watch('test.ts', 'execution');
|
|
152
|
-
const settled = vi.fn();
|
|
153
|
-
watch.promise.then(settled, settled);
|
|
154
|
-
emit({ type: 'app_exited' });
|
|
155
|
-
await waitForClassification();
|
|
156
|
-
expect(settled).not.toHaveBeenCalled();
|
|
157
|
-
watch.cancel();
|
|
158
|
-
});
|
|
159
|
-
it('removes the app session listener on dispose', async () => {
|
|
160
|
-
const { session } = createAppSessionMock();
|
|
161
|
-
const cm = createCrashMonitor({ appSession: session });
|
|
162
|
-
await cm.dispose();
|
|
163
|
-
expect(session.removeListener).toHaveBeenCalledOnce();
|
|
164
|
-
expect(cm.isAlive()).toBe(false);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crash-supervisor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/crash-supervisor.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { createCrashSupervisor } from '../crash-supervisor.js';
|
|
3
|
-
const createMockAppMonitor = (options) => {
|
|
4
|
-
const listeners = new Set();
|
|
5
|
-
const noop = async () => undefined;
|
|
6
|
-
const appMonitor = {
|
|
7
|
-
start: noop,
|
|
8
|
-
stop: noop,
|
|
9
|
-
dispose: noop,
|
|
10
|
-
addListener: (listener) => {
|
|
11
|
-
listeners.add(listener);
|
|
12
|
-
},
|
|
13
|
-
removeListener: (listener) => {
|
|
14
|
-
listeners.delete(listener);
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
if (options?.getCrashDetails) {
|
|
18
|
-
appMonitor.getCrashDetails = options.getCrashDetails;
|
|
19
|
-
}
|
|
20
|
-
const emit = (event) => {
|
|
21
|
-
for (const listener of listeners) {
|
|
22
|
-
listener(event);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
return {
|
|
26
|
-
appMonitor,
|
|
27
|
-
emit,
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
const createPlatformRunner = ({ isAppRunning, getCrashDetails, }) => ({
|
|
31
|
-
startApp: async () => undefined,
|
|
32
|
-
restartApp: async () => undefined,
|
|
33
|
-
stopApp: async () => undefined,
|
|
34
|
-
dispose: async () => undefined,
|
|
35
|
-
isAppRunning,
|
|
36
|
-
createAppMonitor: () => {
|
|
37
|
-
throw new Error('Not used in unit tests');
|
|
38
|
-
},
|
|
39
|
-
getCrashDetails,
|
|
40
|
-
});
|
|
41
|
-
describe('crash-supervisor', () => {
|
|
42
|
-
it('rejects the active test when the app exits during launch', async () => {
|
|
43
|
-
const monitor = createMockAppMonitor();
|
|
44
|
-
const supervisor = createCrashSupervisor({
|
|
45
|
-
appMonitor: monitor.appMonitor,
|
|
46
|
-
platformRunner: createPlatformRunner({
|
|
47
|
-
isAppRunning: vi.fn().mockResolvedValue(false),
|
|
48
|
-
}),
|
|
49
|
-
});
|
|
50
|
-
supervisor.beginLaunch('/tmp/startup.harness.ts');
|
|
51
|
-
const crashPromise = supervisor.waitForCrash('/tmp/startup.harness.ts');
|
|
52
|
-
const expectation = expect(crashPromise).rejects.toMatchObject({
|
|
53
|
-
name: 'NativeCrashError',
|
|
54
|
-
phase: 'startup',
|
|
55
|
-
details: {
|
|
56
|
-
signal: 'SIGSEGV',
|
|
57
|
-
processName: 'com.harnessplayground',
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
monitor.emit({
|
|
61
|
-
type: 'app_exited',
|
|
62
|
-
source: 'logs',
|
|
63
|
-
crashDetails: {
|
|
64
|
-
source: 'logs',
|
|
65
|
-
signal: 'SIGSEGV',
|
|
66
|
-
processName: 'com.harnessplayground',
|
|
67
|
-
rawLines: ['Fatal signal 11 (SIGSEGV)'],
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
await expectation;
|
|
71
|
-
await supervisor.dispose();
|
|
72
|
-
});
|
|
73
|
-
it('treats polling exit events as immediately confirmed crashes', async () => {
|
|
74
|
-
const monitor = createMockAppMonitor();
|
|
75
|
-
const isAppRunning = vi.fn().mockResolvedValue(true);
|
|
76
|
-
const supervisor = createCrashSupervisor({
|
|
77
|
-
appMonitor: monitor.appMonitor,
|
|
78
|
-
platformRunner: createPlatformRunner({
|
|
79
|
-
isAppRunning,
|
|
80
|
-
}),
|
|
81
|
-
});
|
|
82
|
-
supervisor.beginLaunch('/tmp/polling-exit.harness.ts');
|
|
83
|
-
const crashPromise = supervisor.waitForCrash('/tmp/polling-exit.harness.ts');
|
|
84
|
-
monitor.emit({ type: 'app_exited', source: 'polling' });
|
|
85
|
-
await expect(crashPromise).rejects.toMatchObject({
|
|
86
|
-
name: 'NativeCrashError',
|
|
87
|
-
phase: 'startup',
|
|
88
|
-
});
|
|
89
|
-
expect(isAppRunning).not.toHaveBeenCalled();
|
|
90
|
-
await supervisor.dispose();
|
|
91
|
-
});
|
|
92
|
-
it('does not reject when monitoring is stopped', async () => {
|
|
93
|
-
const monitor = createMockAppMonitor();
|
|
94
|
-
const supervisor = createCrashSupervisor({
|
|
95
|
-
appMonitor: monitor.appMonitor,
|
|
96
|
-
platformRunner: createPlatformRunner({
|
|
97
|
-
isAppRunning: vi.fn().mockResolvedValue(false),
|
|
98
|
-
}),
|
|
99
|
-
});
|
|
100
|
-
supervisor.beginTestRun('/tmp/restart.harness.ts');
|
|
101
|
-
await supervisor.stop();
|
|
102
|
-
const reject = vi.fn();
|
|
103
|
-
void supervisor.waitForCrash('/tmp/restart.harness.ts').catch(reject);
|
|
104
|
-
monitor.emit({ type: 'app_exited', source: 'polling' });
|
|
105
|
-
await Promise.resolve();
|
|
106
|
-
expect(reject).not.toHaveBeenCalled();
|
|
107
|
-
await supervisor.dispose();
|
|
108
|
-
});
|
|
109
|
-
it('prefers crash details from the started app monitor over the runner', async () => {
|
|
110
|
-
const monitorGetCrashDetails = vi.fn().mockResolvedValue({
|
|
111
|
-
source: 'logs',
|
|
112
|
-
summary: 'full crash block',
|
|
113
|
-
rawLines: ['full crash block'],
|
|
114
|
-
});
|
|
115
|
-
const runnerGetCrashDetails = vi.fn().mockResolvedValue({
|
|
116
|
-
source: 'logs',
|
|
117
|
-
summary: 'runner details',
|
|
118
|
-
rawLines: ['runner details'],
|
|
119
|
-
});
|
|
120
|
-
const monitor = createMockAppMonitor({
|
|
121
|
-
getCrashDetails: monitorGetCrashDetails,
|
|
122
|
-
});
|
|
123
|
-
const supervisor = createCrashSupervisor({
|
|
124
|
-
appMonitor: monitor.appMonitor,
|
|
125
|
-
platformRunner: createPlatformRunner({
|
|
126
|
-
isAppRunning: vi.fn().mockResolvedValue(false),
|
|
127
|
-
getCrashDetails: runnerGetCrashDetails,
|
|
128
|
-
}),
|
|
129
|
-
});
|
|
130
|
-
supervisor.beginTestRun('/tmp/monitor-details.harness.ts');
|
|
131
|
-
const crashPromise = supervisor.waitForCrash('/tmp/monitor-details.harness.ts');
|
|
132
|
-
monitor.emit({
|
|
133
|
-
type: 'possible_crash',
|
|
134
|
-
source: 'logs',
|
|
135
|
-
crashDetails: {
|
|
136
|
-
source: 'logs',
|
|
137
|
-
processName: 'com.harnessplayground',
|
|
138
|
-
pid: 1234,
|
|
139
|
-
rawLines: ['partial line'],
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
await expect(crashPromise).rejects.toMatchObject({
|
|
143
|
-
details: {
|
|
144
|
-
summary: 'full crash block',
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
expect(monitorGetCrashDetails).toHaveBeenCalled();
|
|
148
|
-
expect(runnerGetCrashDetails).not.toHaveBeenCalled();
|
|
149
|
-
await supervisor.dispose();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { AppBridgeDisconnectedError } from '@react-native-harness/bridge/server';
|
|
4
|
-
import { NativeCrashError, PlatformReadyTimeoutError } from '../errors.js';
|
|
5
|
-
describe('PlatformReadyTimeoutError', () => {
|
|
6
|
-
it('includes the configured timeout and config hint', () => {
|
|
7
|
-
expect(new PlatformReadyTimeoutError(300000).message).toBe('The platform did not become ready within 300000ms. Increase "platformReadyTimeout" if your device, simulator, or emulator needs more time to start.');
|
|
8
|
-
});
|
|
9
|
-
});
|
|
10
|
-
describe('NativeCrashError', () => {
|
|
11
|
-
it('reports the extracted crash log path when available', () => {
|
|
12
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
13
|
-
phase: 'execution',
|
|
14
|
-
artifactPath: path.join(process.cwd(), '.harness', 'crash-reports', 'crash.ips'),
|
|
15
|
-
});
|
|
16
|
-
expect(error.message).toContain(`Harness extracted the crash log: ${path.join('.harness', 'crash-reports', 'crash.ips')}`);
|
|
17
|
-
});
|
|
18
|
-
it('lists enrichment artifact paths when available', () => {
|
|
19
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
20
|
-
phase: 'execution',
|
|
21
|
-
artifactPath: path.join(process.cwd(), '.harness', 'crash-reports', 'logcat.txt'),
|
|
22
|
-
enrichmentArtifacts: [
|
|
23
|
-
{
|
|
24
|
-
artifactType: 'dropbox-native-crash',
|
|
25
|
-
artifactPath: path.join(process.cwd(), '.harness', 'crash-reports', 'dropbox-native-crash.txt'),
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
});
|
|
29
|
-
expect(error.message).toContain('Additional crash artifacts:');
|
|
30
|
-
expect(error.message).toContain(path.join('.harness', 'crash-reports', 'dropbox-native-crash.txt'));
|
|
31
|
-
});
|
|
32
|
-
it('reports crash log extraction failure when no artifact was pulled', () => {
|
|
33
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
34
|
-
phase: 'execution',
|
|
35
|
-
});
|
|
36
|
-
expect(error.message).toContain("Harness couldn't extract the crash log.");
|
|
37
|
-
});
|
|
38
|
-
it('formats the extracted stack trace in the error message', () => {
|
|
39
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
40
|
-
phase: 'execution',
|
|
41
|
-
processName: 'HarnessPlayground',
|
|
42
|
-
pid: 1234,
|
|
43
|
-
signal: 'SIGTRAP',
|
|
44
|
-
exceptionType: 'EXC_BREAKPOINT',
|
|
45
|
-
stackTrace: [
|
|
46
|
-
'0 AppDelegate.crashIfRequested() (AppDelegate.swift:31)',
|
|
47
|
-
'1 AppDelegate.application(_:didFinishLaunchingWithOptions:) (AppDelegate.swift:56)',
|
|
48
|
-
],
|
|
49
|
-
});
|
|
50
|
-
expect(error.message).toContain(' 0 AppDelegate.crashIfRequested() (AppDelegate.swift:31)');
|
|
51
|
-
expect(error.message).toContain(' 1 AppDelegate.application(_:didFinishLaunchingWithOptions:) (AppDelegate.swift:56)');
|
|
52
|
-
});
|
|
53
|
-
it('omits single-line iOS summaries from the rendered error message', () => {
|
|
54
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
55
|
-
phase: 'startup',
|
|
56
|
-
artifactType: 'ios-crash-report',
|
|
57
|
-
summary: '2026-03-12 13:46:18.154 Df HarnessPlayground[18007:65e716] [com.apple.dt.xctest:Default] notify_get_state check indicated test daemon not ready.',
|
|
58
|
-
processName: 'HarnessPlayground',
|
|
59
|
-
pid: 18007,
|
|
60
|
-
signal: 'SIGABRT',
|
|
61
|
-
exceptionType: 'EXC_CRASH',
|
|
62
|
-
});
|
|
63
|
-
expect(error.message).not.toContain('notify_get_state check indicated test daemon not ready');
|
|
64
|
-
expect(error.message).toContain('Signal: SIGABRT');
|
|
65
|
-
expect(error.message).toContain('Exception: EXC_CRASH');
|
|
66
|
-
expect(error.message).toContain('Process: HarnessPlayground (pid 18007)');
|
|
67
|
-
});
|
|
68
|
-
it('does not duplicate stack frames when the summary already contains a crash block', () => {
|
|
69
|
-
const frame = '03-13 07:59:44.943 20373 20373 E AndroidRuntime: \tat com.harnessplayground.MainActivity.onCreate(MainActivity.kt:38)';
|
|
70
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
71
|
-
phase: 'startup',
|
|
72
|
-
summary: [
|
|
73
|
-
'--------- beginning of crash',
|
|
74
|
-
'03-13 07:59:44.943 20373 20373 E AndroidRuntime: FATAL EXCEPTION: main',
|
|
75
|
-
frame,
|
|
76
|
-
].join('\n'),
|
|
77
|
-
stackTrace: [frame],
|
|
78
|
-
});
|
|
79
|
-
expect(error.message.match(/MainActivity\.onCreate\(MainActivity\.kt:38\)/g)).toHaveLength(1);
|
|
80
|
-
});
|
|
81
|
-
it('collapses the native crash stack header so jest does not reprint multiline messages', () => {
|
|
82
|
-
const error = new NativeCrashError('/tmp/crash.harness.ts', {
|
|
83
|
-
phase: 'startup',
|
|
84
|
-
summary: ['line one', 'line two'].join('\n'),
|
|
85
|
-
});
|
|
86
|
-
expect(error.stack).toBe('NativeCrashError: The native app crashed while preparing to run this test file.');
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
describe('AppBridgeDisconnectedError', () => {
|
|
90
|
-
it('explains likely causes without exposing an internal stack', () => {
|
|
91
|
-
const error = new AppBridgeDisconnectedError('app-disconnected');
|
|
92
|
-
expect(error.message).toBe('The app bridge disconnected during test execution. This can happen if the app was killed, crashed, reloaded, or restarted while the test file was running.');
|
|
93
|
-
expect(error.stack).toBe(`AppBridgeDisconnectedError: ${error.message}`);
|
|
94
|
-
});
|
|
95
|
-
it('uses a reconnection-specific message when a newer app connection replaces the old one', () => {
|
|
96
|
-
expect(new AppBridgeDisconnectedError('app-replaced').message).toBe('The app bridge was replaced by a newer app connection. This can happen when the app reloads, restarts, or reconnects while a test file is still running.');
|
|
97
|
-
});
|
|
98
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"execute-run.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/execute-run.test.ts"],"names":[],"mappings":""}
|