@react-native-harness/jest 1.2.0-rc.1 → 1.3.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.
Files changed (75) hide show
  1. package/dist/__tests__/bridge.test.d.ts +2 -0
  2. package/dist/__tests__/bridge.test.d.ts.map +1 -0
  3. package/dist/__tests__/bridge.test.js +142 -0
  4. package/dist/__tests__/client-log-handler.test.js +116 -72
  5. package/dist/__tests__/crash-monitor.test.d.ts +2 -0
  6. package/dist/__tests__/crash-monitor.test.d.ts.map +1 -0
  7. package/dist/__tests__/crash-monitor.test.js +212 -0
  8. package/dist/__tests__/execute-run.test.d.ts +2 -0
  9. package/dist/__tests__/execute-run.test.d.ts.map +1 -0
  10. package/dist/__tests__/execute-run.test.js +229 -0
  11. package/dist/__tests__/fixtures/mock-platform-runner.d.ts +7 -0
  12. package/dist/__tests__/fixtures/mock-platform-runner.d.ts.map +1 -0
  13. package/dist/__tests__/fixtures/mock-platform-runner.js +6 -0
  14. package/dist/__tests__/harness-session.test.d.ts +2 -0
  15. package/dist/__tests__/harness-session.test.d.ts.map +1 -0
  16. package/dist/__tests__/harness-session.test.js +250 -0
  17. package/dist/__tests__/hook-queue.test.d.ts +2 -0
  18. package/dist/__tests__/hook-queue.test.d.ts.map +1 -0
  19. package/dist/__tests__/hook-queue.test.js +56 -0
  20. package/dist/__tests__/index.test.js +94 -37
  21. package/dist/__tests__/resource-lock.test.js +24 -24
  22. package/dist/client-log-handler.d.ts +10 -11
  23. package/dist/client-log-handler.d.ts.map +1 -1
  24. package/dist/client-log-handler.js +36 -58
  25. package/dist/crash-monitor.d.ts +17 -10
  26. package/dist/crash-monitor.d.ts.map +1 -1
  27. package/dist/crash-monitor.js +164 -63
  28. package/dist/execute-run.d.ts +4 -0
  29. package/dist/execute-run.d.ts.map +1 -0
  30. package/dist/execute-run.js +151 -0
  31. package/dist/harness-session.d.ts +34 -0
  32. package/dist/harness-session.d.ts.map +1 -0
  33. package/dist/harness-session.js +523 -0
  34. package/dist/hook-queue.d.ts +6 -0
  35. package/dist/hook-queue.d.ts.map +1 -0
  36. package/dist/hook-queue.js +18 -0
  37. package/dist/index.d.ts +0 -3
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +12 -230
  40. package/dist/logs.d.ts +1 -0
  41. package/dist/logs.d.ts.map +1 -1
  42. package/dist/logs.js +3 -0
  43. package/dist/resource-lock.d.ts +0 -1
  44. package/dist/resource-lock.d.ts.map +1 -1
  45. package/dist/resource-lock.js +1 -1
  46. package/dist/run.d.ts +2 -2
  47. package/dist/run.d.ts.map +1 -1
  48. package/dist/run.js +3 -3
  49. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  50. package/package.json +7 -8
  51. package/src/__tests__/bridge.test.ts +184 -0
  52. package/src/__tests__/client-log-handler.test.ts +117 -81
  53. package/src/__tests__/crash-monitor.test.ts +288 -0
  54. package/src/__tests__/execute-run.test.ts +325 -0
  55. package/src/__tests__/hook-queue.test.ts +77 -0
  56. package/src/__tests__/index.test.ts +135 -55
  57. package/src/__tests__/resource-lock.test.ts +29 -42
  58. package/src/client-log-handler.ts +48 -64
  59. package/src/crash-monitor.ts +248 -0
  60. package/src/execute-run.ts +199 -0
  61. package/src/harness-session.ts +734 -0
  62. package/src/hook-queue.ts +26 -0
  63. package/src/index.ts +17 -330
  64. package/src/logs.ts +4 -0
  65. package/src/resource-lock.ts +1 -1
  66. package/src/run.ts +5 -5
  67. package/tsconfig.tsbuildinfo +1 -0
  68. package/src/__tests__/crash-supervisor.test.ts +0 -200
  69. package/src/__tests__/harness-cache.test.ts +0 -74
  70. package/src/__tests__/harness.test.ts +0 -923
  71. package/src/crash-supervisor.ts +0 -321
  72. package/src/env.d.ts +0 -9
  73. package/src/harness.ts +0 -870
  74. package/src/setup.ts +0 -127
  75. package/src/teardown.ts +0 -14
