appium-remote-debugger 10.0.3 → 10.1.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 (87) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +0 -2
  3. package/build/index.js +18 -33
  4. package/build/lib/atoms.d.ts +17 -0
  5. package/build/lib/atoms.d.ts.map +1 -0
  6. package/build/lib/atoms.js +75 -50
  7. package/build/lib/atoms.js.map +1 -1
  8. package/build/lib/logger.d.ts +3 -0
  9. package/build/lib/logger.d.ts.map +1 -0
  10. package/build/lib/logger.js +5 -11
  11. package/build/lib/logger.js.map +1 -1
  12. package/build/lib/mixins/connect.d.ts +125 -0
  13. package/build/lib/mixins/connect.d.ts.map +1 -0
  14. package/build/lib/mixins/connect.js +299 -202
  15. package/build/lib/mixins/connect.js.map +1 -1
  16. package/build/lib/mixins/events.d.ts +7 -0
  17. package/build/lib/mixins/events.d.ts.map +1 -0
  18. package/build/lib/mixins/events.js +7 -12
  19. package/build/lib/mixins/events.js.map +1 -1
  20. package/build/lib/mixins/execute.d.ts +38 -0
  21. package/build/lib/mixins/execute.d.ts.map +1 -0
  22. package/build/lib/mixins/execute.js +162 -122
  23. package/build/lib/mixins/execute.js.map +1 -1
  24. package/build/lib/mixins/index.d.ts +5 -0
  25. package/build/lib/mixins/index.d.ts.map +1 -0
  26. package/build/lib/mixins/index.js +14 -23
  27. package/build/lib/mixins/index.js.map +1 -1
  28. package/build/lib/mixins/message-handlers.d.ts +92 -0
  29. package/build/lib/mixins/message-handlers.d.ts.map +1 -0
  30. package/build/lib/mixins/message-handlers.js +160 -97
  31. package/build/lib/mixins/message-handlers.js.map +1 -1
  32. package/build/lib/mixins/navigate.d.ts +92 -0
  33. package/build/lib/mixins/navigate.d.ts.map +1 -0
  34. package/build/lib/mixins/navigate.js +199 -141
  35. package/build/lib/mixins/navigate.js.map +1 -1
  36. package/build/lib/protocol/index.d.ts +14 -0
  37. package/build/lib/protocol/index.d.ts.map +1 -0
  38. package/build/lib/protocol/index.js +192 -118
  39. package/build/lib/protocol/index.js.map +1 -1
  40. package/build/lib/remote-debugger-real-device.d.ts +6 -0
  41. package/build/lib/remote-debugger-real-device.d.ts.map +1 -0
  42. package/build/lib/remote-debugger-real-device.js +29 -32
  43. package/build/lib/remote-debugger-real-device.js.map +1 -1
  44. package/build/lib/remote-debugger.d.ts +119 -0
  45. package/build/lib/remote-debugger.d.ts.map +1 -0
  46. package/build/lib/remote-debugger.js +256 -226
  47. package/build/lib/remote-debugger.js.map +1 -1
  48. package/build/lib/rpc/index.d.ts +4 -0
  49. package/build/lib/rpc/index.d.ts.map +1 -0
  50. package/build/lib/rpc/index.js +10 -21
  51. package/build/lib/rpc/index.js.map +1 -1
  52. package/build/lib/rpc/remote-messages.d.ts +51 -0
  53. package/build/lib/rpc/remote-messages.d.ts.map +1 -0
  54. package/build/lib/rpc/remote-messages.js +203 -224
  55. package/build/lib/rpc/remote-messages.js.map +1 -1
  56. package/build/lib/rpc/rpc-client-real-device.d.ts +6 -0
  57. package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -0
  58. package/build/lib/rpc/rpc-client-real-device.js +43 -49
  59. package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
  60. package/build/lib/rpc/rpc-client-simulator.d.ts +15 -0
  61. package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -0
  62. package/build/lib/rpc/rpc-client-simulator.js +138 -125
  63. package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
  64. package/build/lib/rpc/rpc-client.d.ts +142 -0
  65. package/build/lib/rpc/rpc-client.d.ts.map +1 -0
  66. package/build/lib/rpc/rpc-client.js +559 -418
  67. package/build/lib/rpc/rpc-client.js.map +1 -1
  68. package/build/lib/rpc/rpc-message-handler.d.ts +13 -0
  69. package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -0
  70. package/build/lib/rpc/rpc-message-handler.js +181 -166
  71. package/build/lib/rpc/rpc-message-handler.js.map +1 -1
  72. package/build/lib/utils.d.ts +61 -0
  73. package/build/lib/utils.d.ts.map +1 -0
  74. package/build/lib/utils.js +241 -155
  75. package/build/lib/utils.js.map +1 -1
  76. package/lib/atoms.js +25 -4
  77. package/lib/mixins/connect.js +102 -7
  78. package/lib/mixins/execute.js +46 -13
  79. package/lib/mixins/message-handlers.js +44 -1
  80. package/lib/mixins/navigate.js +55 -3
  81. package/lib/remote-debugger.js +112 -0
  82. package/lib/rpc/rpc-client-real-device.js +1 -6
  83. package/lib/rpc/rpc-client-simulator.js +7 -1
  84. package/lib/rpc/rpc-client.js +106 -6
  85. package/lib/rpc/rpc-message-handler.js +1 -1
  86. package/lib/utils.js +31 -1
  87. package/package.json +25 -15
