appium-android-driver 5.14.7 → 6.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.
Files changed (210) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/lib/commands/actions.d.ts +6 -224
  3. package/build/lib/commands/actions.d.ts.map +1 -1
  4. package/build/lib/commands/actions.js +306 -405
  5. package/build/lib/commands/actions.js.map +1 -1
  6. package/build/lib/commands/alert.d.ts +7 -9
  7. package/build/lib/commands/alert.d.ts.map +1 -1
  8. package/build/lib/commands/alert.js +24 -18
  9. package/build/lib/commands/alert.js.map +1 -1
  10. package/build/lib/commands/app-management.d.ts +7 -313
  11. package/build/lib/commands/app-management.d.ts.map +1 -1
  12. package/build/lib/commands/app-management.js +135 -293
  13. package/build/lib/commands/app-management.js.map +1 -1
  14. package/build/lib/commands/context.d.ts +8 -92
  15. package/build/lib/commands/context.d.ts.map +1 -1
  16. package/build/lib/commands/context.js +381 -439
  17. package/build/lib/commands/context.js.map +1 -1
  18. package/build/lib/commands/element.d.ts +8 -35
  19. package/build/lib/commands/element.d.ts.map +1 -1
  20. package/build/lib/commands/element.js +153 -136
  21. package/build/lib/commands/element.js.map +1 -1
  22. package/build/lib/commands/emu-console.d.ts +6 -48
  23. package/build/lib/commands/emu-console.d.ts.map +1 -1
  24. package/build/lib/commands/emu-console.js +19 -34
  25. package/build/lib/commands/emu-console.js.map +1 -1
  26. package/build/lib/commands/execute.d.ts +6 -5
  27. package/build/lib/commands/execute.d.ts.map +1 -1
  28. package/build/lib/commands/execute.js +77 -66
  29. package/build/lib/commands/execute.js.map +1 -1
  30. package/build/lib/commands/file-actions.d.ts +7 -128
  31. package/build/lib/commands/file-actions.d.ts.map +1 -1
  32. package/build/lib/commands/file-actions.js +183 -219
  33. package/build/lib/commands/file-actions.js.map +1 -1
  34. package/build/lib/commands/find.d.ts +8 -12
  35. package/build/lib/commands/find.d.ts.map +1 -1
  36. package/build/lib/commands/find.js +19 -23
  37. package/build/lib/commands/find.js.map +1 -1
  38. package/build/lib/commands/general.d.ts +9 -132
  39. package/build/lib/commands/general.d.ts.map +1 -1
  40. package/build/lib/commands/general.js +281 -312
  41. package/build/lib/commands/general.js.map +1 -1
  42. package/build/lib/commands/ime.d.ts +7 -10
  43. package/build/lib/commands/ime.d.ts.map +1 -1
  44. package/build/lib/commands/ime.js +47 -35
  45. package/build/lib/commands/ime.js.map +1 -1
  46. package/build/lib/commands/index.d.ts +27 -2
  47. package/build/lib/commands/index.d.ts.map +1 -1
  48. package/build/lib/commands/index.js +41 -19
  49. package/build/lib/commands/index.js.map +1 -1
  50. package/build/lib/commands/intent.d.ts +7 -417
  51. package/build/lib/commands/intent.d.ts.map +1 -1
  52. package/build/lib/commands/intent.js +104 -216
  53. package/build/lib/commands/intent.js.map +1 -1
  54. package/build/lib/commands/keyboard.d.ts +6 -5
  55. package/build/lib/commands/keyboard.d.ts.map +1 -1
  56. package/build/lib/commands/keyboard.js +16 -8
  57. package/build/lib/commands/keyboard.js.map +1 -1
  58. package/build/lib/commands/log.d.ts +7 -44
  59. package/build/lib/commands/log.d.ts.map +1 -1
  60. package/build/lib/commands/log.js +146 -108
  61. package/build/lib/commands/log.js.map +1 -1
  62. package/build/lib/commands/media-projection.d.ts +7 -143
  63. package/build/lib/commands/media-projection.d.ts.map +1 -1
  64. package/build/lib/commands/media-projection.js +113 -140
  65. package/build/lib/commands/media-projection.js.map +1 -1
  66. package/build/lib/commands/mixins.d.ts +740 -0
  67. package/build/lib/commands/mixins.d.ts.map +1 -0
  68. package/build/lib/commands/mixins.js +19 -0
  69. package/build/lib/commands/mixins.js.map +1 -0
  70. package/build/lib/commands/network.d.ts +7 -138
  71. package/build/lib/commands/network.d.ts.map +1 -1
  72. package/build/lib/commands/network.js +212 -254
  73. package/build/lib/commands/network.js.map +1 -1
  74. package/build/lib/commands/performance.d.ts +24 -70
  75. package/build/lib/commands/performance.d.ts.map +1 -1
  76. package/build/lib/commands/performance.js +144 -100
  77. package/build/lib/commands/performance.js.map +1 -1
  78. package/build/lib/commands/permissions.d.ts +8 -92
  79. package/build/lib/commands/permissions.d.ts.map +1 -1
  80. package/build/lib/commands/permissions.js +75 -87
  81. package/build/lib/commands/permissions.js.map +1 -1
  82. package/build/lib/commands/recordscreen.d.ts +7 -193
  83. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  84. package/build/lib/commands/recordscreen.js +151 -182
  85. package/build/lib/commands/recordscreen.js.map +1 -1
  86. package/build/lib/commands/shell.d.ts +7 -7
  87. package/build/lib/commands/shell.d.ts.map +1 -1
  88. package/build/lib/commands/shell.js +40 -33
  89. package/build/lib/commands/shell.js.map +1 -1
  90. package/build/lib/commands/streamscreen.d.ts +9 -103
  91. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  92. package/build/lib/commands/streamscreen.js +261 -218
  93. package/build/lib/commands/streamscreen.js.map +1 -1
  94. package/build/lib/commands/system-bars.d.ts +22 -90
  95. package/build/lib/commands/system-bars.d.ts.map +1 -1
  96. package/build/lib/commands/system-bars.js +76 -74
  97. package/build/lib/commands/system-bars.js.map +1 -1
  98. package/build/lib/commands/touch.d.ts +10 -29
  99. package/build/lib/commands/touch.d.ts.map +1 -1
  100. package/build/lib/commands/touch.js +301 -285
  101. package/build/lib/commands/touch.js.map +1 -1
  102. package/build/lib/commands/types.d.ts +978 -0
  103. package/build/lib/commands/types.d.ts.map +1 -0
  104. package/build/lib/commands/types.js +3 -0
  105. package/build/lib/commands/types.js.map +1 -0
  106. package/build/lib/constraints.d.ts +291 -0
  107. package/build/lib/constraints.d.ts.map +1 -0
  108. package/build/lib/{desired-caps.js → constraints.js} +103 -102
  109. package/build/lib/constraints.js.map +1 -0
  110. package/build/lib/driver.d.ts +68 -37
  111. package/build/lib/driver.d.ts.map +1 -1
  112. package/build/lib/driver.js +123 -80
  113. package/build/lib/driver.js.map +1 -1
  114. package/build/lib/helpers/android.d.ts +164 -0
  115. package/build/lib/helpers/android.d.ts.map +1 -0
  116. package/build/lib/helpers/android.js +819 -0
  117. package/build/lib/helpers/android.js.map +1 -0
  118. package/build/lib/helpers/index.d.ts +7 -0
  119. package/build/lib/helpers/index.d.ts.map +1 -0
  120. package/build/lib/helpers/index.js +29 -0
  121. package/build/lib/helpers/index.js.map +1 -0
  122. package/build/lib/helpers/types.d.ts +121 -0
  123. package/build/lib/helpers/types.d.ts.map +1 -0
  124. package/build/lib/helpers/types.js +3 -0
  125. package/build/lib/helpers/types.js.map +1 -0
  126. package/build/lib/helpers/unlock.d.ts +32 -0
  127. package/build/lib/helpers/unlock.d.ts.map +1 -0
  128. package/build/lib/helpers/unlock.js +273 -0
  129. package/build/lib/helpers/unlock.js.map +1 -0
  130. package/build/lib/helpers/webview.d.ts +74 -0
  131. package/build/lib/helpers/webview.d.ts.map +1 -0
  132. package/build/lib/helpers/webview.js +421 -0
  133. package/build/lib/helpers/webview.js.map +1 -0
  134. package/build/lib/index.d.ts +9 -0
  135. package/build/lib/index.d.ts.map +1 -0
  136. package/build/lib/index.js +37 -0
  137. package/build/lib/index.js.map +1 -0
  138. package/build/lib/method-map.d.ts +0 -8
  139. package/build/lib/method-map.d.ts.map +1 -1
  140. package/build/lib/method-map.js +63 -74
  141. package/build/lib/method-map.js.map +1 -1
  142. package/build/lib/stubs.d.ts +0 -1
  143. package/build/lib/stubs.d.ts.map +1 -1
  144. package/build/lib/stubs.js +1 -0
  145. package/build/lib/stubs.js.map +1 -1
  146. package/build/lib/utils.d.ts +1 -1
  147. package/build/lib/utils.d.ts.map +1 -1
  148. package/lib/commands/actions.js +351 -464
  149. package/lib/commands/alert.js +27 -17
  150. package/lib/commands/app-management.js +156 -314
  151. package/lib/commands/context.js +457 -441
  152. package/lib/commands/element.js +201 -157
  153. package/lib/commands/emu-console.js +25 -45
  154. package/lib/commands/execute.js +106 -90
  155. package/lib/commands/file-actions.js +222 -240
  156. package/lib/commands/find.ts +103 -0
  157. package/lib/commands/general.js +327 -339
  158. package/lib/commands/ime.js +50 -34
  159. package/lib/commands/{index.js → index.ts} +20 -24
  160. package/lib/commands/intent.js +108 -249
  161. package/lib/commands/keyboard.js +20 -8
  162. package/lib/commands/log.js +172 -116
  163. package/lib/commands/media-projection.js +134 -161
  164. package/lib/commands/mixins.ts +966 -0
  165. package/lib/commands/network.js +252 -281
  166. package/lib/commands/performance.js +203 -132
  167. package/lib/commands/permissions.js +108 -109
  168. package/lib/commands/recordscreen.js +212 -209
  169. package/lib/commands/shell.js +51 -40
  170. package/lib/commands/streamscreen.js +355 -289
  171. package/lib/commands/system-bars.js +92 -83
  172. package/lib/commands/touch.js +357 -294
  173. package/lib/commands/types.ts +1097 -0
  174. package/lib/{desired-caps.js → constraints.ts} +106 -103
  175. package/lib/{driver.js → driver.ts} +278 -132
  176. package/lib/helpers/android.ts +1143 -0
  177. package/lib/helpers/index.ts +6 -0
  178. package/lib/helpers/types.ts +134 -0
  179. package/lib/helpers/unlock.ts +329 -0
  180. package/lib/helpers/webview.ts +582 -0
  181. package/lib/index.ts +18 -0
  182. package/lib/method-map.js +87 -98
  183. package/lib/stubs.ts +0 -1
  184. package/package.json +26 -19
  185. package/build/index.js +0 -51
  186. package/build/lib/android-helpers.d.ts +0 -136
  187. package/build/lib/android-helpers.d.ts.map +0 -1
  188. package/build/lib/android-helpers.js +0 -855
  189. package/build/lib/android-helpers.js.map +0 -1
  190. package/build/lib/commands/coverage.d.ts +0 -5
  191. package/build/lib/commands/coverage.d.ts.map +0 -1
  192. package/build/lib/commands/coverage.js +0 -19
  193. package/build/lib/commands/coverage.js.map +0 -1
  194. package/build/lib/desired-caps.d.ts +0 -353
  195. package/build/lib/desired-caps.d.ts.map +0 -1
  196. package/build/lib/desired-caps.js.map +0 -1
  197. package/build/lib/unlock-helpers.d.ts +0 -38
  198. package/build/lib/unlock-helpers.d.ts.map +0 -1
  199. package/build/lib/unlock-helpers.js +0 -266
  200. package/build/lib/unlock-helpers.js.map +0 -1
  201. package/build/lib/webview-helpers.d.ts +0 -224
  202. package/build/lib/webview-helpers.d.ts.map +0 -1
  203. package/build/lib/webview-helpers.js +0 -528
  204. package/build/lib/webview-helpers.js.map +0 -1
  205. package/index.js +0 -24
  206. package/lib/android-helpers.js +0 -983
  207. package/lib/commands/coverage.js +0 -18
  208. package/lib/commands/find.js +0 -82
  209. package/lib/unlock-helpers.js +0 -278
  210. package/lib/webview-helpers.js +0 -602
