@react-native-harness/plugins 1.1.0-rc.2
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/LICENSE +20 -0
- package/README.md +106 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/manager.d.ts +18 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +73 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +20 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/types.d.ts +321 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +24 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +40 -0
- package/eslint.config.mjs +19 -0
- package/package.json +25 -0
- package/src/index.ts +40 -0
- package/src/manager.ts +166 -0
- package/src/plugin.ts +35 -0
- package/src/types.ts +564 -0
- package/src/utils.ts +57 -0
- package/tsconfig.json +19 -0
- package/tsconfig.lib.json +25 -0
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HarnessPlatform } from '@react-native-harness/platforms';
|
|
2
|
+
import type { HarnessPlugin } from './types.js';
|
|
3
|
+
import { isHookTree } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export const definePlugin = <
|
|
6
|
+
TState extends object = Record<string, never>,
|
|
7
|
+
TConfig = unknown,
|
|
8
|
+
TRunner extends HarnessPlatform = HarnessPlatform,
|
|
9
|
+
>(
|
|
10
|
+
plugin: HarnessPlugin<TState, TConfig, TRunner>
|
|
11
|
+
): HarnessPlugin<TState, TConfig, TRunner> => {
|
|
12
|
+
return plugin;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const isHarnessPlugin = (value: unknown): value is HarnessPlugin => {
|
|
16
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const candidate = value as HarnessPlugin;
|
|
21
|
+
|
|
22
|
+
if (typeof candidate.name !== 'string' || candidate.name.length === 0) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (candidate.createState != null && typeof candidate.createState !== 'function') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (candidate.hooks != null && !isHookTree(candidate.hooks)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DeviceDescriptor,
|
|
3
|
+
SerializedError,
|
|
4
|
+
TestResultStatus,
|
|
5
|
+
TestSuiteResult,
|
|
6
|
+
} from '@react-native-harness/bridge';
|
|
7
|
+
import type {
|
|
8
|
+
AppCrashDetails,
|
|
9
|
+
AppLaunchOptions,
|
|
10
|
+
HarnessPlatform,
|
|
11
|
+
} from '@react-native-harness/platforms';
|
|
12
|
+
|
|
13
|
+
export type Awaitable<T> = T | Promise<T>;
|
|
14
|
+
|
|
15
|
+
export type HookLogger = {
|
|
16
|
+
debug: (...messages: unknown[]) => void;
|
|
17
|
+
info: (...messages: unknown[]) => void;
|
|
18
|
+
warn: (...messages: unknown[]) => void;
|
|
19
|
+
error: (...messages: unknown[]) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type HarnessRunSummary = {
|
|
23
|
+
passed: number;
|
|
24
|
+
failed: number;
|
|
25
|
+
skipped: number;
|
|
26
|
+
todo: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type HarnessRunStatus = 'passed' | 'failed';
|
|
30
|
+
|
|
31
|
+
export type HarnessPlatformMetadata = {
|
|
32
|
+
name: string;
|
|
33
|
+
platformId: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type HarnessHookMeta<TName extends string = string> = {
|
|
37
|
+
hook: TName;
|
|
38
|
+
invocationId: string;
|
|
39
|
+
runId?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type HarnessBaseHookContext<
|
|
43
|
+
TState extends object,
|
|
44
|
+
TConfig,
|
|
45
|
+
TRunner extends HarnessPlatform,
|
|
46
|
+
TName extends string,
|
|
47
|
+
> = {
|
|
48
|
+
plugin: {
|
|
49
|
+
name: string;
|
|
50
|
+
};
|
|
51
|
+
logger: HookLogger;
|
|
52
|
+
projectRoot: string;
|
|
53
|
+
config: TConfig;
|
|
54
|
+
runner: TRunner;
|
|
55
|
+
platform: HarnessPlatformMetadata;
|
|
56
|
+
state: TState;
|
|
57
|
+
timestamp: number;
|
|
58
|
+
abortSignal: AbortSignal;
|
|
59
|
+
meta: HarnessHookMeta<TName>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type HarnessBeforeCreationContext<
|
|
63
|
+
TState extends object,
|
|
64
|
+
TConfig,
|
|
65
|
+
TRunner extends HarnessPlatform,
|
|
66
|
+
> = HarnessBaseHookContext<
|
|
67
|
+
TState,
|
|
68
|
+
TConfig,
|
|
69
|
+
TRunner,
|
|
70
|
+
'harness:before-creation'
|
|
71
|
+
> & {
|
|
72
|
+
appLaunchOptions?: AppLaunchOptions;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type HarnessBeforeDisposeContext<
|
|
76
|
+
TState extends object,
|
|
77
|
+
TConfig,
|
|
78
|
+
TRunner extends HarnessPlatform,
|
|
79
|
+
> = HarnessBaseHookContext<
|
|
80
|
+
TState,
|
|
81
|
+
TConfig,
|
|
82
|
+
TRunner,
|
|
83
|
+
'harness:before-dispose'
|
|
84
|
+
> & {
|
|
85
|
+
runId?: string;
|
|
86
|
+
reason?: 'normal' | 'abort' | 'error';
|
|
87
|
+
summary?: HarnessRunSummary;
|
|
88
|
+
status?: HarnessRunStatus;
|
|
89
|
+
error?: unknown;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type RunStartedContext<
|
|
93
|
+
TState extends object,
|
|
94
|
+
TConfig,
|
|
95
|
+
TRunner extends HarnessPlatform,
|
|
96
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'run:started'> & {
|
|
97
|
+
runId: string;
|
|
98
|
+
startTime: number;
|
|
99
|
+
testFiles: string[];
|
|
100
|
+
watchMode: boolean;
|
|
101
|
+
coverageEnabled: boolean;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export type RunFinishedContext<
|
|
105
|
+
TState extends object,
|
|
106
|
+
TConfig,
|
|
107
|
+
TRunner extends HarnessPlatform,
|
|
108
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'run:finished'> & {
|
|
109
|
+
runId: string;
|
|
110
|
+
startTime: number;
|
|
111
|
+
duration: number;
|
|
112
|
+
testFiles: string[];
|
|
113
|
+
summary: HarnessRunSummary;
|
|
114
|
+
status: HarnessRunStatus;
|
|
115
|
+
error?: unknown;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export type RuntimeReadyContext<
|
|
119
|
+
TState extends object,
|
|
120
|
+
TConfig,
|
|
121
|
+
TRunner extends HarnessPlatform,
|
|
122
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'runtime:ready'> & {
|
|
123
|
+
runId: string;
|
|
124
|
+
device: DeviceDescriptor;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type RuntimeDisconnectedContext<
|
|
128
|
+
TState extends object,
|
|
129
|
+
TConfig,
|
|
130
|
+
TRunner extends HarnessPlatform,
|
|
131
|
+
> = HarnessBaseHookContext<
|
|
132
|
+
TState,
|
|
133
|
+
TConfig,
|
|
134
|
+
TRunner,
|
|
135
|
+
'runtime:disconnected'
|
|
136
|
+
> & {
|
|
137
|
+
runId: string;
|
|
138
|
+
reason?: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export type MetroInitializedContext<
|
|
142
|
+
TState extends object,
|
|
143
|
+
TConfig,
|
|
144
|
+
TRunner extends HarnessPlatform,
|
|
145
|
+
> = HarnessBaseHookContext<
|
|
146
|
+
TState,
|
|
147
|
+
TConfig,
|
|
148
|
+
TRunner,
|
|
149
|
+
'metro:initialized'
|
|
150
|
+
> & {
|
|
151
|
+
runId: string;
|
|
152
|
+
port: number;
|
|
153
|
+
host?: string;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export type MetroBundleTarget = 'module' | 'setupFile';
|
|
157
|
+
|
|
158
|
+
export type MetroBundleStartedContext<
|
|
159
|
+
TState extends object,
|
|
160
|
+
TConfig,
|
|
161
|
+
TRunner extends HarnessPlatform,
|
|
162
|
+
> = HarnessBaseHookContext<
|
|
163
|
+
TState,
|
|
164
|
+
TConfig,
|
|
165
|
+
TRunner,
|
|
166
|
+
'metro:bundle-started'
|
|
167
|
+
> & {
|
|
168
|
+
runId: string;
|
|
169
|
+
target: MetroBundleTarget;
|
|
170
|
+
file: string;
|
|
171
|
+
setupType?: 'setupFiles' | 'setupFilesAfterEnv';
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export type MetroBundleFinishedContext<
|
|
175
|
+
TState extends object,
|
|
176
|
+
TConfig,
|
|
177
|
+
TRunner extends HarnessPlatform,
|
|
178
|
+
> = HarnessBaseHookContext<
|
|
179
|
+
TState,
|
|
180
|
+
TConfig,
|
|
181
|
+
TRunner,
|
|
182
|
+
'metro:bundle-finished'
|
|
183
|
+
> & {
|
|
184
|
+
runId: string;
|
|
185
|
+
target: MetroBundleTarget;
|
|
186
|
+
file: string;
|
|
187
|
+
setupType?: 'setupFiles' | 'setupFilesAfterEnv';
|
|
188
|
+
duration: number;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export type MetroBundleFailedContext<
|
|
192
|
+
TState extends object,
|
|
193
|
+
TConfig,
|
|
194
|
+
TRunner extends HarnessPlatform,
|
|
195
|
+
> = HarnessBaseHookContext<
|
|
196
|
+
TState,
|
|
197
|
+
TConfig,
|
|
198
|
+
TRunner,
|
|
199
|
+
'metro:bundle-failed'
|
|
200
|
+
> & {
|
|
201
|
+
runId: string;
|
|
202
|
+
target: MetroBundleTarget;
|
|
203
|
+
file: string;
|
|
204
|
+
setupType?: 'setupFiles' | 'setupFilesAfterEnv';
|
|
205
|
+
duration: number;
|
|
206
|
+
error: string;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export type MetroClientLogLevel =
|
|
210
|
+
| 'trace'
|
|
211
|
+
| 'info'
|
|
212
|
+
| 'warn'
|
|
213
|
+
| 'log'
|
|
214
|
+
| 'group'
|
|
215
|
+
| 'groupCollapsed'
|
|
216
|
+
| 'groupEnd'
|
|
217
|
+
| 'debug'
|
|
218
|
+
| 'error';
|
|
219
|
+
|
|
220
|
+
export type MetroClientLogContext<
|
|
221
|
+
TState extends object,
|
|
222
|
+
TConfig,
|
|
223
|
+
TRunner extends HarnessPlatform,
|
|
224
|
+
> = HarnessBaseHookContext<
|
|
225
|
+
TState,
|
|
226
|
+
TConfig,
|
|
227
|
+
TRunner,
|
|
228
|
+
'metro:client-log'
|
|
229
|
+
> & {
|
|
230
|
+
runId: string;
|
|
231
|
+
level: MetroClientLogLevel;
|
|
232
|
+
data: unknown[];
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export type AppStartedContext<
|
|
236
|
+
TState extends object,
|
|
237
|
+
TConfig,
|
|
238
|
+
TRunner extends HarnessPlatform,
|
|
239
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'app:started'> & {
|
|
240
|
+
runId: string;
|
|
241
|
+
testFile?: string;
|
|
242
|
+
pid?: number;
|
|
243
|
+
source?: 'polling' | 'logs';
|
|
244
|
+
line?: string;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export type AppExitedContext<
|
|
248
|
+
TState extends object,
|
|
249
|
+
TConfig,
|
|
250
|
+
TRunner extends HarnessPlatform,
|
|
251
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'app:exited'> & {
|
|
252
|
+
runId: string;
|
|
253
|
+
testFile?: string;
|
|
254
|
+
pid?: number;
|
|
255
|
+
source?: 'polling' | 'logs';
|
|
256
|
+
line?: string;
|
|
257
|
+
isConfirmed?: boolean;
|
|
258
|
+
crashDetails?: AppCrashDetails;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
export type AppPossibleCrashContext<
|
|
262
|
+
TState extends object,
|
|
263
|
+
TConfig,
|
|
264
|
+
TRunner extends HarnessPlatform,
|
|
265
|
+
> = HarnessBaseHookContext<
|
|
266
|
+
TState,
|
|
267
|
+
TConfig,
|
|
268
|
+
TRunner,
|
|
269
|
+
'app:possible-crash'
|
|
270
|
+
> & {
|
|
271
|
+
runId: string;
|
|
272
|
+
testFile?: string;
|
|
273
|
+
pid?: number;
|
|
274
|
+
source?: 'polling' | 'logs';
|
|
275
|
+
line?: string;
|
|
276
|
+
isConfirmed?: boolean;
|
|
277
|
+
crashDetails?: AppCrashDetails;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export type CollectionStartedContext<
|
|
281
|
+
TState extends object,
|
|
282
|
+
TConfig,
|
|
283
|
+
TRunner extends HarnessPlatform,
|
|
284
|
+
> = HarnessBaseHookContext<
|
|
285
|
+
TState,
|
|
286
|
+
TConfig,
|
|
287
|
+
TRunner,
|
|
288
|
+
'collection:started'
|
|
289
|
+
> & {
|
|
290
|
+
runId: string;
|
|
291
|
+
file: string;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
export type CollectionFinishedContext<
|
|
295
|
+
TState extends object,
|
|
296
|
+
TConfig,
|
|
297
|
+
TRunner extends HarnessPlatform,
|
|
298
|
+
> = HarnessBaseHookContext<
|
|
299
|
+
TState,
|
|
300
|
+
TConfig,
|
|
301
|
+
TRunner,
|
|
302
|
+
'collection:finished'
|
|
303
|
+
> & {
|
|
304
|
+
runId: string;
|
|
305
|
+
file: string;
|
|
306
|
+
duration: number;
|
|
307
|
+
totalTests: number;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export type TestFileStartedContext<
|
|
311
|
+
TState extends object,
|
|
312
|
+
TConfig,
|
|
313
|
+
TRunner extends HarnessPlatform,
|
|
314
|
+
> = HarnessBaseHookContext<
|
|
315
|
+
TState,
|
|
316
|
+
TConfig,
|
|
317
|
+
TRunner,
|
|
318
|
+
'test-file:started'
|
|
319
|
+
> & {
|
|
320
|
+
runId: string;
|
|
321
|
+
file: string;
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export type TestFileFinishedContext<
|
|
325
|
+
TState extends object,
|
|
326
|
+
TConfig,
|
|
327
|
+
TRunner extends HarnessPlatform,
|
|
328
|
+
> = HarnessBaseHookContext<
|
|
329
|
+
TState,
|
|
330
|
+
TConfig,
|
|
331
|
+
TRunner,
|
|
332
|
+
'test-file:finished'
|
|
333
|
+
> & {
|
|
334
|
+
runId: string;
|
|
335
|
+
file: string;
|
|
336
|
+
duration: number;
|
|
337
|
+
status: TestResultStatus;
|
|
338
|
+
result: TestSuiteResult | null;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export type SuiteStartedContext<
|
|
342
|
+
TState extends object,
|
|
343
|
+
TConfig,
|
|
344
|
+
TRunner extends HarnessPlatform,
|
|
345
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'suite:started'> & {
|
|
346
|
+
runId: string;
|
|
347
|
+
file: string;
|
|
348
|
+
name: string;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export type SuiteFinishedContext<
|
|
352
|
+
TState extends object,
|
|
353
|
+
TConfig,
|
|
354
|
+
TRunner extends HarnessPlatform,
|
|
355
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'suite:finished'> & {
|
|
356
|
+
runId: string;
|
|
357
|
+
file: string;
|
|
358
|
+
name: string;
|
|
359
|
+
duration: number;
|
|
360
|
+
status: TestResultStatus;
|
|
361
|
+
error?: SerializedError;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
export type TestStartedContext<
|
|
365
|
+
TState extends object,
|
|
366
|
+
TConfig,
|
|
367
|
+
TRunner extends HarnessPlatform,
|
|
368
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'test:started'> & {
|
|
369
|
+
runId: string;
|
|
370
|
+
file: string;
|
|
371
|
+
suite: string;
|
|
372
|
+
name: string;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
export type TestFinishedContext<
|
|
376
|
+
TState extends object,
|
|
377
|
+
TConfig,
|
|
378
|
+
TRunner extends HarnessPlatform,
|
|
379
|
+
> = HarnessBaseHookContext<TState, TConfig, TRunner, 'test:finished'> & {
|
|
380
|
+
runId: string;
|
|
381
|
+
file: string;
|
|
382
|
+
suite: string;
|
|
383
|
+
name: string;
|
|
384
|
+
duration: number;
|
|
385
|
+
status: TestResultStatus;
|
|
386
|
+
error?: SerializedError;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
export type FlatHarnessHookContexts<
|
|
390
|
+
TState extends object,
|
|
391
|
+
TConfig,
|
|
392
|
+
TRunner extends HarnessPlatform,
|
|
393
|
+
> = {
|
|
394
|
+
'harness:before-creation': HarnessBeforeCreationContext<
|
|
395
|
+
TState,
|
|
396
|
+
TConfig,
|
|
397
|
+
TRunner
|
|
398
|
+
>;
|
|
399
|
+
'harness:before-dispose': HarnessBeforeDisposeContext<
|
|
400
|
+
TState,
|
|
401
|
+
TConfig,
|
|
402
|
+
TRunner
|
|
403
|
+
>;
|
|
404
|
+
'run:started': RunStartedContext<TState, TConfig, TRunner>;
|
|
405
|
+
'run:finished': RunFinishedContext<TState, TConfig, TRunner>;
|
|
406
|
+
'runtime:ready': RuntimeReadyContext<TState, TConfig, TRunner>;
|
|
407
|
+
'runtime:disconnected': RuntimeDisconnectedContext<
|
|
408
|
+
TState,
|
|
409
|
+
TConfig,
|
|
410
|
+
TRunner
|
|
411
|
+
>;
|
|
412
|
+
'metro:initialized': MetroInitializedContext<TState, TConfig, TRunner>;
|
|
413
|
+
'metro:bundle-started': MetroBundleStartedContext<
|
|
414
|
+
TState,
|
|
415
|
+
TConfig,
|
|
416
|
+
TRunner
|
|
417
|
+
>;
|
|
418
|
+
'metro:bundle-finished': MetroBundleFinishedContext<
|
|
419
|
+
TState,
|
|
420
|
+
TConfig,
|
|
421
|
+
TRunner
|
|
422
|
+
>;
|
|
423
|
+
'metro:bundle-failed': MetroBundleFailedContext<
|
|
424
|
+
TState,
|
|
425
|
+
TConfig,
|
|
426
|
+
TRunner
|
|
427
|
+
>;
|
|
428
|
+
'metro:client-log': MetroClientLogContext<TState, TConfig, TRunner>;
|
|
429
|
+
'app:started': AppStartedContext<TState, TConfig, TRunner>;
|
|
430
|
+
'app:exited': AppExitedContext<TState, TConfig, TRunner>;
|
|
431
|
+
'app:possible-crash': AppPossibleCrashContext<TState, TConfig, TRunner>;
|
|
432
|
+
'collection:started': CollectionStartedContext<TState, TConfig, TRunner>;
|
|
433
|
+
'collection:finished': CollectionFinishedContext<TState, TConfig, TRunner>;
|
|
434
|
+
'test-file:started': TestFileStartedContext<TState, TConfig, TRunner>;
|
|
435
|
+
'test-file:finished': TestFileFinishedContext<TState, TConfig, TRunner>;
|
|
436
|
+
'suite:started': SuiteStartedContext<TState, TConfig, TRunner>;
|
|
437
|
+
'suite:finished': SuiteFinishedContext<TState, TConfig, TRunner>;
|
|
438
|
+
'test:started': TestStartedContext<TState, TConfig, TRunner>;
|
|
439
|
+
'test:finished': TestFinishedContext<TState, TConfig, TRunner>;
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
export type FlatHarnessHookName = keyof FlatHarnessHookContexts<
|
|
443
|
+
Record<string, never>,
|
|
444
|
+
unknown,
|
|
445
|
+
HarnessPlatform
|
|
446
|
+
>;
|
|
447
|
+
|
|
448
|
+
export type HarnessHookHandler<TContext> = (ctx: TContext) => Awaitable<void>;
|
|
449
|
+
|
|
450
|
+
export type HarnessPluginHooks<
|
|
451
|
+
TState extends object = Record<string, never>,
|
|
452
|
+
TConfig = unknown,
|
|
453
|
+
TRunner extends HarnessPlatform = HarnessPlatform,
|
|
454
|
+
> = {
|
|
455
|
+
harness?: {
|
|
456
|
+
beforeCreation?: HarnessHookHandler<
|
|
457
|
+
HarnessBeforeCreationContext<TState, TConfig, TRunner>
|
|
458
|
+
>;
|
|
459
|
+
beforeDispose?: HarnessHookHandler<
|
|
460
|
+
HarnessBeforeDisposeContext<TState, TConfig, TRunner>
|
|
461
|
+
>;
|
|
462
|
+
};
|
|
463
|
+
run?: {
|
|
464
|
+
started?: HarnessHookHandler<RunStartedContext<TState, TConfig, TRunner>>;
|
|
465
|
+
finished?: HarnessHookHandler<
|
|
466
|
+
RunFinishedContext<TState, TConfig, TRunner>
|
|
467
|
+
>;
|
|
468
|
+
};
|
|
469
|
+
runtime?: {
|
|
470
|
+
ready?: HarnessHookHandler<
|
|
471
|
+
RuntimeReadyContext<TState, TConfig, TRunner>
|
|
472
|
+
>;
|
|
473
|
+
disconnected?: HarnessHookHandler<
|
|
474
|
+
RuntimeDisconnectedContext<TState, TConfig, TRunner>
|
|
475
|
+
>;
|
|
476
|
+
};
|
|
477
|
+
metro?: {
|
|
478
|
+
initialized?: HarnessHookHandler<
|
|
479
|
+
MetroInitializedContext<TState, TConfig, TRunner>
|
|
480
|
+
>;
|
|
481
|
+
bundleStarted?: HarnessHookHandler<
|
|
482
|
+
MetroBundleStartedContext<TState, TConfig, TRunner>
|
|
483
|
+
>;
|
|
484
|
+
bundleFinished?: HarnessHookHandler<
|
|
485
|
+
MetroBundleFinishedContext<TState, TConfig, TRunner>
|
|
486
|
+
>;
|
|
487
|
+
bundleFailed?: HarnessHookHandler<
|
|
488
|
+
MetroBundleFailedContext<TState, TConfig, TRunner>
|
|
489
|
+
>;
|
|
490
|
+
clientLog?: HarnessHookHandler<
|
|
491
|
+
MetroClientLogContext<TState, TConfig, TRunner>
|
|
492
|
+
>;
|
|
493
|
+
};
|
|
494
|
+
app?: {
|
|
495
|
+
started?: HarnessHookHandler<AppStartedContext<TState, TConfig, TRunner>>;
|
|
496
|
+
exited?: HarnessHookHandler<AppExitedContext<TState, TConfig, TRunner>>;
|
|
497
|
+
possibleCrash?: HarnessHookHandler<
|
|
498
|
+
AppPossibleCrashContext<TState, TConfig, TRunner>
|
|
499
|
+
>;
|
|
500
|
+
};
|
|
501
|
+
collection?: {
|
|
502
|
+
started?: HarnessHookHandler<
|
|
503
|
+
CollectionStartedContext<TState, TConfig, TRunner>
|
|
504
|
+
>;
|
|
505
|
+
finished?: HarnessHookHandler<
|
|
506
|
+
CollectionFinishedContext<TState, TConfig, TRunner>
|
|
507
|
+
>;
|
|
508
|
+
};
|
|
509
|
+
testFile?: {
|
|
510
|
+
started?: HarnessHookHandler<
|
|
511
|
+
TestFileStartedContext<TState, TConfig, TRunner>
|
|
512
|
+
>;
|
|
513
|
+
finished?: HarnessHookHandler<
|
|
514
|
+
TestFileFinishedContext<TState, TConfig, TRunner>
|
|
515
|
+
>;
|
|
516
|
+
};
|
|
517
|
+
suite?: {
|
|
518
|
+
started?: HarnessHookHandler<SuiteStartedContext<TState, TConfig, TRunner>>;
|
|
519
|
+
finished?: HarnessHookHandler<
|
|
520
|
+
SuiteFinishedContext<TState, TConfig, TRunner>
|
|
521
|
+
>;
|
|
522
|
+
};
|
|
523
|
+
test?: {
|
|
524
|
+
started?: HarnessHookHandler<TestStartedContext<TState, TConfig, TRunner>>;
|
|
525
|
+
finished?: HarnessHookHandler<
|
|
526
|
+
TestFinishedContext<TState, TConfig, TRunner>
|
|
527
|
+
>;
|
|
528
|
+
};
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
export type HarnessPlugin<
|
|
532
|
+
TState extends object = Record<string, never>,
|
|
533
|
+
TConfig = unknown,
|
|
534
|
+
TRunner extends HarnessPlatform = HarnessPlatform,
|
|
535
|
+
> = {
|
|
536
|
+
name: string;
|
|
537
|
+
hooks?: HarnessPluginHooks<TState, TConfig, TRunner>;
|
|
538
|
+
createState?: () => TState;
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
export const HARNESS_HOOKS = [
|
|
542
|
+
{ flatName: 'harness:before-creation', path: ['harness', 'beforeCreation'] },
|
|
543
|
+
{ flatName: 'harness:before-dispose', path: ['harness', 'beforeDispose'] },
|
|
544
|
+
{ flatName: 'run:started', path: ['run', 'started'] },
|
|
545
|
+
{ flatName: 'run:finished', path: ['run', 'finished'] },
|
|
546
|
+
{ flatName: 'runtime:ready', path: ['runtime', 'ready'] },
|
|
547
|
+
{ flatName: 'runtime:disconnected', path: ['runtime', 'disconnected'] },
|
|
548
|
+
{ flatName: 'metro:initialized', path: ['metro', 'initialized'] },
|
|
549
|
+
{ flatName: 'metro:bundle-started', path: ['metro', 'bundleStarted'] },
|
|
550
|
+
{ flatName: 'metro:bundle-finished', path: ['metro', 'bundleFinished'] },
|
|
551
|
+
{ flatName: 'metro:bundle-failed', path: ['metro', 'bundleFailed'] },
|
|
552
|
+
{ flatName: 'metro:client-log', path: ['metro', 'clientLog'] },
|
|
553
|
+
{ flatName: 'app:started', path: ['app', 'started'] },
|
|
554
|
+
{ flatName: 'app:exited', path: ['app', 'exited'] },
|
|
555
|
+
{ flatName: 'app:possible-crash', path: ['app', 'possibleCrash'] },
|
|
556
|
+
{ flatName: 'collection:started', path: ['collection', 'started'] },
|
|
557
|
+
{ flatName: 'collection:finished', path: ['collection', 'finished'] },
|
|
558
|
+
{ flatName: 'test-file:started', path: ['testFile', 'started'] },
|
|
559
|
+
{ flatName: 'test-file:finished', path: ['testFile', 'finished'] },
|
|
560
|
+
{ flatName: 'suite:started', path: ['suite', 'started'] },
|
|
561
|
+
{ flatName: 'suite:finished', path: ['suite', 'finished'] },
|
|
562
|
+
{ flatName: 'test:started', path: ['test', 'started'] },
|
|
563
|
+
{ flatName: 'test:finished', path: ['test', 'finished'] },
|
|
564
|
+
] as const;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createLogger } from '@react-native-harness/tools';
|
|
2
|
+
import type { HookLogger } from './types.js';
|
|
3
|
+
|
|
4
|
+
export const isHookTree = (value: unknown): boolean => {
|
|
5
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
for (const child of Object.values(value)) {
|
|
10
|
+
if (child === undefined) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof child === 'function') {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (
|
|
19
|
+
child == null ||
|
|
20
|
+
typeof child !== 'object' ||
|
|
21
|
+
Array.isArray(child) ||
|
|
22
|
+
!isHookTree(child)
|
|
23
|
+
) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return true;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const createPluginLogger = (pluginName: string): HookLogger => {
|
|
32
|
+
const pluginLogger = createLogger(`plugin:${pluginName}`);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
debug: (...messages) => pluginLogger.debug(...messages),
|
|
36
|
+
info: (...messages) => pluginLogger.info(...messages),
|
|
37
|
+
warn: (...messages) => pluginLogger.warn(...messages),
|
|
38
|
+
error: (...messages) => pluginLogger.error(...messages),
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const getNestedValue = (
|
|
43
|
+
value: unknown,
|
|
44
|
+
path: readonly string[]
|
|
45
|
+
): unknown => {
|
|
46
|
+
let current = value;
|
|
47
|
+
|
|
48
|
+
for (const segment of path) {
|
|
49
|
+
if (current == null || typeof current !== 'object') {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
current = (current as Record<string, unknown>)[segment];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return current;
|
|
57
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"files": [],
|
|
4
|
+
"include": [],
|
|
5
|
+
"references": [
|
|
6
|
+
{
|
|
7
|
+
"path": "../tools"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": "../platforms"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "../bridge"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": "./tsconfig.lib.json"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
8
|
+
"emitDeclarationOnly": false,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"types": ["node"],
|
|
11
|
+
"lib": ["DOM", "ES2022"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts"],
|
|
14
|
+
"references": [
|
|
15
|
+
{
|
|
16
|
+
"path": "../tools/tsconfig.lib.json"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "../platforms/tsconfig.lib.json"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "../bridge/tsconfig.lib.json"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|