@react-native-harness/platform-android 1.0.0 → 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/dist/__tests__/adb.test.d.ts +2 -0
- package/dist/__tests__/adb.test.d.ts.map +1 -0
- package/dist/__tests__/adb.test.js +72 -0
- package/dist/__tests__/app-monitor.test.d.ts +2 -0
- package/dist/__tests__/app-monitor.test.d.ts.map +1 -0
- package/dist/__tests__/app-monitor.test.js +202 -0
- package/dist/__tests__/crash-parser.test.d.ts +2 -0
- package/dist/__tests__/crash-parser.test.d.ts.map +1 -0
- package/dist/__tests__/crash-parser.test.js +45 -0
- package/dist/__tests__/shared-prefs.test.d.ts +2 -0
- package/dist/__tests__/shared-prefs.test.d.ts.map +1 -0
- package/dist/__tests__/shared-prefs.test.js +87 -0
- package/dist/adb.d.ts +6 -1
- package/dist/adb.d.ts.map +1 -1
- package/dist/adb.js +84 -18
- package/dist/app-monitor.d.ts +13 -0
- package/dist/app-monitor.d.ts.map +1 -0
- package/dist/app-monitor.js +359 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -0
- package/dist/crash-parser.d.ts +11 -0
- package/dist/crash-parser.d.ts.map +1 -0
- package/dist/crash-parser.js +39 -0
- package/dist/runner.d.ts +2 -2
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +21 -5
- package/dist/shared-prefs.d.ts +3 -0
- package/dist/shared-prefs.d.ts.map +1 -0
- package/dist/shared-prefs.js +92 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/eslint.config.mjs +4 -1
- package/package.json +4 -4
- package/src/__tests__/adb.test.ts +89 -0
- package/src/__tests__/app-monitor.test.ts +273 -0
- package/src/__tests__/crash-parser.test.ts +52 -0
- package/src/__tests__/shared-prefs.test.ts +144 -0
- package/src/adb.ts +111 -18
- package/src/app-monitor.ts +544 -0
- package/src/config.ts +10 -0
- package/src/crash-parser.ts +66 -0
- package/src/runner.ts +31 -7
- package/src/shared-prefs.ts +205 -0
- package/tsconfig.json +2 -2
- package/tsconfig.lib.json +2 -2
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/assertions.d.ts +0 -5
- package/dist/assertions.d.ts.map +0 -1
- package/dist/assertions.js +0 -6
- package/dist/emulator.d.ts +0 -6
- package/dist/emulator.d.ts.map +0 -1
- package/dist/emulator.js +0 -27
- package/dist/errors.d.ts +0 -15
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -28
- package/dist/reader.d.ts +0 -6
- package/dist/reader.d.ts.map +0 -1
- package/dist/reader.js +0 -57
- package/dist/types.d.ts +0 -381
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -107
package/src/runner.ts
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DeviceNotFoundError,
|
|
3
3
|
AppNotInstalledError,
|
|
4
|
+
CreateAppMonitorOptions,
|
|
4
5
|
HarnessPlatformRunner,
|
|
5
6
|
} from '@react-native-harness/platforms';
|
|
6
|
-
import { Config } from '@react-native-harness/config';
|
|
7
|
+
import type { Config as HarnessConfig } from '@react-native-harness/config';
|
|
7
8
|
import {
|
|
8
9
|
AndroidPlatformConfigSchema,
|
|
9
10
|
type AndroidPlatformConfig,
|
|
10
11
|
} from './config.js';
|
|
11
12
|
import { getAdbId } from './adb-id.js';
|
|
12
13
|
import * as adb from './adb.js';
|
|
14
|
+
import {
|
|
15
|
+
applyHarnessDebugHttpHost,
|
|
16
|
+
clearHarnessDebugHttpHost,
|
|
17
|
+
} from './shared-prefs.js';
|
|
13
18
|
import { getDeviceName } from './utils.js';
|
|
19
|
+
import { createAndroidAppMonitor } from './app-monitor.js';
|
|
14
20
|
|
|
15
21
|
const getAndroidRunner = async (
|
|
16
22
|
config: AndroidPlatformConfig,
|
|
17
|
-
harnessConfig:
|
|
23
|
+
harnessConfig: HarnessConfig
|
|
18
24
|
): Promise<HarnessPlatformRunner> => {
|
|
19
25
|
const parsedConfig = AndroidPlatformConfigSchema.parse(config);
|
|
20
26
|
const adbId = await getAdbId(parsedConfig.device);
|
|
@@ -32,26 +38,35 @@ const getAndroidRunner = async (
|
|
|
32
38
|
);
|
|
33
39
|
}
|
|
34
40
|
|
|
41
|
+
const metroPort = harnessConfig.metroPort;
|
|
42
|
+
|
|
35
43
|
await Promise.all([
|
|
36
|
-
adb.reversePort(adbId,
|
|
44
|
+
adb.reversePort(adbId, metroPort),
|
|
37
45
|
adb.reversePort(adbId, 8080),
|
|
38
46
|
adb.reversePort(adbId, harnessConfig.webSocketPort),
|
|
47
|
+
adb.setHideErrorDialogs(adbId, true),
|
|
48
|
+
applyHarnessDebugHttpHost(adbId, parsedConfig.bundleId, `localhost:${metroPort}`),
|
|
39
49
|
]);
|
|
50
|
+
const appUid = await adb.getAppUid(adbId, parsedConfig.bundleId);
|
|
40
51
|
|
|
41
52
|
return {
|
|
42
|
-
startApp: async () => {
|
|
53
|
+
startApp: async (options) => {
|
|
43
54
|
await adb.startApp(
|
|
44
55
|
adbId,
|
|
45
56
|
parsedConfig.bundleId,
|
|
46
|
-
parsedConfig.activityName
|
|
57
|
+
parsedConfig.activityName,
|
|
58
|
+
(options as typeof parsedConfig.appLaunchOptions | undefined) ??
|
|
59
|
+
parsedConfig.appLaunchOptions
|
|
47
60
|
);
|
|
48
61
|
},
|
|
49
|
-
restartApp: async () => {
|
|
62
|
+
restartApp: async (options) => {
|
|
50
63
|
await adb.stopApp(adbId, parsedConfig.bundleId);
|
|
51
64
|
await adb.startApp(
|
|
52
65
|
adbId,
|
|
53
66
|
parsedConfig.bundleId,
|
|
54
|
-
parsedConfig.activityName
|
|
67
|
+
parsedConfig.activityName,
|
|
68
|
+
(options as typeof parsedConfig.appLaunchOptions | undefined) ??
|
|
69
|
+
parsedConfig.appLaunchOptions
|
|
55
70
|
);
|
|
56
71
|
},
|
|
57
72
|
stopApp: async () => {
|
|
@@ -59,10 +74,19 @@ const getAndroidRunner = async (
|
|
|
59
74
|
},
|
|
60
75
|
dispose: async () => {
|
|
61
76
|
await adb.stopApp(adbId, parsedConfig.bundleId);
|
|
77
|
+
await clearHarnessDebugHttpHost(adbId, parsedConfig.bundleId);
|
|
78
|
+
await adb.setHideErrorDialogs(adbId, false);
|
|
62
79
|
},
|
|
63
80
|
isAppRunning: async () => {
|
|
64
81
|
return await adb.isAppRunning(adbId, parsedConfig.bundleId);
|
|
65
82
|
},
|
|
83
|
+
createAppMonitor: (options?: CreateAppMonitorOptions) =>
|
|
84
|
+
createAndroidAppMonitor({
|
|
85
|
+
adbId,
|
|
86
|
+
bundleId: parsedConfig.bundleId,
|
|
87
|
+
appUid,
|
|
88
|
+
crashArtifactWriter: options?.crashArtifactWriter,
|
|
89
|
+
}),
|
|
66
90
|
};
|
|
67
91
|
};
|
|
68
92
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { spawn, SubprocessError } from '@react-native-harness/tools';
|
|
2
|
+
|
|
3
|
+
const DEBUG_HTTP_HOST_BLOCK_START =
|
|
4
|
+
'<!-- react-native-harness:debug_http_host:start -->';
|
|
5
|
+
const DEBUG_HTTP_HOST_BLOCK_END =
|
|
6
|
+
'<!-- react-native-harness:debug_http_host:end -->';
|
|
7
|
+
const DEBUG_HTTP_HOST_BACKUP_KEY = 'harness_debug_http_host_backup';
|
|
8
|
+
|
|
9
|
+
const getSharedPrefsPath = (bundleId: string) =>
|
|
10
|
+
`shared_prefs/${bundleId}_preferences.xml`;
|
|
11
|
+
|
|
12
|
+
const escapeRegExp = (value: string): string =>
|
|
13
|
+
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
14
|
+
|
|
15
|
+
const escapeXml = (value: string): string =>
|
|
16
|
+
value
|
|
17
|
+
.replaceAll('&', '&')
|
|
18
|
+
.replaceAll('<', '<')
|
|
19
|
+
.replaceAll('>', '>')
|
|
20
|
+
.replaceAll('"', '"')
|
|
21
|
+
.replaceAll("'", ''');
|
|
22
|
+
|
|
23
|
+
const unescapeXml = (value: string): string =>
|
|
24
|
+
value
|
|
25
|
+
.replaceAll(''', "'")
|
|
26
|
+
.replaceAll('"', '"')
|
|
27
|
+
.replaceAll('>', '>')
|
|
28
|
+
.replaceAll('<', '<')
|
|
29
|
+
.replaceAll('&', '&');
|
|
30
|
+
|
|
31
|
+
const getStringPreferenceRegex = (key: string) =>
|
|
32
|
+
new RegExp(
|
|
33
|
+
`<string\\s+name="${escapeRegExp(key)}">([\\s\\S]*?)<\\/string>`,
|
|
34
|
+
'g'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const getStringPreferenceValue = (
|
|
38
|
+
content: string,
|
|
39
|
+
key: string
|
|
40
|
+
): string | null => {
|
|
41
|
+
const matches = [...content.matchAll(getStringPreferenceRegex(key))];
|
|
42
|
+
const value = matches.at(-1)?.[1];
|
|
43
|
+
|
|
44
|
+
return value == null ? null : unescapeXml(value);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const renameStringPreference = (
|
|
48
|
+
content: string,
|
|
49
|
+
fromKey: string,
|
|
50
|
+
toKey: string
|
|
51
|
+
): string =>
|
|
52
|
+
content.replace(
|
|
53
|
+
new RegExp(
|
|
54
|
+
`(<string\\s+name=")${escapeRegExp(fromKey)}(">[\\s\\S]*?<\\/string>)`,
|
|
55
|
+
'g'
|
|
56
|
+
),
|
|
57
|
+
`$1${toKey}$2`
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const stripStringPreference = (content: string, key: string): string =>
|
|
61
|
+
content.replace(
|
|
62
|
+
new RegExp(
|
|
63
|
+
`\\s*<string\\s+name="${escapeRegExp(key)}">[\\s\\S]*?<\\/string>\\s*`,
|
|
64
|
+
'g'
|
|
65
|
+
),
|
|
66
|
+
'\n'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const normalizeEmptyMap = (content: string): string =>
|
|
70
|
+
content.replace(/<map\s*\/>/g, '<map>\n</map>');
|
|
71
|
+
|
|
72
|
+
const getHarnessDebugHttpHostBlock = (host: string) =>
|
|
73
|
+
[
|
|
74
|
+
DEBUG_HTTP_HOST_BLOCK_START,
|
|
75
|
+
`<string name="debug_http_host">${escapeXml(host)}</string>`,
|
|
76
|
+
DEBUG_HTTP_HOST_BLOCK_END,
|
|
77
|
+
].join('\n');
|
|
78
|
+
|
|
79
|
+
const stripHarnessDebugHttpHostBlock = (content: string): string =>
|
|
80
|
+
content.replace(
|
|
81
|
+
new RegExp(
|
|
82
|
+
`\\s*${escapeRegExp(
|
|
83
|
+
DEBUG_HTTP_HOST_BLOCK_START
|
|
84
|
+
)}\\s*\\n[\\s\\S]*?\\n\\s*${escapeRegExp(DEBUG_HTTP_HOST_BLOCK_END)}\\s*`,
|
|
85
|
+
'g'
|
|
86
|
+
),
|
|
87
|
+
'\n'
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const normalizeSharedPrefsContent = (content: string | null): string => {
|
|
91
|
+
if (!content?.trim()) {
|
|
92
|
+
return ['<?xml version="1.0" encoding="utf-8"?>', '<map>', '</map>'].join(
|
|
93
|
+
'\n'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return normalizeEmptyMap(stripHarnessDebugHttpHostBlock(content)).trim();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const insertBeforeClosingMap = (content: string, block: string): string => {
|
|
101
|
+
if (!content.includes('</map>')) {
|
|
102
|
+
throw new Error('Android shared preferences file is missing </map>.');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return content.replace(
|
|
106
|
+
/<\/map>\s*$/,
|
|
107
|
+
` ${block.replace(/\n/g, '\n ')}\n</map>`
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const readSharedPrefsFile = async (
|
|
112
|
+
adbId: string,
|
|
113
|
+
bundleId: string
|
|
114
|
+
): Promise<string | null> => {
|
|
115
|
+
try {
|
|
116
|
+
const { stdout } = await spawn('adb', [
|
|
117
|
+
'-s',
|
|
118
|
+
adbId,
|
|
119
|
+
'shell',
|
|
120
|
+
`run-as ${bundleId} cat ${getSharedPrefsPath(bundleId)}`,
|
|
121
|
+
]);
|
|
122
|
+
return stdout;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof SubprocessError && error.exitCode === 1) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const writeSharedPrefsFile = async (
|
|
133
|
+
adbId: string,
|
|
134
|
+
bundleId: string,
|
|
135
|
+
content: string
|
|
136
|
+
): Promise<void> => {
|
|
137
|
+
await spawn(
|
|
138
|
+
'adb',
|
|
139
|
+
[
|
|
140
|
+
'-s',
|
|
141
|
+
adbId,
|
|
142
|
+
'shell',
|
|
143
|
+
`run-as ${bundleId} sh -c 'mkdir -p shared_prefs && cat > ${getSharedPrefsPath(
|
|
144
|
+
bundleId
|
|
145
|
+
)}'`,
|
|
146
|
+
],
|
|
147
|
+
{ stdin: { string: `${content.trim()}\n` } }
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const applyHarnessDebugHttpHost = async (
|
|
152
|
+
adbId: string,
|
|
153
|
+
bundleId: string,
|
|
154
|
+
host: string
|
|
155
|
+
): Promise<void> => {
|
|
156
|
+
const existingContent = await readSharedPrefsFile(adbId, bundleId);
|
|
157
|
+
const normalizedContent = normalizeSharedPrefsContent(existingContent);
|
|
158
|
+
const existingHost = getStringPreferenceValue(
|
|
159
|
+
normalizedContent,
|
|
160
|
+
'debug_http_host'
|
|
161
|
+
);
|
|
162
|
+
const contentWithBackup =
|
|
163
|
+
existingHost == null
|
|
164
|
+
? normalizedContent
|
|
165
|
+
: renameStringPreference(
|
|
166
|
+
stripStringPreference(normalizedContent, DEBUG_HTTP_HOST_BACKUP_KEY),
|
|
167
|
+
'debug_http_host',
|
|
168
|
+
DEBUG_HTTP_HOST_BACKUP_KEY
|
|
169
|
+
);
|
|
170
|
+
const nextContent = insertBeforeClosingMap(
|
|
171
|
+
contentWithBackup,
|
|
172
|
+
getHarnessDebugHttpHostBlock(host)
|
|
173
|
+
);
|
|
174
|
+
await writeSharedPrefsFile(adbId, bundleId, nextContent);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export const clearHarnessDebugHttpHost = async (
|
|
178
|
+
adbId: string,
|
|
179
|
+
bundleId: string
|
|
180
|
+
): Promise<void> => {
|
|
181
|
+
const existingContent = await readSharedPrefsFile(adbId, bundleId);
|
|
182
|
+
|
|
183
|
+
if (!existingContent) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const nextContentWithoutHarnessBlock =
|
|
188
|
+
stripHarnessDebugHttpHostBlock(existingContent).trim();
|
|
189
|
+
|
|
190
|
+
if (nextContentWithoutHarnessBlock === existingContent.trim()) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const restoredContent = renameStringPreference(
|
|
195
|
+
nextContentWithoutHarnessBlock,
|
|
196
|
+
DEBUG_HTTP_HOST_BACKUP_KEY,
|
|
197
|
+
'debug_http_host'
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
await writeSharedPrefsFile(
|
|
201
|
+
adbId,
|
|
202
|
+
bundleId,
|
|
203
|
+
normalizeEmptyMap(restoredContent).trim()
|
|
204
|
+
);
|
|
205
|
+
};
|
package/tsconfig.json
CHANGED
package/tsconfig.lib.json
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"include": ["src/**/*.ts"],
|
|
13
13
|
"references": [
|
|
14
14
|
{
|
|
15
|
-
"path": "../
|
|
15
|
+
"path": "../tools/tsconfig.lib.json"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"path": "../
|
|
18
|
+
"path": "../config/tsconfig.lib.json"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"path": "../platforms/tsconfig.lib.json"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.9.3"}
|
package/dist/assertions.d.ts
DELETED
package/dist/assertions.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE5D,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,IAAI,MAAM,GAAG;IAAE,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAO/D"}
|
package/dist/assertions.js
DELETED
package/dist/emulator.d.ts
DELETED
package/dist/emulator.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"emulator.d.ts","sourceRoot":"","sources":["../src/emulator.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,SAAS,MAAM,KACd,OAAO,CAAC,eAAe,CA8BzB,CAAC"}
|
package/dist/emulator.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { spawn } from '@react-native-harness/tools';
|
|
2
|
-
import * as adb from './adb.js';
|
|
3
|
-
export const runEmulator = async (avdName) => {
|
|
4
|
-
const process = spawn('emulator', ['-avd', avdName]);
|
|
5
|
-
await process.nodeChildProcess;
|
|
6
|
-
const adbId = await adb.getEmulatorName(avdName);
|
|
7
|
-
if (!adbId) {
|
|
8
|
-
throw new Error('Emulator not found');
|
|
9
|
-
}
|
|
10
|
-
// Poll for emulator status until it's fully running
|
|
11
|
-
const checkStatus = async () => {
|
|
12
|
-
const status = await adb.isBootCompleted(adbId);
|
|
13
|
-
if (!status) {
|
|
14
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
15
|
-
await checkStatus();
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
// Start checking status after a brief delay to allow emulator to start
|
|
19
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
20
|
-
await checkStatus();
|
|
21
|
-
return {
|
|
22
|
-
adbId,
|
|
23
|
-
stop: async () => {
|
|
24
|
-
await adb.stopEmulator(adbId);
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
};
|
package/dist/errors.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare class ConfigValidationError extends Error {
|
|
2
|
-
readonly filePath: string;
|
|
3
|
-
readonly validationErrors: string[];
|
|
4
|
-
constructor(filePath: string, validationErrors: string[]);
|
|
5
|
-
}
|
|
6
|
-
export declare class ConfigNotFoundError extends Error {
|
|
7
|
-
readonly searchPath: string;
|
|
8
|
-
constructor(searchPath: string);
|
|
9
|
-
}
|
|
10
|
-
export declare class ConfigLoadError extends Error {
|
|
11
|
-
readonly filePath: string;
|
|
12
|
-
readonly cause?: Error;
|
|
13
|
-
constructor(filePath: string, cause?: Error);
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,qBAAsB,SAAQ,KAAK;aAExB,QAAQ,EAAE,MAAM;aAChB,gBAAgB,EAAE,MAAM,EAAE;gBAD1B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,EAAE;CAKjD;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aACd,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAIjD;AAED,qBAAa,eAAgB,SAAQ,KAAK;aAGV,QAAQ,EAAE,MAAM;IAF5C,SAAyB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAEX,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAK9D"}
|
package/dist/errors.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export class ConfigValidationError extends Error {
|
|
2
|
-
filePath;
|
|
3
|
-
validationErrors;
|
|
4
|
-
constructor(filePath, validationErrors) {
|
|
5
|
-
super(`Invalid configuration in ${filePath}`);
|
|
6
|
-
this.filePath = filePath;
|
|
7
|
-
this.validationErrors = validationErrors;
|
|
8
|
-
this.name = 'ConfigValidationError';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export class ConfigNotFoundError extends Error {
|
|
12
|
-
searchPath;
|
|
13
|
-
constructor(searchPath) {
|
|
14
|
-
super(`Config file not found in ${searchPath} or any parent directories`);
|
|
15
|
-
this.searchPath = searchPath;
|
|
16
|
-
this.name = 'ConfigNotFoundError';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class ConfigLoadError extends Error {
|
|
20
|
-
filePath;
|
|
21
|
-
cause;
|
|
22
|
-
constructor(filePath, cause) {
|
|
23
|
-
super(`Failed to load config file ${filePath}`);
|
|
24
|
-
this.filePath = filePath;
|
|
25
|
-
this.name = 'ConfigLoadError';
|
|
26
|
-
this.cause = cause;
|
|
27
|
-
}
|
|
28
|
-
}
|
package/dist/reader.d.ts
DELETED
package/dist/reader.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAsElD,eAAO,MAAM,SAAS,GACpB,KAAK,MAAM,KACV,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAUjD,CAAC"}
|
package/dist/reader.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { ConfigSchema } from './types.js';
|
|
2
|
-
import { ConfigValidationError, ConfigNotFoundError, ConfigLoadError, } from './errors.js';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import { createRequire } from 'node:module';
|
|
6
|
-
import { ZodError } from 'zod';
|
|
7
|
-
const extensions = ['.js', '.mjs', '.cjs', '.json'];
|
|
8
|
-
const importUp = async (dir, name) => {
|
|
9
|
-
const filePath = path.join(dir, name);
|
|
10
|
-
for (const ext of extensions) {
|
|
11
|
-
const filePathWithExt = `${filePath}${ext}`;
|
|
12
|
-
if (fs.existsSync(filePathWithExt)) {
|
|
13
|
-
let rawConfig;
|
|
14
|
-
try {
|
|
15
|
-
if (ext === '.mjs') {
|
|
16
|
-
rawConfig = await import(filePathWithExt).then((module) => module.default);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
const require = createRequire(import.meta.url);
|
|
20
|
-
rawConfig = require(filePathWithExt);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
throw new ConfigLoadError(filePathWithExt, error instanceof Error ? error : undefined);
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
const config = ConfigSchema.parse(rawConfig);
|
|
28
|
-
return { config, filePathWithExt, configDir: dir };
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
if (error instanceof ZodError) {
|
|
32
|
-
const validationErrors = error.errors.map((err) => {
|
|
33
|
-
const path = err.path.length > 0 ? ` at "${err.path.join('.')}"` : '';
|
|
34
|
-
return `${err.message}${path}`;
|
|
35
|
-
});
|
|
36
|
-
throw new ConfigValidationError(filePathWithExt, validationErrors);
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const parentDir = path.dirname(dir);
|
|
43
|
-
if (parentDir === dir) {
|
|
44
|
-
throw new ConfigNotFoundError(dir);
|
|
45
|
-
}
|
|
46
|
-
return importUp(parentDir, name);
|
|
47
|
-
};
|
|
48
|
-
export const getConfig = async (dir) => {
|
|
49
|
-
const { config, configDir } = await importUp(dir, 'rn-harness.config');
|
|
50
|
-
return {
|
|
51
|
-
config: {
|
|
52
|
-
...config,
|
|
53
|
-
reporter: config.reporter,
|
|
54
|
-
},
|
|
55
|
-
projectRoot: configDir,
|
|
56
|
-
};
|
|
57
|
-
};
|