appium-android-driver 12.4.9 → 12.4.10

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.
@@ -1,5 +1,8 @@
1
1
  import {errors} from 'appium/driver';
2
2
  import _ from 'lodash';
3
+ import type {StringRecord} from '@appium/types';
4
+ import type {AndroidDriver} from '../driver';
5
+ import type {StatusBarCommand, WindowProperties} from './types';
3
6
 
4
7
  const WINDOW_TITLE_PATTERN = /^\s+Window\s#\d+\sWindow\{[0-9a-f]+\s\w+\s([\w-]+)\}:$/;
5
8
  const FRAME_PATTERN = /\bm?[Ff]rame=\[([0-9.-]+),([0-9.-]+)\]\[([0-9.-]+),([0-9.-]+)\]/;
@@ -11,7 +14,7 @@ const VIEW_VISIBILITY_PATTERN = /\bmViewVisibility=(0x[0-9a-fA-F]+)/;
11
14
  const VIEW_VISIBLE = 0x0;
12
15
  const STATUS_BAR_WINDOW_NAME_PREFIX = 'StatusBar';
13
16
  const NAVIGATION_BAR_WINDOW_NAME_PREFIX = 'NavigationBar';
14
- const DEFAULT_WINDOW_PROPERTIES = {
17
+ const DEFAULT_WINDOW_PROPERTIES: WindowProperties = {
15
18
  visible: false,
16
19
  x: 0,
17
20
  y: 0,
@@ -20,48 +23,53 @@ const DEFAULT_WINDOW_PROPERTIES = {
20
23
  };
21
24
 
22
25
  /**
23
- * @this {import('../driver').AndroidDriver}
24
- * @returns {Promise<StringRecord>}
26
+ * Gets the system bars (status bar and navigation bar) properties.
27
+ *
28
+ * @returns Promise that resolves to an object containing statusBar and navigationBar properties.
29
+ * @throws {Error} If system bars details cannot be retrieved or parsed.
25
30
  */
26
- export async function getSystemBars() {
27
- /** @type {string} */
28
- let stdout;
31
+ export async function getSystemBars(
32
+ this: AndroidDriver,
33
+ ): Promise<StringRecord> {
34
+ let stdout: string;
29
35
  try {
30
36
  stdout = await this.adb.shell(['dumpsys', 'window', 'windows']);
31
37
  } catch (e) {
32
38
  throw new Error(
33
- `Cannot retrieve system bars details. Original error: ${/** @type {Error} */ (e).message}`,
39
+ `Cannot retrieve system bars details. Original error: ${(e as Error).message}`,
34
40
  );
35
41
  }
36
42
  return parseWindows.bind(this)(stdout);
37
43
  }
38
44
 
39
45
  /**
40
- * @this {import('../driver').AndroidDriver}
41
- * @param {import('./types').StatusBarCommand} command Each list
42
- * item must separated with a new line (`\n`) character.
43
- * @param {string} [component] The name of the tile component.
46
+ * Performs a status bar command.
47
+ *
48
+ * @param command The status bar command to perform.
49
+ * @param component The name of the tile component.
44
50
  * It is only required for `(add|remove|click)Tile` commands.
45
51
  * Example value: `com.package.name/.service.QuickSettingsTileComponent`
46
- * @returns {Promise<string>}
52
+ * @returns Promise that resolves to the command output string.
53
+ * @throws {errors.InvalidArgumentError} If the command is unknown.
47
54
  */
48
- export async function mobilePerformStatusBarCommand(command, component) {
49
- /**
50
- *
51
- * @param {string} cmd
52
- * @param {(() => string[]|string)} [argsCallable]
53
- * @returns
54
- */
55
- const toStatusBarCommandCallable = (cmd, argsCallable) => async () =>
55
+ export async function mobilePerformStatusBarCommand(
56
+ this: AndroidDriver,
57
+ command: StatusBarCommand,
58
+ component?: string,
59
+ ): Promise<string> {
60
+ const toStatusBarCommandCallable = (
61
+ cmd: string,
62
+ argsCallable?: () => string[] | string,
63
+ ) => async (): Promise<string> =>
56
64
  await this.adb.shell([
57
65
  'cmd',
58
66
  'statusbar',
59
67
  cmd,
60
68
  ...(argsCallable ? _.castArray(argsCallable()) : []),
61
69
  ]);
62
- const tileCommandArgsCallable = () => /** @type {string} */ (component);
70
+ const tileCommandArgsCallable = () => component as string;
63
71
  const statusBarCommands = _.fromPairs(
64
- /** @type {const} */ ([
72
+ ([
65
73
  ['expandNotifications', ['expand-notifications']],
66
74
  ['expandSettings', ['expand-settings']],
67
75
  ['collapse', ['collapse']],
@@ -69,8 +77,8 @@ export async function mobilePerformStatusBarCommand(command, component) {
69
77
  ['removeTile', ['remove-tile', tileCommandArgsCallable]],
70
78
  ['clickTile', ['click-tile', tileCommandArgsCallable]],
71
79
  ['getStatusIcons', ['get-status-icons']],
72
- ]).map(([name, args]) => [name, toStatusBarCommandCallable(args[0], args[1])]),
73
- );
80
+ ] as const).map(([name, args]) => [name, toStatusBarCommandCallable(args[0], args[1])]),
81
+ ) as Record<StatusBarCommand, () => Promise<string>>;
74
82
 
75
83
  const action = statusBarCommands[command];
76
84
  if (!action) {
@@ -87,14 +95,17 @@ export async function mobilePerformStatusBarCommand(command, component) {
87
95
  /**
88
96
  * Parses window properties from adb dumpsys output
89
97
  *
90
- * @this {import('../driver').AndroidDriver}
91
- * @param {string} name The name of the window whose properties are being parsed
92
- * @param {Array<string>} props The list of particular window property lines.
98
+ * @param name The name of the window whose properties are being parsed
99
+ * @param props The list of particular window property lines.
93
100
  * Check the corresponding unit tests for more details on the input format.
94
- * @returns {WindowProperties} Parsed properties object
101
+ * @returns Parsed properties object
95
102
  * @throws {Error} If there was an issue while parsing the properties string
96
103
  */
97
- export function parseWindowProperties(name, props) {
104
+ export function parseWindowProperties(
105
+ this: AndroidDriver,
106
+ name: string,
107
+ props: string[],
108
+ ): WindowProperties {
98
109
  const result = _.cloneDeep(DEFAULT_WINDOW_PROPERTIES);
99
110
  const propLines = props.join('\n');
100
111
  const frameMatch = FRAME_PATTERN.exec(propLines);
@@ -118,19 +129,18 @@ export function parseWindowProperties(name, props) {
118
129
  /**
119
130
  * Extracts status and navigation bar information from the window manager output.
120
131
  *
121
- * @this {import('../driver').AndroidDriver}
122
- * @param {string} lines Output from dumpsys command.
132
+ * @param lines Output from dumpsys command.
123
133
  * Check the corresponding unit tests for more details on the input format.
124
- * @return {StringRecord} An object containing two items where keys are statusBar and navigationBar,
134
+ * @return An object containing two items where keys are statusBar and navigationBar,
125
135
  * and values are corresponding WindowProperties objects
126
136
  * @throws {Error} If no window properties could be parsed
127
137
  */
128
- export function parseWindows(lines) {
129
- /**
130
- * @type {StringRecord}
131
- */
132
- const windows = {};
133
- let currentWindowName = null;
138
+ export function parseWindows(
139
+ this: AndroidDriver,
140
+ lines: string,
141
+ ): SystemBarsResult {
142
+ const windows: StringRecord<string[]> = {};
143
+ let currentWindowName: string | null = null;
134
144
  for (const line of lines.split('\n').map(_.trimEnd)) {
135
145
  const match = WINDOW_TITLE_PATTERN.exec(line);
136
146
  if (match) {
@@ -152,40 +162,39 @@ export function parseWindows(lines) {
152
162
  throw new Error('Cannot parse any window information from the dumpsys output');
153
163
  }
154
164
 
155
- /** @type {{statusBar?: WindowProperties, navigationBar?: WindowProperties}} */
156
- const result = {};
165
+ const result: SystemBarsResult = {};
157
166
  for (const [name, props] of _.toPairs(windows)) {
158
167
  if (
159
168
  name.startsWith(STATUS_BAR_WINDOW_NAME_PREFIX)
160
- || props.some((/** @type {string} */ line) => STATUS_BAR_TYPE_PATTERN.test(line))
169
+ || props.some((line: string) => STATUS_BAR_TYPE_PATTERN.test(line))
161
170
  ) {
162
171
  result.statusBar = parseWindowProperties.bind(this)(name, props);
163
172
  } else if (
164
173
  name.startsWith(NAVIGATION_BAR_WINDOW_NAME_PREFIX)
165
- || props.some((/** @type {string} */ line) => NAVIGATION_BAR_TYPE_PATTERN.test(line))
174
+ || props.some((line: string) => NAVIGATION_BAR_TYPE_PATTERN.test(line))
166
175
  ) {
167
176
  result.navigationBar = parseWindowProperties.bind(this)(name, props);
168
177
  }
169
178
  }
170
- const unmatchedWindows = /** @type {const} */ ([
179
+ const unmatchedWindows = ([
171
180
  ['statusBar', STATUS_BAR_WINDOW_NAME_PREFIX],
172
181
  ['navigationBar', NAVIGATION_BAR_WINDOW_NAME_PREFIX],
173
- ]).filter(([name]) => _.isNil(result[name]));
182
+ ] as const).filter(([name]) => _.isNil(result[name as keyof SystemBarsResult]));
174
183
  for (const [window, namePrefix] of unmatchedWindows) {
175
184
  this.log.info(
176
185
  `No windows have been found whose title matches to ` +
177
186
  `'${namePrefix}'. Assuming it is invisible. ` +
178
187
  `Only the following windows are available: ${_.keys(windows)}`,
179
188
  );
180
- result[window] = _.cloneDeep(DEFAULT_WINDOW_PROPERTIES);
189
+ result[window as keyof SystemBarsResult] = _.cloneDeep(DEFAULT_WINDOW_PROPERTIES);
181
190
  }
182
191
  return result;
183
192
  }
184
193
 
185
194
  // #endregion
186
195
 
187
- /**
188
- * @typedef {import('appium-adb').ADB} ADB
189
- * @typedef {import('@appium/types').StringRecord} StringRecord
190
- * @typedef {import('./types').WindowProperties} WindowProperties
191
- */
196
+ interface SystemBarsResult {
197
+ statusBar?: WindowProperties;
198
+ navigationBar?: WindowProperties;
199
+ }
200
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-android-driver",
3
- "version": "12.4.9",
3
+ "version": "12.4.10",
4
4
  "description": "Android UiAutomator and Chrome support for Appium",
5
5
  "keywords": [
6
6
  "appium",
@@ -1,158 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
-
3
- import {errors} from 'appium/driver';
4
-
5
- /**
6
- * @this {import('../driver').AndroidDriver}
7
- * @param {string} attribute
8
- * @param {string} elementId
9
- * @returns {Promise<string?>}
10
- */
11
- export async function getAttribute(attribute, elementId) {
12
- throw new errors.NotImplementedError('Not implemented');
13
- }
14
-
15
- /**
16
- * @this {import('../driver').AndroidDriver}
17
- * @param {string} elementId
18
- * @returns {Promise<void>}
19
- */
20
- export async function click(elementId) {
21
- throw new errors.NotImplementedError('Not implemented');
22
- }
23
-
24
- /**
25
- * @this {import('../driver').AndroidDriver}
26
- * @param {string} elementId
27
- * @returns {Promise<string>}
28
- */
29
- export async function getText(elementId) {
30
- throw new errors.NotImplementedError('Not implemented');
31
- }
32
-
33
- /**
34
- * @this {import('../driver').AndroidDriver}
35
- * @param {string} elementId
36
- * @returns {Promise<import('@appium/types').Position>}
37
- */
38
- export async function getLocation(elementId) {
39
- throw new errors.NotImplementedError('Not implemented');
40
- }
41
-
42
- /**
43
- * @this {import('../driver').AndroidDriver}
44
- * @param {string} elementId
45
- * @returns {Promise<import('@appium/types').Size>}
46
- */
47
- export async function getSize(elementId) {
48
- throw new errors.NotImplementedError('Not implemented');
49
- }
50
-
51
- /**
52
- * @this {import('../driver').AndroidDriver}
53
- * @param {string} elementId
54
- * @returns {Promise<string>}
55
- */
56
- export async function getName(elementId) {
57
- return /** @type {string} */ (await this.getAttribute('className', elementId));
58
- }
59
-
60
- /**
61
- * @this {import('../driver').AndroidDriver}
62
- * @param {string} elementId
63
- * @returns {Promise<boolean>}
64
- */
65
- export async function elementDisplayed(elementId) {
66
- return (await this.getAttribute('displayed', elementId)) === 'true';
67
- }
68
-
69
- /**
70
- * @this {import('../driver').AndroidDriver}
71
- * @param {string} elementId
72
- * @returns {Promise<boolean>}
73
- */
74
- export async function elementEnabled(elementId) {
75
- return (await this.getAttribute('enabled', elementId)) === 'true';
76
- }
77
-
78
- /**
79
- * @this {import('../driver').AndroidDriver}
80
- * @param {string} elementId
81
- * @returns {Promise<boolean>}
82
- */
83
- export async function elementSelected(elementId) {
84
- return (await this.getAttribute('selected', elementId)) === 'true';
85
- }
86
-
87
- /**
88
- * @this {import('../driver').AndroidDriver}
89
- * @param {string|string[]} keys
90
- * @param {string} elementId
91
- * @param {boolean} [replace=false]
92
- * @returns {Promise<void>}
93
- */
94
- export async function setElementValue(keys, elementId, replace = false) {
95
- const text = keys instanceof Array ? keys.join('') : keys;
96
- return await this.doSetElementValue({
97
- elementId,
98
- text: String(text),
99
- replace,
100
- });
101
- }
102
-
103
- /**
104
- * Reason for isolating doSetElementValue from setElementValue is for reusing setElementValue
105
- * across android-drivers (like appium-uiautomator2-driver) and to avoid code duplication.
106
- * Other android-drivers (like appium-uiautomator2-driver) need to override doSetElementValue
107
- * to facilitate setElementValue.
108
- *
109
- * @this {import('../driver').AndroidDriver}
110
- * @param {import('./types').DoSetElementValueOpts} params
111
- * @returns {Promise<void>}
112
- */
113
- export async function doSetElementValue(params) {
114
- throw new errors.NotImplementedError('Not implemented');
115
- }
116
-
117
- /**
118
- * @this {import('../driver').AndroidDriver}
119
- * @param {string|string[]} keys
120
- * @param {string} elementId
121
- * @returns {Promise<void>}
122
- */
123
- export async function setValue(keys, elementId) {
124
- return await this.setElementValue(keys, elementId, false);
125
- }
126
-
127
- /**
128
- * @this {import('../driver').AndroidDriver}
129
- * @param {string|string[]} keys
130
- * @param {string} elementId
131
- * @returns {Promise<void>}
132
- */
133
- export async function replaceValue(keys, elementId) {
134
- return await this.setElementValue(keys, elementId, true);
135
- }
136
-
137
- /**
138
- * @this {import('../driver').AndroidDriver}
139
- * @param {string|string[]} keys
140
- * @param {string} elementId
141
- * @returns {Promise<void>}
142
- */
143
- export async function setValueImmediate(keys, elementId) {
144
- const text = Array.isArray(keys) ? keys.join('') : keys;
145
- // first, make sure we are focused on the element
146
- await this.click(elementId);
147
- // then send through adb
148
- await this.adb.inputText(/** @type {string} */ (text));
149
- }
150
-
151
- /**
152
- * @this {import('../driver').AndroidDriver}
153
- * @param {string} elementId
154
- * @returns {Promise<import('@appium/types').Position>}
155
- */
156
- export async function getLocationInView(elementId) {
157
- return await this.getLocation(elementId);
158
- }