package/lib/atoms.js CHANGED
@@ -6,6 +6,10 @@ import { getModuleRoot } from './utils';
6
6
 
7
7
  const ATOMS_CACHE = {};
8
8
 
9
+ /**
10
+ * @param {any} obj
11
+ * @returns {string}
12
+ */
9
13
  function atomsStringify(obj) {
10
14
  if (typeof obj === 'undefined') {
11
15
  return 'undefined';
@@ -13,7 +17,11 @@ function atomsStringify(obj) {
13
17
  return JSON.stringify(obj);
14
18
  }
15
19
 
16
-
20
+ /**
21
+ *
22
+ * @param {string} atomName
23
+ * @returns {Promise<Buffer>}
24
+ */
17
25
  async function getAtom (atomName) {
18
26
  // check if we have already loaded and cached this atom
19
27
  if (!_.has(ATOMS_CACHE, atomName)) {
@@ -28,15 +36,28 @@ async function getAtom (atomName) {
28
36
  return ATOMS_CACHE[atomName];
29
37
  }
30
38
 
39
+ /**
40
+ * @param {string} script
41
+ * @param {string} frame
42
+ * @returns {Promise<string>}
43
+ */
31
44
  async function wrapScriptForFrame (script, frame) {
32
45
  log.debug(`Wrapping script for frame '${frame}'`);
33
46
  const elFromCache = await getAtom('get_element_from_cache');
34
47
  return `(function (window) { var document = window.document; ` +
35
- `return (${script}); })((${elFromCache.toString('utf8')})(${atomsStringify(frame)}))`;
48
+ `return (${script}); })((${elFromCache.toString('utf8')})(${atomsStringify(frame)}))`;
36
49
  }
37
50
 
38
- async function getScriptForAtom (atom, args, frames = [], asyncCallBack = null) {
39
- const atomSrc = await getAtom(atom);
51
+ /**
52
+ *
53
+ * @param {string} atom
54
+ * @param {any[]} [args]
55
+ * @param {string[]} [frames]
56
+ * @param {string?} [asyncCallBack]
57
+ * @returns {Promise<string>}
58
+ */
59
+ async function getScriptForAtom (atom, args = [], frames = [], asyncCallBack = null) {
60
+ const atomSrc = (await getAtom(atom)).toString('utf8');
40
61
  let script;
41
62
  if (frames.length > 0) {
42
63
  script = atomSrc;
@@ -1,6 +1,8 @@
1
1
  import log from '../logger';
2
- import { appInfoFromDict, pageArrayFromDict, getDebuggerAppKey,
3
- getPossibleDebuggerAppKeys, simpleStringify, deferredPromise } from '../utils';
2
+ import {
3
+ appInfoFromDict, pageArrayFromDict, getDebuggerAppKey,
4
+ getPossibleDebuggerAppKeys, simpleStringify, deferredPromise
5
+ } from '../utils';
4
6
  import events from './events';
5
7
  import { timing } from '@appium/support';
6
8
  import { retryInterval, waitForCondition } from 'asyncbox';
@@ -14,20 +16,48 @@ const SELECT_APP_RETRY_SLEEP_MS = 500;
14
16
  const SAFARI_BUNDLE_ID = 'com.apple.mobilesafari';
15
17
  const BLANK_PAGE_URL = 'about:blank';
16
18
 
19
+ /**
20
+ * @typedef {Object} AppPages
21
+ * @property {string} appIdKey
22
+ * @property {Record<string, any>} pageDict
23
+ */
17
24
 
25
+ /**
26
+ * @typedef {Object} App
27
+ * @property {string} id
28
+ * @property {string} bundleId
29
+ */
30
+
31
+
32
+ /**
33
+ *
34
+ * @this {import('../remote-debugger').RemoteDebugger}
35
+ */
18
36
  async function setConnectionKey () {
19
37
  log.debug('Sending connection key request');
38
+ if (!this.rpcClient) {
39
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
40
+ }
41
+
20
42
  // send but only wait to make sure the socket worked
21
43
  // as response from Web Inspector can take a long time
22
44
  await this.rpcClient.send('setConnectionKey', {}, false);
23
45
  }
24
46
 
47
+ /**
48
+ *
49
+ * @this {import('../remote-debugger').RemoteDebugger}
50
+ */
25
51
  async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
26
52
  this.setup();
27
53
 
28
54
  // initialize the rpc client
29
55
  this.initRpcClient();
30
56
 
57
+ if (!this.rpcClient) {
58
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
59
+ }
60
+
31
61
  // listen for basic debugger-level events
32
62
  this.rpcClient.on('_rpc_reportSetup:', _.noop);
33
63
  this.rpcClient.on('_rpc_forwardGetListing:', this.onPageChange.bind(this));
@@ -43,13 +73,13 @@ async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
43
73
 
44
74
  // get the connection information about the app
45
75
  try {
46
- await this.setConnectionKey();
76
+ this.setConnectionKey();
47
77
  if (timeout) {
48
78
  log.debug(`Waiting up to ${timeout}ms for applications to be reported`);
49
79
  try {
50
80
  await waitForCondition(() => !_.isEmpty(this.appDict), {
51
81
  waitMs: timeout,
52
- interval: APP_CONNECT_INTERVAL_MS,
82
+ intervalMs: APP_CONNECT_INTERVAL_MS,
53
83
  });
54
84
  } catch (err) {
55
85
  log.debug(`Timed out waiting for applications to be reported`);
@@ -63,6 +93,11 @@ async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
63
93
  }
64
94
  }
65
95
 
96
+ /**
97
+ *
98
+ * @this {import('../remote-debugger').RemoteDebugger}
99
+ * @returns {Promise<void>}
100
+ */
66
101
  async function disconnect () {
67
102
  if (this.rpcClient) {
68
103
  await this.rpcClient.disconnect();
@@ -71,12 +106,24 @@ async function disconnect () {
71
106
  this.teardown();
72
107
  }
73
108
 
109
+ /**
110
+ *
111
+ * @this {import('../remote-debugger').RemoteDebugger}
112
+ * @param {string?} currentUrl
113
+ * @param {number} [maxTries]
114
+ * @param {boolean} [ignoreAboutBlankUrl]
115
+ * @returns {Promise<AppPages[]>}
116
+ */
74
117
  async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, ignoreAboutBlankUrl = false) {
118
+ log.debug('Selecting application');
119
+ if (!this.rpcClient) {
120
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
121
+ }
122
+
75
123
  const shouldCheckForTarget = this.rpcClient.shouldCheckForTarget;
76
124
  this.rpcClient.shouldCheckForTarget = false;
77
125
  try {
78
126
  const timer = new timing.Timer().start();
79
- log.debug('Selecting application');
80
127
  if (!this.appDict || _.isEmpty(this.appDict)) {
81
128
  log.debug('No applications currently connected.');
82
129
  return [];
@@ -125,12 +172,24 @@ async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, igno
125
172
  }
126
173
  }
127
174
 
175
+ /**
176
+ *
177
+ * @this {import('../remote-debugger').RemoteDebugger}
178
+ * @param {string?} currentUrl
179
+ * @param {number} maxTries
180
+ * @param {boolean} ignoreAboutBlankUrl
181
+ * @returns {Promise<AppPages?>}
182
+ */
128
183
  async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
129
184
  const bundleIds = this.includeSafari && !this.isSafari
130
185
  ? [this.bundleId, ...this.additionalBundleIds, SAFARI_BUNDLE_ID]
131
186
  : [this.bundleId, ...this.additionalBundleIds];
132
187
  try {
133
188
  return await retryInterval(maxTries, SELECT_APP_RETRY_SLEEP_MS, async (retryCount) => {
189
+ if (!this.rpcClient) {
190
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
191
+ }
192
+
134
193
  logApplicationDictionary(this.appDict);
135
194
  const possibleAppIds = getPossibleDebuggerAppKeys(bundleIds, this.appDict);
136
195
  log.debug(`Trying out the possible app ids: ${possibleAppIds.join(', ')} (try #${retryCount + 1} of ${maxTries})`);
@@ -141,7 +200,7 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
141
200
  continue;
142
201
  }
143
202
  log.debug(`Attempting app '${attemptedAppIdKey}'`);
144
- const [appIdKey, pageDict] = await this.rpcClient.selectApp(attemptedAppIdKey, this.onAppConnect.bind(this));
203
+ const [appIdKey, pageDict] = await this.rpcClient.selectApp(attemptedAppIdKey);
145
204
  // in iOS 8.2 the connect logic happens, but with an empty dictionary
146
205
  // which leads to the remote debugger getting disconnected, and into a loop
147
206
  if (_.isEmpty(pageDict)) {
@@ -175,8 +234,17 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
175
234
  } catch (ign) {
176
235
  log.errorAndThrow(`Could not connect to a valid app after ${maxTries} tries.`);
177
236
  }
237
+ return null;
178
238
  }
179
239
 
240
+ /**
241
+ *
242
+ * @this {import('../remote-debugger').RemoteDebugger}
243
+ * @param {Record<string, any>} appsDict
244
+ * @param {string?} currentUrl
245
+ * @param {boolean} [ignoreAboutBlankUrl]
246
+ * @returns {AppPages?}
247
+ */
180
248
  function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false) {
181
249
  for (const appDict of _.values(appsDict)) {
182
250
  if (!appDict || !appDict.isActive || !appDict.pageArray || appDict.pageArray.promise) {
@@ -193,11 +261,22 @@ function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false
193
261
  return null;
194
262
  }
195
263
 
264
+ /**
265
+ *
266
+ * @this {import('../remote-debugger').RemoteDebugger}
267
+ * @param {string} appIdKey
268
+ * @param {string} pageIdKey
269
+ * @param {boolean} [skipReadyCheck]
270
+ * @returns {Promise<void>}
271
+ */
196
272
  async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
197
273
  this.appIdKey = `PID:${appIdKey}`;
198
274
  this.pageIdKey = pageIdKey;
199
275
 
200
276
  log.debug(`Selecting page '${pageIdKey}' on app '${this.appIdKey}' and forwarding socket setup`);
277
+ if (!this.rpcClient) {
278
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
279
+ }
201
280
 
202
281
  const timer = new timing.Timer().start();
203
282
 
@@ -211,7 +290,13 @@ async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
211
290
  log.debug(`Selected page after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
212
291
  }
213
292
 
293
+ /**
294
+ *
295
+ * @param {Record<string, any>} apps
296
+ * @returns {void}
297
+ */
214
298
  function logApplicationDictionary (apps) {
299
+
215
300
  function getValueString (key, value) {
216
301
  if (_.isFunction(value)) {
217
302
  return '[Function]';
@@ -221,6 +306,7 @@ function logApplicationDictionary (apps) {
221
306
  }
222
307
  return JSON.stringify(value);
223
308
  }
309
+
224
310
  log.debug('Current applications available:');
225
311
  for (const [app, info] of _.toPairs(apps)) {
226
312
  log.debug(` Application: "${app}"`);
@@ -242,6 +328,12 @@ function logApplicationDictionary (apps) {
242
328
  }
243
329
  }
244
330
 
331
+ /**
332
+ *
333
+ * @this {import('../remote-debugger').RemoteDebugger}
334
+ * @param {Record<string, any>} dict
335
+ * @returns {void}
336
+ */
245
337
  function updateAppsWithDict (dict) {
246
338
  // get the dictionary entry into a nice form, and add it to the
247
339
  // application dictionary
@@ -264,4 +356,7 @@ function updateAppsWithDict (dict) {
264
356
  }
265
357
  }
266
358
 
267
- export default { setConnectionKey, connect, disconnect, selectApp, searchForApp, searchForPage, selectPage, updateAppsWithDict };
359
+ export default {
360
+ setConnectionKey, connect, disconnect, selectApp,
361
+ searchForApp, searchForPage, selectPage, updateAppsWithDict
362
+ };
@@ -13,12 +13,12 @@ const RPC_RESPONSE_TIMEOUT_MS = 5000;
13
13
  /**
14
14
  * Execute a Selenium atom in Safari
15
15
  * @param {string} atom Name of Selenium atom (see atoms/ directory)
16
- * @param {Array<*>} args Arguments passed to the atom
17
- * @param {Array<string>} frames
18
- * @returns {string} The result received from the atom
16
+ * @param {any[]} args Arguments passed to the atom
17
+ * @param {string[]} frames
18
+ * @returns {Promise<string>} The result received from the atom
19
19
  */
20
- async function executeAtom (atom, args, frames) {
21
- if (!this.rpcClient.isConnected) {
20
+ async function executeAtom (atom, args = [], frames = []) {
21
+ if (!this.rpcClient?.isConnected) {
22
22
  throw new Error('Remote debugger is not connected');
23
23
  }
24
24
 
@@ -29,13 +29,25 @@ async function executeAtom (atom, args, frames) {
29
29
  return value;
30
30
  }
31
31
 
32
- async function executeAtomAsync (atom, args, frames) {
32
+ /**
33
+ * @this {import('../remote-debugger').RemoteDebugger}
34
+ * @param {string} atom
35
+ * @param {any[]} [args]
36
+ * @param {string[]} [frames]
37
+ * @returns {Promise<any>}
38
+ */
39
+ async function executeAtomAsync (atom, args = [], frames = []) {
33
40
  // helper to send directly to the web inspector
34
- const evaluate = async (method, opts) => await this.rpcClient.send(method, Object.assign({
35
- appIdKey: this.appIdKey,
36
- pageIdKey: this.pageIdKey,
37
- returnByValue: false,
38
- }, opts));
41
+ const evaluate = async (method, opts) => {
42
+ if (!this.rpcClient?.isConnected) {
43
+ throw new Error('Remote debugger is not connected');
44
+ }
45
+ return await this.rpcClient.send(method, Object.assign({
46
+ appIdKey: this.appIdKey,
47
+ pageIdKey: this.pageIdKey,
48
+ returnByValue: false,
49
+ }, opts));
50
+ };
39
51
 
40
52
  // first create a Promise on the page, saving the resolve/reject functions
41
53
  // as properties
@@ -80,7 +92,7 @@ async function executeAtomAsync (atom, args, frames) {
80
92
  const retryWait = 100;
81
93
  const timeout = (args.length >= 3) ? args[2] : RPC_RESPONSE_TIMEOUT_MS;
82
94
  // if the timeout math turns up 0 retries, make sure it happens once
83
- const retries = parseInt(timeout / retryWait, 10) || 1;
95
+ const retries = parseInt(`${timeout / retryWait}`, 10) || 1;
84
96
  const timer = new timing.Timer().start();
85
97
  log.debug(`Waiting up to ${timeout}ms for async execute to finish`);
86
98
  res = await retryInterval(retries, retryWait, async () => {
@@ -105,12 +117,20 @@ async function executeAtomAsync (atom, args, frames) {
105
117
  } finally {
106
118
  try {
107
119
  // try to get rid of the promise
108
- await this.executeAtom('execute_script', [`delete window.${promiseName};`, [null, null], subcommandTimeout], frames);
120
+ await this.executeAtom(
121
+ 'execute_script', [`delete window.${promiseName};`, [null, null], subcommandTimeout], frames
122
+ );
109
123
  } catch (ign) {}
110
124
  }
111
125
  return convertResult(res);
112
126
  }
113
127
 
128
+ /**
129
+ * @this {import('../remote-debugger').RemoteDebugger}
130
+ * @param {string} command
131
+ * @param {boolean} [override]
132
+ * @returns {Promise<any>}
133
+ */
114
134
  async function execute (command, override) {
115
135
  // if the page is not loaded yet, wait for it
116
136
  if (this.pageLoading && !override) {
@@ -130,6 +150,9 @@ async function execute (command, override) {
130
150
  }
131
151
 
132
152
  log.debug(`Sending javascript command: '${_.truncate(command, {length: 50})}'`);
153
+ if (!this.rpcClient?.isConnected) {
154
+ throw new Error('Remote debugger is not connected');
155
+ }
133
156
  const res = await this.rpcClient.send('Runtime.evaluate', {
134
157
  expression: command,
135
158
  returnByValue: true,
@@ -140,7 +163,17 @@ async function execute (command, override) {
140
163
  return convertResult(res);
141
164
  }
142
165
 
166
+ /**
167
+ * @this {import('../remote-debugger').RemoteDebugger}
168
+ * @param {string} objectId
169
+ * @param {any} fn
170
+ * @param {any[]} [args]
171
+ */
143
172
  async function callFunction (objectId, fn, args) {
173
+ if (!this.rpcClient?.isConnected) {
174
+ throw new Error('Remote debugger is not connected');
175
+ }
176
+
144
177
  checkParams({appIdKey: this.appIdKey, pageIdKey: this.pageIdKey});
145
178
 
146
179
  if (this.garbageCollectOnExecute) {
@@ -9,6 +9,13 @@ import _ from 'lodash';
9
9
  * These will be added to the prototype.
10
10
  */
11
11
 
12
+ /**
13
+ * @this {import('../remote-debugger').RemoteDebugger}
14
+ * @param {Error?} err
15
+ * @param {string} appIdKey
16
+ * @param {Record<string, any>} pageDict
17
+ * @returns {Promise<void>}
18
+ */
12
19
  async function onPageChange (err, appIdKey, pageDict) {
13
20
  if (_.isEmpty(pageDict)) {
14
21
  return;
@@ -54,10 +61,16 @@ async function onPageChange (err, appIdKey, pageDict) {
54
61
  });
55
62
  }
56
63
 
64
+ /**
65
+ * @this {import('../remote-debugger').RemoteDebugger}
66
+ * @param {Error?} err
67
+ * @param {Record<string, any>} dict
68
+ * @returns {Promise<void>}
69
+ */
57
70
  async function onAppConnect (err, dict) {
58
71
  const appIdKey = dict.WIRApplicationIdentifierKey;
59
72
  log.debug(`Notified that new application '${appIdKey}' has connected`);
60
- await this.useAppDictLock((done) => {
73
+ await this.useAppDictLock((/** @type {() => Void} */done) => {
61
74
  try {
62
75
  this.updateAppsWithDict(dict);
63
76
  } finally {
@@ -66,6 +79,12 @@ async function onAppConnect (err, dict) {
66
79
  });
67
80
  }
68
81
 
82
+ /**
83
+ * @this {import('../remote-debugger').RemoteDebugger}
84
+ * @param {Error?} err
85
+ * @param {Record<string, any>} dict
86
+ * @returns {void}
87
+ */
69
88
  function onAppDisconnect (err, dict) {
70
89
  const appIdKey = dict.WIRApplicationIdentifierKey;
71
90
  log.debug(`Application '${appIdKey}' disconnected. Removing from app dictionary.`);
@@ -89,6 +108,12 @@ function onAppDisconnect (err, dict) {
89
108
  }
90
109
  }
91
110
 
111
+ /**
112
+ * @this {import('../remote-debugger').RemoteDebugger}
113
+ * @param {Error?} err
114
+ * @param {Record<string, any>} dict
115
+ * @returns {Promise<void>}
116
+ */
92
117
  async function onAppUpdate (err, dict) {
93
118
  await this.useAppDictLock((done) => {
94
119
  try {
@@ -99,11 +124,23 @@ async function onAppUpdate (err, dict) {
99
124
  });
100
125
  }
101
126
 
127
+ /**
128
+ * @this {import('../remote-debugger').RemoteDebugger}
129
+ * @param {Error?} err
130
+ * @param {Record<string, any>} drivers
131
+ * @returns {void}
132
+ */
102
133
  function onConnectedDriverList (err, drivers) {
103
134
  this.connectedDrivers = drivers.WIRDriverDictionaryKey;
104
135
  log.debug(`Received connected driver list: ${JSON.stringify(this.connectedDrivers)}`);
105
136
  }
106
137
 
138
+ /**
139
+ * @this {import('../remote-debugger').RemoteDebugger}
140
+ * @param {Error?} err
141
+ * @param {Record<string, any>} state
142
+ * @returns {void}
143
+ */
107
144
  function onCurrentState (err, state) {
108
145
  this.currentState = state.WIRAutomationAvailabilityKey;
109
146
  // This state changes when 'Remote Automation' in 'Settings app' > 'Safari' > 'Advanced' > 'Remote Automation' changes
@@ -111,6 +148,12 @@ function onCurrentState (err, state) {
111
148
  log.debug(`Received connected automation availability state: ${JSON.stringify(this.currentState)}`);
112
149
  }
113
150
 
151
+ /**
152
+ * @this {import('../remote-debugger').RemoteDebugger}
153
+ * @param {Error?} err
154
+ * @param {Record<string, any>} apps
155
+ * @returns {Promise<void>}
156
+ */
114
157
  async function onConnectedApplicationList (err, apps) {
115
158
  log.debug(`Received connected applications list: ${_.keys(apps).join(', ')}`);
116
159
 
@@ -6,10 +6,24 @@ import _ from 'lodash';
6
6
  import B from 'bluebird';
7
7
 
8
8
 
9
+ /**
10
+ * @typedef {(() => Promise<any>|void)|undefined} TPageLoadVerifyHook
11
+ */
12
+
13
+ /**
14
+ * @this {import('../remote-debugger').RemoteDebugger}
15
+ * @returns {void}
16
+ */
9
17
  function frameDetached () {
10
18
  this.emit(events.EVENT_FRAMES_DETACHED);
11
19
  }
12
20
 
21
+ /**
22
+ * @this {import('../remote-debugger').RemoteDebugger}
23
+ * @param {timing.Timer?} startPageLoadTimer
24
+ * @param {TPageLoadVerifyHook} [pageLoadVerifyHook]
25
+ * @returns {Promise<void>}
26
+ */
13
27
  async function pageLoad (startPageLoadTimer, pageLoadVerifyHook = _.noop) {
14
28
  const timeoutMs = 500;
15
29
  if (!_.isFunction(startPageLoadTimer?.getDuration)) {
@@ -43,6 +57,7 @@ async function pageLoad (startPageLoadTimer, pageLoadVerifyHook = _.noop) {
43
57
  }
44
58
 
45
59
  // if we are ready, or we've spend too much time on this
60
+ // @ts-ignore startPageLoadTimer is defined here
46
61
  const elapsedMs = startPageLoadTimer.getDuration().asMilliSeconds;
47
62
  if (await this.checkPageIsReady() || (this.pageLoadMs > 0 && elapsedMs > this.pageLoadMs)) {
48
63
  log.debug('Page is ready');
@@ -55,11 +70,15 @@ async function pageLoad (startPageLoadTimer, pageLoadVerifyHook = _.noop) {
55
70
  try {
56
71
  await verify();
57
72
  } finally {
73
+ // @ts-ignore startPageLoadTimer is defined here
58
74
  log.debug(`Page load completed in ${startPageLoadTimer.getDuration().asMilliSeconds.toFixed(0)}ms`);
59
75
  this.pageLoading = false;
60
76
  }
61
77
  }
62
-
78
+ /**
79
+ * @this {import('../remote-debugger').RemoteDebugger}
80
+ * @returns {void}
81
+ */
63
82
  function cancelPageLoad () {
64
83
  log.debug('Unregistering from page readiness notifications');
65
84
  this.pageLoading = false;
@@ -68,16 +87,30 @@ function cancelPageLoad () {
68
87
  }
69
88
  }
70
89
 
90
+ /**
91
+ * @this {import('../remote-debugger').RemoteDebugger}
92
+ * @returns {Promise<void>}
93
+ */
71
94
  async function pageUnload () {
72
95
  log.debug('Page unloading');
73
96
  await this.waitForDom();
74
97
  }
75
98
 
99
+ /**
100
+ * @this {import('../remote-debugger').RemoteDebugger}
101
+ * @param {timing.Timer|null|undefined} startPageLoadTimer
102
+ * @param {TPageLoadVerifyHook} [pageLoadVerifyHook]
103
+ * @returns {Promise<void>}
104
+ */
76
105
  async function waitForDom (startPageLoadTimer, pageLoadVerifyHook) {
77
106
  log.debug('Waiting for dom...');
78
107
  await this.pageLoad(startPageLoadTimer, pageLoadVerifyHook);
79
108
  }
80
109
 
110
+ /**
111
+ * @this {import('../remote-debugger').RemoteDebugger}
112
+ * @returns {Promise<boolean>}
113
+ */
81
114
  async function checkPageIsReady () {
82
115
  checkParams({appIdKey: this.appIdKey});
83
116
 
@@ -98,9 +131,19 @@ async function checkPageIsReady () {
98
131
  return readyState === 'complete';
99
132
  }
100
133
 
134
+ /**
135
+ * @this {import('../remote-debugger').RemoteDebugger}
136
+ * @param {string} url
137
+ * @param {TPageLoadVerifyHook} [pageLoadVerifyHook]
138
+ * @returns {Promise<void>}
139
+ */
101
140
  async function navToUrl (url, pageLoadVerifyHook) {
102
141
  checkParams({appIdKey: this.appIdKey, pageIdKey: this.pageIdKey});
103
142
 
143
+ if (!this.rpcClient) {
144
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
145
+ }
146
+
104
147
  this._navigatingToPage = true;
105
148
 
106
149
  try {
@@ -136,10 +179,17 @@ async function navToUrl (url, pageLoadVerifyHook) {
136
179
  }
137
180
  }
138
181
 
182
+ /**
183
+ * @this {import('../remote-debugger').RemoteDebugger}
184
+ * @returns {Promise<any>}
185
+ */
139
186
  async function waitForFrameNavigated () {
140
187
  let navEventListener;
141
188
  return await new B(async (resolve) => {
142
189
  log.debug('Waiting for frame navigated message...');
190
+ if (!this.rpcClient) {
191
+ throw new Error('rpcClient is undefined. Is the debugger connected?');
192
+ }
143
193
  const start = new timing.Timer().start();
144
194
 
145
195
  // add a handler for the `Page.frameNavigated` message
@@ -177,10 +227,12 @@ async function waitForFrameNavigated () {
177
227
  }
178
228
  }).finally(() => {
179
229
  if (navEventListener) {
180
- this.rpcClient.off('Page.frameNavigated', navEventListener);
230
+ this.rpcClient?.off('Page.frameNavigated', navEventListener);
181
231
  }
182
232
  });
183
233
  }
184
234
 
185
235
 
186
- export default { frameDetached, pageLoad, cancelPageLoad, pageUnload, waitForDom, checkPageIsReady, navToUrl, waitForFrameNavigated };
236
+ export default {
237
+ frameDetached, pageLoad, cancelPageLoad, pageUnload, waitForDom, checkPageIsReady, navToUrl, waitForFrameNavigated
238
+ };