@react-native-harness/jest 1.5.0 → 1.6.0
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-supervisor.d.ts +21 -0
- package/dist/crash-supervisor.d.ts.map +1 -0
- package/dist/crash-supervisor.js +210 -0
- package/dist/event-mapper.d.ts +16 -0
- package/dist/event-mapper.d.ts.map +1 -0
- package/dist/event-mapper.js +120 -0
- package/dist/global-setup.d.ts +3 -0
- package/dist/global-setup.d.ts.map +1 -0
- package/dist/global-setup.js +60 -0
- package/dist/global-teardown.d.ts +3 -0
- package/dist/global-teardown.d.ts.map +1 -0
- package/dist/global-teardown.js +11 -0
- package/dist/harness-reporter.d.ts +8 -0
- package/dist/harness-reporter.d.ts.map +1 -0
- package/dist/harness-reporter.js +12 -0
- package/dist/harness-session.d.ts.map +1 -1
- package/dist/harness-session.js +5 -2
- package/dist/harness.d.ts +47 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +619 -0
- package/dist/jest-options.d.ts +2 -0
- package/dist/jest-options.d.ts.map +1 -0
- package/dist/jest-options.js +1 -0
- package/dist/setup.d.ts +3 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +80 -0
- package/dist/teardown.d.ts +3 -0
- package/dist/teardown.d.ts.map +1 -0
- package/dist/teardown.js +10 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +8 -8
- package/src/harness-session.ts +5 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type AppMonitor, type HarnessPlatformRunner } from '@react-native-harness/platforms';
|
|
2
|
+
export type CrashSupervisorState = 'idle' | 'launching' | 'ready' | 'running' | 'disposing';
|
|
3
|
+
export type CrashSupervisor = {
|
|
4
|
+
setActiveTestFile: (testFilePath: string | null) => void;
|
|
5
|
+
beginLaunch: (testFilePath: string) => void;
|
|
6
|
+
markReady: () => void;
|
|
7
|
+
beginTestRun: (testFilePath: string) => void;
|
|
8
|
+
stop: () => Promise<void>;
|
|
9
|
+
start: () => Promise<void>;
|
|
10
|
+
waitForCrash: (testFilePath: string) => Promise<never>;
|
|
11
|
+
isReady: () => boolean;
|
|
12
|
+
cancelCrashWaiters: () => void;
|
|
13
|
+
reset: () => void;
|
|
14
|
+
dispose: () => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export type CrashSupervisorOptions = {
|
|
17
|
+
appMonitor: AppMonitor;
|
|
18
|
+
platformRunner: HarnessPlatformRunner;
|
|
19
|
+
};
|
|
20
|
+
export declare const createCrashSupervisor: ({ appMonitor, platformRunner, }: CrashSupervisorOptions) => CrashSupervisor;
|
|
21
|
+
//# sourceMappingURL=crash-supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-supervisor.d.ts","sourceRoot":"","sources":["../src/crash-supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAIf,KAAK,qBAAqB,EAC3B,MAAM,iCAAiC,CAAC;AAUzC,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,WAAW,GACX,OAAO,GACP,SAAS,GACT,WAAW,CAAC;AAEhB,MAAM,MAAM,eAAe,GAAG;IAC5B,iBAAiB,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzD,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,EAAE,qBAAqB,CAAC;CACvC,CAAC;AAmCF,eAAO,MAAM,qBAAqB,GAAI,iCAGnC,sBAAsB,KAAG,eAkP3B,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { NativeCrashError, } from './errors.js';
|
|
2
|
+
import { logger } from '@react-native-harness/tools';
|
|
3
|
+
const crashLogger = logger.child('crash');
|
|
4
|
+
const getCrashPhase = (state) => state === 'running' ? 'execution' : 'startup';
|
|
5
|
+
const mergeCrashDetails = (phase, initialDetails, enrichedDetails, fallbackSummary) => ({
|
|
6
|
+
phase,
|
|
7
|
+
source: enrichedDetails?.source ?? initialDetails?.source,
|
|
8
|
+
summary: enrichedDetails?.summary ?? initialDetails?.summary ?? fallbackSummary,
|
|
9
|
+
signal: enrichedDetails?.signal ?? initialDetails?.signal,
|
|
10
|
+
exceptionType: enrichedDetails?.exceptionType ?? initialDetails?.exceptionType,
|
|
11
|
+
processName: enrichedDetails?.processName ?? initialDetails?.processName,
|
|
12
|
+
pid: enrichedDetails?.pid ?? initialDetails?.pid,
|
|
13
|
+
stackTrace: enrichedDetails?.stackTrace ?? initialDetails?.stackTrace,
|
|
14
|
+
rawLines: enrichedDetails?.rawLines ?? initialDetails?.rawLines,
|
|
15
|
+
artifactType: enrichedDetails?.artifactType ?? initialDetails?.artifactType,
|
|
16
|
+
artifactPath: enrichedDetails?.artifactPath ?? initialDetails?.artifactPath,
|
|
17
|
+
});
|
|
18
|
+
export const createCrashSupervisor = ({ appMonitor, platformRunner, }) => {
|
|
19
|
+
let state = 'idle';
|
|
20
|
+
let activeTestFilePath = null;
|
|
21
|
+
let crashRejectors = new Set();
|
|
22
|
+
let disposed = false;
|
|
23
|
+
let monitoring = true;
|
|
24
|
+
let isResolvingCrash = false;
|
|
25
|
+
const getCrashDetailsProvider = () => {
|
|
26
|
+
if ('getCrashDetails' in appMonitor) {
|
|
27
|
+
return appMonitor;
|
|
28
|
+
}
|
|
29
|
+
if (platformRunner.getCrashDetails) {
|
|
30
|
+
return platformRunner;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
};
|
|
34
|
+
const rejectCrashWaiters = (testFilePath, details) => {
|
|
35
|
+
const error = new NativeCrashError(testFilePath, details);
|
|
36
|
+
for (const reject of crashRejectors) {
|
|
37
|
+
reject(error);
|
|
38
|
+
}
|
|
39
|
+
crashRejectors = new Set();
|
|
40
|
+
};
|
|
41
|
+
const handleCrash = async (reason, details) => {
|
|
42
|
+
if (isResolvingCrash ||
|
|
43
|
+
(state !== 'launching' && state !== 'running' && state !== 'ready')) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!activeTestFilePath) {
|
|
47
|
+
crashLogger.debug('ignoring crash signal without active test: %s', reason);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
isResolvingCrash = true;
|
|
51
|
+
crashLogger.debug('native crash detected during %s (state=%s reason=%s)', activeTestFilePath, state, reason || '(none)');
|
|
52
|
+
for (const line of details?.rawLines ?? []) {
|
|
53
|
+
crashLogger.debug('%s', line);
|
|
54
|
+
}
|
|
55
|
+
const phase = getCrashPhase(state);
|
|
56
|
+
const testFilePath = activeTestFilePath;
|
|
57
|
+
state = 'idle';
|
|
58
|
+
try {
|
|
59
|
+
const enrichedDetails = await getCrashDetailsProvider()?.getCrashDetails?.({
|
|
60
|
+
processName: details?.processName,
|
|
61
|
+
pid: details?.pid,
|
|
62
|
+
occurredAt: Date.now(),
|
|
63
|
+
});
|
|
64
|
+
const mergedDetails = mergeCrashDetails(phase, details, enrichedDetails, reason);
|
|
65
|
+
crashLogger.debug('crash details: %o', {
|
|
66
|
+
phase: mergedDetails.phase,
|
|
67
|
+
source: mergedDetails.source,
|
|
68
|
+
summary: mergedDetails.summary,
|
|
69
|
+
signal: mergedDetails.signal,
|
|
70
|
+
exceptionType: mergedDetails.exceptionType,
|
|
71
|
+
processName: mergedDetails.processName,
|
|
72
|
+
pid: mergedDetails.pid,
|
|
73
|
+
});
|
|
74
|
+
rejectCrashWaiters(testFilePath, mergedDetails);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
isResolvingCrash = false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const confirmCrash = async (reason, details) => {
|
|
81
|
+
if (disposed || !monitoring || state === 'disposing') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const isRunning = await platformRunner.isAppRunning();
|
|
86
|
+
if (!isRunning) {
|
|
87
|
+
void handleCrash(reason, details);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
crashLogger.debug('crash confirmation failed', error);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const appMonitorListener = (event) => {
|
|
95
|
+
if (disposed || !monitoring) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (event.type === 'app_started') {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (event.type === 'app_exited') {
|
|
102
|
+
const details = {
|
|
103
|
+
source: event.crashDetails?.source ?? event.source,
|
|
104
|
+
summary: event.crashDetails?.summary,
|
|
105
|
+
signal: event.crashDetails?.signal,
|
|
106
|
+
exceptionType: event.crashDetails?.exceptionType,
|
|
107
|
+
processName: event.crashDetails?.processName,
|
|
108
|
+
pid: event.crashDetails?.pid ?? event.pid,
|
|
109
|
+
stackTrace: event.crashDetails?.stackTrace,
|
|
110
|
+
rawLines: event.crashDetails?.rawLines ??
|
|
111
|
+
(event.line ? [event.line] : undefined),
|
|
112
|
+
};
|
|
113
|
+
if (event.isConfirmed ?? event.source === 'polling') {
|
|
114
|
+
void handleCrash('', details);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
void confirmCrash('', details);
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (event.type === 'possible_crash') {
|
|
122
|
+
const details = {
|
|
123
|
+
source: event.crashDetails?.source ?? event.source,
|
|
124
|
+
summary: event.crashDetails?.summary,
|
|
125
|
+
signal: event.crashDetails?.signal,
|
|
126
|
+
exceptionType: event.crashDetails?.exceptionType,
|
|
127
|
+
processName: event.crashDetails?.processName,
|
|
128
|
+
pid: event.crashDetails?.pid ?? event.pid,
|
|
129
|
+
stackTrace: event.crashDetails?.stackTrace,
|
|
130
|
+
rawLines: event.crashDetails?.rawLines ??
|
|
131
|
+
(event.line ? [event.line] : undefined),
|
|
132
|
+
};
|
|
133
|
+
if (event.isConfirmed) {
|
|
134
|
+
void handleCrash(`possible crash signal (${event.source ?? 'unknown'})`, details);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
void confirmCrash(`possible crash signal (${event.source ?? 'unknown'})`, details);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
appMonitor.addListener(appMonitorListener);
|
|
142
|
+
const setActiveTestFile = (testFilePath) => {
|
|
143
|
+
activeTestFilePath = testFilePath;
|
|
144
|
+
};
|
|
145
|
+
const beginLaunch = (testFilePath) => {
|
|
146
|
+
activeTestFilePath = testFilePath;
|
|
147
|
+
state = 'launching';
|
|
148
|
+
};
|
|
149
|
+
const markReady = () => {
|
|
150
|
+
if (state !== 'disposing') {
|
|
151
|
+
state = 'ready';
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const beginTestRun = (testFilePath) => {
|
|
155
|
+
activeTestFilePath = testFilePath;
|
|
156
|
+
state = 'running';
|
|
157
|
+
};
|
|
158
|
+
const stop = async () => {
|
|
159
|
+
monitoring = false;
|
|
160
|
+
await appMonitor.stop();
|
|
161
|
+
};
|
|
162
|
+
const start = async () => {
|
|
163
|
+
monitoring = true;
|
|
164
|
+
await appMonitor.start();
|
|
165
|
+
};
|
|
166
|
+
const waitForCrash = (testFilePath) => new Promise((_, reject) => {
|
|
167
|
+
if (disposed) {
|
|
168
|
+
reject(new NativeCrashError(testFilePath, {
|
|
169
|
+
phase: 'startup',
|
|
170
|
+
source: 'polling',
|
|
171
|
+
summary: 'Crash supervisor disposed while waiting for app startup.',
|
|
172
|
+
}));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
crashRejectors.add(reject);
|
|
176
|
+
});
|
|
177
|
+
const isReady = () => state === 'ready' || state === 'running';
|
|
178
|
+
const cancelCrashWaiters = () => {
|
|
179
|
+
crashRejectors = new Set();
|
|
180
|
+
};
|
|
181
|
+
const reset = () => {
|
|
182
|
+
cancelCrashWaiters();
|
|
183
|
+
isResolvingCrash = false;
|
|
184
|
+
if (state !== 'disposing') {
|
|
185
|
+
state = 'idle';
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const dispose = async () => {
|
|
189
|
+
disposed = true;
|
|
190
|
+
monitoring = false;
|
|
191
|
+
state = 'disposing';
|
|
192
|
+
crashRejectors = new Set();
|
|
193
|
+
isResolvingCrash = false;
|
|
194
|
+
appMonitor.removeListener(appMonitorListener);
|
|
195
|
+
await appMonitor.dispose();
|
|
196
|
+
};
|
|
197
|
+
return {
|
|
198
|
+
setActiveTestFile,
|
|
199
|
+
beginLaunch,
|
|
200
|
+
markReady,
|
|
201
|
+
beginTestRun,
|
|
202
|
+
stop,
|
|
203
|
+
start,
|
|
204
|
+
waitForCrash,
|
|
205
|
+
isReady,
|
|
206
|
+
cancelCrashWaiters,
|
|
207
|
+
reset,
|
|
208
|
+
dispose,
|
|
209
|
+
};
|
|
210
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseReporter } from '@jest/reporters';
|
|
2
|
+
export default class HarnessReporter extends BaseReporter {
|
|
3
|
+
#globalConfig;
|
|
4
|
+
constructor(globalConfig) {
|
|
5
|
+
super();
|
|
6
|
+
this.#globalConfig = globalConfig;
|
|
7
|
+
}
|
|
8
|
+
onRunStart() {
|
|
9
|
+
super.onRunStart();
|
|
10
|
+
this.log(`Selected runner: ${this.#globalConfig.selectedRunner.name}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-session.d.ts","sourceRoot":"","sources":["../src/harness-session.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"harness-session.d.ts","sourceRoot":"","sources":["../src/harness-session.ts"],"names":[],"mappings":"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"}
|
package/dist/harness-session.js
CHANGED
|
@@ -257,6 +257,9 @@ export const createHarnessSession = async (globalConfig, { lockManager = default
|
|
|
257
257
|
preRunMessage.remove(process.stderr);
|
|
258
258
|
const setupStartedAt = Date.now();
|
|
259
259
|
const { harnessConfig, platform, projectRoot, configProjectRoot } = await loadConfig(globalConfig);
|
|
260
|
+
// Metro platform for prewarm and startup detection. Vega apps request
|
|
261
|
+
// "kepler" bundles while the harness platform id stays "vega".
|
|
262
|
+
const bundlePlatform = platform.bundlePlatform ?? platform.platformId;
|
|
260
263
|
applyEnvVars(harnessConfig, globalConfig);
|
|
261
264
|
const diagnostics = createDiagnostics({
|
|
262
265
|
enabled: isDiagnosticsEnabled(harnessConfig),
|
|
@@ -394,7 +397,7 @@ export const createHarnessSession = async (globalConfig, { lockManager = default
|
|
|
394
397
|
const prewarmSpan = diagnostics.start('metro.prewarm');
|
|
395
398
|
instance
|
|
396
399
|
.prewarm({
|
|
397
|
-
platform:
|
|
400
|
+
platform: bundlePlatform,
|
|
398
401
|
signal: sessionController.signal,
|
|
399
402
|
})
|
|
400
403
|
.then((completed) => prewarmSpan.end({ completed }))
|
|
@@ -462,7 +465,7 @@ export const createHarnessSession = async (globalConfig, { lockManager = default
|
|
|
462
465
|
const appReadyBaseOptions = {
|
|
463
466
|
metroInstance,
|
|
464
467
|
bridge,
|
|
465
|
-
platformId:
|
|
468
|
+
platformId: bundlePlatform,
|
|
466
469
|
bundleStartTimeout: runtimeConfig.bundleStartTimeout ?? 60000,
|
|
467
470
|
readyTimeout: runtimeConfig.bridgeTimeout,
|
|
468
471
|
maxAppRestarts: runtimeConfig.maxAppRestarts ?? 2,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BridgeServer } from '@react-native-harness/bridge/server';
|
|
2
|
+
import { HarnessContext, TestExecutionOptions, TestSuiteResult } from '@react-native-harness/bridge';
|
|
3
|
+
import { type AppLaunchOptions, HarnessPlatform, HarnessPlatformRunner } from '@react-native-harness/platforms';
|
|
4
|
+
import { type MetroInstance } from '@react-native-harness/bundler-metro';
|
|
5
|
+
import { type HarnessPluginManager, type HarnessRunStatus, type HarnessRunSummary } from '@react-native-harness/plugins';
|
|
6
|
+
import { Config as HarnessConfig } from '@react-native-harness/config';
|
|
7
|
+
import { type CrashSupervisor } from './crash-supervisor.js';
|
|
8
|
+
export type HarnessRunTestsOptions = Exclude<TestExecutionOptions, 'platform'>;
|
|
9
|
+
export type HarnessRunState = {
|
|
10
|
+
runId: string;
|
|
11
|
+
startTime: number;
|
|
12
|
+
testFiles: string[];
|
|
13
|
+
watchMode: boolean;
|
|
14
|
+
coverageEnabled: boolean;
|
|
15
|
+
summary?: HarnessRunSummary;
|
|
16
|
+
status?: HarnessRunStatus;
|
|
17
|
+
error?: unknown;
|
|
18
|
+
};
|
|
19
|
+
export type Harness = {
|
|
20
|
+
context: HarnessContext;
|
|
21
|
+
config: HarnessConfig;
|
|
22
|
+
runTests: (path: string, options: HarnessRunTestsOptions) => Promise<TestSuiteResult>;
|
|
23
|
+
ensureAppReady: (testFilePath: string) => Promise<void>;
|
|
24
|
+
restart: (testFilePath?: string) => Promise<void>;
|
|
25
|
+
dispose: () => Promise<void>;
|
|
26
|
+
crashSupervisor: CrashSupervisor;
|
|
27
|
+
callHook: HarnessPluginManager<HarnessConfig, HarnessPlatform>['callHook'];
|
|
28
|
+
setRunState: (runState: HarnessRunState | null) => void;
|
|
29
|
+
getRunState: () => HarnessRunState | null;
|
|
30
|
+
};
|
|
31
|
+
export declare const maybeLogMetroCacheReuse: (config: HarnessConfig, platform: HarnessPlatform, projectRoot: string) => void;
|
|
32
|
+
export declare const waitForAppReady: (options: {
|
|
33
|
+
metroInstance: MetroInstance;
|
|
34
|
+
serverBridge: BridgeServer;
|
|
35
|
+
platformInstance: HarnessPlatformRunner;
|
|
36
|
+
platformId: string;
|
|
37
|
+
bundleStartTimeout: number;
|
|
38
|
+
readyTimeout: number;
|
|
39
|
+
maxAppRestarts: number;
|
|
40
|
+
testFilePath: string;
|
|
41
|
+
crashSupervisor: CrashSupervisor;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
appLaunchOptions?: AppLaunchOptions;
|
|
44
|
+
launchApp?: () => Promise<void>;
|
|
45
|
+
}) => Promise<void>;
|
|
46
|
+
export declare const getHarness: (config: HarnessConfig, platform: HarnessPlatform, projectRoot: string) => Promise<Harness>;
|
|
47
|
+
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACb,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAEL,cAAc,EAGd,oBAAoB,EACpB,eAAe,EAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAEL,KAAK,gBAAgB,EACrB,eAAe,EAEf,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAIL,KAAK,aAAa,EAGnB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AAQvC,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAgB/B,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,sBAAsB,KAC5B,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;IACjC,QAAQ,EAAE,oBAAoB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,UAAU,CAAC,CAAC;IAC3E,WAAW,EAAE,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAC;IACxD,WAAW,EAAE,MAAM,eAAe,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,QAAQ,aAAa,EACrB,UAAU,eAAe,EACzB,aAAa,MAAM,KAClB,IAIF,CAAC;AAgDF,eAAO,MAAM,eAAe,GAAU,SAAS;IAC7C,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC,KAAG,OAAO,CAAC,IAAI,CA2Ef,CAAC;AA0mBF,eAAO,MAAM,UAAU,GACrB,QAAQ,aAAa,EACrB,UAAU,eAAe,EACzB,aAAa,MAAM,KAClB,OAAO,CAAC,OAAO,CAYjB,CAAC"}
|