@@ -1,24 +1,32 @@
1
1
  "use strict";
2
+ // @ts-check
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
5
  };
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.helpers = exports.commands = void 0;
7
- const lodash_1 = __importDefault(require("lodash"));
8
- const android_helpers_1 = __importDefault(require("../android-helpers"));
9
- const bluebird_1 = __importDefault(require("bluebird"));
7
+ const support_1 = require("@appium/support");
10
8
  const driver_1 = require("appium/driver");
11
9
  const asyncbox_1 = require("asyncbox");
12
- const support_1 = require("@appium/support");
13
- let commands = {}, helpers = {}, extensions = {};
14
- exports.commands = commands;
15
- exports.helpers = helpers;
10
+ const bluebird_1 = __importDefault(require("bluebird"));
11
+ const lodash_1 = __importDefault(require("lodash"));
12
+ const android_1 = __importDefault(require("../helpers/android"));
13
+ const mixins_1 = require("./mixins");
14
+ /**
15
+ *
16
+ * @param {number|null} [val]
17
+ * @returns {number}
18
+ */
16
19
  function getCoordDefault(val) {
17
20
  // going the long way and checking for undefined and null since
18
21
  // we can't be assured `elId` is a string and not an int. Same
19
22
  // thing with destElement below.
20
23
  return support_1.util.hasValue(val) ? val : 0.5;
21
24
  }
