appium-android-driver 7.8.3 → 8.0.1
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/CHANGELOG.md +32 -0
- package/build/lib/commands/app-management.d.ts +129 -5
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +433 -128
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +17 -4
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +32 -33
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/context/cache.d.ts +19 -0
- package/build/lib/commands/context/cache.d.ts.map +1 -0
- package/build/lib/commands/context/cache.js +32 -0
- package/build/lib/commands/context/cache.js.map +1 -0
- package/build/lib/commands/context/exports.d.ts +141 -0
- package/build/lib/commands/context/exports.d.ts.map +1 -0
- package/build/lib/commands/context/exports.js +351 -0
- package/build/lib/commands/context/exports.js.map +1 -0
- package/build/lib/commands/context/helpers.d.ts +98 -0
- package/build/lib/commands/context/helpers.d.ts.map +1 -0
- package/build/lib/commands/context/helpers.js +715 -0
- package/build/lib/commands/context/helpers.js.map +1 -0
- package/build/lib/commands/device/common.d.ts +23 -0
- package/build/lib/commands/device/common.d.ts.map +1 -0
- package/build/lib/commands/device/common.js +230 -0
- package/build/lib/commands/device/common.js.map +1 -0
- package/build/lib/commands/device/emulator-actions.d.ts +114 -0
- package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-actions.js +197 -0
- package/build/lib/commands/device/emulator-actions.js.map +1 -0
- package/build/lib/commands/device/emulator-console.d.ts +7 -0
- package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-console.js +24 -0
- package/build/lib/commands/device/emulator-console.js.map +1 -0
- package/build/lib/commands/device/utils.d.ts +50 -0
- package/build/lib/commands/device/utils.d.ts.map +1 -0
- package/build/lib/commands/device/utils.js +238 -0
- package/build/lib/commands/device/utils.js.map +1 -0
- package/build/lib/commands/deviceidle.d.ts +8 -5
- package/build/lib/commands/deviceidle.d.ts.map +1 -1
- package/build/lib/commands/deviceidle.js +31 -37
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.d.ts +99 -5
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +152 -116
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +12 -4
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +83 -78
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +42 -5
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +230 -194
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +5 -4
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +7 -10
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +45 -0
- package/build/lib/commands/geolocation.d.ts.map +1 -0
- package/build/lib/commands/geolocation.js +182 -0
- package/build/lib/commands/geolocation.js.map +1 -0
- package/build/lib/commands/ime.d.ts +25 -5
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +59 -42
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.d.ts +56 -5
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +135 -83
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +58 -4
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +119 -17
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts +301 -0
- package/build/lib/commands/lock/exports.d.ts.map +1 -0
- package/build/lib/commands/lock/exports.js +121 -0
- package/build/lib/commands/lock/exports.js.map +1 -0
- package/build/lib/commands/lock/helpers.d.ts +349 -0
- package/build/lib/commands/lock/helpers.d.ts.map +1 -0
- package/build/lib/commands/lock/helpers.js +375 -0
- package/build/lib/commands/lock/helpers.js.map +1 -0
- package/build/lib/commands/log.d.ts +59 -5
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +150 -140
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +16 -5
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +69 -58
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -5
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +19 -24
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/misc.d.ts +42 -0
- package/build/lib/commands/misc.d.ts.map +1 -0
- package/build/lib/commands/misc.js +100 -0
- package/build/lib/commands/misc.js.map +1 -0
- package/build/lib/commands/network.d.ts +61 -5
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +196 -189
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +67 -27
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -80
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +12 -6
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +65 -62
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +44 -5
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +131 -126
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/resources.d.ts +16 -0
- package/build/lib/commands/resources.d.ts.map +1 -0
- package/build/lib/commands/resources.js +91 -0
- package/build/lib/commands/resources.js.map +1 -0
- package/build/lib/commands/shell.d.ts +8 -5
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +29 -33
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +34 -6
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +166 -162
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +18 -13
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +68 -64
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/time.d.ts +14 -0
- package/build/lib/commands/time.d.ts.map +1 -0
- package/build/lib/commands/time.js +39 -0
- package/build/lib/commands/time.js.map +1 -0
- package/build/lib/commands/touch.d.ts +99 -6
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +399 -280
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/types.d.ts +110 -2
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/doctor/checks.d.ts.map +1 -1
- package/build/lib/doctor/checks.js +4 -4
- package/build/lib/doctor/checks.js.map +1 -1
- package/build/lib/driver.d.ts +224 -27
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +232 -7
- package/build/lib/driver.js.map +1 -1
- package/build/lib/index.d.ts +1 -4
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +1 -13
- package/build/lib/index.js.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/method-map.d.ts +0 -23
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +0 -11
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/utils.d.ts +12 -0
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +38 -2
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.js +470 -145
- package/lib/commands/appearance.js +29 -36
- package/lib/commands/context/cache.js +29 -0
- package/lib/commands/context/exports.js +379 -0
- package/lib/commands/context/helpers.js +802 -0
- package/lib/commands/device/common.js +264 -0
- package/lib/commands/device/emulator-actions.js +194 -0
- package/lib/commands/device/emulator-console.js +24 -0
- package/lib/commands/device/utils.js +285 -0
- package/lib/commands/deviceidle.js +31 -44
- package/lib/commands/element.js +149 -142
- package/lib/commands/execute.js +86 -87
- package/lib/commands/file-actions.js +249 -222
- package/lib/commands/find.ts +13 -19
- package/lib/commands/geolocation.js +179 -0
- package/lib/commands/ime.js +53 -45
- package/lib/commands/intent.js +149 -91
- package/lib/commands/keyboard.js +114 -17
- package/lib/commands/lock/exports.js +139 -0
- package/lib/commands/lock/helpers.js +379 -0
- package/lib/commands/log.js +170 -166
- package/lib/commands/media-projection.js +75 -70
- package/lib/commands/memory.js +17 -29
- package/lib/commands/misc.js +94 -0
- package/lib/commands/network.js +209 -223
- package/lib/commands/performance.js +88 -73
- package/lib/commands/permissions.js +83 -84
- package/lib/commands/recordscreen.js +171 -170
- package/lib/commands/resources.js +96 -0
- package/lib/commands/shell.js +28 -42
- package/lib/commands/streamscreen.js +207 -206
- package/lib/commands/system-bars.js +76 -77
- package/lib/commands/time.js +36 -0
- package/lib/commands/touch.js +442 -346
- package/lib/commands/types.ts +123 -2
- package/lib/doctor/checks.js +24 -16
- package/lib/driver.ts +454 -12
- package/lib/index.ts +1 -13
- package/lib/logger.js +1 -1
- package/lib/method-map.js +0 -11
- package/lib/utils.js +40 -3
- package/package.json +2 -2
- package/build/lib/commands/actions.d.ts +0 -8
- package/build/lib/commands/actions.d.ts.map +0 -1
- package/build/lib/commands/actions.js +0 -207
- package/build/lib/commands/actions.js.map +0 -1
- package/build/lib/commands/alert.d.ts +0 -8
- package/build/lib/commands/alert.d.ts.map +0 -1
- package/build/lib/commands/alert.js +0 -29
- package/build/lib/commands/alert.js.map +0 -1
- package/build/lib/commands/context.d.ts +0 -10
- package/build/lib/commands/context.d.ts.map +0 -1
- package/build/lib/commands/context.js +0 -431
- package/build/lib/commands/context.js.map +0 -1
- package/build/lib/commands/emu-console.d.ts +0 -7
- package/build/lib/commands/emu-console.d.ts.map +0 -1
- package/build/lib/commands/emu-console.js +0 -27
- package/build/lib/commands/emu-console.js.map +0 -1
- package/build/lib/commands/general.d.ts +0 -9
- package/build/lib/commands/general.d.ts.map +0 -1
- package/build/lib/commands/general.js +0 -293
- package/build/lib/commands/general.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -28
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -57
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/commands/mixins.d.ts +0 -747
- package/build/lib/commands/mixins.d.ts.map +0 -1
- package/build/lib/commands/mixins.js +0 -19
- package/build/lib/commands/mixins.js.map +0 -1
- package/build/lib/helpers/android.d.ts +0 -163
- package/build/lib/helpers/android.d.ts.map +0 -1
- package/build/lib/helpers/android.js +0 -818
- package/build/lib/helpers/android.js.map +0 -1
- package/build/lib/helpers/index.d.ts +0 -7
- package/build/lib/helpers/index.d.ts.map +0 -1
- package/build/lib/helpers/index.js +0 -29
- package/build/lib/helpers/index.js.map +0 -1
- package/build/lib/helpers/types.d.ts +0 -122
- package/build/lib/helpers/types.d.ts.map +0 -1
- package/build/lib/helpers/types.js +0 -3
- package/build/lib/helpers/types.js.map +0 -1
- package/build/lib/helpers/unlock.d.ts +0 -32
- package/build/lib/helpers/unlock.d.ts.map +0 -1
- package/build/lib/helpers/unlock.js +0 -273
- package/build/lib/helpers/unlock.js.map +0 -1
- package/build/lib/helpers/webview.d.ts +0 -74
- package/build/lib/helpers/webview.d.ts.map +0 -1
- package/build/lib/helpers/webview.js +0 -448
- package/build/lib/helpers/webview.js.map +0 -1
- package/lib/commands/actions.js +0 -244
- package/lib/commands/alert.js +0 -34
- package/lib/commands/context.js +0 -507
- package/lib/commands/emu-console.js +0 -31
- package/lib/commands/general.js +0 -343
- package/lib/commands/index.ts +0 -54
- package/lib/commands/mixins.ts +0 -976
- package/lib/helpers/android.ts +0 -1153
- package/lib/helpers/index.ts +0 -6
- package/lib/helpers/types.ts +0 -136
- package/lib/helpers/unlock.ts +0 -329
- package/lib/helpers/webview.ts +0 -610
|
@@ -1,17 +1,260 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import _ from 'lodash';
|
|
4
2
|
import {fs, util, zip, tempDir} from '@appium/support';
|
|
5
3
|
import path from 'path';
|
|
6
4
|
import {errors} from 'appium/driver';
|
|
7
5
|
import {requireArgs} from '../utils';
|
|
8
|
-
import {mixin} from './mixins';
|
|
9
6
|
|
|
10
7
|
const CONTAINER_PATH_MARKER = '@';
|
|
11
8
|
// https://regex101.com/r/PLdB0G/2
|
|
12
9
|
const CONTAINER_PATH_PATTERN = new RegExp(`^${CONTAINER_PATH_MARKER}([^/]+)/(.+)`);
|
|
13
10
|
const ANDROID_MEDIA_RESCAN_INTENT = 'android.intent.action.MEDIA_SCANNER_SCAN_FILE';
|
|
14
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @this {import('../driver').AndroidDriver}
|
|
14
|
+
* @param {string} remotePath
|
|
15
|
+
* @returns {Promise<string>}
|
|
16
|
+
*/
|
|
17
|
+
export async function pullFile(remotePath) {
|
|
18
|
+
if (remotePath.endsWith('/')) {
|
|
19
|
+
throw new errors.InvalidArgumentError(
|
|
20
|
+
`It is expected that remote path points to a file and not to a folder. ` +
|
|
21
|
+
`'${remotePath}' is given instead`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
let tmpDestination = null;
|
|
25
|
+
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
26
|
+
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
27
|
+
this.log.debug(
|
|
28
|
+
`Parsed package identifier '${packageId}' from '${remotePath}'. Will get the data from '${pathInContainer}'`,
|
|
29
|
+
);
|
|
30
|
+
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
31
|
+
try {
|
|
32
|
+
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
33
|
+
await this.adb.shell([
|
|
34
|
+
'run-as',
|
|
35
|
+
packageId,
|
|
36
|
+
`cp -f '${escapePath(pathInContainer)}' '${escapePath(tmpDestination)}'`,
|
|
37
|
+
]);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
this.log.errorAndThrow(
|
|
40
|
+
`Cannot access the container of '${packageId}' application. ` +
|
|
41
|
+
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
42
|
+
`Original error: ${/** @type {Error} */ (e).message}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
|
|
47
|
+
try {
|
|
48
|
+
await this.adb.pull(tmpDestination || remotePath, localFile);
|
|
49
|
+
return (await util.toInMemoryBase64(localFile)).toString();
|
|
50
|
+
} finally {
|
|
51
|
+
if (await fs.exists(localFile)) {
|
|
52
|
+
await fs.unlink(localFile);
|
|
53
|
+
}
|
|
54
|
+
if (tmpDestination) {
|
|
55
|
+
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @this {import('../driver').AndroidDriver}
|
|
62
|
+
* @param {import('./types').PullFileOpts} opts
|
|
63
|
+
* @returns {Promise<string>}
|
|
64
|
+
*/
|
|
65
|
+
export async function mobilePullFile(opts) {
|
|
66
|
+
const {remotePath} = requireArgs('remotePath', opts);
|
|
67
|
+
return await this.pullFile(remotePath);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @this {import('../driver').AndroidDriver}
|
|
72
|
+
* @param {string} remotePath
|
|
73
|
+
* @param {string} base64Data
|
|
74
|
+
* @returns {Promise<void>}
|
|
75
|
+
*/
|
|
76
|
+
export async function pushFile(remotePath, base64Data) {
|
|
77
|
+
if (remotePath.endsWith('/')) {
|
|
78
|
+
throw new errors.InvalidArgumentError(
|
|
79
|
+
`It is expected that remote path points to a file and not to a folder. ` +
|
|
80
|
+
`'${remotePath}' is given instead`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
|
|
84
|
+
if (_.isArray(base64Data)) {
|
|
85
|
+
// some clients (ahem) java, send a byte array encoding utf8 characters
|
|
86
|
+
// instead of a string, which would be infinitely better!
|
|
87
|
+
base64Data = Buffer.from(base64Data).toString('utf8');
|
|
88
|
+
}
|
|
89
|
+
const content = Buffer.from(base64Data, 'base64');
|
|
90
|
+
let tmpDestination = null;
|
|
91
|
+
try {
|
|
92
|
+
await fs.writeFile(localFile, content.toString('binary'), 'binary');
|
|
93
|
+
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
94
|
+
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
95
|
+
this.log.debug(
|
|
96
|
+
`Parsed package identifier '${packageId}' from '${remotePath}'. ` +
|
|
97
|
+
`Will put the data into '${pathInContainer}'`,
|
|
98
|
+
);
|
|
99
|
+
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
100
|
+
try {
|
|
101
|
+
await this.adb.shell([
|
|
102
|
+
'run-as',
|
|
103
|
+
packageId,
|
|
104
|
+
`mkdir -p '${escapePath(path.posix.dirname(pathInContainer))}'`,
|
|
105
|
+
]);
|
|
106
|
+
await this.adb.shell(['run-as', packageId, `touch '${escapePath(pathInContainer)}'`]);
|
|
107
|
+
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
108
|
+
await this.adb.push(localFile, tmpDestination);
|
|
109
|
+
await this.adb.shell([
|
|
110
|
+
'run-as',
|
|
111
|
+
packageId,
|
|
112
|
+
`cp -f '${escapePath(tmpDestination)}' '${escapePath(pathInContainer)}'`,
|
|
113
|
+
]);
|
|
114
|
+
} catch (e) {
|
|
115
|
+
this.log.errorAndThrow(
|
|
116
|
+
`Cannot access the container of '${packageId}' application. ` +
|
|
117
|
+
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
118
|
+
`Original error: ${/** @type {Error} */ (e).message}`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// adb push creates folders and overwrites existing files.
|
|
123
|
+
await this.adb.push(localFile, remotePath);
|
|
124
|
+
|
|
125
|
+
// if we have pushed a file, it might be a media file, so ensure that
|
|
126
|
+
// apps know about it
|
|
127
|
+
await scanMedia.bind(this)(remotePath);
|
|
128
|
+
}
|
|
129
|
+
} finally {
|
|
130
|
+
if (await fs.exists(localFile)) {
|
|
131
|
+
await fs.unlink(localFile);
|
|
132
|
+
}
|
|
133
|
+
if (tmpDestination) {
|
|
134
|
+
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @this {import('../driver').AndroidDriver}
|
|
141
|
+
* @param {import('./types').PushFileOpts} opts
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
export async function mobilePushFile(opts) {
|
|
145
|
+
const {remotePath, payload} = requireArgs(['remotePath', 'payload'], opts);
|
|
146
|
+
return await this.pushFile(remotePath, payload);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @this {import('../driver').AndroidDriver}
|
|
151
|
+
* @param {string} remotePath
|
|
152
|
+
* @returns {Promise<string>}
|
|
153
|
+
*/
|
|
154
|
+
export async function pullFolder(remotePath) {
|
|
155
|
+
const tmpRoot = await tempDir.openDir();
|
|
156
|
+
try {
|
|
157
|
+
await this.adb.pull(remotePath, tmpRoot);
|
|
158
|
+
return (
|
|
159
|
+
await zip.toInMemoryZip(tmpRoot, {
|
|
160
|
+
encodeToBase64: true,
|
|
161
|
+
})
|
|
162
|
+
).toString();
|
|
163
|
+
} finally {
|
|
164
|
+
await fs.rimraf(tmpRoot);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @this {import('../driver').AndroidDriver}
|
|
170
|
+
* @param {import('./types').PullFolderOpts} opts
|
|
171
|
+
* @returns {Promise<string>}
|
|
172
|
+
*/
|
|
173
|
+
export async function mobilePullFolder(opts) {
|
|
174
|
+
const {remotePath} = requireArgs('remotePath', opts);
|
|
175
|
+
return await this.pullFolder(remotePath);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @this {import('../driver').AndroidDriver}
|
|
180
|
+
* @param {import('./types').DeleteFileOpts} opts
|
|
181
|
+
* @returns {Promise<boolean>}
|
|
182
|
+
*/
|
|
183
|
+
export async function mobileDeleteFile(opts) {
|
|
184
|
+
const {remotePath} = requireArgs('remotePath', opts);
|
|
185
|
+
if (remotePath.endsWith('/')) {
|
|
186
|
+
throw new errors.InvalidArgumentError(
|
|
187
|
+
`It is expected that remote path points to a folder and not to a file. ` +
|
|
188
|
+
`'${remotePath}' is given instead`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return await deleteFileOrFolder.call(this, this.adb, remotePath);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Deletes the given folder or file from the remote device
|
|
196
|
+
*
|
|
197
|
+
* @param {ADB} adb
|
|
198
|
+
* @param {string} remotePath The full path to the remote folder
|
|
199
|
+
* or file (folder names must end with a single slash)
|
|
200
|
+
* @throws {Error} If the provided remote path is invalid or
|
|
201
|
+
* the package content cannot be accessed
|
|
202
|
+
* @returns {Promise<boolean>} `true` if the remote item has been successfully deleted.
|
|
203
|
+
* If the remote path is valid, but the remote path does not exist
|
|
204
|
+
* this function return `false`.
|
|
205
|
+
* @this {import('../driver').AndroidDriver}
|
|
206
|
+
*/
|
|
207
|
+
async function deleteFileOrFolder(adb, remotePath) {
|
|
208
|
+
const {isDir, isPresent, isFile} = createFSTests(adb);
|
|
209
|
+
let dstPath = remotePath;
|
|
210
|
+
/** @type {string|undefined} */
|
|
211
|
+
let pkgId;
|
|
212
|
+
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
213
|
+
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
214
|
+
this.log.debug(`Parsed package identifier '${packageId}' from '${remotePath}'`);
|
|
215
|
+
dstPath = pathInContainer;
|
|
216
|
+
pkgId = packageId;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (pkgId) {
|
|
220
|
+
try {
|
|
221
|
+
await adb.shell(['run-as', pkgId, 'ls']);
|
|
222
|
+
} catch (e) {
|
|
223
|
+
this.log.errorAndThrow(
|
|
224
|
+
`Cannot access the container of '${pkgId}' application. ` +
|
|
225
|
+
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
226
|
+
`Original error: ${/** @type {Error} */ (e).message}`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!(await isPresent(dstPath, pkgId))) {
|
|
232
|
+
this.log.info(`The item at '${dstPath}' does not exist. Perhaps, already deleted?`);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const expectsFile = !remotePath.endsWith('/');
|
|
237
|
+
if (expectsFile && !(await isFile(dstPath, pkgId))) {
|
|
238
|
+
this.log.errorAndThrow(`The item at '${dstPath}' is not a file`);
|
|
239
|
+
} else if (!expectsFile && !(await isDir(dstPath, pkgId))) {
|
|
240
|
+
this.log.errorAndThrow(`The item at '${dstPath}' is not a folder`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (pkgId) {
|
|
244
|
+
await adb.shell(['run-as', pkgId, `rm -f${expectsFile ? '' : 'r'} '${escapePath(dstPath)}'`]);
|
|
245
|
+
} else {
|
|
246
|
+
await adb.shell(['rm', `-f${expectsFile ? '' : 'r'}`, dstPath]);
|
|
247
|
+
}
|
|
248
|
+
if (await isPresent(dstPath, pkgId)) {
|
|
249
|
+
this.log.errorAndThrow(
|
|
250
|
+
`The item at '${dstPath}' still exists after being deleted. ` + `Is it writable?`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// #region Internal helpers
|
|
257
|
+
|
|
15
258
|
/**
|
|
16
259
|
* Parses the actual destination path from the given value
|
|
17
260
|
*
|
|
@@ -26,7 +269,7 @@ function parseContainerPath(remotePath) {
|
|
|
26
269
|
if (!match) {
|
|
27
270
|
throw new Error(
|
|
28
271
|
`It is expected that package identifier is separated from the relative path with a single slash. ` +
|
|
29
|
-
`'${remotePath}' is given instead
|
|
272
|
+
`'${remotePath}' is given instead`,
|
|
30
273
|
);
|
|
31
274
|
}
|
|
32
275
|
return [match[1], path.posix.resolve(`/data/data/${match[1]}`, match[2])];
|
|
@@ -62,7 +305,7 @@ async function scanMedia(remotePath) {
|
|
|
62
305
|
this.log.warn(
|
|
63
306
|
`Ignoring an unexpected error upon media scanning of '${remotePath}': ${
|
|
64
307
|
err.stderr ?? err.message
|
|
65
|
-
}
|
|
308
|
+
}`,
|
|
66
309
|
);
|
|
67
310
|
}
|
|
68
311
|
}
|
|
@@ -78,158 +321,6 @@ function escapePath(p) {
|
|
|
78
321
|
return p.replace(/'/g, `\\'`);
|
|
79
322
|
}
|
|
80
323
|
|
|
81
|
-
/**
|
|
82
|
-
* @type {import('./mixins').FileActionsMixin & ThisType<import('../driver').AndroidDriver>}
|
|
83
|
-
* @satisfies {import('@appium/types').ExternalDriver}
|
|
84
|
-
*/
|
|
85
|
-
const FileActionsMixin = {
|
|
86
|
-
async pullFile(remotePath) {
|
|
87
|
-
if (remotePath.endsWith('/')) {
|
|
88
|
-
throw new errors.InvalidArgumentError(
|
|
89
|
-
`It is expected that remote path points to a file and not to a folder. ` +
|
|
90
|
-
`'${remotePath}' is given instead`
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
let tmpDestination = null;
|
|
94
|
-
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
95
|
-
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
96
|
-
this.log.debug(
|
|
97
|
-
`Parsed package identifier '${packageId}' from '${remotePath}'. Will get the data from '${pathInContainer}'`
|
|
98
|
-
);
|
|
99
|
-
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
100
|
-
try {
|
|
101
|
-
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
102
|
-
await this.adb.shell([
|
|
103
|
-
'run-as',
|
|
104
|
-
packageId,
|
|
105
|
-
`cp -f '${escapePath(pathInContainer)}' '${escapePath(tmpDestination)}'`,
|
|
106
|
-
]);
|
|
107
|
-
} catch (e) {
|
|
108
|
-
this.log.errorAndThrow(
|
|
109
|
-
`Cannot access the container of '${packageId}' application. ` +
|
|
110
|
-
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
111
|
-
`Original error: ${/** @type {Error} */ (e).message}`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
|
|
116
|
-
try {
|
|
117
|
-
await this.adb.pull(tmpDestination || remotePath, localFile);
|
|
118
|
-
return (await util.toInMemoryBase64(localFile)).toString();
|
|
119
|
-
} finally {
|
|
120
|
-
if (await fs.exists(localFile)) {
|
|
121
|
-
await fs.unlink(localFile);
|
|
122
|
-
}
|
|
123
|
-
if (tmpDestination) {
|
|
124
|
-
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
async mobilePullFile(opts) {
|
|
130
|
-
const {remotePath} = requireArgs('remotePath', opts);
|
|
131
|
-
return await this.pullFile(remotePath);
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
async pushFile(remotePath, base64Data) {
|
|
135
|
-
if (remotePath.endsWith('/')) {
|
|
136
|
-
throw new errors.InvalidArgumentError(
|
|
137
|
-
`It is expected that remote path points to a file and not to a folder. ` +
|
|
138
|
-
`'${remotePath}' is given instead`
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
|
|
142
|
-
if (_.isArray(base64Data)) {
|
|
143
|
-
// some clients (ahem) java, send a byte array encoding utf8 characters
|
|
144
|
-
// instead of a string, which would be infinitely better!
|
|
145
|
-
base64Data = Buffer.from(base64Data).toString('utf8');
|
|
146
|
-
}
|
|
147
|
-
const content = Buffer.from(base64Data, 'base64');
|
|
148
|
-
let tmpDestination = null;
|
|
149
|
-
try {
|
|
150
|
-
await fs.writeFile(localFile, content.toString('binary'), 'binary');
|
|
151
|
-
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
152
|
-
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
153
|
-
this.log.debug(
|
|
154
|
-
`Parsed package identifier '${packageId}' from '${remotePath}'. ` +
|
|
155
|
-
`Will put the data into '${pathInContainer}'`
|
|
156
|
-
);
|
|
157
|
-
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
158
|
-
try {
|
|
159
|
-
await this.adb.shell([
|
|
160
|
-
'run-as',
|
|
161
|
-
packageId,
|
|
162
|
-
`mkdir -p '${escapePath(path.posix.dirname(pathInContainer))}'`,
|
|
163
|
-
]);
|
|
164
|
-
await this.adb.shell(['run-as', packageId, `touch '${escapePath(pathInContainer)}'`]);
|
|
165
|
-
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
166
|
-
await this.adb.push(localFile, tmpDestination);
|
|
167
|
-
await this.adb.shell([
|
|
168
|
-
'run-as',
|
|
169
|
-
packageId,
|
|
170
|
-
`cp -f '${escapePath(tmpDestination)}' '${escapePath(pathInContainer)}'`,
|
|
171
|
-
]);
|
|
172
|
-
} catch (e) {
|
|
173
|
-
this.log.errorAndThrow(
|
|
174
|
-
`Cannot access the container of '${packageId}' application. ` +
|
|
175
|
-
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
176
|
-
`Original error: ${/** @type {Error} */ (e).message}`
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
// adb push creates folders and overwrites existing files.
|
|
181
|
-
await this.adb.push(localFile, remotePath);
|
|
182
|
-
|
|
183
|
-
// if we have pushed a file, it might be a media file, so ensure that
|
|
184
|
-
// apps know about it
|
|
185
|
-
await scanMedia.bind(this)(remotePath);
|
|
186
|
-
}
|
|
187
|
-
} finally {
|
|
188
|
-
if (await fs.exists(localFile)) {
|
|
189
|
-
await fs.unlink(localFile);
|
|
190
|
-
}
|
|
191
|
-
if (tmpDestination) {
|
|
192
|
-
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
async mobilePushFile(opts) {
|
|
198
|
-
const {remotePath, payload} = requireArgs(['remotePath', 'payload'], opts);
|
|
199
|
-
return await this.pushFile(remotePath, payload);
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
async pullFolder(remotePath) {
|
|
203
|
-
const tmpRoot = await tempDir.openDir();
|
|
204
|
-
try {
|
|
205
|
-
await this.adb.pull(remotePath, tmpRoot);
|
|
206
|
-
return (
|
|
207
|
-
await zip.toInMemoryZip(tmpRoot, {
|
|
208
|
-
encodeToBase64: true,
|
|
209
|
-
})
|
|
210
|
-
).toString();
|
|
211
|
-
} finally {
|
|
212
|
-
await fs.rimraf(tmpRoot);
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
|
|
216
|
-
async mobilePullFolder(opts) {
|
|
217
|
-
const {remotePath} = requireArgs('remotePath', opts);
|
|
218
|
-
return await this.pullFolder(remotePath);
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
async mobileDeleteFile(opts) {
|
|
222
|
-
const {remotePath} = requireArgs('remotePath', opts);
|
|
223
|
-
if (remotePath.endsWith('/')) {
|
|
224
|
-
throw new errors.InvalidArgumentError(
|
|
225
|
-
`It is expected that remote path points to a folder and not to a file. ` +
|
|
226
|
-
`'${remotePath}' is given instead`
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
return await deleteFileOrFolder.call(this, this.adb, remotePath);
|
|
230
|
-
},
|
|
231
|
-
};
|
|
232
|
-
|
|
233
324
|
/**
|
|
234
325
|
* Factory providing filesystem test functions using ADB
|
|
235
326
|
* @param {ADB} adb
|
|
@@ -272,72 +363,8 @@ function createFSTests(adb) {
|
|
|
272
363
|
return {isFile, isDir, isPresent};
|
|
273
364
|
}
|
|
274
365
|
|
|
275
|
-
|
|
276
|
-
* Deletes the given folder or file from the remote device
|
|
277
|
-
*
|
|
278
|
-
* @param {ADB} adb
|
|
279
|
-
* @param {string} remotePath The full path to the remote folder
|
|
280
|
-
* or file (folder names must end with a single slash)
|
|
281
|
-
* @throws {Error} If the provided remote path is invalid or
|
|
282
|
-
* the package content cannot be accessed
|
|
283
|
-
* @returns {Promise<boolean>} `true` if the remote item has been successfully deleted.
|
|
284
|
-
* If the remote path is valid, but the remote path does not exist
|
|
285
|
-
* this function return `false`.
|
|
286
|
-
* @this {import('../driver').AndroidDriver}
|
|
287
|
-
*/
|
|
288
|
-
async function deleteFileOrFolder(adb, remotePath) {
|
|
289
|
-
const {isDir, isPresent, isFile} = createFSTests(adb);
|
|
290
|
-
let dstPath = remotePath;
|
|
291
|
-
/** @type {string|undefined} */
|
|
292
|
-
let pkgId;
|
|
293
|
-
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
294
|
-
const [packageId, pathInContainer] = parseContainerPath(remotePath);
|
|
295
|
-
this.log.debug(`Parsed package identifier '${packageId}' from '${remotePath}'`);
|
|
296
|
-
dstPath = pathInContainer;
|
|
297
|
-
pkgId = packageId;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (pkgId) {
|
|
301
|
-
try {
|
|
302
|
-
await adb.shell(['run-as', pkgId, 'ls']);
|
|
303
|
-
} catch (e) {
|
|
304
|
-
this.log.errorAndThrow(
|
|
305
|
-
`Cannot access the container of '${pkgId}' application. ` +
|
|
306
|
-
`Is the application installed and has 'debuggable' build option set to true? ` +
|
|
307
|
-
`Original error: ${/** @type {Error} */ (e).message}`
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (!(await isPresent(dstPath, pkgId))) {
|
|
313
|
-
this.log.info(`The item at '${dstPath}' does not exist. Perhaps, already deleted?`);
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const expectsFile = !remotePath.endsWith('/');
|
|
318
|
-
if (expectsFile && !(await isFile(dstPath, pkgId))) {
|
|
319
|
-
this.log.errorAndThrow(`The item at '${dstPath}' is not a file`);
|
|
320
|
-
} else if (!expectsFile && !(await isDir(dstPath, pkgId))) {
|
|
321
|
-
this.log.errorAndThrow(`The item at '${dstPath}' is not a folder`);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (pkgId) {
|
|
325
|
-
await adb.shell(['run-as', pkgId, `rm -f${expectsFile ? '' : 'r'} '${escapePath(dstPath)}'`]);
|
|
326
|
-
} else {
|
|
327
|
-
await adb.shell(['rm', `-f${expectsFile ? '' : 'r'}`, dstPath]);
|
|
328
|
-
}
|
|
329
|
-
if (await isPresent(dstPath, pkgId)) {
|
|
330
|
-
this.log.errorAndThrow(
|
|
331
|
-
`The item at '${dstPath}' still exists after being deleted. ` + `Is it writable?`
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
return true;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
mixin(FileActionsMixin);
|
|
366
|
+
// #endregion
|
|
338
367
|
|
|
339
368
|
/**
|
|
340
369
|
* @typedef {import('appium-adb').ADB} ADB
|
|
341
370
|
*/
|
|
342
|
-
|
|
343
|
-
export default FileActionsMixin;
|
package/lib/commands/find.ts
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1
2
|
/**
|
|
2
|
-
* @privateRemarks This file needed to be converted to TS because the overload of `findElOrEls` is seemingly impossible to express in JS since the value of `this` cannot be bound via a type assertion.
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import _ from 'lodash';
|
|
7
|
-
import {mixin, type FindMixin} from './mixins';
|
|
8
7
|
import {errors, isErrorType} from 'appium/driver';
|
|
9
8
|
import type {AndroidDriver} from '../driver';
|
|
10
9
|
import type {Element} from '@appium/types';
|
|
11
10
|
import type {FindElementOpts} from './types';
|
|
12
11
|
|
|
13
|
-
async function findElOrEls(
|
|
12
|
+
export async function findElOrEls(
|
|
14
13
|
this: AndroidDriver,
|
|
15
14
|
strategy: string,
|
|
16
15
|
selector: string,
|
|
17
16
|
mult: true,
|
|
18
|
-
context?: string
|
|
17
|
+
context?: string,
|
|
19
18
|
): Promise<Element[]>;
|
|
20
|
-
async function findElOrEls(
|
|
19
|
+
export async function findElOrEls(
|
|
21
20
|
this: AndroidDriver,
|
|
22
21
|
strategy: string,
|
|
23
22
|
selector: string,
|
|
24
23
|
mult: false,
|
|
25
|
-
context?: string
|
|
24
|
+
context?: string,
|
|
26
25
|
): Promise<Element>;
|
|
27
|
-
async function findElOrEls(
|
|
26
|
+
export async function findElOrEls(
|
|
28
27
|
this: AndroidDriver,
|
|
29
28
|
strategy: string,
|
|
30
29
|
selector: string,
|
|
31
30
|
mult: boolean,
|
|
32
|
-
context = ''
|
|
31
|
+
context = '',
|
|
33
32
|
) {
|
|
34
33
|
if (!selector) {
|
|
35
34
|
throw new Error('Must provide a selector when finding elements');
|
|
@@ -89,14 +88,9 @@ async function findElOrEls(
|
|
|
89
88
|
return element as Element;
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
mixin(FindMixin);
|
|
101
|
-
|
|
102
|
-
export default FindMixin;
|
|
91
|
+
export async function doFindElementOrEls(
|
|
92
|
+
this: AndroidDriver,
|
|
93
|
+
params: FindElementOpts,
|
|
94
|
+
): Promise<Element | Element[]> {
|
|
95
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
96
|
+
}
|