appium-uiautomator2-driver 2.42.2 → 2.43.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 +14 -0
- package/build/lib/commands/actions.d.ts +22 -1
- package/build/lib/commands/actions.d.ts.map +1 -1
- package/build/lib/commands/actions.js +30 -62
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +28 -1
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +42 -23
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +19 -0
- package/build/lib/commands/app-management.d.ts.map +1 -0
- package/build/lib/commands/app-management.js +45 -0
- package/build/lib/commands/app-management.js.map +1 -0
- package/build/lib/commands/app-strings.d.ts +9 -0
- package/build/lib/commands/app-strings.d.ts.map +1 -1
- package/build/lib/commands/app-strings.js +11 -79
- package/build/lib/commands/app-strings.js.map +1 -1
- package/build/lib/commands/battery.d.ts +7 -0
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +14 -20
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/element.d.ts +100 -1
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +175 -125
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +25 -0
- package/build/lib/commands/execute.d.ts.map +1 -0
- package/build/lib/commands/execute.js +109 -0
- package/build/lib/commands/execute.js.map +1 -0
- package/build/lib/commands/find.d.ts +10 -0
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +25 -27
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/gestures.d.ts +103 -1
- package/build/lib/commands/gestures.d.ts.map +1 -1
- package/build/lib/commands/gestures.js +202 -173
- package/build/lib/commands/gestures.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +47 -0
- package/build/lib/commands/keyboard.d.ts.map +1 -0
- package/build/lib/commands/keyboard.js +92 -0
- package/build/lib/commands/keyboard.js.map +1 -0
- package/build/lib/commands/misc.d.ts +48 -0
- package/build/lib/commands/misc.d.ts.map +1 -0
- package/build/lib/commands/misc.js +75 -0
- package/build/lib/commands/misc.js.map +1 -0
- package/build/lib/commands/navigation.d.ts +20 -0
- package/build/lib/commands/navigation.d.ts.map +1 -0
- package/build/lib/commands/navigation.js +35 -0
- package/build/lib/commands/navigation.js.map +1 -0
- package/build/lib/commands/screenshot.d.ts +24 -1
- package/build/lib/commands/screenshot.d.ts.map +1 -1
- package/build/lib/commands/screenshot.js +87 -64
- package/build/lib/commands/screenshot.js.map +1 -1
- package/build/lib/commands/touch.d.ts +81 -0
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +158 -41
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/viewport.d.ts +37 -1
- package/build/lib/commands/viewport.d.ts.map +1 -1
- package/build/lib/commands/viewport.js +80 -36
- package/build/lib/commands/viewport.js.map +1 -1
- package/build/lib/driver.d.ts +94 -24
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +114 -28
- package/build/lib/driver.js.map +1 -1
- package/build/lib/helpers.d.ts +12 -6
- package/build/lib/helpers.d.ts.map +1 -1
- package/build/lib/helpers.js +18 -18
- package/build/lib/helpers.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/uiautomator2.js +3 -3
- package/build/lib/uiautomator2.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/commands/actions.js +37 -114
- package/lib/commands/alert.js +51 -37
- package/lib/commands/app-management.js +42 -0
- package/lib/commands/app-strings.js +9 -89
- package/lib/commands/battery.js +16 -26
- package/lib/commands/element.js +235 -214
- package/lib/commands/execute.js +120 -0
- package/lib/commands/find.js +31 -37
- package/lib/commands/gestures.js +252 -234
- package/lib/commands/keyboard.js +103 -0
- package/lib/commands/misc.js +106 -0
- package/lib/commands/navigation.js +31 -0
- package/lib/commands/screenshot.js +96 -77
- package/lib/commands/touch.js +190 -48
- package/lib/commands/viewport.js +100 -50
- package/lib/driver.ts +225 -36
- package/lib/helpers.js +15 -22
- package/lib/uiautomator2.js +3 -3
- package/npm-shrinkwrap.json +34 -34
- package/package.json +2 -2
- package/build/lib/commands/general.d.ts +0 -4
- package/build/lib/commands/general.d.ts.map +0 -1
- package/build/lib/commands/general.js +0 -214
- package/build/lib/commands/general.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -2
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -14
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/commands/mixins.d.ts +0 -87
- package/build/lib/commands/mixins.d.ts.map +0 -1
- package/build/lib/commands/mixins.js +0 -26
- package/build/lib/commands/mixins.js.map +0 -1
- package/build/lib/utils.d.ts +0 -10
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js +0 -26
- package/build/lib/utils.js.map +0 -1
- package/lib/commands/general.js +0 -289
- package/lib/commands/index.js +0 -11
- package/lib/commands/mixins.ts +0 -169
- package/lib/utils.js +0 -19
package/lib/commands/element.js
CHANGED
|
@@ -1,241 +1,262 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import B from 'bluebird';
|
|
4
2
|
import _ from 'lodash';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {requireArgs} from '../utils';
|
|
8
|
-
import {mixin} from './mixins';
|
|
3
|
+
import {PROTOCOLS} from 'appium/driver';
|
|
4
|
+
import {utils} from 'appium-android-driver';
|
|
9
5
|
|
|
10
6
|
/**
|
|
11
|
-
* @
|
|
12
|
-
* @returns {
|
|
7
|
+
* @this {AndroidUiautomator2Driver}
|
|
8
|
+
* @returns {Promise<import('@appium/types').Element>}
|
|
13
9
|
*/
|
|
14
|
-
function
|
|
15
|
-
return
|
|
10
|
+
export async function active() {
|
|
11
|
+
return /** @type {import('@appium/types').Element} */ (
|
|
12
|
+
await this.uiautomator2.jwproxy.command(
|
|
13
|
+
'/element/active',
|
|
14
|
+
'GET'
|
|
15
|
+
)
|
|
16
|
+
);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
|
-
* @
|
|
20
|
-
* @
|
|
20
|
+
* @this {AndroidUiautomator2Driver}
|
|
21
|
+
* @param {string} attribute
|
|
22
|
+
* @param {string} elementId
|
|
23
|
+
* @returns {Promise<string?>}
|
|
21
24
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return /** @type {import('@appium/types').Element} */ (
|
|
25
|
-
await this.uiautomator2.jwproxy.command(
|
|
26
|
-
'/element/active',
|
|
27
|
-
'GET'
|
|
28
|
-
)
|
|
29
|
-
);
|
|
30
|
-
},
|
|
31
|
-
async getAttribute(attribute, elementId) {
|
|
32
|
-
return String(
|
|
33
|
-
await this.uiautomator2.jwproxy.command(
|
|
34
|
-
`/element/${elementId}/attribute/${attribute}`,
|
|
35
|
-
'GET',
|
|
36
|
-
{}
|
|
37
|
-
)
|
|
38
|
-
);
|
|
39
|
-
},
|
|
40
|
-
async elementDisplayed(elementId) {
|
|
41
|
-
return toBool(await this.getAttribute('displayed', elementId));
|
|
42
|
-
},
|
|
43
|
-
async elementEnabled(elementId) {
|
|
44
|
-
return toBool(await this.getAttribute('enabled', elementId));
|
|
45
|
-
},
|
|
46
|
-
async elementSelected(elementId) {
|
|
47
|
-
return toBool(await this.getAttribute('selected', elementId));
|
|
48
|
-
},
|
|
49
|
-
async getName(elementId) {
|
|
50
|
-
return /** @type {string} */ (
|
|
51
|
-
await this.uiautomator2.jwproxy.command(
|
|
52
|
-
`/element/${elementId}/name`,
|
|
53
|
-
'GET',
|
|
54
|
-
{}
|
|
55
|
-
)
|
|
56
|
-
);
|
|
57
|
-
},
|
|
58
|
-
async getLocation(elementId) {
|
|
59
|
-
return /** @type {import('@appium/types').Position} */ (
|
|
60
|
-
await this.uiautomator2.jwproxy.command(
|
|
61
|
-
`/element/${elementId}/location`,
|
|
62
|
-
'GET',
|
|
63
|
-
{}
|
|
64
|
-
)
|
|
65
|
-
);
|
|
66
|
-
},
|
|
67
|
-
async getSize(elementId) {
|
|
68
|
-
return /** @type {import('@appium/types').Size} */ (
|
|
69
|
-
await this.uiautomator2.jwproxy.command(
|
|
70
|
-
`/element/${elementId}/size`,
|
|
71
|
-
'GET',
|
|
72
|
-
{}
|
|
73
|
-
)
|
|
74
|
-
);
|
|
75
|
-
},
|
|
76
|
-
async touchLongClick(element, x, y, duration) {
|
|
77
|
-
let params = {element, x, y, duration};
|
|
78
|
-
await this.uiautomator2.jwproxy.command(
|
|
79
|
-
`/touch/longclick`,
|
|
80
|
-
'POST',
|
|
81
|
-
{params}
|
|
82
|
-
);
|
|
83
|
-
},
|
|
84
|
-
async touchDown(element, x, y) {
|
|
85
|
-
let params = {element, x, y};
|
|
86
|
-
await this.uiautomator2.jwproxy.command(
|
|
87
|
-
`/touch/down`,
|
|
88
|
-
'POST',
|
|
89
|
-
{params}
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
async touchUp(element, x, y) {
|
|
93
|
-
let params = {element, x, y};
|
|
25
|
+
export async function getAttribute(attribute, elementId) {
|
|
26
|
+
return String(
|
|
94
27
|
await this.uiautomator2.jwproxy.command(
|
|
95
|
-
`/
|
|
96
|
-
'
|
|
97
|
-
{
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
28
|
+
`/element/${elementId}/attribute/${attribute}`,
|
|
29
|
+
'GET',
|
|
30
|
+
{}
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @this {AndroidUiautomator2Driver}
|
|
37
|
+
* @param {string} elementId
|
|
38
|
+
* @returns {Promise<boolean>}
|
|
39
|
+
*/
|
|
40
|
+
export async function elementDisplayed(elementId) {
|
|
41
|
+
return toBool(await this.getAttribute('displayed', elementId));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @this {AndroidUiautomator2Driver}
|
|
46
|
+
* @param {string} elementId
|
|
47
|
+
* @returns {Promise<boolean>}
|
|
48
|
+
*/
|
|
49
|
+
export async function elementEnabled(elementId) {
|
|
50
|
+
return toBool(await this.getAttribute('enabled', elementId));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @this {AndroidUiautomator2Driver}
|
|
55
|
+
* @param {string} elementId
|
|
56
|
+
* @returns {Promise<boolean>}
|
|
57
|
+
*/
|
|
58
|
+
export async function elementSelected(elementId) {
|
|
59
|
+
return toBool(await this.getAttribute('selected', elementId));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @this {AndroidUiautomator2Driver}
|
|
64
|
+
* @param {string} elementId
|
|
65
|
+
* @returns {Promise<string>}
|
|
66
|
+
*/
|
|
67
|
+
export async function getName(elementId) {
|
|
68
|
+
return /** @type {string} */ (
|
|
109
69
|
await this.uiautomator2.jwproxy.command(
|
|
110
|
-
`/element/${
|
|
111
|
-
'
|
|
112
|
-
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
|
|
70
|
+
`/element/${elementId}/name`,
|
|
71
|
+
'GET',
|
|
72
|
+
{}
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @this {AndroidUiautomator2Driver}
|
|
79
|
+
* @param {string} elementId
|
|
80
|
+
* @returns {Promise<import('@appium/types').Position>}
|
|
81
|
+
*/
|
|
82
|
+
export async function getLocation(elementId) {
|
|
83
|
+
return /** @type {import('@appium/types').Position} */ (
|
|
116
84
|
await this.uiautomator2.jwproxy.command(
|
|
117
|
-
`/element/${elementId}/
|
|
118
|
-
'
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
{}
|
|
132
|
-
)
|
|
133
|
-
);
|
|
134
|
-
},
|
|
135
|
-
async click(element) {
|
|
85
|
+
`/element/${elementId}/location`,
|
|
86
|
+
'GET',
|
|
87
|
+
{}
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @this {AndroidUiautomator2Driver}
|
|
94
|
+
* @param {string} elementId
|
|
95
|
+
* @returns {Promise<import('@appium/types').Size>}
|
|
96
|
+
*/
|
|
97
|
+
export async function getSize(elementId) {
|
|
98
|
+
return /** @type {import('@appium/types').Size} */ (
|
|
136
99
|
await this.uiautomator2.jwproxy.command(
|
|
137
|
-
`/element/${
|
|
138
|
-
'
|
|
139
|
-
{
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return String(
|
|
144
|
-
await this.uiautomator2.jwproxy.command(
|
|
145
|
-
`/element/${element}/screenshot`,
|
|
146
|
-
'GET',
|
|
147
|
-
{}
|
|
148
|
-
)
|
|
149
|
-
);
|
|
150
|
-
},
|
|
100
|
+
`/element/${elementId}/size`,
|
|
101
|
+
'GET',
|
|
102
|
+
{}
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
151
106
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
107
|
+
/**
|
|
108
|
+
* @this {AndroidUiautomator2Driver}
|
|
109
|
+
* @param {import('appium-android-driver').DoSetElementValueOpts} params
|
|
110
|
+
* @returns {Promise<void>}
|
|
111
|
+
*/
|
|
112
|
+
export async function doSetElementValue(params) {
|
|
113
|
+
await this.uiautomator2.jwproxy.command(
|
|
114
|
+
`/element/${params.elementId}/value`,
|
|
115
|
+
'POST',
|
|
116
|
+
params
|
|
117
|
+
);
|
|
118
|
+
}
|
|
157
119
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
y,
|
|
173
|
-
[W3C_ELEMENT_KEY]: elementId,
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
}
|
|
120
|
+
/**
|
|
121
|
+
* @this {AndroidUiautomator2Driver}
|
|
122
|
+
* @param {string|string[]} keys
|
|
123
|
+
* @param {string} elementId
|
|
124
|
+
* @returns {Promise<void>}
|
|
125
|
+
*/
|
|
126
|
+
export async function setValueImmediate(keys, elementId) {
|
|
127
|
+
await this.uiautomator2.jwproxy.command(
|
|
128
|
+
`/element/${elementId}/value`,
|
|
129
|
+
'POST',
|
|
130
|
+
{
|
|
131
|
+
elementId,
|
|
132
|
+
text: _.isArray(keys) ? keys.join('') : keys,
|
|
133
|
+
replace: false,
|
|
177
134
|
}
|
|
178
|
-
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @this {AndroidUiautomator2Driver}
|
|
140
|
+
* @param {string} elementId
|
|
141
|
+
* @returns {Promise<string>}
|
|
142
|
+
*/
|
|
143
|
+
export async function getText(elementId) {
|
|
144
|
+
return String(
|
|
145
|
+
await this.uiautomator2.jwproxy.command(
|
|
146
|
+
`/element/${elementId}/text`,
|
|
147
|
+
'GET',
|
|
148
|
+
{}
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @this {AndroidUiautomator2Driver}
|
|
155
|
+
* @param {string} element
|
|
156
|
+
* @returns {Promise<void>}
|
|
157
|
+
*/
|
|
158
|
+
export async function click(element) {
|
|
159
|
+
await this.uiautomator2.jwproxy.command(
|
|
160
|
+
`/element/${element}/click`,
|
|
161
|
+
'POST',
|
|
162
|
+
{element}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
179
165
|
|
|
180
|
-
|
|
166
|
+
/**
|
|
167
|
+
* @this {AndroidUiautomator2Driver}
|
|
168
|
+
* @param {string} element
|
|
169
|
+
* @returns {Promise<string>}
|
|
170
|
+
*/
|
|
171
|
+
export async function getElementScreenshot(element) {
|
|
172
|
+
return String(
|
|
181
173
|
await this.uiautomator2.jwproxy.command(
|
|
182
|
-
`/element/${
|
|
183
|
-
'
|
|
184
|
-
{
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
`/element/${element}/screenshot`,
|
|
175
|
+
'GET',
|
|
176
|
+
{}
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @this {AndroidUiautomator2Driver}
|
|
183
|
+
* @param {string} elementId
|
|
184
|
+
* @returns {Promise<void>}
|
|
185
|
+
*/
|
|
186
|
+
export async function clear(elementId) {
|
|
187
|
+
await this.uiautomator2.jwproxy.command(
|
|
188
|
+
`/element/${elementId}/clear`,
|
|
189
|
+
'POST',
|
|
190
|
+
{
|
|
191
|
+
elementId,
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @this {AndroidUiautomator2Driver}
|
|
198
|
+
* @param {string} elementId
|
|
199
|
+
* @returns {Promise<import('@appium/types').Rect>}
|
|
200
|
+
*/
|
|
201
|
+
export async function getElementRect(elementId) {
|
|
202
|
+
const chromedriver = /** @type {import('appium-chromedriver').default} */ (this.chromedriver);
|
|
203
|
+
if (this.isWebContext()) {
|
|
204
|
+
this.log.debug(
|
|
205
|
+
`Detected downstream chromedriver protocol: ${chromedriver.jwproxy.downstreamProtocol}`
|
|
187
206
|
);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const [{x, y}, {width, height}] =
|
|
198
|
-
/** @type {[import('@appium/types').Position, import('@appium/types').Size]} */ (
|
|
199
|
-
await B.all([
|
|
200
|
-
chromedriver.jwproxy.command(`/element/${elementId}/location`, 'GET'),
|
|
201
|
-
chromedriver.jwproxy.command(`/element/${elementId}/size`, 'GET'),
|
|
202
|
-
])
|
|
203
|
-
);
|
|
204
|
-
return {x, y, width, height};
|
|
205
|
-
}
|
|
206
|
-
return /** @type {import('@appium/types').Rect} */ (
|
|
207
|
-
await chromedriver.jwproxy.command(`/element/${elementId}/rect`, 'GET')
|
|
208
|
-
);
|
|
207
|
+
if (chromedriver.jwproxy.downstreamProtocol === PROTOCOLS.MJSONWP) {
|
|
208
|
+
const [{x, y}, {width, height}] =
|
|
209
|
+
/** @type {[import('@appium/types').Position, import('@appium/types').Size]} */ (
|
|
210
|
+
await B.all([
|
|
211
|
+
chromedriver.jwproxy.command(`/element/${elementId}/location`, 'GET'),
|
|
212
|
+
chromedriver.jwproxy.command(`/element/${elementId}/size`, 'GET'),
|
|
213
|
+
])
|
|
214
|
+
);
|
|
215
|
+
return {x, y, width, height};
|
|
209
216
|
}
|
|
210
217
|
return /** @type {import('@appium/types').Rect} */ (
|
|
211
|
-
await
|
|
212
|
-
`/element/${elementId}/rect`,
|
|
213
|
-
'GET'
|
|
214
|
-
)
|
|
218
|
+
await chromedriver.jwproxy.command(`/element/${elementId}/rect`, 'GET')
|
|
215
219
|
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Sends text to the given element by replacing its previous content
|
|
220
|
-
*
|
|
221
|
-
* @param {import('./types').ReplaceValueOptions} opts
|
|
222
|
-
* @throws {Error} If there was a faulre while setting the text
|
|
223
|
-
*/
|
|
224
|
-
async mobileReplaceElementValue(opts) {
|
|
225
|
-
const {elementId, text} = requireArgs(['elementId', 'text'], opts);
|
|
220
|
+
}
|
|
221
|
+
return /** @type {import('@appium/types').Rect} */ (
|
|
226
222
|
await this.uiautomator2.jwproxy.command(
|
|
227
|
-
`/element/${elementId}/
|
|
228
|
-
'
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
223
|
+
`/element/${elementId}/rect`,
|
|
224
|
+
'GET'
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Sends text to the given element by replacing its previous content
|
|
231
|
+
* @this {AndroidUiautomator2Driver}
|
|
232
|
+
* @param {import('./types').ReplaceValueOptions} opts
|
|
233
|
+
* @throws {Error} If there was a faulre while setting the text
|
|
234
|
+
* @returns {Promise<void>}
|
|
235
|
+
*/
|
|
236
|
+
export async function mobileReplaceElementValue(opts) {
|
|
237
|
+
const {elementId, text} = utils.requireArgs(['elementId', 'text'], opts);
|
|
238
|
+
await this.uiautomator2.jwproxy.command(
|
|
239
|
+
`/element/${elementId}/value`,
|
|
240
|
+
'POST',
|
|
241
|
+
{
|
|
242
|
+
text,
|
|
243
|
+
replace: true,
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// #region Internal Helpers
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {any} s
|
|
252
|
+
* @returns {boolean}
|
|
253
|
+
*/
|
|
254
|
+
function toBool(s) {
|
|
255
|
+
return _.isString(s) ? s.toLowerCase() === 'true' : !!s;
|
|
256
|
+
}
|
|
236
257
|
|
|
237
|
-
|
|
258
|
+
// #endregion
|
|
238
259
|
|
|
239
260
|
/**
|
|
240
|
-
* @typedef {import('../
|
|
261
|
+
* @typedef {import('../driver').AndroidUiautomator2Driver} AndroidUiautomator2Driver
|
|
241
262
|
*/
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {errors, PROTOCOLS} from 'appium/driver';
|
|
3
|
+
import {AndroidUiautomator2Driver} from '../driver';
|
|
4
|
+
|
|
5
|
+
const MOBILE_SCRIPT_NAME_PREFIX = 'mobile:';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @override
|
|
9
|
+
* @privateRemarks Because the "mobile" commands (execute methods) in this
|
|
10
|
+
* driver universally accept an options object, this method will _not_ call
|
|
11
|
+
* into `BaseDriver.executeMethod`.
|
|
12
|
+
* @this {AndroidUiautomator2Driver}
|
|
13
|
+
* @param {string} script
|
|
14
|
+
* @param {any[]} [args]
|
|
15
|
+
* @returns {Promise<any>}
|
|
16
|
+
*/
|
|
17
|
+
export async function execute(script, args) {
|
|
18
|
+
const mobileScriptName = toExecuteMethodName(script);
|
|
19
|
+
const isWebContext = this.isWebContext();
|
|
20
|
+
if (mobileScriptName && isWebContext || !isWebContext) {
|
|
21
|
+
if (mobileScriptName) {
|
|
22
|
+
const executeMethodArgs = preprocessExecuteMethodArgs(args);
|
|
23
|
+
this.log.info(`Executing method '${mobileScriptName}'`);
|
|
24
|
+
return await this.executeMobile(mobileScriptName, executeMethodArgs);
|
|
25
|
+
}
|
|
26
|
+
// Just pass the script name through and let it fail with a proper error message
|
|
27
|
+
return await this.executeMobile(`${script}`, {});
|
|
28
|
+
}
|
|
29
|
+
const endpoint =
|
|
30
|
+
/** @type {import('appium-chromedriver').Chromedriver} */ (this.chromedriver).jwproxy
|
|
31
|
+
.downstreamProtocol === PROTOCOLS.MJSONWP
|
|
32
|
+
? '/execute'
|
|
33
|
+
: '/execute/sync';
|
|
34
|
+
return await /** @type {import('appium-chromedriver').Chromedriver} */ (
|
|
35
|
+
this.chromedriver
|
|
36
|
+
).jwproxy.command(endpoint, 'POST', {
|
|
37
|
+
script,
|
|
38
|
+
args,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @override
|
|
44
|
+
* @this {AndroidUiautomator2Driver}
|
|
45
|
+
* @param {string} script Must be of the form `mobile: <something>`, which
|
|
46
|
+
* differs from its parent class implementation.
|
|
47
|
+
* @param {import('@appium/types').StringRecord} [opts={}]
|
|
48
|
+
* @returns {Promise<any>}
|
|
49
|
+
*/
|
|
50
|
+
export async function executeMobile(script, opts = {}) {
|
|
51
|
+
if (!(script in AndroidUiautomator2Driver.executeMethodMap)) {
|
|
52
|
+
const commandNames = _.map(
|
|
53
|
+
_.keys(AndroidUiautomator2Driver.executeMethodMap),
|
|
54
|
+
(value) => value.slice(8)
|
|
55
|
+
);
|
|
56
|
+
throw new errors.UnknownCommandError(
|
|
57
|
+
`Unknown mobile command "${script}". ` +
|
|
58
|
+
`Only ${commandNames.join(', ')} commands are supported.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const methodName =
|
|
62
|
+
AndroidUiautomator2Driver.executeMethodMap[
|
|
63
|
+
/** @type {keyof import('../execute-method-map').Uiautomator2ExecuteMethodMap} */ (script)
|
|
64
|
+
].command;
|
|
65
|
+
|
|
66
|
+
return await /** @type {(opts?: any) => Promise<unknown>} */ (this[methodName])(opts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// #region Internal Helpers
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Messages the arguments going into an execute method.
|
|
73
|
+
* @remarks A similar method is implemented in `appium-xcuitest-driver`, but it
|
|
74
|
+
* appears the methods in here handle unwrapping of `Element` objects, so we do
|
|
75
|
+
* not do that here.
|
|
76
|
+
* @param {readonly any[] | readonly [StringRecord] | Readonly<StringRecord>} [args]
|
|
77
|
+
* @internal
|
|
78
|
+
* @returns {StringRecord<unknown>}
|
|
79
|
+
*/
|
|
80
|
+
function preprocessExecuteMethodArgs(args) {
|
|
81
|
+
if (_.isArray(args)) {
|
|
82
|
+
args = _.first(args);
|
|
83
|
+
}
|
|
84
|
+
const executeMethodArgs = /** @type {StringRecord<unknown>} */ (args ?? {});
|
|
85
|
+
/**
|
|
86
|
+
* Renames the deprecated `element` key to `elementId`. Historically,
|
|
87
|
+
* all of the pre-Execute-Method-Map execute methods accepted an `element` _or_ and `elementId` param.
|
|
88
|
+
* This assigns the `element` value to `elementId` if `elementId` is not already present.
|
|
89
|
+
*/
|
|
90
|
+
if (!('elementId' in executeMethodArgs) && 'element' in executeMethodArgs) {
|
|
91
|
+
executeMethodArgs.elementId = executeMethodArgs.element;
|
|
92
|
+
delete executeMethodArgs.element;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return executeMethodArgs;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Type guard to check if a script is an execute method.
|
|
100
|
+
* @param {any} script
|
|
101
|
+
* @internal
|
|
102
|
+
* @returns {string?}
|
|
103
|
+
*/
|
|
104
|
+
function toExecuteMethodName(script) {
|
|
105
|
+
return _.startsWith(script, MOBILE_SCRIPT_NAME_PREFIX)
|
|
106
|
+
? script.replace(new RegExp(`${MOBILE_SCRIPT_NAME_PREFIX}\\s*`), `${MOBILE_SCRIPT_NAME_PREFIX} `)
|
|
107
|
+
: null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// #endregion
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @typedef {import('../uiautomator2').UiAutomator2Server} UiAutomator2Server
|
|
114
|
+
* @typedef {import('appium-adb').ADB} ADB
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @template [T=any]
|
|
119
|
+
* @typedef {import('@appium/types').StringRecord<T>} StringRecord
|
|
120
|
+
*/
|
package/lib/commands/find.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import CssConverter from '../css-converter';
|
|
4
|
-
import {mixin} from './mixins';
|
|
5
2
|
|
|
6
3
|
// we override the xpath search for this first-visible-child selector, which
|
|
7
4
|
// looks like /*[@firstVisible="true"]
|
|
@@ -11,43 +8,40 @@ const MAGIC_SCROLLABLE_SEL = /\/\/\*\[@scrollable ?= ?('|")true\1\]/;
|
|
|
11
8
|
const MAGIC_SCROLLABLE_BY = 'new UiSelector().scrollable(true)';
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
|
-
* @
|
|
15
|
-
*
|
|
11
|
+
* @privateRemarks Overriding helpers.doFindElementOrEls functionality of appium-android-driver,
|
|
12
|
+
* this.element initialized in find.js of appium-android-drive.
|
|
13
|
+
*
|
|
14
|
+
* @this {AndroidUiautomator2Driver}
|
|
15
|
+
* @param {import('appium-android-driver').FindElementOpts} params
|
|
16
|
+
* @returns {Promise<Element | Element[]>}
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
);
|
|
26
|
-
if (params.strategy === 'xpath' && MAGIC_FIRST_VIS_CHILD_SEL.test(params.selector)) {
|
|
27
|
-
let elementId = params.context;
|
|
28
|
-
return /** @type {Element} */ (
|
|
29
|
-
await uiautomator2.jwproxy.command(`/appium/element/${elementId}/first_visible`, 'GET', {})
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
if (params.strategy === 'xpath' && MAGIC_SCROLLABLE_SEL.test(params.selector)) {
|
|
33
|
-
params.strategy = '-android uiautomator';
|
|
34
|
-
params.selector = MAGIC_SCROLLABLE_BY;
|
|
35
|
-
}
|
|
36
|
-
if (params.strategy === 'css selector') {
|
|
37
|
-
params.strategy = '-android uiautomator';
|
|
38
|
-
params.selector = new CssConverter(
|
|
39
|
-
params.selector,
|
|
40
|
-
this.opts.appPackage
|
|
41
|
-
).toUiAutomatorSelector();
|
|
42
|
-
}
|
|
43
|
-
return /** @type {Element|Element[]} */ (
|
|
44
|
-
await uiautomator2.jwproxy.command(`/element${params.multiple ? 's' : ''}`, 'POST', params)
|
|
18
|
+
export async function doFindElementOrEls(params) {
|
|
19
|
+
const uiautomator2 = /** @type {import('../uiautomator2').UiAutomator2Server} */ (
|
|
20
|
+
this.uiautomator2
|
|
21
|
+
);
|
|
22
|
+
if (params.strategy === 'xpath' && MAGIC_FIRST_VIS_CHILD_SEL.test(params.selector)) {
|
|
23
|
+
let elementId = params.context;
|
|
24
|
+
return /** @type {Element} */ (
|
|
25
|
+
await uiautomator2.jwproxy.command(`/appium/element/${elementId}/first_visible`, 'GET', {})
|
|
45
26
|
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
27
|
+
}
|
|
28
|
+
if (params.strategy === 'xpath' && MAGIC_SCROLLABLE_SEL.test(params.selector)) {
|
|
29
|
+
params.strategy = '-android uiautomator';
|
|
30
|
+
params.selector = MAGIC_SCROLLABLE_BY;
|
|
31
|
+
}
|
|
32
|
+
if (params.strategy === 'css selector') {
|
|
33
|
+
params.strategy = '-android uiautomator';
|
|
34
|
+
params.selector = new CssConverter(
|
|
35
|
+
params.selector,
|
|
36
|
+
this.opts.appPackage
|
|
37
|
+
).toUiAutomatorSelector();
|
|
38
|
+
}
|
|
39
|
+
return /** @type {Element|Element[]} */ (
|
|
40
|
+
await uiautomator2.jwproxy.command(`/element${params.multiple ? 's' : ''}`, 'POST', params)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
50
43
|
|
|
51
44
|
/**
|
|
52
45
|
* @typedef {import('@appium/types').Element} Element
|
|
46
|
+
* @typedef {import('../driver').AndroidUiautomator2Driver} AndroidUiautomator2Driver
|
|
53
47
|
*/
|