25
+ /**
26
+ *
27
+ * @param {NonReleaseTouchAction} waitGesture
28
+ * @returns {number}
29
+ */
22
30
  function getSwipeTouchDuration(waitGesture) {
23
31
  // the touch action api uses ms, we want seconds
24
32
  // 0.8 is the default time for the operation
@@ -33,314 +41,322 @@ function getSwipeTouchDuration(waitGesture) {
33
41
  }
34
42
  return duration;
35
43
  }
36
- commands.doTouchAction = async function doTouchAction(action, opts = {}) {
37
- const { element, x, y, count, ms, duration } = opts;
38
- // parseTouch precalculates absolute element positions
39
- // so there is no need to pass `element` to the affected gestures
40
- switch (action) {
41
- case 'tap':
42
- return await this.tap(null, x, y, count);
43
- case 'press':
44
- return await this.touchDown(null, x, y);
45
- case 'release':
46
- return await this.touchUp(element, x, y);
47
- case 'moveTo':
48
- return await this.touchMove(null, x, y);
49
- case 'wait':
50
- return await bluebird_1.default.delay(ms);
51
- case 'longPress':
52
- return await this.touchLongClick(null, x, y, duration || 1000);
53
- case 'cancel':
54
- // TODO: clarify behavior of 'cancel' action and fix this
55
- this.log.warn('Cancel action currently has no effect');
56
- break;
57
- default:
58
- this.log.errorAndThrow(`unknown action ${action}`);
59
- }
60
- };
61
- // drag is *not* press-move-release, so we need to translate
62
- // drag works fine for scroll, as well
63
- helpers.doTouchDrag = async function doTouchDrag(gestures) {
64
- let longPress = gestures[0];
65
- let moveTo = gestures[1];
66
- let startX = longPress.options.x || 0, startY = longPress.options.y || 0, endX = moveTo.options.x || 0, endY = moveTo.options.y || 0;
67
- if (longPress.options.element) {
68
- let { x, y } = await this.getLocationInView(longPress.options.element);
69
- startX += x || 0;
70
- startY += y || 0;
71
- }
72
- if (moveTo.options.element) {
73
- let { x, y } = await this.getLocationInView(moveTo.options.element);
74
- endX += x || 0;
75
- endY += y || 0;
76
- }
77
- let apiLevel = await this.adb.getApiLevel();
78
- // lollipop takes a little longer to get things rolling
79
- let duration = apiLevel >= 5 ? 2 : 1;
80
- // make sure that if the long press has a duration, we use it.
81
- if (longPress.options && longPress.options.duration) {
82
- duration = Math.max(longPress.options.duration / 1000, duration);
83
- }
84
- // `drag` will take care of whether there is an element or not at that level
85
- return await this.drag(startX, startY, endX, endY, duration, 1, longPress.options.element, moveTo.options.element);
86
- };
87
- // Release gesture needs element or co-ordinates to release it from that position
88
- // or else release gesture is performed from center of the screen, so to fix it
89
- // This method sets co-ordinates/element to release gesture if it has no options set already.
90
- helpers.fixRelease = async function fixRelease(gestures) {
91
- let release = lodash_1.default.last(gestures);
92
- // sometimes there are no options
93
- release.options = release.options || {};
94
- // nothing to do if release options are already set
95
- if (release.options.element || (release.options.x && release.options.y)) {
96
- return;
97
- }
98
- // without coordinates, `release` uses the center of the screen, which,
99
- // generally speaking, is not what we want
100
- // therefore: loop backwards and use the last command with an element and/or
101
- // offset coordinates
102
- gestures = lodash_1.default.clone(gestures);
103
- let ref = null;
104
- for (let gesture of gestures.reverse()) {
105
- let opts = gesture.options;
106
- if (opts.element || (opts.x && opts.y)) {
107
- ref = gesture;
108
- break;
44
+ /**
45
+ * @type {import('./mixins').TouchMixin & ThisType<import('../driver').AndroidDriver>}
46
+ * @satisfies {import('@appium/types').ExternalDriver}
47
+ */
48
+ const TouchMixin = {
49
+ async doTouchAction(action, opts = {}) {
50
+ const { element, x, y, count, ms, duration } = opts;
51
+ // parseTouch precalculates absolute element positions
52
+ // so there is no need to pass `element` to the affected gestures
53
+ switch (action) {
54
+ case 'tap':
55
+ return await this.tap('', x, y, count);
56
+ case 'press':
57
+ return await this.touchDown('', /** @type {number} */ (x), /** @type {number} */ (y));
58
+ case 'release':
59
+ return await this.touchUp(String(element),
60
+ /** @type {number} */ (x),
61
+ /** @type {number} */ (y));
62
+ case 'moveTo':
63
+ return await this.touchMove('', /** @type {number} */ (x), /** @type {number} */ (y));
64
+ case 'wait':
65
+ return await bluebird_1.default.delay(/** @type {number} */ (ms));
66
+ case 'longPress':
67
+ return await this.touchLongClick('',
68
+ /** @type {number} */ (x),
69
+ /** @type {number} */ (y), duration ?? 1000);
70
+ case 'cancel':
71
+ // TODO: clarify behavior of 'cancel' action and fix this
72
+ this.log.warn('Cancel action currently has no effect');
73
+ break;
74
+ default:
75
+ this.log.errorAndThrow(`unknown action ${action}`);
109
76
  }
110
- }
111
- if (ref) {
112
- let opts = ref.options;
113
- if (opts.element) {
114
- let loc = await this.getLocationInView(opts.element);
115
- if (opts.x && opts.y) {
116
- // this is an offset from the element
117
- release.options = {
118
- x: loc.x + opts.x,
119
- y: loc.y + opts.y
120
- };
77
+ },
78
+ async doTouchDrag(gestures) {
79
+ let longPress = gestures[0];
80
+ let moveTo = gestures[1];
81
+ let startX = longPress.options.x || 0, startY = longPress.options.y || 0, endX = moveTo.options.x || 0, endY = moveTo.options.y || 0;
82
+ if (longPress.options.element) {
83
+ let { x, y } = await this.getLocationInView(longPress.options.element);
84
+ startX += x || 0;
85
+ startY += y || 0;
86
+ }
87
+ if (moveTo.options.element) {
88
+ let { x, y } = await this.getLocationInView(moveTo.options.element);
89
+ endX += x || 0;
90
+ endY += y || 0;
91
+ }
92
+ let apiLevel = await /** @type {ADB} */ (this.adb).getApiLevel();
93
+ // lollipop takes a little longer to get things rolling
94
+ let duration = apiLevel >= 5 ? 2 : 1;
95
+ // make sure that if the long press has a duration, we use it.
96
+ if (longPress.options && longPress.options.duration) {
97
+ duration = Math.max(longPress.options.duration / 1000, duration);
98
+ }
99
+ // `drag` will take care of whether there is an element or not at that level
100
+ return await this.drag(startX, startY, endX, endY, duration, 1, longPress.options.element, moveTo.options.element);
101
+ },
102
+ async fixRelease(gestures) {
103
+ let release = /** @type {import('./types').ReleaseTouchAction} */ (lodash_1.default.last(gestures));
104
+ // sometimes there are no options
105
+ release.options = release.options || {};
106
+ // nothing to do if release options are already set
107
+ if (release.options.element || (release.options.x && release.options.y)) {
108
+ return;
109
+ }
110
+ // without coordinates, `release` uses the center of the screen, which,
111
+ // generally speaking, is not what we want
112
+ // therefore: loop backwards and use the last command with an element and/or
113
+ // offset coordinates
114
+ gestures = lodash_1.default.clone(gestures);
115
+ let ref = null;
116
+ for (let gesture of /** @type {NonReleaseTouchAction[]} */ (gestures.reverse())) {
117
+ let opts = gesture.options;
118
+ if (opts.element || (opts.x && opts.y)) {
119
+ ref = gesture;
120
+ break;
121
+ }
122
+ }
123
+ if (ref) {
124
+ let opts = ref.options;
125
+ if (opts.element) {
126
+ let loc = await this.getLocationInView(opts.element);
127
+ if (opts.x && opts.y) {
128
+ // this is an offset from the element
129
+ release.options = {
130
+ x: loc.x + opts.x,
131
+ y: loc.y + opts.y,
132
+ };
133
+ }
134
+ else {
135
+ // this is the center of the element
136
+ let size = await this.getSize(opts.element);
137
+ release.options = {
138
+ x: loc.x + size.width / 2,
139
+ y: loc.y + size.height / 2,
140
+ };
141
+ }
121
142
  }
122
143
  else {
123
- // this is the center of the element
124
- let size = await this.getSize(opts.element);
125
- release.options = {
126
- x: loc.x + size.width / 2,
127
- y: loc.y + size.height / 2
128
- };
144
+ release.options = lodash_1.default.pick(opts, 'x', 'y');
129
145
  }
130
146
  }
131
- else {
132
- release.options = lodash_1.default.pick(opts, 'x', 'y');
133
- }
134
- }
135
- return release;
136
- };
137
- // Perform one gesture
138
- helpers.performGesture = async function performGesture(gesture) {
139
- try {
140
- return await this.doTouchAction(gesture.action, gesture.options || {});
141
- }
142
- catch (e) {
143
- // sometime the element is not available when releasing, retry without it
144
- if ((0, driver_1.isErrorType)(e, driver_1.errors.NoSuchElementError) && gesture.action === 'release' &&
145
- gesture.options.element) {
146
- delete gesture.options.element;
147
- this.log.debug(`retrying release without element opts: ${gesture.options}.`);
147
+ return release;
148
+ },
149
+ async performGesture(gesture) {
150
+ try {
148
151
  return await this.doTouchAction(gesture.action, gesture.options || {});
149
152
  }
150
- throw e;
151
- }
152
- };
153
- commands.getSwipeOptions = async function getSwipeOptions(gestures, touchCount = 1) {
154
- let startX = getCoordDefault(gestures[0].options.x), startY = getCoordDefault(gestures[0].options.y), endX = getCoordDefault(gestures[2].options.x), endY = getCoordDefault(gestures[2].options.y), duration = getSwipeTouchDuration(gestures[1]), element = gestures[0].options.element, destElement = gestures[2].options.element || gestures[0].options.element;
155
- // there's no destination element handling in bootstrap and since it applies to all platforms, we handle it here
156
- if (support_1.util.hasValue(destElement)) {
157
- let locResult = await this.getLocationInView(destElement);
158
- let sizeResult = await this.getSize(destElement);
159
- let offsetX = (Math.abs(endX) < 1 && Math.abs(endX) > 0) ? sizeResult.width * endX : endX;
160
- let offsetY = (Math.abs(endY) < 1 && Math.abs(endY) > 0) ? sizeResult.height * endY : endY;
161
- endX = locResult.x + offsetX;
162
- endY = locResult.y + offsetY;
163
- // if the target element was provided, the coordinates for the destination need to be relative to it.
164
- if (support_1.util.hasValue(element)) {
165
- let firstElLocation = await this.getLocationInView(element);
166
- endX -= firstElLocation.x;
167
- endY -= firstElLocation.y;
168
- }
169
- }
170
- // clients are responsible to use these options correctly
171
- return { startX, startY, endX, endY, duration, touchCount, element };
172
- };
173
- commands.performTouch = async function performTouch(gestures) {
174
- // press-wait-moveTo-release is `swipe`, so use native method
175
- if (gestures.length === 4 &&
176
- gestures[0].action === 'press' &&
177
- gestures[1].action === 'wait' &&
178
- gestures[2].action === 'moveTo' &&
179
- gestures[3].action === 'release') {
180
- let swipeOpts = await this.getSwipeOptions(gestures);
181
- return await this.swipe(swipeOpts.startX, swipeOpts.startY, swipeOpts.endX, swipeOpts.endY, swipeOpts.duration, swipeOpts.touchCount, swipeOpts.element);
182
- }
183
- let actions = lodash_1.default.map(gestures, 'action');
184
- if (actions[0] === 'longPress' && actions[1] === 'moveTo' && actions[2] === 'release') {
185
- // some things are special
186
- return await this.doTouchDrag(gestures);
187
- }
188
- else {
189
- if (actions.length === 2) {
190
- // `press` without a wait is too slow and gets interpretted as a `longPress`
191
- if (lodash_1.default.head(actions) === 'press' && lodash_1.default.last(actions) === 'release') {
192
- actions[0] = 'tap';
193
- gestures[0].action = 'tap';
153
+ catch (e) {
154
+ // sometime the element is not available when releasing, retry without it
155
+ if ((0, driver_1.isErrorType)(e, driver_1.errors.NoSuchElementError) &&
156
+ gesture.action === 'release' &&
157
+ gesture.options?.element) {
158
+ delete gesture.options.element;
159
+ this.log.debug(`retrying release without element opts: ${gesture.options}.`);
160
+ return await this.doTouchAction(gesture.action, gesture.options || {});
194
161
  }
195
- // the `longPress` and `tap` methods release on their own
196
- if ((lodash_1.default.head(actions) === 'tap' || lodash_1.default.head(actions) === 'longPress') && lodash_1.default.last(actions) === 'release') {
197
- gestures.pop();
198
- actions.pop();
162
+ throw e;
163
+ }
164
+ },
165
+ async getSwipeOptions(gestures, touchCount = 1) {
166
+ let startX = getCoordDefault(gestures[0].options.x), startY = getCoordDefault(gestures[0].options.y), endX = getCoordDefault(gestures[2].options.x), endY = getCoordDefault(gestures[2].options.y), duration = getSwipeTouchDuration(gestures[1]), element = /** @type {string} */ (gestures[0].options.element), destElement = gestures[2].options.element || gestures[0].options.element;
167
+ // there's no destination element handling in bootstrap and since it applies to all platforms, we handle it here
168
+ if (support_1.util.hasValue(destElement)) {
169
+ let locResult = await this.getLocationInView(destElement);
170
+ let sizeResult = await this.getSize(destElement);
171
+ let offsetX = Math.abs(endX) < 1 && Math.abs(endX) > 0 ? sizeResult.width * endX : endX;
172
+ let offsetY = Math.abs(endY) < 1 && Math.abs(endY) > 0 ? sizeResult.height * endY : endY;
173
+ endX = locResult.x + offsetX;
174
+ endY = locResult.y + offsetY;
175
+ // if the target element was provided, the coordinates for the destination need to be relative to it.
176
+ if (support_1.util.hasValue(element)) {
177
+ let firstElLocation = await this.getLocationInView(element);
178
+ endX -= firstElLocation.x;
179
+ endY -= firstElLocation.y;
199
180
  }
200
181
  }
182
+ // clients are responsible to use these options correctly
183
+ return { startX, startY, endX, endY, duration, touchCount, element };
184
+ },
185
+ async performTouch(gestures) {
186
+ // press-wait-moveTo-release is `swipe`, so use native method
187
+ if (gestures.length === 4 &&
188
+ gestures[0].action === 'press' &&
189
+ gestures[1].action === 'wait' &&
190
+ gestures[2].action === 'moveTo' &&
191
+ gestures[3].action === 'release') {
192
+ let swipeOpts = await this.getSwipeOptions(
193
+ /** @type {import('./types').SwipeAction} */ (gestures));
194
+ return await this.swipe(swipeOpts.startX, swipeOpts.startY, swipeOpts.endX, swipeOpts.endY, swipeOpts.duration, swipeOpts.touchCount, swipeOpts.element);
195
+ }
196
+ let actions = /** @type {(import('./types').TouchActionKind|TouchAction)[]} */ (lodash_1.default.map(gestures, 'action'));
197
+ if (actions[0] === 'longPress' && actions[1] === 'moveTo' && actions[2] === 'release') {
198
+ // some things are special
199
+ return await this.doTouchDrag(/** @type {import('./types').TouchDragAction} */ (gestures));
200
+ }
201
201
  else {
202
- // longpress followed by anything other than release should become a press and wait
203
- if (actions[0] === 'longPress') {
204
- actions = ['press', 'wait', ...actions.slice(1)];
205
- let press = gestures.shift();
206
- press.action = 'press';
207
- let wait = {
208
- action: 'wait',
209
- options: { ms: press.options.duration || 1000 }
210
- };
211
- delete press.options.duration;
212
- gestures = [press, wait, ...gestures];
202
+ if (actions.length === 2) {
203
+ // `press` without a wait is too slow and gets interpretted as a `longPress`
204
+ if (lodash_1.default.head(actions) === 'press' && lodash_1.default.last(actions) === 'release') {
205
+ actions[0] = 'tap';
206
+ gestures[0].action = 'tap';
207
+ }
208
+ // the `longPress` and `tap` methods release on their own
209
+ if ((lodash_1.default.head(actions) === 'tap' || lodash_1.default.head(actions) === 'longPress') &&
210
+ lodash_1.default.last(actions) === 'release') {
211
+ gestures.pop();
212
+ actions.pop();
213
+ }
214
+ }
215
+ else {
216
+ // longpress followed by anything other than release should become a press and wait
217
+ if (actions[0] === 'longPress') {
218
+ actions = ['press', 'wait', ...actions.slice(1)];
219
+ let press = /** @type {NonReleaseTouchAction} */ (gestures.shift());
220
+ press.action = 'press';
221
+ /** @type {NonReleaseTouchAction} */
222
+ let wait = {
223
+ action: 'wait',
224
+ options: { ms: press.options.duration || 1000 },
225
+ };
226
+ delete press.options.duration;
227
+ gestures = [press, wait, ...gestures];
228
+ }
229
+ }
230
+ let fixedGestures = await this.parseTouch(gestures, false);
231
+ // fix release action then perform all actions
232
+ if (actions[actions.length - 1] === 'release') {
233
+ actions[actions.length - 1] = /** @type {TouchAction} */ (await this.fixRelease(gestures));
234
+ }
235
+ for (let g of fixedGestures) {
236
+ await this.performGesture(g);
213
237
  }
214
238
  }
215
- let fixedGestures = await this.parseTouch(gestures, false);
216
- // fix release action then perform all actions
217
- if (actions[actions.length - 1] === 'release') {
218
- actions[actions.length - 1] = await this.fixRelease(gestures);
219
- }
220
- for (let g of fixedGestures) {
221
- await this.performGesture(g);
239
+ },
240
+ async parseTouch(gestures, multi) {
241
+ // because multi-touch releases at the end by default
242
+ if (multi && /** @type {TouchAction} */ (lodash_1.default.last(gestures)).action === 'release') {
243
+ gestures.pop();
222
244
  }
223
- }
224
- };
225
- helpers.parseTouch = async function parseTouch(gestures, multi) {
226
- // because multi-touch releases at the end by default
227
- if (multi && lodash_1.default.last(gestures).action === 'release') {
228
- gestures.pop();
229
- }
230
- let touchStateObjects = await (0, asyncbox_1.asyncmap)(gestures, async (gesture) => {
231
- let options = gesture.options || {};
232
- if (lodash_1.default.includes(['press', 'moveTo', 'tap', 'longPress'], gesture.action)) {
233
- options.offset = false;
234
- let elementId = gesture.options.element;
235
- if (elementId) {
236
- let pos = await this.getLocationInView(elementId);
237
- if (gesture.options.x || gesture.options.y) {
238
- options.x = pos.x + (gesture.options.x || 0);
239
- options.y = pos.y + (gesture.options.y || 0);
245
+ let touchStateObjects = await (0, asyncbox_1.asyncmap)(gestures, async (gesture) => {
246
+ let options = gesture.options || {};
247
+ if (lodash_1.default.includes(['press', 'moveTo', 'tap', 'longPress'], gesture.action)) {
248
+ options.offset = false;
249
+ let elementId = gesture.options.element;
250
+ if (elementId) {
251
+ let pos = await this.getLocationInView(elementId);
252
+ if (gesture.options.x || gesture.options.y) {
253
+ options.x = pos.x + (gesture.options.x || 0);
254
+ options.y = pos.y + (gesture.options.y || 0);
255
+ }
256
+ else {
257
+ const { width, height } = await this.getSize(elementId);
258
+ options.x = pos.x + width / 2;
259
+ options.y = pos.y + height / 2;
260
+ }
261
+ let touchStateObject = {
262
+ action: gesture.action,
263
+ options,
264
+ timeOffset: 0.005,
265
+ };
266
+ return touchStateObject;
240
267
  }
241
268
  else {
242
- const { width, height } = await this.getSize(elementId);
243
- options.x = pos.x + (width / 2);
244
- options.y = pos.y + (height / 2);
269
+ options.x = gesture.options.x || 0;
270
+ options.y = gesture.options.y || 0;
271
+ let touchStateObject = {
272
+ action: gesture.action,
273
+ options,
274
+ timeOffset: 0.005,
275
+ };
276
+ return touchStateObject;
245
277
  }
246
- let touchStateObject = {
247
- action: gesture.action,
248
- options,
249
- timeOffset: 0.005,
250
- };
251
- return touchStateObject;
252
278
  }
253
279
  else {
254
- options.x = (gesture.options.x || 0);
255
- options.y = (gesture.options.y || 0);
280
+ let offset = 0.005;
281
+ if (gesture.action === 'wait') {
282
+ options = gesture.options;
283
+ offset = parseInt(gesture.options.ms, 10) / 1000;
284
+ }
256
285
  let touchStateObject = {
257
286
  action: gesture.action,
258
287
  options,
259
- timeOffset: 0.005,
288
+ timeOffset: offset,
260
289
  };
261
290
  return touchStateObject;
262
291
  }
263
- }
264
- else {
265
- let offset = 0.005;
266
- if (gesture.action === 'wait') {
267
- options = gesture.options;
268
- offset = (parseInt(gesture.options.ms, 10) / 1000);
292
+ }, false);
293
+ // we need to change the time (which is now an offset)
294
+ // and the position (which may be an offset)
295
+ let prevPos = null, time = 0;
296
+ for (let state of touchStateObjects) {
297
+ if (lodash_1.default.isUndefined(state.options.x) && lodash_1.default.isUndefined(state.options.y) && prevPos !== null) {
298
+ // this happens with wait
299
+ state.options.x = prevPos.x;
300
+ state.options.y = prevPos.y;
269
301
  }
270
- let touchStateObject = {
271
- action: gesture.action,
272
- options,
273
- timeOffset: offset,
274
- };
275
- return touchStateObject;
276
- }
277
- }, false);
278
- // we need to change the time (which is now an offset)
279
- // and the position (which may be an offset)
280
- let prevPos = null, time = 0;
281
- for (let state of touchStateObjects) {
282
- if (lodash_1.default.isUndefined(state.options.x) && lodash_1.default.isUndefined(state.options.y) && prevPos !== null) {
283
- // this happens with wait
284
- state.options.x = prevPos.x;
285
- state.options.y = prevPos.y;
302
+ if (state.options.offset && prevPos) {
303
+ // the current position is an offset
304
+ state.options.x += prevPos.x;
305
+ state.options.y += prevPos.y;
306
+ }
307
+ delete state.options.offset;
308
+ if (!lodash_1.default.isUndefined(state.options.x) && !lodash_1.default.isUndefined(state.options.y)) {
309
+ prevPos = state.options;
310
+ }
311
+ if (multi) {
312
+ let timeOffset = state.timeOffset;
313
+ time += timeOffset;
314
+ state.time = android_1.default.truncateDecimals(time, 3);
315
+ // multi gestures require 'touch' rather than 'options'
316
+ if (!lodash_1.default.isUndefined(state.options.x) && !lodash_1.default.isUndefined(state.options.y)) {
317
+ state.touch = {
318
+ x: state.options.x,
319
+ y: state.options.y,
320
+ };
321
+ }
322
+ delete state.options;
323
+ }
324
+ delete state.timeOffset;
286
325
  }
287
- if (state.options.offset && prevPos) {
288
- // the current position is an offset
289
- state.options.x += prevPos.x;
290
- state.options.y += prevPos.y;
326
+ return touchStateObjects;
327
+ },
328
+ async performMultiAction(actions, elementId) {
329
+ // Android needs at least two actions to be able to perform a multi pointer gesture
330
+ if (actions.length === 1) {
331
+ throw new Error('Multi Pointer Gestures need at least two actions. ' +
332
+ 'Use Touch Actions for a single action.');
291
333
  }
292
- delete state.options.offset;
293
- if (!lodash_1.default.isUndefined(state.options.x) && !lodash_1.default.isUndefined(state.options.y)) {
294
- prevPos = state.options;
334
+ const states = await (0, asyncbox_1.asyncmap)(actions, async (action) => await this.parseTouch(action, true), false);
335
+ return await this.doPerformMultiAction(elementId, states);
336
+ },
337
+ async doPerformMultiAction(elementId, states) {
338
+ let opts;
339
+ if (elementId) {
340
+ opts = {
341
+ elementId,
342
+ actions: states,
343
+ };
344
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('element:performMultiPointerGesture', opts);
295
345
  }
296
- if (multi) {
297
- let timeOffset = state.timeOffset;
298
- time += timeOffset;
299
- state.time = android_helpers_1.default.truncateDecimals(time, 3);
300
- // multi gestures require 'touch' rather than 'options'
301
- if (!lodash_1.default.isUndefined(state.options.x) && !lodash_1.default.isUndefined(state.options.y)) {
302
- state.touch = {
303
- x: state.options.x,
304
- y: state.options.y
305
- };
306
- }
307
- delete state.options;
346
+ else {
347
+ opts = {
348
+ actions: states,
349
+ };
350
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('performMultiPointerGesture', opts);
308
351
  }
309
- delete state.timeOffset;
310
- }
311
- return touchStateObjects;
312
- };
313
- commands.performMultiAction = async function performMultiAction(actions, elementId) {
314
- // Android needs at least two actions to be able to perform a multi pointer gesture
315
- if (actions.length === 1) {
316
- throw new Error('Multi Pointer Gestures need at least two actions. ' +
317
- 'Use Touch Actions for a single action.');
318
- }
319
- const states = await (0, asyncbox_1.asyncmap)(actions, async (action) => await this.parseTouch(action, true), false);
320
- return await this.doPerformMultiAction(elementId, states);
352
+ },
321
353
  };
354
+ (0, mixins_1.mixin)(TouchMixin);
355
+ exports.default = TouchMixin;
322
356
  /**
323
- * Reason for isolating doPerformMultiAction from performMultiAction is for reusing performMultiAction
324
- * across android-drivers (like appium-uiautomator2-driver) and to avoid code duplication.
325
- * Other android-drivers (like appium-uiautomator2-driver) need to override doPerformMultiAction
326
- * to facilitate performMultiAction.
357
+ * @typedef {import('appium-adb').ADB} ADB
358
+ * @typedef {import('./types').TouchAction} TouchAction
359
+ * @typedef {import('./types').NonReleaseTouchAction} NonReleaseTouchAction
360
+ * @typedef {import('../bootstrap').AndroidBootstrap} AndroidBootstrap
327
361
  */
328
- commands.doPerformMultiAction = async function doPerformMultiAction(elementId, states) {
329
- let opts;
330
- if (elementId) {
331
- opts = {
332
- elementId,
333
- actions: states
334
- };
335
- return await this.bootstrap.sendAction('element:performMultiPointerGesture', opts);
336
- }
337
- else {
338
- opts = {
339
- actions: states
340
- };
341
- return await this.bootstrap.sendAction('performMultiPointerGesture', opts);
342
- }
343
- };
344
- Object.assign(extensions, commands, helpers);
345
- exports.default = extensions;
346
362
  //# sourceMappingURL=touch.js.map