@react-native-harness/cli 1.1.0 → 1.2.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/__tests__/platform-commands.test.d.ts +2 -0
- package/dist/__tests__/platform-commands.test.d.ts.map +1 -0
- package/dist/__tests__/platform-commands.test.js +207 -0
- package/dist/bundlers/metro.d.ts +5 -0
- package/dist/bundlers/metro.d.ts.map +1 -0
- package/dist/bundlers/metro.js +71 -0
- package/dist/bundlers/webpack.d.ts +2 -0
- package/dist/bundlers/webpack.d.ts.map +1 -0
- package/dist/bundlers/webpack.js +49 -0
- 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 +113 -6
- package/dist/jest.d.ts +2 -0
- package/dist/jest.d.ts.map +1 -0
- package/dist/jest.js +7 -0
- package/dist/platform-commands.d.ts +18 -0
- package/dist/platform-commands.d.ts.map +1 -0
- package/dist/platform-commands.js +84 -0
- package/dist/platforms/android/build.d.ts +5 -0
- package/dist/platforms/android/build.d.ts.map +1 -0
- package/dist/platforms/android/build.js +29 -0
- 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 +10 -0
- package/dist/platforms/android/emulator.d.ts.map +1 -0
- package/dist/platforms/android/emulator.js +116 -0
- package/dist/platforms/android/index.d.ts +4 -0
- package/dist/platforms/android/index.d.ts.map +1 -0
- package/dist/platforms/android/index.js +56 -0
- package/dist/platforms/ios/build.d.ts +7 -0
- package/dist/platforms/ios/build.d.ts.map +1 -0
- package/dist/platforms/ios/build.js +48 -0
- 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 +4 -0
- package/dist/platforms/ios/index.d.ts.map +1 -0
- package/dist/platforms/ios/index.js +43 -0
- package/dist/platforms/ios/simulator.d.ts +11 -0
- package/dist/platforms/ios/simulator.d.ts.map +1 -0
- package/dist/platforms/ios/simulator.js +129 -0
- package/dist/platforms/platform-adapter.d.ts +10 -0
- package/dist/platforms/platform-adapter.d.ts.map +1 -0
- package/dist/platforms/platform-adapter.js +1 -0
- package/dist/platforms/platform-registry.d.ts +3 -0
- package/dist/platforms/platform-registry.d.ts.map +1 -0
- package/dist/platforms/platform-registry.js +21 -0
- 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 +4 -0
- package/dist/platforms/web/index.d.ts.map +1 -0
- package/dist/platforms/web/index.js +9 -0
- package/dist/process.d.ts +3 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +28 -0
- package/dist/reporters/default-reporter.d.ts +3 -0
- package/dist/reporters/default-reporter.d.ts.map +1 -0
- package/dist/reporters/default-reporter.js +116 -0
- 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.js +1 -1
- 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/eslint.config.mjs +1 -1
- package/package.json +8 -8
- package/skills/core.md +92 -0
- package/skills/mocking.md +87 -0
- package/skills/ui.md +59 -0
- package/src/__tests__/platform-commands.test.ts +232 -0
- package/src/index.ts +152 -5
- package/src/platform-commands.ts +148 -0
- package/src/wizard/bundleId.ts +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ConfigLoadError, ConfigNotFoundError, ConfigValidationError, } from '@react-native-harness/config';
|
|
2
|
+
import { AssertionError } from '../utils.js';
|
|
3
|
+
import { NoRunnerSpecifiedError, RunnerNotFoundError, EnvironmentInitializationError, TestExecutionError, RpcClientError, BridgeTimeoutError, BundlingFailedError, MetroPortUnavailableError, } from './errors.js';
|
|
4
|
+
export const formatError = (error) => {
|
|
5
|
+
const lines = [];
|
|
6
|
+
if (error instanceof AssertionError) {
|
|
7
|
+
lines.push(`\n❌ Assertion Error`);
|
|
8
|
+
lines.push(`\nError: ${error.message}`);
|
|
9
|
+
lines.push(`\nPlease check your configuration and try again.`);
|
|
10
|
+
}
|
|
11
|
+
else if (error instanceof ConfigValidationError) {
|
|
12
|
+
lines.push(`\n❌ Configuration Error`);
|
|
13
|
+
lines.push(`\nFile: ${error.filePath}`);
|
|
14
|
+
lines.push(`\nValidation errors:`);
|
|
15
|
+
error.validationErrors.forEach((err) => {
|
|
16
|
+
lines.push(` • ${err}`);
|
|
17
|
+
});
|
|
18
|
+
lines.push(`\nPlease fix the configuration errors and try again.`);
|
|
19
|
+
}
|
|
20
|
+
else if (error instanceof ConfigNotFoundError) {
|
|
21
|
+
lines.push(`\n❌ Configuration Not Found`);
|
|
22
|
+
lines.push(`\nCould not find 'rn-harness.config' in '${error.searchPath}' or any parent directories.`);
|
|
23
|
+
lines.push(`\nSupported file extensions: .js, .mjs, .cjs, .json`);
|
|
24
|
+
lines.push(`\nPlease create a configuration file or run from a directory that contains one.`);
|
|
25
|
+
}
|
|
26
|
+
else if (error instanceof ConfigLoadError) {
|
|
27
|
+
lines.push(`\n❌ Configuration Load Error`);
|
|
28
|
+
lines.push(`\nFile: ${error.filePath}`);
|
|
29
|
+
lines.push(`Error: ${error.message}`);
|
|
30
|
+
if (error.cause) {
|
|
31
|
+
lines.push(`\nCause: ${error.cause.message}`);
|
|
32
|
+
}
|
|
33
|
+
lines.push(`\nPlease check your configuration file syntax and try again.`);
|
|
34
|
+
}
|
|
35
|
+
else if (error instanceof NoRunnerSpecifiedError) {
|
|
36
|
+
lines.push('\n❌ No runner specified');
|
|
37
|
+
lines.push('\nPlease specify a runner name or set a defaultRunner in your config.');
|
|
38
|
+
lines.push('\nUsage: react-native-harness test [runner-name] [pattern]');
|
|
39
|
+
lines.push('\nAvailable runners:');
|
|
40
|
+
error.availableRunners.forEach((r) => {
|
|
41
|
+
lines.push(` • ${r.name} (${r.platform})`);
|
|
42
|
+
});
|
|
43
|
+
lines.push('\nTo set a default runner, add "defaultRunner" to your config:');
|
|
44
|
+
lines.push(' { "defaultRunner": "your-runner-name" }');
|
|
45
|
+
}
|
|
46
|
+
else if (error instanceof RunnerNotFoundError) {
|
|
47
|
+
lines.push(`\n❌ Runner "${error.runnerName}" not found`);
|
|
48
|
+
lines.push('\nAvailable runners:');
|
|
49
|
+
error.availableRunners.forEach((r) => {
|
|
50
|
+
lines.push(` • ${r.name} (${r.platform})`);
|
|
51
|
+
});
|
|
52
|
+
lines.push('\nTo add a new runner, update your rn-harness.config file.');
|
|
53
|
+
}
|
|
54
|
+
else if (error instanceof EnvironmentInitializationError) {
|
|
55
|
+
lines.push(`\n❌ Environment Initialization Error`);
|
|
56
|
+
lines.push(`\nRunner: ${error.runnerName} (${error.platform})`);
|
|
57
|
+
lines.push(`\nError: ${error.message}`);
|
|
58
|
+
if (error.details) {
|
|
59
|
+
lines.push(`\nDetails: ${error.details}`);
|
|
60
|
+
}
|
|
61
|
+
lines.push(`\nTroubleshooting steps:`);
|
|
62
|
+
lines.push(` • Verify that ${error.platform} development environment is properly set up`);
|
|
63
|
+
lines.push(` • Check that the app is built and ready for testing`);
|
|
64
|
+
lines.push(` • Ensure all required dependencies are installed`);
|
|
65
|
+
if (error.platform === 'ios') {
|
|
66
|
+
lines.push(` • Verify Xcode and iOS Simulator are working correctly`);
|
|
67
|
+
}
|
|
68
|
+
else if (error.platform === 'android') {
|
|
69
|
+
lines.push(` • Verify Android SDK and emulator are working correctly`);
|
|
70
|
+
}
|
|
71
|
+
lines.push(`\nPlease check your environment configuration and try again.`);
|
|
72
|
+
}
|
|
73
|
+
else if (error instanceof TestExecutionError) {
|
|
74
|
+
lines.push(`\n❌ Test Execution Error`);
|
|
75
|
+
lines.push(`\nFile: ${error.testFile}`);
|
|
76
|
+
if (error.testSuite) {
|
|
77
|
+
lines.push(`\nSuite: ${error.testSuite}`);
|
|
78
|
+
}
|
|
79
|
+
if (error.testName) {
|
|
80
|
+
lines.push(`\nTest: ${error.testName}`);
|
|
81
|
+
}
|
|
82
|
+
lines.push(`\nError: ${error.message}`);
|
|
83
|
+
lines.push(`\nTroubleshooting steps:`);
|
|
84
|
+
lines.push(` • Check the test file syntax and logic`);
|
|
85
|
+
lines.push(` • Verify all test dependencies are available`);
|
|
86
|
+
lines.push(` • Ensure the app is in the expected state for the test`);
|
|
87
|
+
lines.push(` • Check device/emulator logs for additional error details`);
|
|
88
|
+
lines.push(`\nPlease check your test file and try again.`);
|
|
89
|
+
}
|
|
90
|
+
else if (error instanceof RpcClientError) {
|
|
91
|
+
lines.push(`\n❌ RPC Client Error`);
|
|
92
|
+
lines.push(`\nError: ${error.message}`);
|
|
93
|
+
if (error.bridgePort) {
|
|
94
|
+
lines.push(`\nBridge Port: ${error.bridgePort}`);
|
|
95
|
+
}
|
|
96
|
+
if (error.connectionStatus) {
|
|
97
|
+
lines.push(`\nConnection Status: ${error.connectionStatus}`);
|
|
98
|
+
}
|
|
99
|
+
lines.push(`\nTroubleshooting steps:`);
|
|
100
|
+
lines.push(` • Verify the React Native app is running and connected`);
|
|
101
|
+
lines.push(` • Check that the bridge port is not blocked by firewall`);
|
|
102
|
+
lines.push(` • Ensure the app has the React Native Harness runtime integrated`);
|
|
103
|
+
lines.push(` • Try restarting the app and test harness`);
|
|
104
|
+
lines.push(`\nPlease check your bridge connection and try again.`);
|
|
105
|
+
}
|
|
106
|
+
else if (error instanceof BundlingFailedError) {
|
|
107
|
+
lines.push(`\n❌ Test File Bundling Error`);
|
|
108
|
+
lines.push(`\nFile: ${error.modulePath}`);
|
|
109
|
+
lines.push(`\nError: ${error.reason}`);
|
|
110
|
+
lines.push(`\nTroubleshooting steps:`);
|
|
111
|
+
lines.push(` • Check the test file syntax and imports`);
|
|
112
|
+
lines.push(` • Verify all imported modules exist and are accessible`);
|
|
113
|
+
lines.push(` • Ensure the Metro bundler configuration is correct`);
|
|
114
|
+
lines.push(` • Check for any circular dependencies in the test file`);
|
|
115
|
+
lines.push(` • Verify that all required packages are installed`);
|
|
116
|
+
lines.push(`\nPlease fix the bundling issues and try again.`);
|
|
117
|
+
}
|
|
118
|
+
else if (error instanceof BridgeTimeoutError) {
|
|
119
|
+
lines.push(`\n❌ Bridge Connection Timeout`);
|
|
120
|
+
lines.push(`\nThe bridge connection timed out after ${error.timeout}ms while waiting for the "${error.runnerName}" (${error.platform}) runner to be ready.`);
|
|
121
|
+
lines.push(`\nThis usually indicates that:`);
|
|
122
|
+
lines.push(` • The React Native app failed to load or connect to the bridge`);
|
|
123
|
+
lines.push(` • The app crashed during startup`);
|
|
124
|
+
lines.push(` • Network connectivity issues between the app and the test harness`);
|
|
125
|
+
lines.push(` • The app is taking longer than expected to initialize`);
|
|
126
|
+
lines.push(`\nTo resolve this issue:`);
|
|
127
|
+
lines.push(` • Check that the app is properly installed and can start normally`);
|
|
128
|
+
lines.push(` • Verify that the app has the React Native Harness runtime integrated`);
|
|
129
|
+
lines.push(` • Check device/emulator logs for any startup errors`);
|
|
130
|
+
lines.push(` • Ensure the test harness bridge port (3001) is not blocked`);
|
|
131
|
+
lines.push(`\nIf the app needs more time to start, consider increasing the timeout in the configuration.`);
|
|
132
|
+
}
|
|
133
|
+
else if (error instanceof MetroPortUnavailableError) {
|
|
134
|
+
lines.push(`\n❌ Metro Port Unavailable`);
|
|
135
|
+
lines.push(`\nPort ${error.port} is already in use or unavailable.`);
|
|
136
|
+
lines.push(`\nThis usually indicates that:`);
|
|
137
|
+
lines.push(` • Another Metro bundler instance is already running`);
|
|
138
|
+
lines.push(` • Another application is using port ${error.port}`);
|
|
139
|
+
lines.push(` • The port is blocked by a firewall or security software`);
|
|
140
|
+
lines.push(`\nTo resolve this issue:`);
|
|
141
|
+
lines.push(` • Stop any running Metro bundler instances`);
|
|
142
|
+
lines.push(` • Check for other applications using port ${error.port}: lsof -i :${error.port}`);
|
|
143
|
+
lines.push(` • Kill the process using the port: kill -9 <PID>`);
|
|
144
|
+
lines.push(` • Or use a different port by updating your Metro configuration`);
|
|
145
|
+
lines.push(`\nPlease free up the port and try again.`);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// Re-throw the error to be handled by the caller
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
return lines.join('');
|
|
152
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
type TestRunnerConfig = any;
|
|
2
|
+
export declare class NoRunnerSpecifiedError extends Error {
|
|
3
|
+
constructor(availableRunners: TestRunnerConfig[]);
|
|
4
|
+
availableRunners: TestRunnerConfig[];
|
|
5
|
+
}
|
|
6
|
+
export declare class RunnerNotFoundError extends Error {
|
|
7
|
+
constructor(runnerName: string, availableRunners: TestRunnerConfig[]);
|
|
8
|
+
runnerName: string;
|
|
9
|
+
availableRunners: TestRunnerConfig[];
|
|
10
|
+
}
|
|
11
|
+
export declare class EnvironmentInitializationError extends Error {
|
|
12
|
+
constructor(message: string, runnerName: string, platform: string, details?: string);
|
|
13
|
+
runnerName: string;
|
|
14
|
+
platform: string;
|
|
15
|
+
details?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class TestExecutionError extends Error {
|
|
18
|
+
constructor(testFile: string, error: unknown, testSuite?: string, testName?: string);
|
|
19
|
+
testFile: string;
|
|
20
|
+
testSuite?: string;
|
|
21
|
+
testName?: string;
|
|
22
|
+
originalError: unknown;
|
|
23
|
+
}
|
|
24
|
+
export declare class RpcClientError extends Error {
|
|
25
|
+
constructor(message: string, bridgePort?: number, connectionStatus?: string);
|
|
26
|
+
bridgePort?: number;
|
|
27
|
+
connectionStatus?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class BridgeTimeoutError extends Error {
|
|
30
|
+
readonly timeout: number;
|
|
31
|
+
readonly runnerName: string;
|
|
32
|
+
readonly platform: string;
|
|
33
|
+
constructor(timeout: number, runnerName: string, platform: string);
|
|
34
|
+
}
|
|
35
|
+
export declare class BundlingFailedError extends Error {
|
|
36
|
+
readonly modulePath: string;
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
constructor(modulePath: string, reason: string);
|
|
39
|
+
}
|
|
40
|
+
export declare class MetroPortUnavailableError extends Error {
|
|
41
|
+
readonly port: number;
|
|
42
|
+
constructor(port: number);
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"AAAA,KAAK,gBAAgB,GAAG,GAAG,CAAC;AAE5B,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,gBAAgB,EAAE,gBAAgB,EAAE;IAKhD,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;CACtC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE;IAMpE,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;CACtC;AAED,qBAAa,8BAA+B,SAAQ,KAAK;gBAErD,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM;IAUlB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAEzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM;IAenB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM;IAS3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;aAEzB,OAAO,EAAE,MAAM;aACf,UAAU,EAAE,MAAM;aAClB,QAAQ,EAAE,MAAM;gBAFhB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM;CAOnC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;gBADd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;CAKjC;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIzC"}
|
|
@@ -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,101 @@
|
|
|
1
1
|
import { run, yargsOptions } from 'jest-cli';
|
|
2
2
|
import { getConfig } from '@react-native-harness/config';
|
|
3
3
|
import { runInitWizard } from './wizard/index.js';
|
|
4
|
+
import { runPlatformCommand } from './platform-commands.js';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
6
|
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
6
8
|
const JEST_CONFIG_EXTENSIONS = ['.mjs', '.js', '.cjs'];
|
|
7
9
|
const JEST_HARNESS_CONFIG_BASE = 'jest.harness.config';
|
|
10
|
+
const SKILLS_DIRECTORY = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../skills');
|
|
11
|
+
const readSkillMetadata = (fileName) => {
|
|
12
|
+
const filePath = path.join(SKILLS_DIRECTORY, fileName);
|
|
13
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
14
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
15
|
+
const metadata = {
|
|
16
|
+
name: fileName.replace(/\.md$/, ''),
|
|
17
|
+
description: '',
|
|
18
|
+
};
|
|
19
|
+
if (frontmatterMatch) {
|
|
20
|
+
for (const line of frontmatterMatch[1].split('\n')) {
|
|
21
|
+
const separatorIndex = line.indexOf(':');
|
|
22
|
+
if (separatorIndex === -1) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
26
|
+
const value = line.slice(separatorIndex + 1).trim().replace(/^['"]|['"]$/g, '');
|
|
27
|
+
if (key === 'name') {
|
|
28
|
+
metadata.name = value;
|
|
29
|
+
}
|
|
30
|
+
if (key === 'description') {
|
|
31
|
+
metadata.description = value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
fileName,
|
|
37
|
+
name: metadata.name,
|
|
38
|
+
description: metadata.description,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const listSkills = () => fs
|
|
42
|
+
.readdirSync(SKILLS_DIRECTORY)
|
|
43
|
+
.filter((file) => file.endsWith('.md'))
|
|
44
|
+
.map(readSkillMetadata)
|
|
45
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
46
|
+
const printSkillList = () => {
|
|
47
|
+
for (const skill of listSkills()) {
|
|
48
|
+
console.log(`${skill.name}: ${skill.description}`);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const printSkillUsage = () => {
|
|
52
|
+
console.log(`Usage: harness skill <command>
|
|
53
|
+
|
|
54
|
+
Commands:
|
|
55
|
+
list List bundled skills
|
|
56
|
+
get <name> Print a bundled skill file
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
harness skill list
|
|
60
|
+
harness skill get core`);
|
|
61
|
+
};
|
|
62
|
+
const getErrorMessage = (error) => {
|
|
63
|
+
if (error instanceof Error) {
|
|
64
|
+
return error.message;
|
|
65
|
+
}
|
|
66
|
+
return String(error);
|
|
67
|
+
};
|
|
68
|
+
const runSkillCommand = () => {
|
|
69
|
+
const [, , commandName, subcommand, skillName] = process.argv;
|
|
70
|
+
if (subcommand === undefined || subcommand === 'list') {
|
|
71
|
+
printSkillList();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (subcommand === '--help' || subcommand === '-h') {
|
|
75
|
+
printSkillUsage();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (subcommand === 'get') {
|
|
79
|
+
if (!skillName) {
|
|
80
|
+
console.error('Missing skill name.');
|
|
81
|
+
printSkillUsage();
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const skillPath = path.join(SKILLS_DIRECTORY, `${skillName}.md`);
|
|
85
|
+
if (!fs.existsSync(skillPath)) {
|
|
86
|
+
console.error(`Unknown skill '${skillName}'.`);
|
|
87
|
+
console.error(`Available skills: ${listSkills()
|
|
88
|
+
.map((skill) => skill.name)
|
|
89
|
+
.join(', ')}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
console.log(fs.readFileSync(skillPath, 'utf8'));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
console.error(`Unknown ${commandName} subcommand '${subcommand}'.`);
|
|
96
|
+
printSkillUsage();
|
|
97
|
+
process.exit(1);
|
|
98
|
+
};
|
|
8
99
|
const checkForOldConfig = async () => {
|
|
9
100
|
try {
|
|
10
101
|
const { config } = await getConfig(process.cwd());
|
|
@@ -62,10 +153,21 @@ const patchYargsOptions = () => {
|
|
|
62
153
|
delete yargsOptions.coverageProvider;
|
|
63
154
|
delete yargsOptions.logHeapUsage;
|
|
64
155
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
156
|
+
const main = async () => {
|
|
157
|
+
if (process.argv[2] === 'skill' || process.argv[2] === 'skills') {
|
|
158
|
+
runSkillCommand();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (process.argv.includes('init')) {
|
|
162
|
+
runInitWizard();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (await runPlatformCommand({
|
|
166
|
+
argv: process.argv.slice(2),
|
|
167
|
+
cwd: process.cwd(),
|
|
168
|
+
})) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
69
171
|
patchYargsOptions();
|
|
70
172
|
const hasConfigArg = process.argv.includes('--config') || process.argv.includes('-c');
|
|
71
173
|
if (!hasConfigArg) {
|
|
@@ -74,5 +176,10 @@ else {
|
|
|
74
176
|
process.argv.push('--config', `${JEST_HARNESS_CONFIG_BASE}${existingConfigExt}`);
|
|
75
177
|
}
|
|
76
178
|
}
|
|
77
|
-
checkForOldConfig()
|
|
78
|
-
|
|
179
|
+
await checkForOldConfig();
|
|
180
|
+
run();
|
|
181
|
+
};
|
|
182
|
+
main().catch((error) => {
|
|
183
|
+
console.error(getErrorMessage(error));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
});
|
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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getConfig } from '@react-native-harness/config';
|
|
2
|
+
import type { HarnessCliCommand } from '@react-native-harness/platforms';
|
|
3
|
+
type ConfigLoader = typeof getConfig;
|
|
4
|
+
type DiscoveredPlatformCommands = {
|
|
5
|
+
commands: HarnessCliCommand[];
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const discoverPlatformCommands: (options: {
|
|
9
|
+
cwd: string;
|
|
10
|
+
loadConfig?: ConfigLoader;
|
|
11
|
+
}) => Promise<DiscoveredPlatformCommands | null>;
|
|
12
|
+
export declare const runPlatformCommand: (options: {
|
|
13
|
+
argv: string[];
|
|
14
|
+
cwd: string;
|
|
15
|
+
loadConfig?: ConfigLoader;
|
|
16
|
+
}) => Promise<boolean>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=platform-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-commands.d.ts","sourceRoot":"","sources":["../src/platform-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,KAAK,YAAY,GAAG,OAAO,SAAS,CAAC;AAErC,KAAK,0BAA0B,GAAG;IAChC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAsEF,eAAO,MAAM,wBAAwB,GAAU,SAAS;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,KAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAgC5C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,SAAS;IAChD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,KAAG,OAAO,CAAC,OAAO,CA4BlB,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ConfigNotFoundError, getConfig } from '@react-native-harness/config';
|
|
2
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
3
|
+
const getModuleCommands = (importedModule, modulePath) => {
|
|
4
|
+
const moduleValue = isRecord(importedModule)
|
|
5
|
+
? importedModule
|
|
6
|
+
: {};
|
|
7
|
+
const defaultExport = isRecord(moduleValue.default)
|
|
8
|
+
? moduleValue.default
|
|
9
|
+
: undefined;
|
|
10
|
+
const commandsValue = moduleValue.commands ?? defaultExport?.commands;
|
|
11
|
+
if (!Array.isArray(commandsValue)) {
|
|
12
|
+
throw new Error(`Invalid platform CLI module '${modulePath}': expected a commands array.`);
|
|
13
|
+
}
|
|
14
|
+
return commandsValue.map((command, index) => {
|
|
15
|
+
if (!isRecord(command) || typeof command.name !== 'string') {
|
|
16
|
+
throw new Error(`Invalid platform CLI module '${modulePath}': command #${index + 1} is missing a valid name.`);
|
|
17
|
+
}
|
|
18
|
+
if (typeof command.run !== 'function') {
|
|
19
|
+
throw new Error(`Invalid platform CLI module '${modulePath}': command '${command.name}' is missing a run handler.`);
|
|
20
|
+
}
|
|
21
|
+
if (command.aliases !== undefined &&
|
|
22
|
+
(!Array.isArray(command.aliases) ||
|
|
23
|
+
command.aliases.some((alias) => typeof alias !== 'string'))) {
|
|
24
|
+
throw new Error(`Invalid platform CLI module '${modulePath}': command '${command.name}' has invalid aliases.`);
|
|
25
|
+
}
|
|
26
|
+
return command;
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const registerCommandNames = (seenNames, modulePath, command) => {
|
|
30
|
+
const names = [command.name, ...(command.aliases ?? [])];
|
|
31
|
+
for (const name of names) {
|
|
32
|
+
const existingSource = seenNames.get(name);
|
|
33
|
+
if (existingSource !== undefined) {
|
|
34
|
+
throw new Error(`Duplicate platform CLI command '${name}' in '${modulePath}' and '${existingSource}'.`);
|
|
35
|
+
}
|
|
36
|
+
seenNames.set(name, modulePath);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
export const discoverPlatformCommands = async (options) => {
|
|
40
|
+
const loadConfig = options.loadConfig ?? getConfig;
|
|
41
|
+
try {
|
|
42
|
+
const { config, projectRoot } = await loadConfig(options.cwd);
|
|
43
|
+
const modulePaths = [...new Set(config.runners.map((runner) => runner.cli))].filter((modulePath) => typeof modulePath === 'string');
|
|
44
|
+
const commands = [];
|
|
45
|
+
const seenNames = new Map();
|
|
46
|
+
for (const modulePath of modulePaths) {
|
|
47
|
+
const importedModule = await import(modulePath);
|
|
48
|
+
const moduleCommands = getModuleCommands(importedModule, modulePath);
|
|
49
|
+
for (const command of moduleCommands) {
|
|
50
|
+
registerCommandNames(seenNames, modulePath, command);
|
|
51
|
+
commands.push(command);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
commands,
|
|
56
|
+
projectRoot,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof ConfigNotFoundError) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
export const runPlatformCommand = async (options) => {
|
|
67
|
+
const commandName = options.argv[0];
|
|
68
|
+
if (typeof commandName !== 'string' || commandName.length === 0) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const discoveredCommands = await discoverPlatformCommands(options);
|
|
72
|
+
if (discoveredCommands === null) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const command = discoveredCommands.commands.find((entry) => entry.name === commandName || entry.aliases?.includes(commandName) === true);
|
|
76
|
+
if (command === undefined) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
await command.run(options.argv.slice(1), {
|
|
80
|
+
cwd: options.cwd,
|
|
81
|
+
projectRoot: discoveredCommands.projectRoot,
|
|
82
|
+
});
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const buildAndroidApp: () => Promise<void>;
|
|
2
|
+
export declare const installApp: (deviceId: string) => Promise<void>;
|
|
3
|
+
export declare const killApp: (deviceId: string, bundleId: string) => Promise<void>;
|
|
4
|
+
export declare const runApp: (deviceId: string, bundleId: string, activityName: string) => Promise<void>;
|
|
5
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
]);
|
|
14
|
+
};
|
|
15
|
+
export const killApp = async (deviceId, bundleId) => {
|
|
16
|
+
await spawn('adb', ['-s', deviceId, 'shell', 'am', 'force-stop', bundleId]);
|
|
17
|
+
};
|
|
18
|
+
export const runApp = async (deviceId, bundleId, activityName) => {
|
|
19
|
+
await killApp(deviceId, bundleId);
|
|
20
|
+
await spawn('adb', [
|
|
21
|
+
'-s',
|
|
22
|
+
deviceId,
|
|
23
|
+
'shell',
|
|
24
|
+
'am',
|
|
25
|
+
'start',
|
|
26
|
+
'-n',
|
|
27
|
+
`${bundleId}/${activityName}`,
|
|
28
|
+
]);
|
|
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
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ChildProcess } from 'node:child_process';
|
|
2
|
+
export type AndroidEmulatorStatus = 'running' | 'loading' | 'stopped';
|
|
3
|
+
export declare const getEmulatorNameFromId: (emulatorId: string) => Promise<string | null>;
|
|
4
|
+
export declare const getEmulatorDeviceId: (avdName: string) => Promise<string | null>;
|
|
5
|
+
export declare const getEmulatorStatus: (avdName: string) => Promise<AndroidEmulatorStatus>;
|
|
6
|
+
export declare const runEmulator: (name: string) => Promise<ChildProcess>;
|
|
7
|
+
export declare const stopEmulator: (avdName: string) => Promise<void>;
|
|
8
|
+
export declare const isAppInstalled: (emulatorId: string, bundleId: string) => Promise<boolean>;
|
|
9
|
+
export declare const reversePort: (port: number) => Promise<void>;
|
|
10
|
+
//# sourceMappingURL=emulator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|