appium-adb 14.1.2 → 14.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/tools/aab-utils.d.ts +5 -4
  3. package/build/lib/tools/aab-utils.d.ts.map +1 -1
  4. package/build/lib/tools/aab-utils.js +13 -11
  5. package/build/lib/tools/aab-utils.js.map +1 -1
  6. package/build/lib/tools/android-manifest.d.ts +26 -30
  7. package/build/lib/tools/android-manifest.d.ts.map +1 -1
  8. package/build/lib/tools/android-manifest.js +33 -47
  9. package/build/lib/tools/android-manifest.js.map +1 -1
  10. package/build/lib/tools/apks-utils.d.ts +25 -29
  11. package/build/lib/tools/apks-utils.d.ts.map +1 -1
  12. package/build/lib/tools/apks-utils.js +41 -52
  13. package/build/lib/tools/apks-utils.js.map +1 -1
  14. package/build/lib/tools/emulator-commands.d.ts.map +1 -1
  15. package/build/lib/tools/emulator-commands.js +2 -1
  16. package/build/lib/tools/emulator-commands.js.map +1 -1
  17. package/build/lib/tools/fs-commands.d.ts +25 -30
  18. package/build/lib/tools/fs-commands.d.ts.map +1 -1
  19. package/build/lib/tools/fs-commands.js +19 -26
  20. package/build/lib/tools/fs-commands.js.map +1 -1
  21. package/build/lib/tools/general-commands.d.ts +36 -58
  22. package/build/lib/tools/general-commands.d.ts.map +1 -1
  23. package/build/lib/tools/general-commands.js +41 -47
  24. package/build/lib/tools/general-commands.js.map +1 -1
  25. package/build/lib/tools/keyboard-commands.d.ts +27 -36
  26. package/build/lib/tools/keyboard-commands.d.ts.map +1 -1
  27. package/build/lib/tools/keyboard-commands.js +24 -34
  28. package/build/lib/tools/keyboard-commands.js.map +1 -1
  29. package/build/lib/tools/lockmgmt.d.ts +25 -36
  30. package/build/lib/tools/lockmgmt.d.ts.map +1 -1
  31. package/build/lib/tools/lockmgmt.js +34 -38
  32. package/build/lib/tools/lockmgmt.js.map +1 -1
  33. package/build/lib/tools/logcat-commands.d.ts +11 -30
  34. package/build/lib/tools/logcat-commands.d.ts.map +1 -1
  35. package/build/lib/tools/logcat-commands.js +16 -17
  36. package/build/lib/tools/logcat-commands.js.map +1 -1
  37. package/build/lib/tools/network-commands.d.ts +24 -31
  38. package/build/lib/tools/network-commands.d.ts.map +1 -1
  39. package/build/lib/tools/network-commands.js +14 -24
  40. package/build/lib/tools/network-commands.js.map +1 -1
  41. package/lib/tools/{aab-utils.js → aab-utils.ts} +24 -15
  42. package/lib/tools/{android-manifest.js → android-manifest.ts} +66 -59
  43. package/lib/tools/{apks-utils.js → apks-utils.ts} +76 -68
  44. package/lib/tools/emulator-commands.ts +3 -2
  45. package/lib/tools/{fs-commands.js → fs-commands.ts} +41 -35
  46. package/lib/tools/{general-commands.js → general-commands.ts} +71 -68
  47. package/lib/tools/{keyboard-commands.js → keyboard-commands.ts} +42 -49
  48. package/lib/tools/{lockmgmt.js → lockmgmt.ts} +71 -56
  49. package/lib/tools/{logcat-commands.js → logcat-commands.ts} +24 -22
  50. package/lib/tools/{network-commands.js → network-commands.ts} +42 -34
  51. package/package.json +2 -2
@@ -4,17 +4,21 @@ import {log} from '../logger.js';
4
4
  import {unzipFile, APKS_EXTENSION, readPackageManifest} from '../helpers.js';
5
5
  import {fs, zip, tempDir, util} from '@appium/support';
