@react-native-harness/cli 1.0.0-canary.1766225407244 → 1.0.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/bundlers/metro.d.ts +2 -2
- package/dist/bundlers/metro.d.ts.map +1 -1
- package/dist/bundlers/metro.js +47 -24
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +140 -0
- package/dist/discovery/index.d.ts +3 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +1 -0
- package/dist/discovery/testDiscovery.d.ts +11 -0
- package/dist/discovery/testDiscovery.d.ts.map +1 -0
- package/dist/discovery/testDiscovery.js +29 -0
- package/dist/errors/appNotInstalledError.d.ts +7 -0
- package/dist/errors/appNotInstalledError.d.ts.map +1 -0
- package/dist/errors/appNotInstalledError.js +12 -0
- package/dist/errors/bridgeTimeoutError.d.ts +7 -0
- package/dist/errors/bridgeTimeoutError.d.ts.map +1 -0
- package/dist/errors/bridgeTimeoutError.js +12 -0
- package/dist/errors/errorHandler.d.ts +2 -0
- package/dist/errors/errorHandler.d.ts.map +1 -0
- package/dist/errors/errorHandler.js +152 -0
- package/dist/errors/errors.d.ts +45 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +89 -0
- package/dist/index.js +21 -4
- package/dist/jest.d.ts +2 -0
- package/dist/jest.d.ts.map +1 -0
- package/dist/jest.js +7 -0
- package/dist/platforms/android/build.d.ts +3 -2
- package/dist/platforms/android/build.d.ts.map +1 -1
- package/dist/platforms/android/build.js +24 -49
- package/dist/platforms/android/device.d.ts +5 -0
- package/dist/platforms/android/device.d.ts.map +1 -0
- package/dist/platforms/android/device.js +36 -0
- package/dist/platforms/android/emulator.d.ts +0 -1
- package/dist/platforms/android/emulator.d.ts.map +1 -1
- package/dist/platforms/android/emulator.js +101 -132
- package/dist/platforms/android/index.d.ts.map +1 -1
- package/dist/platforms/android/index.js +23 -19
- package/dist/platforms/ios/build.d.ts +5 -7
- package/dist/platforms/ios/build.d.ts.map +1 -1
- package/dist/platforms/ios/build.js +41 -116
- package/dist/platforms/ios/device.d.ts +11 -0
- package/dist/platforms/ios/device.d.ts.map +1 -0
- package/dist/platforms/ios/device.js +51 -0
- package/dist/platforms/ios/index.d.ts.map +1 -1
- package/dist/platforms/ios/index.js +24 -32
- package/dist/platforms/ios/simulator.d.ts +4 -4
- package/dist/platforms/ios/simulator.d.ts.map +1 -1
- package/dist/platforms/ios/simulator.js +104 -131
- package/dist/platforms/platform-adapter.d.ts +2 -4
- package/dist/platforms/platform-adapter.d.ts.map +1 -1
- package/dist/platforms/platform-registry.d.ts.map +1 -1
- package/dist/platforms/platform-registry.js +5 -1
- package/dist/platforms/vega/build.d.ts +23 -0
- package/dist/platforms/vega/build.d.ts.map +1 -0
- package/dist/platforms/vega/build.js +55 -0
- package/dist/platforms/vega/device.d.ts +57 -0
- package/dist/platforms/vega/device.d.ts.map +1 -0
- package/dist/platforms/vega/device.js +206 -0
- package/dist/platforms/vega/index.d.ts +4 -0
- package/dist/platforms/vega/index.d.ts.map +1 -0
- package/dist/platforms/vega/index.js +75 -0
- package/dist/platforms/web/index.d.ts +3 -1
- package/dist/platforms/web/index.d.ts.map +1 -1
- package/dist/platforms/web/index.js +9 -50
- package/dist/process.js +1 -1
- package/dist/reporters/default-reporter.d.ts.map +1 -1
- package/dist/reporters/default-reporter.js +22 -17
- package/dist/reporters/junit-reporter.d.ts +3 -0
- package/dist/reporters/junit-reporter.d.ts.map +1 -0
- package/dist/reporters/junit-reporter.js +119 -0
- package/dist/reporters/live-reporter.d.ts +20 -0
- package/dist/reporters/live-reporter.d.ts.map +1 -0
- package/dist/reporters/live-reporter.js +176 -0
- package/dist/src/reporters/default-reporter.js +135 -0
- package/dist/test-reporter-demo.js +95 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/utils/status-formatter.d.ts +27 -0
- package/dist/utils/status-formatter.d.ts.map +1 -0
- package/dist/utils/status-formatter.js +54 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +26 -0
- package/dist/wizard/bundleId.d.ts +2 -0
- package/dist/wizard/bundleId.d.ts.map +1 -0
- package/dist/wizard/bundleId.js +68 -0
- package/dist/wizard/configGenerator.d.ts +4 -0
- package/dist/wizard/configGenerator.d.ts.map +1 -0
- package/dist/wizard/configGenerator.js +89 -0
- package/dist/wizard/index.d.ts +2 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +40 -0
- package/dist/wizard/jestConfig.d.ts +2 -0
- package/dist/wizard/jestConfig.d.ts.map +1 -0
- package/dist/wizard/jestConfig.js +22 -0
- package/dist/wizard/jestIntegration.d.ts +2 -0
- package/dist/wizard/jestIntegration.d.ts.map +1 -0
- package/dist/wizard/jestIntegration.js +15 -0
- package/dist/wizard/packageManager.d.ts +2 -0
- package/dist/wizard/packageManager.d.ts.map +1 -0
- package/dist/wizard/packageManager.js +10 -0
- package/dist/wizard/platforms.d.ts +2 -0
- package/dist/wizard/platforms.d.ts.map +1 -0
- package/dist/wizard/platforms.js +34 -0
- package/dist/wizard/projectType.d.ts +6 -0
- package/dist/wizard/projectType.d.ts.map +1 -0
- package/dist/wizard/projectType.js +63 -0
- package/dist/wizard/targets.d.ts +3 -0
- package/dist/wizard/targets.d.ts.map +1 -0
- package/dist/wizard/targets.js +62 -0
- package/eslint.config.mjs +1 -1
- package/package.json +9 -4
- package/src/index.ts +33 -4
- package/src/wizard/bundleId.ts +70 -0
- package/src/wizard/configGenerator.ts +139 -0
- package/src/wizard/index.ts +72 -0
- package/src/wizard/jestConfig.ts +28 -0
- package/src/wizard/platforms.ts +44 -0
- package/src/wizard/projectType.ts +77 -0
- package/src/wizard/targets.ts +78 -0
- package/tsconfig.json +15 -0
- package/tsconfig.lib.json +15 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export class NoRunnerSpecifiedError extends Error {
|
|
2
|
+
constructor(availableRunners) {
|
|
3
|
+
super('No runner specified');
|
|
4
|
+
this.name = 'NoRunnerSpecifiedError';
|
|
5
|
+
this.availableRunners = availableRunners;
|
|
6
|
+
}
|
|
7
|
+
availableRunners;
|
|
8
|
+
}
|
|
9
|
+
export class RunnerNotFoundError extends Error {
|
|
10
|
+
constructor(runnerName, availableRunners) {
|
|
11
|
+
super(`Runner "${runnerName}" not found`);
|
|
12
|
+
this.name = 'RunnerNotFoundError';
|
|
13
|
+
this.runnerName = runnerName;
|
|
14
|
+
this.availableRunners = availableRunners;
|
|
15
|
+
}
|
|
16
|
+
runnerName;
|
|
17
|
+
availableRunners;
|
|
18
|
+
}
|
|
19
|
+
export class EnvironmentInitializationError extends Error {
|
|
20
|
+
constructor(message, runnerName, platform, details) {
|
|
21
|
+
super(`Failed to initialize environment for "${runnerName}" (${platform}): ${message}`);
|
|
22
|
+
this.name = 'EnvironmentInitializationError';
|
|
23
|
+
this.runnerName = runnerName;
|
|
24
|
+
this.platform = platform;
|
|
25
|
+
this.details = details;
|
|
26
|
+
}
|
|
27
|
+
runnerName;
|
|
28
|
+
platform;
|
|
29
|
+
details;
|
|
30
|
+
}
|
|
31
|
+
export class TestExecutionError extends Error {
|
|
32
|
+
constructor(testFile, error, testSuite, testName) {
|
|
33
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
34
|
+
const suiteInfo = testSuite ? ` in suite "${testSuite}"` : '';
|
|
35
|
+
const testInfo = testName ? ` test "${testName}"` : '';
|
|
36
|
+
super(`Test execution failed for ${testFile}${suiteInfo}${testInfo}: ${errorMessage}`);
|
|
37
|
+
this.name = 'TestExecutionError';
|
|
38
|
+
this.testFile = testFile;
|
|
39
|
+
this.testSuite = testSuite;
|
|
40
|
+
this.testName = testName;
|
|
41
|
+
this.originalError = error;
|
|
42
|
+
}
|
|
43
|
+
testFile;
|
|
44
|
+
testSuite;
|
|
45
|
+
testName;
|
|
46
|
+
originalError;
|
|
47
|
+
}
|
|
48
|
+
export class RpcClientError extends Error {
|
|
49
|
+
constructor(message, bridgePort, connectionStatus) {
|
|
50
|
+
const portInfo = bridgePort ? ` (port ${bridgePort})` : '';
|
|
51
|
+
const statusInfo = connectionStatus ? ` - Status: ${connectionStatus}` : '';
|
|
52
|
+
super(`RPC client error${portInfo}: ${message}${statusInfo}`);
|
|
53
|
+
this.name = 'RpcClientError';
|
|
54
|
+
this.bridgePort = bridgePort;
|
|
55
|
+
this.connectionStatus = connectionStatus;
|
|
56
|
+
}
|
|
57
|
+
bridgePort;
|
|
58
|
+
connectionStatus;
|
|
59
|
+
}
|
|
60
|
+
export class BridgeTimeoutError extends Error {
|
|
61
|
+
timeout;
|
|
62
|
+
runnerName;
|
|
63
|
+
platform;
|
|
64
|
+
constructor(timeout, runnerName, platform) {
|
|
65
|
+
super(`Bridge connection timed out after ${timeout}ms while waiting for "${runnerName}" (${platform}) runner to be ready`);
|
|
66
|
+
this.timeout = timeout;
|
|
67
|
+
this.runnerName = runnerName;
|
|
68
|
+
this.platform = platform;
|
|
69
|
+
this.name = 'BridgeTimeoutError';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class BundlingFailedError extends Error {
|
|
73
|
+
modulePath;
|
|
74
|
+
reason;
|
|
75
|
+
constructor(modulePath, reason) {
|
|
76
|
+
super(`Bundling of ${modulePath} failed: ${reason}`);
|
|
77
|
+
this.modulePath = modulePath;
|
|
78
|
+
this.reason = reason;
|
|
79
|
+
this.name = 'BundlingFailedError';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export class MetroPortUnavailableError extends Error {
|
|
83
|
+
port;
|
|
84
|
+
constructor(port) {
|
|
85
|
+
super(`Metro port ${port} is not available`);
|
|
86
|
+
this.port = port;
|
|
87
|
+
this.name = 'MetroPortUnavailableError';
|
|
88
|
+
}
|
|
89
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { run, yargsOptions } from 'jest-cli';
|
|
2
2
|
import { getConfig } from '@react-native-harness/config';
|
|
3
|
+
import { runInitWizard } from './wizard/index.js';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
const JEST_CONFIG_EXTENSIONS = ['.mjs', '.js', '.cjs'];
|
|
7
|
+
const JEST_HARNESS_CONFIG_BASE = 'jest.harness.config';
|
|
3
8
|
const checkForOldConfig = async () => {
|
|
4
9
|
try {
|
|
5
10
|
const { config } = await getConfig(process.cwd());
|
|
6
11
|
if (config.include) {
|
|
7
|
-
console.error('\n❌ Migration
|
|
12
|
+
console.error('\n❌ Migration required\n');
|
|
8
13
|
console.error('React Native Harness has migrated to the Jest CLI.');
|
|
9
14
|
console.error('The "include" property in your rn-harness.config file is no longer supported.\n');
|
|
10
15
|
console.error('Please follow the migration guide to update your configuration:');
|
|
@@ -19,7 +24,7 @@ const checkForOldConfig = async () => {
|
|
|
19
24
|
const patchYargsOptions = () => {
|
|
20
25
|
yargsOptions.harnessRunner = {
|
|
21
26
|
type: 'string',
|
|
22
|
-
description: 'Specify which
|
|
27
|
+
description: 'Specify which harness runner to use',
|
|
23
28
|
requiresArg: true,
|
|
24
29
|
};
|
|
25
30
|
// Remove all options that are not supported by Harness
|
|
@@ -57,5 +62,17 @@ const patchYargsOptions = () => {
|
|
|
57
62
|
delete yargsOptions.coverageProvider;
|
|
58
63
|
delete yargsOptions.logHeapUsage;
|
|
59
64
|
};
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
if (process.argv.includes('init')) {
|
|
66
|
+
runInitWizard();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
patchYargsOptions();
|
|
70
|
+
const hasConfigArg = process.argv.includes('--config') || process.argv.includes('-c');
|
|
71
|
+
if (!hasConfigArg) {
|
|
72
|
+
const existingConfigExt = JEST_CONFIG_EXTENSIONS.find((ext) => fs.existsSync(path.join(process.cwd(), `${JEST_HARNESS_CONFIG_BASE}${ext}`)));
|
|
73
|
+
if (existingConfigExt) {
|
|
74
|
+
process.argv.push('--config', `${JEST_HARNESS_CONFIG_BASE}${existingConfigExt}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
checkForOldConfig().then(() => run());
|
|
78
|
+
}
|
package/dist/jest.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jest.d.ts","sourceRoot":"","sources":["../src/jest.ts"],"names":[],"mappings":""}
|
package/dist/jest.js
ADDED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare const buildAndroidApp: (
|
|
1
|
+
export declare const buildAndroidApp: () => Promise<void>;
|
|
2
|
+
export declare const installApp: (deviceId: string) => Promise<void>;
|
|
2
3
|
export declare const killApp: (deviceId: string, bundleId: string) => Promise<void>;
|
|
3
|
-
export declare const runApp: (deviceId: string, bundleId: string) => Promise<void>;
|
|
4
|
+
export declare const runApp: (deviceId: string, bundleId: string, activityName: string) => Promise<void>;
|
|
4
5
|
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/build.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/build.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,IAAI,CAEpD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAiB/D,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,UAAU,MAAM,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,UAAU,MAAM,EAChB,UAAU,MAAM,EAChB,cAAc,MAAM,KACnB,OAAO,CAAC,IAAI,CAWd,CAAC"}
|
|
@@ -1,54 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export const buildAndroidApp = async (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
setTimeout(attemptBuild, 3000);
|
|
15
|
-
}
|
|
16
|
-
catch (reloadError) {
|
|
17
|
-
console.warn('Reload failed, retrying build anyway...');
|
|
18
|
-
setTimeout(attemptBuild, 3000);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
reject(error);
|
|
23
|
-
}
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
resolve();
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
attemptBuild();
|
|
30
|
-
});
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { spawn } from '@react-native-harness/tools';
|
|
3
|
+
export const buildAndroidApp = async () => {
|
|
4
|
+
await spawn('react-native', ['build-android', '--tasks', 'assembleDebug']);
|
|
5
|
+
};
|
|
6
|
+
export const installApp = async (deviceId) => {
|
|
7
|
+
await spawn('adb', [
|
|
8
|
+
'-s',
|
|
9
|
+
deviceId,
|
|
10
|
+
'install',
|
|
11
|
+
'-r',
|
|
12
|
+
path.join(process.cwd(), 'android', 'app', 'build', 'outputs', 'apk', 'debug', 'app-debug.apk'),
|
|
13
|
+
]);
|
|
31
14
|
};
|
|
32
15
|
export const killApp = async (deviceId, bundleId) => {
|
|
33
|
-
|
|
34
|
-
exec(`adb -s ${deviceId} shell am force-stop ${bundleId}`, (error) => {
|
|
35
|
-
if (error) {
|
|
36
|
-
reject(error);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
resolve();
|
|
40
|
-
});
|
|
41
|
-
});
|
|
16
|
+
await spawn('adb', ['-s', deviceId, 'shell', 'am', 'force-stop', bundleId]);
|
|
42
17
|
};
|
|
43
|
-
export const runApp = async (deviceId, bundleId) => {
|
|
18
|
+
export const runApp = async (deviceId, bundleId, activityName) => {
|
|
44
19
|
await killApp(deviceId, bundleId);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
20
|
+
await spawn('adb', [
|
|
21
|
+
'-s',
|
|
22
|
+
deviceId,
|
|
23
|
+
'shell',
|
|
24
|
+
'am',
|
|
25
|
+
'start',
|
|
26
|
+
'-n',
|
|
27
|
+
`${bundleId}/${activityName}`,
|
|
28
|
+
]);
|
|
54
29
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const killApp: (deviceId: string, bundleId: string) => Promise<void>;
|
|
2
|
+
export declare const runApp: (deviceId: string, bundleId: string) => Promise<void>;
|
|
3
|
+
export declare const isAppInstalled: (deviceId: string, bundleId: string) => Promise<boolean>;
|
|
4
|
+
export declare const reversePort: (port: number) => Promise<void>;
|
|
5
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/device.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,GAClB,UAAU,MAAM,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,UAAU,MAAM,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAWd,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,UAAU,MAAM,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAejB,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAE5D,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { spawn } from '@react-native-harness/tools';
|
|
2
|
+
export const killApp = async (deviceId, bundleId) => {
|
|
3
|
+
await spawn('adb', ['-s', deviceId, 'shell', 'am', 'force-stop', bundleId]);
|
|
4
|
+
};
|
|
5
|
+
export const runApp = async (deviceId, bundleId) => {
|
|
6
|
+
await killApp(deviceId, bundleId);
|
|
7
|
+
await spawn('adb', [
|
|
8
|
+
'-s',
|
|
9
|
+
deviceId,
|
|
10
|
+
'shell',
|
|
11
|
+
'am',
|
|
12
|
+
'start',
|
|
13
|
+
'-n',
|
|
14
|
+
`${bundleId}/.MainActivity`,
|
|
15
|
+
]);
|
|
16
|
+
};
|
|
17
|
+
export const isAppInstalled = async (deviceId, bundleId) => {
|
|
18
|
+
try {
|
|
19
|
+
const { stdout } = await spawn('adb', [
|
|
20
|
+
'-s',
|
|
21
|
+
deviceId,
|
|
22
|
+
'shell',
|
|
23
|
+
'pm',
|
|
24
|
+
'list',
|
|
25
|
+
'packages',
|
|
26
|
+
bundleId,
|
|
27
|
+
]);
|
|
28
|
+
return stdout.trim() !== '';
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const reversePort = async (port) => {
|
|
35
|
+
await spawn('adb', ['reverse', `tcp:${port}`, `tcp:${port}`]);
|
|
36
|
+
};
|
|
@@ -7,5 +7,4 @@ export declare const runEmulator: (name: string) => Promise<ChildProcess>;
|
|
|
7
7
|
export declare const stopEmulator: (avdName: string) => Promise<void>;
|
|
8
8
|
export declare const isAppInstalled: (emulatorId: string, bundleId: string) => Promise<boolean>;
|
|
9
9
|
export declare const reversePort: (port: number) => Promise<void>;
|
|
10
|
-
export declare const getEmulatorScreenshot: (emulatorId: string, name?: string) => Promise<string>;
|
|
11
10
|
//# sourceMappingURL=emulator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emulator.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/emulator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"emulator.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/emulator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtE,eAAO,MAAM,qBAAqB,GAChC,YAAY,MAAM,KACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAcvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,MAAM,KACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAmBvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,KACd,OAAO,CAAC,qBAAqB,CAoB/B,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,YAAY,CA2BpE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,IAAI,CAQhE,CAAC;AAOF,eAAO,MAAM,cAAc,GACzB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAejB,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAE5D,CAAC"}
|
|
@@ -1,147 +1,116 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from '@react-native-harness/tools';
|
|
2
2
|
export const getEmulatorNameFromId = async (emulatorId) => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
try {
|
|
4
|
+
const { stdout } = await spawn('adb', [
|
|
5
|
+
'-s',
|
|
6
|
+
emulatorId,
|
|
7
|
+
'emu',
|
|
8
|
+
'avd',
|
|
9
|
+
'name',
|
|
10
|
+
]);
|
|
11
|
+
const avdName = stdout.split('\n')[0].trim();
|
|
12
|
+
return avdName || null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
13
17
|
};
|
|
14
18
|
export const getEmulatorDeviceId = async (avdName) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const emulatorId = parts[0].trim();
|
|
26
|
-
const name = await getEmulatorNameFromId(emulatorId);
|
|
27
|
-
if (name === avdName) {
|
|
28
|
-
resolve(emulatorId);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
19
|
+
try {
|
|
20
|
+
const { stdout } = await spawn('adb', ['devices']);
|
|
21
|
+
const lines = stdout.split('\n');
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
const parts = line.trim().split('\t');
|
|
24
|
+
if (parts.length === 2 && parts[0].startsWith('emulator-')) {
|
|
25
|
+
const emulatorId = parts[0].trim();
|
|
26
|
+
const name = await getEmulatorNameFromId(emulatorId);
|
|
27
|
+
if (name === avdName) {
|
|
28
|
+
return emulatorId;
|
|
31
29
|
}
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
36
37
|
};
|
|
37
|
-
export const getEmulatorStatus = (avdName) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
export const getEmulatorStatus = async (avdName) => {
|
|
39
|
+
const emulatorId = await getEmulatorDeviceId(avdName);
|
|
40
|
+
if (!emulatorId) {
|
|
41
|
+
return 'stopped';
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
// Check if device is fully booted by checking boot completion
|
|
45
|
+
const { stdout } = await spawn('adb', [
|
|
46
|
+
'-s',
|
|
47
|
+
emulatorId,
|
|
48
|
+
'shell',
|
|
49
|
+
'getprop',
|
|
50
|
+
'sys.boot_completed',
|
|
51
|
+
]);
|
|
52
|
+
const bootCompleted = stdout.trim() === '1';
|
|
53
|
+
return bootCompleted ? 'running' : 'loading';
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return 'loading';
|
|
57
|
+
}
|
|
55
58
|
};
|
|
56
|
-
export const runEmulator = (name) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
catch (error) {
|
|
82
|
-
reject(error);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
// Start checking status after a brief delay to allow emulator to start
|
|
86
|
-
setTimeout(checkStatus, 3000);
|
|
87
|
-
});
|
|
59
|
+
export const runEmulator = async (name) => {
|
|
60
|
+
// Start the emulator
|
|
61
|
+
const process = spawn('emulator', ['-avd', name]);
|
|
62
|
+
const nodeChildProcess = await process.nodeChildProcess;
|
|
63
|
+
// Poll for emulator status until it's fully running
|
|
64
|
+
const checkStatus = async () => {
|
|
65
|
+
const status = await getEmulatorStatus(name);
|
|
66
|
+
if (status === 'running') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
else if (status === 'loading') {
|
|
70
|
+
// Check again in 2 seconds
|
|
71
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
72
|
+
await checkStatus();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Still stopped, check again in 1 second
|
|
76
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
77
|
+
await checkStatus();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
// Start checking status after a brief delay to allow emulator to start
|
|
81
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
82
|
+
await checkStatus();
|
|
83
|
+
return nodeChildProcess;
|
|
88
84
|
};
|
|
89
|
-
export const stopEmulator = (avdName) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
stopEmulatorById(emulatorId, resolve, reject);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
85
|
+
export const stopEmulator = async (avdName) => {
|
|
86
|
+
// First, get the emulator device ID
|
|
87
|
+
const emulatorId = await getEmulatorDeviceId(avdName);
|
|
88
|
+
if (!emulatorId) {
|
|
89
|
+
return; // No emulator running, nothing to stop
|
|
90
|
+
}
|
|
91
|
+
await stopEmulatorById(emulatorId);
|
|
100
92
|
};
|
|
101
|
-
const stopEmulatorById = (emulatorId
|
|
93
|
+
const stopEmulatorById = async (emulatorId) => {
|
|
102
94
|
// Stop the emulator using the found ID
|
|
103
|
-
|
|
104
|
-
if (killError) {
|
|
105
|
-
reject(killError);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
resolve();
|
|
109
|
-
});
|
|
95
|
+
await spawn('adb', ['-s', emulatorId, 'emu', 'kill']);
|
|
110
96
|
};
|
|
111
97
|
export const isAppInstalled = async (emulatorId, bundleId) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
98
|
+
try {
|
|
99
|
+
const { stdout } = await spawn('adb', [
|
|
100
|
+
'-s',
|
|
101
|
+
emulatorId,
|
|
102
|
+
'shell',
|
|
103
|
+
'pm',
|
|
104
|
+
'list',
|
|
105
|
+
'packages',
|
|
106
|
+
bundleId,
|
|
107
|
+
]);
|
|
108
|
+
return stdout.trim() !== '';
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
122
113
|
};
|
|
123
114
|
export const reversePort = async (port) => {
|
|
124
|
-
|
|
125
|
-
exec(`adb reverse tcp:${port} tcp:${port}`, (error) => {
|
|
126
|
-
if (error) {
|
|
127
|
-
reject(error);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
resolve();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
|
-
export const getEmulatorScreenshot = async (emulatorId, name = `${emulatorId}-${new Date()
|
|
135
|
-
.toISOString()
|
|
136
|
-
.replace(/:/g, '-')
|
|
137
|
-
.replace(/\//g, '-')}.png`) => {
|
|
138
|
-
return new Promise((resolve, reject) => {
|
|
139
|
-
exec(`adb -s ${emulatorId} exec-out screencap -p > ${name}`, (error) => {
|
|
140
|
-
if (error) {
|
|
141
|
-
reject(error);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
resolve(name);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
115
|
+
await spawn('adb', ['reverse', `tcp:${port}`, `tcp:${port}`]);
|
|
147
116
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/platforms/android/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAa9D,QAAA,MAAM,sBAAsB,EAAE,eAgE7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { assertAndroidRunnerConfig, } from '@react-native-harness/config';
|
|
2
|
+
import { logger } from '@react-native-harness/tools';
|
|
3
3
|
import { runEmulator, getEmulatorDeviceId, reversePort, isAppInstalled, getEmulatorStatus, } from './emulator.js';
|
|
4
|
-
import {
|
|
4
|
+
import { runApp, killApp } from './build.js';
|
|
5
5
|
import { killWithAwait } from '../../process.js';
|
|
6
6
|
import { runMetro } from '../../bundlers/metro.js';
|
|
7
|
+
import { AppNotInstalledError } from '../../errors/errors.js';
|
|
7
8
|
const androidPlatformAdapter = {
|
|
8
9
|
name: 'android',
|
|
9
|
-
getEnvironment: async (
|
|
10
|
-
|
|
10
|
+
getEnvironment: async (runner) => {
|
|
11
|
+
assertAndroidRunnerConfig(runner);
|
|
11
12
|
let emulator = null;
|
|
12
|
-
const emulatorStatus = await getEmulatorStatus(
|
|
13
|
+
const emulatorStatus = await getEmulatorStatus(runner.deviceId);
|
|
14
|
+
logger.debug(`Emulator status: ${emulatorStatus}`);
|
|
13
15
|
const metroPromise = runMetro();
|
|
14
16
|
if (emulatorStatus === 'stopped') {
|
|
15
|
-
|
|
17
|
+
logger.debug(`Emulator ${runner.deviceId} is stopped, starting it`);
|
|
18
|
+
emulator = await runEmulator(runner.deviceId);
|
|
16
19
|
}
|
|
17
|
-
const
|
|
18
|
-
|
|
20
|
+
const deviceId = await getEmulatorDeviceId(runner.deviceId);
|
|
21
|
+
logger.debug(`Device ID: ${deviceId}`);
|
|
19
22
|
if (!deviceId) {
|
|
20
23
|
throw new Error('Emulator not found');
|
|
21
24
|
}
|
|
@@ -24,28 +27,29 @@ const androidPlatformAdapter = {
|
|
|
24
27
|
reversePort(8080),
|
|
25
28
|
reversePort(3001),
|
|
26
29
|
]);
|
|
27
|
-
|
|
30
|
+
logger.debug('Ports reversed');
|
|
31
|
+
const isInstalled = await isAppInstalled(deviceId, runner.bundleId);
|
|
32
|
+
logger.debug(`App is installed: ${isInstalled}`);
|
|
28
33
|
if (!isInstalled) {
|
|
29
|
-
|
|
34
|
+
throw new AppNotInstalledError(runner.deviceId, runner.bundleId, 'android');
|
|
30
35
|
}
|
|
31
|
-
|
|
32
|
-
await runApp(deviceId, config.runner.bundleId);
|
|
33
|
-
}
|
|
34
|
-
const interactionEngine = await interactionEnginePromise;
|
|
36
|
+
logger.debug('Waiting for Metro to start');
|
|
35
37
|
const metro = await metroPromise;
|
|
38
|
+
logger.debug('Metro started');
|
|
39
|
+
logger.debug('Running app');
|
|
40
|
+
await runApp(deviceId, runner.bundleId, runner.activityName);
|
|
41
|
+
logger.debug('App running');
|
|
36
42
|
return {
|
|
37
43
|
restart: async () => {
|
|
38
|
-
await runApp(
|
|
44
|
+
await runApp(deviceId, runner.bundleId, runner.activityName);
|
|
39
45
|
},
|
|
40
46
|
dispose: async () => {
|
|
47
|
+
await killApp(deviceId, runner.bundleId);
|
|
41
48
|
if (emulator) {
|
|
42
49
|
await killWithAwait(emulator);
|
|
43
50
|
}
|
|
44
|
-
await interactionEngine.close();
|
|
45
51
|
await killWithAwait(metro);
|
|
46
|
-
await killApp(deviceId, config.runner.bundleId);
|
|
47
52
|
},
|
|
48
|
-
interactionEngine,
|
|
49
53
|
};
|
|
50
54
|
},
|
|
51
55
|
};
|