@@ -1,321 +0,0 @@
1
- import {
2
- type AppMonitor,
3
- type AppCrashDetails,
4
- type AppMonitorEvent,
5
- type AppMonitorListener,
6
- type HarnessPlatformRunner,
7
- } from '@react-native-harness/platforms';
8
- import {
9
- NativeCrashError,
10
- type NativeCrashDetails,
11
- type NativeCrashPhase,
12
- } from './errors.js';
13
- import { logger } from '@react-native-harness/tools';
14
-
15
- const crashLogger = logger.child('crash');
16
-
17
- export type CrashSupervisorState =
18
- | 'idle'
19
- | 'launching'
20
- | 'ready'
21
- | 'running'
22
- | 'disposing';
23
-
24
- export type CrashSupervisor = {
25
- setActiveTestFile: (testFilePath: string | null) => void;
26
- beginLaunch: (testFilePath: string) => void;
27
- markReady: () => void;
28
- beginTestRun: (testFilePath: string) => void;
29
- stop: () => Promise<void>;
30
- start: () => Promise<void>;
31
- waitForCrash: (testFilePath: string) => Promise<never>;
32
- isReady: () => boolean;
33
- cancelCrashWaiters: () => void;
34
- reset: () => void;
35
- dispose: () => Promise<void>;
36
- };
37
-
38
- export type CrashSupervisorOptions = {
39
- appMonitor: AppMonitor;
40
- platformRunner: HarnessPlatformRunner;
41
- };
42
-
43
- type CrashDetailsProvider = {
44
- getCrashDetails?: (
45
- options: {
46
- processName?: string;
47
- pid?: number;
48
- occurredAt: number;
49
- }
50
- ) => Promise<AppCrashDetails | null>;
51
- };
52
-
53
- const getCrashPhase = (state: CrashSupervisorState): NativeCrashPhase =>
54
- state === 'running' ? 'execution' : 'startup';
55
-
56
- const mergeCrashDetails = (
57
- phase: NativeCrashPhase,
58
- initialDetails?: AppCrashDetails,
59
- enrichedDetails?: AppCrashDetails | null,
60
- fallbackSummary?: string
61
- ): NativeCrashDetails => ({
62
- phase,
63
- source: enrichedDetails?.source ?? initialDetails?.source,
64
- summary:
65
- enrichedDetails?.summary ?? initialDetails?.summary ?? fallbackSummary,
66
- signal: enrichedDetails?.signal ?? initialDetails?.signal,
67
- exceptionType: enrichedDetails?.exceptionType ?? initialDetails?.exceptionType,
68
- processName: enrichedDetails?.processName ?? initialDetails?.processName,
69
- pid: enrichedDetails?.pid ?? initialDetails?.pid,
70
- stackTrace: enrichedDetails?.stackTrace ?? initialDetails?.stackTrace,
71
- rawLines: enrichedDetails?.rawLines ?? initialDetails?.rawLines,
72
- artifactType: enrichedDetails?.artifactType ?? initialDetails?.artifactType,
73
- artifactPath: enrichedDetails?.artifactPath ?? initialDetails?.artifactPath,
74
- });
75
-
76
- export const createCrashSupervisor = ({
77
- appMonitor,
78
- platformRunner,
79
- }: CrashSupervisorOptions): CrashSupervisor => {
80
- let state: CrashSupervisorState = 'idle';
81
- let activeTestFilePath: string | null = null;
82
- let crashRejectors = new Set<(error: NativeCrashError) => void>();
83
- let disposed = false;
84
- let monitoring = true;
85
- let isResolvingCrash = false;
86
-
87
- const getCrashDetailsProvider = (): CrashDetailsProvider | null => {
88
- if ('getCrashDetails' in appMonitor) {
89
- return appMonitor as AppMonitor & CrashDetailsProvider;
90
- }
91
-
92
- if (platformRunner.getCrashDetails) {
93
- return platformRunner;
94
- }
95
-
96
- return null;
97
- };
98
-
99
- const rejectCrashWaiters = (testFilePath: string, details: NativeCrashDetails) => {
100
- const error = new NativeCrashError(testFilePath, details);
101
-
102
- for (const reject of crashRejectors) {
103
- reject(error);
104
- }
105
-
106
- crashRejectors = new Set();
107
- };
108
-
109
- const handleCrash = async (reason: string, details?: AppCrashDetails) => {
110
- if (
111
- isResolvingCrash ||
112
- (state !== 'launching' && state !== 'running' && state !== 'ready')
113
- ) {
114
- return;
115
- }
116
-
117
- if (!activeTestFilePath) {
118
- crashLogger.debug('ignoring crash signal without active test: %s', reason);
119
- return;
120
- }
121
-
122
- isResolvingCrash = true;
123
- crashLogger.debug(
124
- 'native crash detected during %s (state=%s reason=%s)',
125
- activeTestFilePath,
126
- state,
127
- reason || '(none)'
128
- );
129
-
130
- for (const line of details?.rawLines ?? []) {
131
- crashLogger.debug('%s', line);
132
- }
133
-
134
- const phase = getCrashPhase(state);
135
- const testFilePath = activeTestFilePath;
136
- state = 'idle';
137
-
138
- try {
139
- const enrichedDetails = await getCrashDetailsProvider()?.getCrashDetails?.({
140
- processName: details?.processName,
141
- pid: details?.pid,
142
- occurredAt: Date.now(),
143
- });
144
-
145
- const mergedDetails = mergeCrashDetails(phase, details, enrichedDetails, reason);
146
- crashLogger.debug('crash details: %o', {
147
- phase: mergedDetails.phase,
148
- source: mergedDetails.source,
149
- summary: mergedDetails.summary,
150
- signal: mergedDetails.signal,
151
- exceptionType: mergedDetails.exceptionType,
152
- processName: mergedDetails.processName,
153
- pid: mergedDetails.pid,
154
- });
155
- rejectCrashWaiters(testFilePath, mergedDetails);
156
- } finally {
157
- isResolvingCrash = false;
158
- }
159
- };
160
-
161
- const confirmCrash = async (reason: string, details?: AppCrashDetails) => {
162
- if (disposed || !monitoring || state === 'disposing') {
163
- return;
164
- }
165
-
166
- try {
167
- const isRunning = await platformRunner.isAppRunning();
168
-
169
- if (!isRunning) {
170
- void handleCrash(reason, details);
171
- }
172
- } catch (error) {
173
- crashLogger.debug('crash confirmation failed', error);
174
- }
175
- };
176
-
177
- const appMonitorListener: AppMonitorListener = (event: AppMonitorEvent) => {
178
- if (disposed || !monitoring) {
179
- return;
180
- }
181
-
182
- if (event.type === 'app_started') {
183
- return;
184
- }
185
-
186
- if (event.type === 'app_exited') {
187
- const details = {
188
- source: event.crashDetails?.source ?? event.source,
189
- summary: event.crashDetails?.summary,
190
- signal: event.crashDetails?.signal,
191
- exceptionType: event.crashDetails?.exceptionType,
192
- processName: event.crashDetails?.processName,
193
- pid: event.crashDetails?.pid ?? event.pid,
194
- stackTrace: event.crashDetails?.stackTrace,
195
- rawLines:
196
- event.crashDetails?.rawLines ??
197
- (event.line ? [event.line] : undefined),
198
- };
199
-
200
- if (event.isConfirmed ?? event.source === 'polling') {
201
- void handleCrash('', details);
202
- } else {
203
- void confirmCrash('', details);
204
- }
205
- return;
206
- }
207
-
208
- if (event.type === 'possible_crash') {
209
- const details = {
210
- source: event.crashDetails?.source ?? event.source,
211
- summary: event.crashDetails?.summary,
212
- signal: event.crashDetails?.signal,
213
- exceptionType: event.crashDetails?.exceptionType,
214
- processName: event.crashDetails?.processName,
215
- pid: event.crashDetails?.pid ?? event.pid,
216
- stackTrace: event.crashDetails?.stackTrace,
217
- rawLines:
218
- event.crashDetails?.rawLines ??
219
- (event.line ? [event.line] : undefined),
220
- };
221
-
222
- if (event.isConfirmed) {
223
- void handleCrash(
224
- `possible crash signal (${event.source ?? 'unknown'})`,
225
- details
226
- );
227
- } else {
228
- void confirmCrash(
229
- `possible crash signal (${event.source ?? 'unknown'})`,
230
- details
231
- );
232
- }
233
- }
234
- };
235
-
236
- appMonitor.addListener(appMonitorListener);
237
-
238
- const setActiveTestFile = (testFilePath: string | null) => {
239
- activeTestFilePath = testFilePath;
240
- };
241
-
242
- const beginLaunch = (testFilePath: string) => {
243
- activeTestFilePath = testFilePath;
244
- state = 'launching';
245
- };
246
-
247
- const markReady = () => {
248
- if (state !== 'disposing') {
249
- state = 'ready';
250
- }
251
- };
252
-
253
- const beginTestRun = (testFilePath: string) => {
254
- activeTestFilePath = testFilePath;
255
- state = 'running';
256
- };
257
-
258
- const stop = async () => {
259
- monitoring = false;
260
- await appMonitor.stop();
261
- };
262
-
263
- const start = async () => {
264
- monitoring = true;
265
- await appMonitor.start();
266
- };
267
-
268
- const waitForCrash = (testFilePath: string): Promise<never> =>
269
- new Promise<never>((_, reject) => {
270
- if (disposed) {
271
- reject(
272
- new NativeCrashError(testFilePath, {
273
- phase: 'startup',
274
- source: 'polling',
275
- summary: 'Crash supervisor disposed while waiting for app startup.',
276
- })
277
- );
278
- return;
279
- }
280
-
281
- crashRejectors.add(reject);
282
- });
283
-
284
- const isReady = () => state === 'ready' || state === 'running';
285
-
286
- const cancelCrashWaiters = () => {
287
- crashRejectors = new Set();
288
- };
289
-
290
- const reset = () => {
291
- cancelCrashWaiters();
292
- isResolvingCrash = false;
293
- if (state !== 'disposing') {
294
- state = 'idle';
295
- }
296
- };
297
-
298
- const dispose = async () => {
299
- disposed = true;
300
- monitoring = false;
301
- state = 'disposing';
302
- crashRejectors = new Set();
303
- isResolvingCrash = false;
304
- appMonitor.removeListener(appMonitorListener);
305
- await appMonitor.dispose();
306
- };
307
-
308
- return {
309
- setActiveTestFile,
310
- beginLaunch,
311
- markReady,
312
- beginTestRun,
313
- stop,
314
- start,
315
- waitForCrash,
316
- isReady,
317
- cancelCrashWaiters,
318
- reset,
319
- dispose,
320
- };
321
- };
package/src/env.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { Harness } from './harness.js';
2
- import type { Config as HarnessConfig } from '@react-native-harness/config';
3
-
4
- declare global {
5
- var HARNESS: Harness;
6
- var HARNESS_CONFIG: HarnessConfig;
7
- }
8
-
9
- export {};