6
6
  import path from 'path';
7
+ import type {ADB} from '../adb.js';
8
+ import type {APKInfo, PlatformInfo, StringRecord} from './types.js';
7
9
 
8
10
  /**
9
11
  * Extract package and main activity name from application manifest.
10
12
  *
11
- * @this {import('../adb.js').ADB}
12
- * @param {string} appPath - The full path to application .apk(s) package
13
- * @return {Promise<import('./types').APKInfo>} The parsed application info.
13
+ * @param appPath - The full path to application .apk(s) package
14
+ * @return The parsed application info.
14
15
  * @throws {error} If there was an error while getting the data from the given
15
16
  * application package.
16
17
  */
17
- export async function packageAndLaunchActivityFromManifest(appPath) {
18
+ export async function packageAndLaunchActivityFromManifest(
19
+ this: ADB,
20
+ appPath: string,
21
+ ): Promise<APKInfo> {
18
22
  if (appPath.endsWith(APKS_EXTENSION)) {
19
23
  appPath = await this.extractBaseApk(appPath);
20
24
  }
@@ -31,13 +35,12 @@ export async function packageAndLaunchActivityFromManifest(appPath) {
31
35
  /**
32
36
  * Extract target SDK version from application manifest.
33
37
  *
34
- * @this {import('../adb.js').ADB}
35
- * @param {string} appPath - The full path to .apk(s) package.
36
- * @return {Promise<number>} The version of the target SDK.
38
+ * @param appPath - The full path to .apk(s) package.
39
+ * @return The version of the target SDK.
37
40
  * @throws {error} If there was an error while getting the data from the given
38
41
  * application package.
39
42
  */
40
- export async function targetSdkVersionFromManifest(appPath) {
43
+ export async function targetSdkVersionFromManifest(this: ADB, appPath: string): Promise<number> {
41
44
  log.debug(`Extracting target SDK version of '${appPath}'`);
42
45
  const originalAppPath = appPath;
43
46
  if (appPath.endsWith(APKS_EXTENSION)) {
@@ -57,13 +60,16 @@ export async function targetSdkVersionFromManifest(appPath) {
57
60
  /**
58
61
  * Extract target SDK version from package information.
59
62
  *
60
- * @this {import('../adb.js').ADB}
61
- * @param {string} pkg - The class name of the package installed on the device under test.
62
- * @param {string?} [cmdOutput=null] - Optional parameter containing the output of
63
+ * @param pkg - The class name of the package installed on the device under test.
64
+ * @param cmdOutput - Optional parameter containing the output of
63
65
  * _dumpsys package_ command. It may speed up the method execution.
64
- * @return {Promise<number>} The version of the target SDK.
66
+ * @return The version of the target SDK.
65
67
  */
66
- export async function targetSdkVersionUsingPKG(pkg, cmdOutput = null) {
68
+ export async function targetSdkVersionUsingPKG(
69
+ this: ADB,
70
+ pkg: string,
71
+ cmdOutput: string | null = null,
72
+ ): Promise<number> {
67
73
  const stdout = cmdOutput || (await this.shell(['dumpsys', 'package', pkg]));
68
74
  const targetSdkVersionMatch = new RegExp(/targetSdk=([^\s\s]+)/g).exec(stdout);
69
75
  return targetSdkVersionMatch && targetSdkVersionMatch.length >= 2
@@ -76,14 +82,18 @@ export async function targetSdkVersionUsingPKG(pkg, cmdOutput = null) {
76
82
  * `${manifest}.apk` file will be created as the result of this method
77
83
  * containing the compiled manifest.
78
84
  *
79
- * @this {import('../adb.js').ADB}
80
- * @param {string} manifest - Full path to the initial manifest template
81
- * @param {string} manifestPackage - The name of the manifest package
82
- * @param {string} targetPackage - The name of the destination package
85
+ * @param manifest - Full path to the initial manifest template
86
+ * @param manifestPackage - The name of the manifest package
87
+ * @param targetPackage - The name of the destination package
83
88
  */
84
- export async function compileManifest(manifest, manifestPackage, targetPackage) {
89
+ export async function compileManifest(
90
+ this: ADB,
91
+ manifest: string,
92
+ manifestPackage: string,
93
+ targetPackage: string,
94
+ ): Promise<void> {
85
95
  const {platform, platformPath} = await getAndroidPlatformAndPath(
86
- /** @type {string} */ (this.sdkRoot),
96
+ this.sdkRoot as string,
87
97
  );
88
98
  if (!platform || !platformPath) {
89
99
  throw new Error(
@@ -98,6 +108,7 @@ export async function compileManifest(manifest, manifestPackage, targetPackage)
98
108
  try {
99
109
  await this.initAapt2();
100
110
  // https://developer.android.com/studio/command-line/aapt2
111
+ const binaries = this.binaries as StringRecord;
101
112
  const args = [
102
113
  'link',
103
114
  '-o',
@@ -113,18 +124,16 @@ export async function compileManifest(manifest, manifestPackage, targetPackage)
113
124
  '-v',
114
125
  ];
115
126
  log.debug(
116
- `Compiling the manifest using '${util.quote([
117
- /** @type {import('./types').StringRecord} */ (this.binaries).aapt2,
118
- ...args,
119
- ])}'`,
127
+ `Compiling the manifest using '${util.quote([binaries.aapt2, ...args])}'`,
120
128
  );
121
- await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt2, args);
129
+ await exec(binaries.aapt2, args);
122
130
  } catch (e) {
123
131
  log.debug(
124
132
  'Cannot compile the manifest using aapt2. Defaulting to aapt. ' +
125
- `Original error: ${e.stderr || e.message}`,
133
+ `Original error: ${(e as Error).message || (e as {stderr?: string}).stderr}`,
126
134
  );
127
135
  await this.initAapt();
136
+ const binaries = this.binaries as StringRecord;
128
137
  const args = [
129
138
  'package',
130
139
  '-M',
@@ -140,15 +149,14 @@ export async function compileManifest(manifest, manifestPackage, targetPackage)
140
149
  '-f',
141
150
  ];
142
151
  log.debug(
143
- `Compiling the manifest using '${util.quote([
144
- /** @type {import('./types').StringRecord} */ (this.binaries).aapt,
145
- ...args,
146
- ])}'`,
152
+ `Compiling the manifest using '${util.quote([binaries.aapt, ...args])}'`,
147
153
  );
148
154
  try {
149
- await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt, args);
155
+ await exec(binaries.aapt, args);
150
156
  } catch (e1) {
151
- throw new Error(`Cannot compile the manifest. Original error: ${e1.stderr || e1.message}`);
157
+ throw new Error(
158
+ `Cannot compile the manifest. Original error: ${(e1 as Error).message || (e1 as {stderr?: string}).stderr}`,
159
+ );
152
160
  }
153
161
  }
154
162
  log.debug(`Compiled the manifest at '${resultPath}'`);
@@ -158,41 +166,40 @@ export async function compileManifest(manifest, manifestPackage, targetPackage)
158
166
  * Replace/insert the specially precompiled manifest file into the
159
167
  * particular package.
160
168
  *
161
- * @this {import('../adb.js').ADB}
162
- * @param {string} manifest - Full path to the precompiled manifest
169
+ * @param manifest - Full path to the precompiled manifest
163
170
  * created by `compileManifest` method call
164
171
  * without .apk extension
165
- * @param {string} srcApk - Full path to the existing valid application package, where
172
+ * @param srcApk - Full path to the existing valid application package, where
166
173
  * this manifest has to be insetred to. This package
167
174
  * will NOT be modified.
168
- * @param {string} dstApk - Full path to the resulting package.
175
+ * @param dstApk - Full path to the resulting package.
169
176
  * The file will be overridden if it already exists.
170
177
  */
171
- export async function insertManifest(manifest, srcApk, dstApk) {
178
+ export async function insertManifest(
179
+ this: ADB,
180
+ manifest: string,
181
+ srcApk: string,
182
+ dstApk: string,
183
+ ): Promise<void> {
172
184
  log.debug(`Inserting manifest '${manifest}', src: '${srcApk}', dst: '${dstApk}'`);
173
185
  await zip.assertValidZip(srcApk);
174
186
  await unzipFile(`${manifest}.apk`);
175
187
  const manifestName = path.basename(manifest);
176
188
  try {
177
189
  await this.initAapt();
190
+ const binaries = this.binaries as StringRecord;
178
191
  await fs.copyFile(srcApk, dstApk);
179
192
  log.debug('Moving manifest');
180
193
  try {
181
- await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt, [
182
- 'remove',
183
- dstApk,
184
- manifestName,
185
- ]);
194
+ await exec(binaries.aapt, ['remove', dstApk, manifestName]);
186
195
  } catch {}
187
- await exec(
188
- /** @type {import('./types').StringRecord} */ (this.binaries).aapt,
189
- ['add', dstApk, manifestName],
190
- {cwd: path.dirname(manifest)},
191
- );
196
+ await exec(binaries.aapt, ['add', dstApk, manifestName], {
197
+ cwd: path.dirname(manifest),
198
+ });
192
199
  } catch (e) {
193
200
  log.debug(
194
201
  'Cannot insert manifest using aapt. Defaulting to zip. ' +
195
- `Original error: ${e.stderr || e.message}`,
202
+ `Original error: ${(e as Error).message || (e as {stderr?: string}).stderr}`,
196
203
  );
197
204
  const tmpRoot = await tempDir.openDir();
198
205
  try {
@@ -217,20 +224,20 @@ export async function insertManifest(manifest, srcApk, dstApk) {
217
224
  /**
218
225
  * Check whether package manifest contains Internet permissions.
219
226
  *
220
- * @this {import('../adb.js').ADB}
221
- * @param {string} appPath - The full path to .apk(s) package.
222
- * @return {Promise<boolean>} True if the manifest requires Internet access permission.
227
+ * @param appPath - The full path to .apk(s) package.
228
+ * @return True if the manifest requires Internet access permission.
223
229
  */
224
- export async function hasInternetPermissionFromManifest(appPath) {
230
+ export async function hasInternetPermissionFromManifest(
231
+ this: ADB,
232
+ appPath: string,
233
+ ): Promise<boolean> {
225
234
  log.debug(`Checking if '${appPath}' requires internet access permission in the manifest`);
226
235
  if (appPath.endsWith(APKS_EXTENSION)) {
227
236
  appPath = await this.extractBaseApk(appPath);
228
237
  }
229
238
 
230
239
  const {usesPermissions} = await readPackageManifest.bind(this)(appPath);
231
- return usesPermissions.some(
232
- (/** @type {string} */ name) => name === 'android.permission.INTERNET',
233
- );
240
+ return usesPermissions.some((name: string) => name === 'android.permission.INTERNET');
234
241
  }
235
242
 
236
243
  // #region Private functions
@@ -238,16 +245,15 @@ export async function hasInternetPermissionFromManifest(appPath) {
238
245
  /**
239
246
  * Retrieve the path to the recent installed Android platform.
240
247
  *
241
- * @param {string} sdkRoot
242
- * @return {Promise<import('./types').PlatformInfo>} The resulting path to the newest installed platform.
248
+ * @param sdkRoot
249
+ * @return The resulting path to the newest installed platform.
243
250
  */
244
- export async function getAndroidPlatformAndPath(sdkRoot) {
251
+ export async function getAndroidPlatformAndPath(sdkRoot: string): Promise<PlatformInfo> {
245
252
  const propsPaths = await fs.glob('*/build.prop', {
246
253
  cwd: path.resolve(sdkRoot, 'platforms'),
247
254
  absolute: true,
248
255
  });
249
- /** @type {Record<string, import('./types').PlatformInfo>} */
250
- const platformsMapping = {};
256
+ const platformsMapping: Record<string, PlatformInfo> = {};
251
257
  for (const propsPath of propsPaths) {
252
258
  const propsContent = await fs.readFile(propsPath, 'utf-8');
253
259
  const platformPath = path.dirname(propsPath);
@@ -280,3 +286,4 @@ export async function getAndroidPlatformAndPath(sdkRoot) {
280
286
  }
281
287
 
282
288
  // #endregion
289
+
@@ -7,13 +7,14 @@ import {LRUCache} from 'lru-cache';
7
7
  import {getJavaForOs, unzipFile, buildInstallArgs, APK_INSTALL_TIMEOUT} from '../helpers.js';
8
8
  import AsyncLock from 'async-lock';
9
9
  import B from 'bluebird';
10
+ import type {ADB} from '../adb.js';
11
+ import type {InstallMultipleApksOptions, InstallApksOptions, StringRecord} from './types.js';
10
12
 
11
13
  const BASE_APK = 'base-master.apk';
12
- const LANGUAGE_APK = (lang) => `base-${lang}.apk`;
13
- /** @type {LRUCache<string, string>} */
14
- const APKS_CACHE = new LRUCache({
14
+ const LANGUAGE_APK = (lang: string) => `base-${lang}.apk`;
15
+ const APKS_CACHE = new LRUCache<string, string>({
15
16
  max: 10,
16
- dispose: (extractedFilesRoot) => fs.rimraf(/** @type {string} */ (extractedFilesRoot)),
17
+ dispose: (extractedFilesRoot) => fs.rimraf(extractedFilesRoot),
17
18
  });
18
19
  const APKS_CACHE_GUARD = new AsyncLock();
19
20
  const BUNDLETOOL_TIMEOUT_MS = 4 * 60 * 1000;
@@ -24,7 +25,7 @@ process.on('exit', () => {
24
25
  return;
25
26
  }
26
27
 
27
- const paths = /** @type {string[]} */ ([...APKS_CACHE.values()]);
28
+ const paths = [...APKS_CACHE.values()];
28
29
  log.debug(
29
30
  `Performing cleanup of ${paths.length} cached .apks ` + util.pluralize('package', paths.length),
30
31
  );
@@ -33,7 +34,7 @@ process.on('exit', () => {
33
34
  // Asynchronous calls are not supported in onExit handler
34
35
  fs.rimrafSync(appPath);
35
36
  } catch (e) {
36
- log.warn(e.message);
37
+ log.warn((e as Error).message);
37
38
  }
38
39
  }
39
40
  });
@@ -44,17 +45,15 @@ process.on('exit', () => {
44
45
  * The resulting temporary path, where the .apks file has been extracted,
45
46
  * will be stored into the internal LRU cache for better performance.
46
47
  *
47
- * @param {string} apks - The full path to the .apks file
48
- * @param {string|string[]} dstPath - The relative path to the destination file,
48
+ * @param apks - The full path to the .apks file
49
+ * @param dstPath - The relative path to the destination file,
49
50
  * which is going to be extracted, where each path component is an array item
50
- * @returns {Promise<string>} Full path to the extracted file
51
+ * @returns Full path to the extracted file
51
52
  * @throws {Error} If the requested item does not exist in the extracted archive or the provides
52
53
  * apks file is not a valid bundle
53
54
  */
54
- async function extractFromApks(apks, dstPath) {
55
- if (!_.isArray(dstPath)) {
56
- dstPath = [dstPath];
57
- }
55
+ async function extractFromApks(apks: string, dstPath: string | string[]): Promise<string> {
56
+ const normalizedDstPath = _.isArray(dstPath) ? dstPath : [dstPath];
58
57
 
59
58
  return await APKS_CACHE_GUARD.acquire(apks, async () => {
60
59
  // It might be that the original file has been replaced,
@@ -64,9 +63,12 @@ async function extractFromApks(apks, dstPath) {
64
63
  log.debug(`Calculated '${apks}' hash: ${apksHash}`);
65
64
 
66
65
  if (APKS_CACHE.has(apksHash)) {
67
- const resultPath = path.resolve(/** @type {string} */ (APKS_CACHE.get(apksHash)), ...dstPath);
68
- if (await fs.exists(resultPath)) {
69
- return resultPath;
66
+ const cachedRoot = APKS_CACHE.get(apksHash);
67
+ if (cachedRoot) {
68
+ const resultPath = path.resolve(cachedRoot, ...normalizedDstPath);
69
+ if (await fs.exists(resultPath)) {
70
+ return resultPath;
71
+ }
70
72
  }
71
73
  APKS_CACHE.delete(apksHash);
72
74
  }
@@ -74,10 +76,10 @@ async function extractFromApks(apks, dstPath) {
74
76
  const tmpRoot = await tempDir.openDir();
75
77
  log.debug(`Unpacking application bundle at '${apks}' to '${tmpRoot}'`);
76
78
  await unzipFile(apks, tmpRoot);
77
- const resultPath = path.resolve(tmpRoot, ...(_.isArray(dstPath) ? dstPath : [dstPath]));
79
+ const resultPath = path.resolve(tmpRoot, ...normalizedDstPath);
78
80
  if (!(await fs.exists(resultPath))) {
79
81
  throw new Error(
80
- `${_.isArray(dstPath) ? dstPath.join(path.sep) : dstPath} cannot be found in '${apks}' bundle. ` +
82
+ `${normalizedDstPath.join(path.sep)} cannot be found in '${apks}' bundle. ` +
81
83
  `Does the archive contain a valid application bundle?`,
82
84
  );
83
85
  }
@@ -89,20 +91,20 @@ async function extractFromApks(apks, dstPath) {
89
91
  /**
90
92
  * Executes bundletool utility with given arguments and returns the actual stdout
91
93
  *
92
- * @this {import('../adb.js').ADB}
93
- * @param {Array<String>} args - the list of bundletool arguments
94
- * @param {string} errorMsg - The customized error message string
95
- * @returns {Promise<string>} the actual command stdout
94
+ * @param args - the list of bundletool arguments
95
+ * @param errorMsg - The customized error message string
96
+ * @returns the actual command stdout
96
97
  * @throws {Error} If bundletool jar does not exist in PATH or there was an error while
97
98
  * executing it
98
99
  */
99
- export async function execBundletool(args, errorMsg) {
100
+ export async function execBundletool(
101
+ this: ADB,
102
+ args: string[],
103
+ errorMsg: string,
104
+ ): Promise<string> {
100
105
  await this.initBundletool();
101
- args = [
102
- '-jar',
103
- /** @type {import('./types').StringRecord} */ (this.binaries).bundletool,
104
- ...args,
105
- ];
106
+ const binaries = this.binaries as StringRecord;
107
+ args = ['-jar', binaries.bundletool, ...args];
106
108
  const env = process.env;
107
109
  if (this.adbPort) {
108
110
  env.ANDROID_ADB_SERVER_PORT = `${this.adbPort}`;
@@ -111,7 +113,7 @@ export async function execBundletool(args, errorMsg) {
111
113
  env.ANDROID_ADB_SERVER_HOST = this.adbHost;
112
114
  }
113
115
  log.debug(`Executing bundletool with arguments: ${JSON.stringify(args)}`);
114
- let stdout;
116
+ let stdout: string;
115
117
  try {
116
118
  ({stdout} = await exec(await getJavaForOs(), args, {
117
119
  env,
@@ -120,31 +122,30 @@ export async function execBundletool(args, errorMsg) {
120
122
  log.debug(`Command stdout: ${_.truncate(stdout, {length: 300})}`);
121
123
  return stdout;
122
124
  } catch (e) {
123
- if (e.stdout) {
124
- log.debug(`Command stdout: ${e.stdout}`);
125
+ const err = e as Error & {stdout?: string; stderr?: string};
126
+ if (err.stdout) {
127
+ log.debug(`Command stdout: ${err.stdout}`);
125
128
  }
126
- if (e.stderr) {
127
- log.debug(`Command stderr: ${e.stderr}`);
129
+ if (err.stderr) {
130
+ log.debug(`Command stderr: ${err.stderr}`);
128
131
  }
129
- throw new Error(`${errorMsg}. Original error: ${e.message}`);
132
+ throw new Error(`${errorMsg}. Original error: ${err.message}`);
130
133
  }
131
134
  }
132
135
 
133
136
  /**
134
137
  *
135
- * @this {import('../adb.js').ADB}
136
- * @param {string} specLocation - The full path to the generated device spec location
137
- * @returns {Promise<string>} The same `specLocation` value
138
+ * @param specLocation - The full path to the generated device spec location
139
+ * @returns The same `specLocation` value
138
140
  * @throws {Error} If it is not possible to retrieve the spec for the current device
139
141
  */
140
- export async function getDeviceSpec(specLocation) {
141
- /** @type {string[]} */
142
- const args = [
142
+ export async function getDeviceSpec(this: ADB, specLocation: string): Promise<string> {
143
+ const args: string[] = [
143
144
  'get-device-spec',
144
145
  '--adb',
145
146
  this.executable.path,
146
147
  '--device-id',
147
- /** @type {string} */ (this.curDeviceId),
148
+ this.curDeviceId as string,
148
149
  '--output',
149
150
  specLocation,
150
151
  ];
@@ -156,15 +157,18 @@ export async function getDeviceSpec(specLocation) {
156
157
  /**
157
158
  * Installs the given apks into the device under test
158
159
  *
159
- * @this {import('../adb.js').ADB}
160
- * @param {Array<string>} apkPathsToInstall - The full paths to install apks
161
- * @param {import('./types').InstallMultipleApksOptions} [options={}] - Installation options
160
+ * @param apkPathsToInstall - The full paths to install apks
161
+ * @param options - Installation options
162
162
  */
163
- export async function installMultipleApks(apkPathsToInstall, options = {}) {
163
+ export async function installMultipleApks(
164
+ this: ADB,
165
+ apkPathsToInstall: string[],
166
+ options: InstallMultipleApksOptions = {},
167
+ ): Promise<string> {
164
168
  const installArgs = buildInstallArgs(await this.getApiLevel(), options);
165
169
  return await this.adbExec(['install-multiple', ...installArgs, ...apkPathsToInstall], {
166
170
  // @ts-ignore This validation works
167
- timeout: isNaN(options.timeout) ? undefined : options.timeout,
171
+ timeout: isNaN(Number(options.timeout)) ? undefined : options.timeout,
168
172
  timeoutCapName: options.timeoutCapName,
169
173
  });
170
174
  }
@@ -172,16 +176,18 @@ export async function installMultipleApks(apkPathsToInstall, options = {}) {
172
176
  /**
173
177
  * Installs the given .apks package into the device under test
174
178
  *
175
- * @this {import('../adb.js').ADB}
176
- * @param {string} apks - The full path to the .apks file
177
- * @param {import('./types').InstallApksOptions} [options={}] - Installation options
179
+ * @param apks - The full path to the .apks file
180
+ * @param options - Installation options
178
181
  * @throws {Error} If the .apks bundle cannot be installed
179
182
  */
180
- export async function installApks(apks, options = {}) {
183
+ export async function installApks(
184
+ this: ADB,
185
+ apks: string,
186
+ options: InstallApksOptions = {},
187
+ ): Promise<void> {
181
188
  const {grantPermissions, allowTestPackages, timeout} = options;
182
189
 
183
- /** @type {string[]} */
184
- const args = [
190
+ const args: string[] = [
185
191
  'install-apks',
186
192
  '--adb',
187
193
  this.executable.path,
@@ -190,13 +196,12 @@ export async function installApks(apks, options = {}) {
190
196
  '--timeout-millis',
191
197
  `${timeout || APKS_INSTALL_TIMEOUT}`,
192
198
  '--device-id',
193
- /** @type {string} */ (this.curDeviceId),
199
+ this.curDeviceId as string,
194
200
  ];
195
201
  if (allowTestPackages) {
196
202
  args.push('--allow-test-only');
197
203
  }
198
- /** @type {Promise[]} */
199
- const tasks = [
204
+ const tasks: Promise<any>[] = [
200
205
  this.execBundletool(
201
206
  args,
202
207
  `Cannot install '${path.basename(apks)}' to the device ${this.curDeviceId}`,
@@ -215,12 +220,11 @@ export async function installApks(apks, options = {}) {
215
220
  /**
216
221
  * Extracts and returns the full path to the master .apk file inside the bundle.
217
222
  *
218
- * @this {import('../adb.js').ADB}
219
- * @param {string} apks - The full path to the .apks file
220
- * @returns {Promise<string>} The full path to the master bundle .apk
223
+ * @param apks - The full path to the .apks file
224
+ * @returns The full path to the master bundle .apk
221
225
  * @throws {Error} If there was an error while extracting/finding the file
222
226
  */
223
- export async function extractBaseApk(apks) {
227
+ export async function extractBaseApk(this: ADB, apks: string): Promise<string> {
224
228
  return await extractFromApks(apks, ['splits', BASE_APK]);
225
229
  }
226
230
 
@@ -228,20 +232,23 @@ export async function extractBaseApk(apks) {
228
232
  * Extracts and returns the full path to the .apk, which contains the corresponding
229
233
  * resources for the given language in the .apks bundle.
230
234
  *
231
- * @this {import('../adb.js').ADB}
232
- * @param {string} apks - The full path to the .apks file
233
- * @param {?string} [language=null] - The language abbreviation. The default language is
235
+ * @param apks - The full path to the .apks file
236
+ * @param language - The language abbreviation. The default language is
234
237
  * going to be selected if it is not set.
235
- * @returns {Promise<string>} The full path to the corresponding language .apk or the master .apk
238
+ * @returns The full path to the corresponding language .apk or the master .apk
236
239
  * if language split is not enabled for the bundle.
237
240
  * @throws {Error} If there was an error while extracting/finding the file
238
241
  */
239
- export async function extractLanguageApk(apks, language = null) {
242
+ export async function extractLanguageApk(
243
+ this: ADB,
244
+ apks: string,
245
+ language: string | null = null,
246
+ ): Promise<string> {
240
247
  if (language) {
241
248
  try {
242
249
  return await extractFromApks(apks, ['splits', LANGUAGE_APK(language)]);
243
250
  } catch (e) {
244
- log.debug(e.message);
251
+ log.debug((e as Error).message);
245
252
  log.info(
246
253
  `Assuming that splitting by language is not enabled for the '${apks}' bundle ` +
247
254
  `and returning the main apk instead`,
@@ -266,9 +273,10 @@ export async function extractLanguageApk(apks, language = null) {
266
273
 
267
274
  /**
268
275
  *
269
- * @param {string} output
270
- * @returns {boolean}
276
+ * @param output
277
+ * @returns
271
278
  */
272
- export function isTestPackageOnlyError(output) {
279
+ export function isTestPackageOnlyError(output: string): boolean {
273
280
  return /\[INSTALL_FAILED_TEST_ONLY\]/.test(output);
274
281
  }
282
+
@@ -348,8 +348,9 @@ export async function execEmuConsoleCommand(
348
348
  );
349
349
  });
350
350
 
351
- client.on('data', (chunk) => {
352
- serverResponse.push(chunk);
351
+ client.on('data', (chunk: Buffer | string) => {
352
+ const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
353
+ serverResponse.push(buf);
353
354
  const output = Buffer.concat(serverResponse).toString('utf8').trim();
354
355
  if (okFlag.test(output)) {
355
356
  // The initial incoming data chunk confirms the interface is ready for input