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.
- package/CHANGELOG.md +14 -0
- package/README.md +0 -2
- package/build/index.js +18 -33
- package/build/lib/atoms.d.ts +17 -0
- package/build/lib/atoms.d.ts.map +1 -0
- package/build/lib/atoms.js +75 -50
- package/build/lib/atoms.js.map +1 -1
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +5 -11
- package/build/lib/logger.js.map +1 -1
- package/build/lib/mixins/connect.d.ts +125 -0
- package/build/lib/mixins/connect.d.ts.map +1 -0
- package/build/lib/mixins/connect.js +299 -202
- package/build/lib/mixins/connect.js.map +1 -1
- package/build/lib/mixins/events.d.ts +7 -0
- package/build/lib/mixins/events.d.ts.map +1 -0
- package/build/lib/mixins/events.js +7 -12
- package/build/lib/mixins/events.js.map +1 -1
- package/build/lib/mixins/execute.d.ts +38 -0
- package/build/lib/mixins/execute.d.ts.map +1 -0
- package/build/lib/mixins/execute.js +162 -122
- package/build/lib/mixins/execute.js.map +1 -1
- package/build/lib/mixins/index.d.ts +5 -0
- package/build/lib/mixins/index.d.ts.map +1 -0
- package/build/lib/mixins/index.js +14 -23
- package/build/lib/mixins/index.js.map +1 -1
- package/build/lib/mixins/message-handlers.d.ts +92 -0
- package/build/lib/mixins/message-handlers.d.ts.map +1 -0
- package/build/lib/mixins/message-handlers.js +160 -97
- package/build/lib/mixins/message-handlers.js.map +1 -1
- package/build/lib/mixins/navigate.d.ts +92 -0
- package/build/lib/mixins/navigate.d.ts.map +1 -0
- package/build/lib/mixins/navigate.js +199 -141
- package/build/lib/mixins/navigate.js.map +1 -1
- package/build/lib/protocol/index.d.ts +14 -0
- package/build/lib/protocol/index.d.ts.map +1 -0
- package/build/lib/protocol/index.js +192 -118
- package/build/lib/protocol/index.js.map +1 -1
- package/build/lib/remote-debugger-real-device.d.ts +6 -0
- package/build/lib/remote-debugger-real-device.d.ts.map +1 -0
- package/build/lib/remote-debugger-real-device.js +29 -32
- package/build/lib/remote-debugger-real-device.js.map +1 -1
- package/build/lib/remote-debugger.d.ts +119 -0
- package/build/lib/remote-debugger.d.ts.map +1 -0
- package/build/lib/remote-debugger.js +256 -226
- package/build/lib/remote-debugger.js.map +1 -1
- package/build/lib/rpc/index.d.ts +4 -0
- package/build/lib/rpc/index.d.ts.map +1 -0
- package/build/lib/rpc/index.js +10 -21
- package/build/lib/rpc/index.js.map +1 -1
- package/build/lib/rpc/remote-messages.d.ts +51 -0
- package/build/lib/rpc/remote-messages.d.ts.map +1 -0
- package/build/lib/rpc/remote-messages.js +203 -224
- package/build/lib/rpc/remote-messages.js.map +1 -1
- package/build/lib/rpc/rpc-client-real-device.d.ts +6 -0
- package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client-real-device.js +43 -49
- package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
- package/build/lib/rpc/rpc-client-simulator.d.ts +15 -0
- package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client-simulator.js +138 -125
- package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
- package/build/lib/rpc/rpc-client.d.ts +142 -0
- package/build/lib/rpc/rpc-client.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client.js +559 -418
- package/build/lib/rpc/rpc-client.js.map +1 -1
- package/build/lib/rpc/rpc-message-handler.d.ts +13 -0
- package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -0
- package/build/lib/rpc/rpc-message-handler.js +181 -166
- package/build/lib/rpc/rpc-message-handler.js.map +1 -1
- package/build/lib/utils.d.ts +61 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +241 -155
- package/build/lib/utils.js.map +1 -1
- package/lib/atoms.js +25 -4
- package/lib/mixins/connect.js +102 -7
- package/lib/mixins/execute.js +46 -13
- package/lib/mixins/message-handlers.js +44 -1
- package/lib/mixins/navigate.js +55 -3
- package/lib/remote-debugger.js +112 -0
- package/lib/rpc/rpc-client-real-device.js +1 -6
- package/lib/rpc/rpc-client-simulator.js +7 -1
- package/lib/rpc/rpc-client.js +106 -6
- package/lib/rpc/rpc-message-handler.js +1 -1
- package/lib/utils.js +31 -1
- 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
|
-
|
|
48
|
+
`return (${script}); })((${elFromCache.toString('utf8')})(${atomsStringify(frame)}))`;
|
|
36
49
|
}
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
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;
|
package/lib/mixins/connect.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import log from '../logger';
|
|
2
|
-
import {
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
359
|
+
export default {
|
|
360
|
+
setConnectionKey, connect, disconnect, selectApp,
|
|
361
|
+
searchForApp, searchForPage, selectPage, updateAppsWithDict
|
|
362
|
+
};
|
package/lib/mixins/execute.js
CHANGED
|
@@ -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 {
|
|
17
|
-
* @param {
|
|
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
|
|
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
|
-
|
|
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) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
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(
|
|
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
|
|
package/lib/mixins/navigate.js
CHANGED
|
@@ -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
|
|
230
|
+
this.rpcClient?.off('Page.frameNavigated', navEventListener);
|
|
181
231
|
}
|
|
182
232
|
});
|
|
183
233
|
}
|
|
184
234
|
|
|
185
235
|
|
|
186
|
-
export default {
|
|
236
|
+
export default {
|
|
237
|
+
frameDetached, pageLoad, cancelPageLoad, pageUnload, waitForDom, checkPageIsReady, navToUrl, waitForFrameNavigated
|
|
238
|
+
};
|