appium-remote-debugger 11.4.1 → 11.5.0
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 +12 -0
- package/build/lib/mixins/connect.d.ts +53 -56
- package/build/lib/mixins/connect.d.ts.map +1 -1
- package/build/lib/mixins/connect.js +72 -96
- package/build/lib/mixins/connect.js.map +1 -1
- package/build/lib/mixins/cookies.d.ts +22 -0
- package/build/lib/mixins/cookies.d.ts.map +1 -0
- package/build/lib/mixins/cookies.js +48 -0
- package/build/lib/mixins/cookies.js.map +1 -0
- package/build/lib/mixins/events.d.ts +17 -2
- package/build/lib/mixins/events.d.ts.map +1 -1
- package/build/lib/mixins/events.js +29 -2
- package/build/lib/mixins/events.js.map +1 -1
- package/build/lib/mixins/execute.d.ts +5 -12
- package/build/lib/mixins/execute.d.ts.map +1 -1
- package/build/lib/mixins/execute.js +18 -30
- package/build/lib/mixins/execute.js.map +1 -1
- package/build/lib/mixins/message-handlers.d.ts +13 -23
- package/build/lib/mixins/message-handlers.d.ts.map +1 -1
- package/build/lib/mixins/message-handlers.js +56 -27
- package/build/lib/mixins/message-handlers.js.map +1 -1
- package/build/lib/mixins/misc.d.ts +51 -0
- package/build/lib/mixins/misc.d.ts.map +1 -0
- package/build/lib/mixins/misc.js +132 -0
- package/build/lib/mixins/misc.js.map +1 -0
- package/build/lib/mixins/navigate.d.ts +20 -29
- package/build/lib/mixins/navigate.d.ts.map +1 -1
- package/build/lib/mixins/navigate.js +25 -23
- package/build/lib/mixins/navigate.js.map +1 -1
- package/build/lib/mixins/screenshot.d.ts +13 -0
- package/build/lib/mixins/screenshot.d.ts.map +1 -0
- package/build/lib/mixins/screenshot.js +31 -0
- package/build/lib/mixins/screenshot.js.map +1 -0
- package/build/lib/remote-debugger-real-device.d.ts +16 -2
- package/build/lib/remote-debugger-real-device.d.ts.map +1 -1
- package/build/lib/remote-debugger-real-device.js +11 -1
- package/build/lib/remote-debugger-real-device.js.map +1 -1
- package/build/lib/remote-debugger.d.ts +155 -174
- package/build/lib/remote-debugger.d.ts.map +1 -1
- package/build/lib/remote-debugger.js +149 -210
- package/build/lib/remote-debugger.js.map +1 -1
- package/build/lib/rpc/rpc-client.d.ts +14 -13
- package/build/lib/rpc/rpc-client.d.ts.map +1 -1
- package/build/lib/rpc/rpc-client.js +8 -6
- package/build/lib/rpc/rpc-client.js.map +1 -1
- package/build/lib/utils.d.ts +20 -16
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +33 -25
- package/build/lib/utils.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/mixins/connect.js +77 -111
- package/lib/mixins/cookies.js +45 -0
- package/lib/mixins/events.js +25 -1
- package/lib/mixins/execute.js +18 -39
- package/lib/mixins/message-handlers.js +67 -36
- package/lib/mixins/misc.js +128 -0
- package/lib/mixins/navigate.js +26 -30
- package/lib/mixins/screenshot.js +34 -0
- package/lib/remote-debugger-real-device.js +14 -1
- package/lib/remote-debugger.js +138 -302
- package/lib/rpc/rpc-client.js +9 -7
- package/lib/utils.js +42 -38
- package/package.json +1 -1
- package/build/lib/mixins/index.d.ts +0 -5
- package/build/lib/mixins/index.d.ts.map +0 -1
- package/build/lib/mixins/index.js +0 -16
- package/build/lib/mixins/index.js.map +0 -1
- package/lib/mixins/index.js +0 -14
package/lib/mixins/connect.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import log from '../logger';
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
getPossibleDebuggerAppKeys,
|
|
2
|
+
pageArrayFromDict,
|
|
3
|
+
getPossibleDebuggerAppKeys,
|
|
4
|
+
simpleStringify,
|
|
5
5
|
} from '../utils';
|
|
6
6
|
import events from './events';
|
|
7
7
|
import { timing } from '@appium/support';
|
|
@@ -32,62 +32,60 @@ const BLANK_PAGE_URL = 'about:blank';
|
|
|
32
32
|
/**
|
|
33
33
|
*
|
|
34
34
|
* @this {import('../remote-debugger').RemoteDebugger}
|
|
35
|
+
* @returns {Promise<void>}
|
|
35
36
|
*/
|
|
36
|
-
async function setConnectionKey () {
|
|
37
|
-
log.debug('Sending connection key request');
|
|
38
|
-
if (!this.rpcClient) {
|
|
39
|
-
throw new Error('rpcClient is undefined. Is the debugger connected?');
|
|
40
|
-
}
|
|
37
|
+
export async function setConnectionKey () {
|
|
38
|
+
this.log.debug('Sending connection key request');
|
|
41
39
|
|
|
42
40
|
// send but only wait to make sure the socket worked
|
|
43
41
|
// as response from Web Inspector can take a long time
|
|
44
|
-
await this.
|
|
42
|
+
await this.requireRpcClient().send('setConnectionKey', {}, false);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
/**
|
|
48
46
|
*
|
|
49
47
|
* @this {import('../remote-debugger').RemoteDebugger}
|
|
48
|
+
* @param {number} [timeout=APP_CONNECT_TIMEOUT_MS]
|
|
49
|
+
* @returns {Promise<import('@appium/types').StringRecord>}
|
|
50
50
|
*/
|
|
51
|
-
async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
|
|
51
|
+
export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
|
|
52
52
|
this.setup();
|
|
53
53
|
|
|
54
54
|
// initialize the rpc client
|
|
55
55
|
this.initRpcClient();
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
throw new Error('rpcClient is undefined. Is the debugger connected?');
|
|
59
|
-
}
|
|
57
|
+
const rpcClient = this.requireRpcClient();
|
|
60
58
|
|
|
61
59
|
// listen for basic debugger-level events
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
await
|
|
60
|
+
rpcClient.on('_rpc_reportSetup:', _.noop);
|
|
61
|
+
rpcClient.on('_rpc_forwardGetListing:', this.onPageChange.bind(this));
|
|
62
|
+
rpcClient.on('_rpc_reportConnectedApplicationList:', this.onConnectedApplicationList.bind(this));
|
|
63
|
+
rpcClient.on('_rpc_applicationConnected:', this.onAppConnect.bind(this));
|
|
64
|
+
rpcClient.on('_rpc_applicationDisconnected:', this.onAppDisconnect.bind(this));
|
|
65
|
+
rpcClient.on('_rpc_applicationUpdated:', this.onAppUpdate.bind(this));
|
|
66
|
+
rpcClient.on('_rpc_reportConnectedDriverList:', this.onConnectedDriverList.bind(this));
|
|
67
|
+
rpcClient.on('_rpc_reportCurrentState:', this.onCurrentState.bind(this));
|
|
68
|
+
rpcClient.on('Page.frameDetached', this.frameDetached.bind(this));
|
|
69
|
+
|
|
70
|
+
await rpcClient.connect();
|
|
73
71
|
|
|
74
72
|
// get the connection information about the app
|
|
75
73
|
try {
|
|
76
74
|
this.setConnectionKey();
|
|
77
75
|
if (timeout) {
|
|
78
|
-
log.debug(`Waiting up to ${timeout}ms for applications to be reported`);
|
|
76
|
+
this.log.debug(`Waiting up to ${timeout}ms for applications to be reported`);
|
|
79
77
|
try {
|
|
80
78
|
await waitForCondition(() => !_.isEmpty(this.appDict), {
|
|
81
79
|
waitMs: timeout,
|
|
82
80
|
intervalMs: APP_CONNECT_INTERVAL_MS,
|
|
83
81
|
});
|
|
84
82
|
} catch (err) {
|
|
85
|
-
log.debug(`Timed out waiting for applications to be reported`);
|
|
83
|
+
this.log.debug(`Timed out waiting for applications to be reported`);
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
return this.appDict || {};
|
|
89
87
|
} catch (err) {
|
|
90
|
-
log.error(`Error setting connection key: ${err.message}`);
|
|
88
|
+
this.log.error(`Error setting connection key: ${err.message}`);
|
|
91
89
|
await this.disconnect();
|
|
92
90
|
throw err;
|
|
93
91
|
}
|
|
@@ -98,7 +96,7 @@ async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
|
|
|
98
96
|
* @this {import('../remote-debugger').RemoteDebugger}
|
|
99
97
|
* @returns {Promise<void>}
|
|
100
98
|
*/
|
|
101
|
-
async function disconnect () {
|
|
99
|
+
export async function disconnect () {
|
|
102
100
|
if (this.rpcClient) {
|
|
103
101
|
await this.rpcClient.disconnect();
|
|
104
102
|
}
|
|
@@ -106,50 +104,58 @@ async function disconnect () {
|
|
|
106
104
|
this.teardown();
|
|
107
105
|
}
|
|
108
106
|
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {Object} Page
|
|
109
|
+
* @property {string} url
|
|
110
|
+
* @property {string} title
|
|
111
|
+
* @property {number} id
|
|
112
|
+
* @property {boolean} isKey
|
|
113
|
+
* @property {string} [bundleId]
|
|
114
|
+
*/
|
|
115
|
+
|
|
109
116
|
/**
|
|
110
117
|
*
|
|
111
118
|
* @this {import('../remote-debugger').RemoteDebugger}
|
|
112
119
|
* @param {string?} currentUrl
|
|
113
120
|
* @param {number} [maxTries]
|
|
114
121
|
* @param {boolean} [ignoreAboutBlankUrl]
|
|
115
|
-
* @returns {Promise<
|
|
122
|
+
* @returns {Promise<Page[]>}
|
|
116
123
|
*/
|
|
117
|
-
async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, ignoreAboutBlankUrl = false) {
|
|
118
|
-
log.debug('Selecting application');
|
|
119
|
-
|
|
120
|
-
throw new Error('rpcClient is undefined. Is the debugger connected?');
|
|
121
|
-
}
|
|
124
|
+
export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, ignoreAboutBlankUrl = false) {
|
|
125
|
+
this.log.debug('Selecting application');
|
|
126
|
+
const rpcClient = this.requireRpcClient();
|
|
122
127
|
|
|
123
|
-
const shouldCheckForTarget =
|
|
124
|
-
|
|
128
|
+
const shouldCheckForTarget = rpcClient.shouldCheckForTarget;
|
|
129
|
+
rpcClient.shouldCheckForTarget = false;
|
|
125
130
|
try {
|
|
126
131
|
const timer = new timing.Timer().start();
|
|
127
132
|
if (!this.appDict || _.isEmpty(this.appDict)) {
|
|
128
|
-
log.debug('No applications currently connected.');
|
|
133
|
+
this.log.debug('No applications currently connected.');
|
|
129
134
|
return [];
|
|
130
135
|
}
|
|
131
136
|
|
|
132
|
-
const {appIdKey, pageDict} = await this.searchForApp(currentUrl, maxTries, ignoreAboutBlankUrl);
|
|
137
|
+
const {appIdKey, pageDict} = await this.searchForApp(currentUrl, maxTries, ignoreAboutBlankUrl) ?? {};
|
|
133
138
|
|
|
134
139
|
// if, after all this, we have no dictionary, we have failed
|
|
135
140
|
if (!appIdKey || !pageDict) {
|
|
136
|
-
log.
|
|
141
|
+
throw this.log.errorWithException(`Could not connect to a valid app after ${maxTries} tries.`);
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
if (this.appIdKey !== appIdKey) {
|
|
140
|
-
log.debug(`Received altered app id, updating from '${this.appIdKey}' to '${appIdKey}'`);
|
|
145
|
+
this.log.debug(`Received altered app id, updating from '${this.appIdKey}' to '${appIdKey}'`);
|
|
141
146
|
this.appIdKey = appIdKey;
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
logApplicationDictionary(this.appDict);
|
|
149
|
+
logApplicationDictionary.bind(this)(this.appDict);
|
|
145
150
|
|
|
146
151
|
// translate the dictionary into a useful form, and return to sender
|
|
147
152
|
const pageArray = _.isEmpty(this.appDict[appIdKey].pageArray)
|
|
148
153
|
? pageArrayFromDict(pageDict)
|
|
149
154
|
: this.appDict[appIdKey].pageArray;
|
|
150
|
-
log.debug(`Finally selecting app ${this.appIdKey}: ${simpleStringify(pageArray)}`);
|
|
155
|
+
this.log.debug(`Finally selecting app ${this.appIdKey}: ${simpleStringify(pageArray)}`);
|
|
151
156
|
|
|
152
|
-
|
|
157
|
+
/** @type {Page[]} */
|
|
158
|
+
const fullPageArray = [];
|
|
153
159
|
for (const [app, info] of _.toPairs(this.appDict)) {
|
|
154
160
|
if (!_.isArray(info.pageArray) || !info.isActive) {
|
|
155
161
|
continue;
|
|
@@ -157,7 +163,7 @@ async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, igno
|
|
|
157
163
|
const id = app.replace('PID:', '');
|
|
158
164
|
for (const page of info.pageArray) {
|
|
159
165
|
if (!(ignoreAboutBlankUrl && page.url === BLANK_PAGE_URL)) {
|
|
160
|
-
|
|
166
|
+
const pageDict = _.clone(page);
|
|
161
167
|
pageDict.id = `${id}.${pageDict.id}`;
|
|
162
168
|
pageDict.bundleId = info.bundleId;
|
|
163
169
|
fullPageArray.push(pageDict);
|
|
@@ -165,10 +171,10 @@ async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, igno
|
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
|
|
168
|
-
log.debug(`Selected app after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
174
|
+
this.log.debug(`Selected app after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
169
175
|
return fullPageArray;
|
|
170
176
|
} finally {
|
|
171
|
-
|
|
177
|
+
rpcClient.shouldCheckForTarget = shouldCheckForTarget;
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
180
|
|
|
@@ -180,32 +186,28 @@ async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, igno
|
|
|
180
186
|
* @param {boolean} ignoreAboutBlankUrl
|
|
181
187
|
* @returns {Promise<AppPages?>}
|
|
182
188
|
*/
|
|
183
|
-
async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
189
|
+
export async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
184
190
|
const bundleIds = this.includeSafari && !this.isSafari
|
|
185
191
|
? [this.bundleId, ...this.additionalBundleIds, SAFARI_BUNDLE_ID]
|
|
186
192
|
: [this.bundleId, ...this.additionalBundleIds];
|
|
187
193
|
let retryCount = 0;
|
|
188
194
|
try {
|
|
189
195
|
return await retryInterval(maxTries, SELECT_APP_RETRY_SLEEP_MS, async () => {
|
|
190
|
-
|
|
191
|
-
throw new Error('rpcClient is undefined. Is the debugger connected?');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
logApplicationDictionary(this.appDict);
|
|
196
|
+
logApplicationDictionary.bind(this)(this.appDict);
|
|
195
197
|
const possibleAppIds = getPossibleDebuggerAppKeys(/** @type {string[]} */ (bundleIds), this.appDict);
|
|
196
|
-
log.debug(`Trying out the possible app ids: ${possibleAppIds.join(', ')} (try #${retryCount + 1} of ${maxTries})`);
|
|
198
|
+
this.log.debug(`Trying out the possible app ids: ${possibleAppIds.join(', ')} (try #${retryCount + 1} of ${maxTries})`);
|
|
197
199
|
for (const attemptedAppIdKey of possibleAppIds) {
|
|
198
200
|
try {
|
|
199
201
|
if (!this.appDict[attemptedAppIdKey].isActive) {
|
|
200
|
-
log.debug(`Skipping app '${attemptedAppIdKey}' because it is not active`);
|
|
202
|
+
this.log.debug(`Skipping app '${attemptedAppIdKey}' because it is not active`);
|
|
201
203
|
continue;
|
|
202
204
|
}
|
|
203
|
-
log.debug(`Attempting app '${attemptedAppIdKey}'`);
|
|
204
|
-
const [appIdKey, pageDict] = await this.
|
|
205
|
+
this.log.debug(`Attempting app '${attemptedAppIdKey}'`);
|
|
206
|
+
const [appIdKey, pageDict] = await this.requireRpcClient().selectApp(attemptedAppIdKey);
|
|
205
207
|
// in iOS 8.2 the connect logic happens, but with an empty dictionary
|
|
206
208
|
// which leads to the remote debugger getting disconnected, and into a loop
|
|
207
209
|
if (_.isEmpty(pageDict)) {
|
|
208
|
-
log.debug('Empty page dictionary received. Trying again.');
|
|
210
|
+
this.log.debug('Empty page dictionary received. Trying again.');
|
|
209
211
|
continue;
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -221,19 +223,19 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
if (currentUrl) {
|
|
224
|
-
log.debug(`Received app, but expected url ('${currentUrl}') was not found. Trying again.`);
|
|
226
|
+
this.log.debug(`Received app, but expected url ('${currentUrl}') was not found. Trying again.`);
|
|
225
227
|
} else {
|
|
226
|
-
log.debug('Received app, but no match was found. Trying again.');
|
|
228
|
+
this.log.debug('Received app, but no match was found. Trying again.');
|
|
227
229
|
}
|
|
228
230
|
} catch (err) {
|
|
229
|
-
log.debug(`Error checking application: '${err.message}'. Retrying connection`);
|
|
231
|
+
this.log.debug(`Error checking application: '${err.message}'. Retrying connection`);
|
|
230
232
|
}
|
|
231
233
|
}
|
|
232
234
|
retryCount++;
|
|
233
235
|
throw new Error('Failed to find an app to select');
|
|
234
236
|
});
|
|
235
237
|
} catch (ign) {
|
|
236
|
-
log.errorAndThrow(`Could not connect to a valid app after ${maxTries} tries.`);
|
|
238
|
+
this.log.errorAndThrow(`Could not connect to a valid app after ${maxTries} tries.`);
|
|
237
239
|
}
|
|
238
240
|
return null;
|
|
239
241
|
}
|
|
@@ -246,7 +248,7 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
|
246
248
|
* @param {boolean} [ignoreAboutBlankUrl]
|
|
247
249
|
* @returns {AppPages?}
|
|
248
250
|
*/
|
|
249
|
-
function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false) {
|
|
251
|
+
export function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false) {
|
|
250
252
|
for (const appDict of _.values(appsDict)) {
|
|
251
253
|
if (!appDict || !appDict.isActive || !appDict.pageArray || appDict.pageArray.promise) {
|
|
252
254
|
continue;
|
|
@@ -265,34 +267,31 @@ function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false
|
|
|
265
267
|
/**
|
|
266
268
|
*
|
|
267
269
|
* @this {import('../remote-debugger').RemoteDebugger}
|
|
268
|
-
* @param {string} appIdKey
|
|
269
|
-
* @param {string} pageIdKey
|
|
270
|
+
* @param {string|number} appIdKey
|
|
271
|
+
* @param {string|number} pageIdKey
|
|
270
272
|
* @param {boolean} [skipReadyCheck]
|
|
271
273
|
* @returns {Promise<void>}
|
|
272
274
|
*/
|
|
273
|
-
async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
|
|
274
|
-
this.appIdKey = `PID:${appIdKey}`;
|
|
275
|
+
export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
|
|
276
|
+
this.appIdKey = _.startsWith(`${appIdKey}`, 'PID:') ? `${appIdKey}` : `PID:${appIdKey}`;
|
|
275
277
|
this.pageIdKey = pageIdKey;
|
|
276
278
|
|
|
277
|
-
log.debug(`Selecting page '${pageIdKey}' on app '${this.appIdKey}' and forwarding socket setup`);
|
|
278
|
-
if (!this.rpcClient) {
|
|
279
|
-
throw new Error('rpcClient is undefined. Is the debugger connected?');
|
|
280
|
-
}
|
|
279
|
+
this.log.debug(`Selecting page '${pageIdKey}' on app '${this.appIdKey}' and forwarding socket setup`);
|
|
281
280
|
|
|
282
281
|
const timer = new timing.Timer().start();
|
|
283
282
|
|
|
284
|
-
await this.
|
|
283
|
+
await this.requireRpcClient().selectPage(this.appIdKey, pageIdKey);
|
|
285
284
|
|
|
286
285
|
// make sure everything is ready to go
|
|
287
286
|
if (!skipReadyCheck && !await this.checkPageIsReady()) {
|
|
288
287
|
await this.waitForDom();
|
|
289
288
|
}
|
|
290
289
|
|
|
291
|
-
log.debug(`Selected page after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
290
|
+
this.log.debug(`Selected page after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
292
291
|
}
|
|
293
292
|
|
|
294
293
|
/**
|
|
295
|
-
*
|
|
294
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
296
295
|
* @param {Record<string, any>} apps
|
|
297
296
|
* @returns {void}
|
|
298
297
|
*/
|
|
@@ -308,56 +307,23 @@ function logApplicationDictionary (apps) {
|
|
|
308
307
|
return JSON.stringify(value);
|
|
309
308
|
}
|
|
310
309
|
|
|
311
|
-
log.debug('Current applications available:');
|
|
310
|
+
this.log.debug('Current applications available:');
|
|
312
311
|
for (const [app, info] of _.toPairs(apps)) {
|
|
313
|
-
log.debug(` Application: "${app}"`);
|
|
312
|
+
this.log.debug(` Application: "${app}"`);
|
|
314
313
|
for (const [key, value] of _.toPairs(info)) {
|
|
315
314
|
if (key === 'pageArray' && Array.isArray(value) && value.length) {
|
|
316
|
-
log.debug(` ${key}:`);
|
|
315
|
+
this.log.debug(` ${key}:`);
|
|
317
316
|
for (const page of value) {
|
|
318
317
|
let prefix = '- ';
|
|
319
318
|
for (const [k, v] of _.toPairs(page)) {
|
|
320
|
-
log.debug(` ${prefix}${k}: ${JSON.stringify(v)}`);
|
|
319
|
+
this.log.debug(` ${prefix}${k}: ${JSON.stringify(v)}`);
|
|
321
320
|
prefix = ' ';
|
|
322
321
|
}
|
|
323
322
|
}
|
|
324
323
|
} else {
|
|
325
324
|
const valueString = getValueString(key, value);
|
|
326
|
-
log.debug(` ${key}: ${valueString}`);
|
|
325
|
+
this.log.debug(` ${key}: ${valueString}`);
|
|
327
326
|
}
|
|
328
327
|
}
|
|
329
328
|
}
|
|
330
329
|
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
*
|
|
334
|
-
* @this {import('../remote-debugger').RemoteDebugger}
|
|
335
|
-
* @param {Record<string, any>} dict
|
|
336
|
-
* @returns {void}
|
|
337
|
-
*/
|
|
338
|
-
function updateAppsWithDict (dict) {
|
|
339
|
-
// get the dictionary entry into a nice form, and add it to the
|
|
340
|
-
// application dictionary
|
|
341
|
-
this.appDict = this.appDict || {};
|
|
342
|
-
let [id, entry] = appInfoFromDict(dict);
|
|
343
|
-
if (this.appDict[id]) {
|
|
344
|
-
// preserve the page dictionary for this entry
|
|
345
|
-
entry.pageArray = this.appDict[id].pageArray;
|
|
346
|
-
}
|
|
347
|
-
this.appDict[id] = entry;
|
|
348
|
-
|
|
349
|
-
// add a promise to get the page dictionary
|
|
350
|
-
if (_.isUndefined(entry.pageArray)) {
|
|
351
|
-
entry.pageArray = deferredPromise();
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// try to get the app id from our connected apps
|
|
355
|
-
if (!this.appIdKey) {
|
|
356
|
-
this.appIdKey = getDebuggerAppKey(/** @type {string} */ (this.bundleId), this.appDict);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
export default {
|
|
361
|
-
setConnectionKey, connect, disconnect, selectApp,
|
|
362
|
-
searchForApp, searchForPage, selectPage, updateAppsWithDict
|
|
363
|
-
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
7
|
+
export async function getCookies () {
|
|
8
|
+
this.log.debug('Getting cookies');
|
|
9
|
+
return await this.requireRpcClient().send('Page.getCookies', {
|
|
10
|
+
appIdKey: this.appIdKey,
|
|
11
|
+
pageIdKey: this.pageIdKey
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
18
|
+
* @param {any} cookie
|
|
19
|
+
* @returns {Promise<any>}
|
|
20
|
+
*/
|
|
21
|
+
export async function setCookie (cookie) {
|
|
22
|
+
this.log.debug('Setting cookie');
|
|
23
|
+
return await this.requireRpcClient().send('Page.setCookie', {
|
|
24
|
+
appIdKey: this.appIdKey,
|
|
25
|
+
pageIdKey: this.pageIdKey,
|
|
26
|
+
cookie
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
33
|
+
* @param {string} cookieName
|
|
34
|
+
* @param {string} url
|
|
35
|
+
* @returns {Promise<any>}
|
|
36
|
+
*/
|
|
37
|
+
export async function deleteCookie (cookieName, url) {
|
|
38
|
+
this.log.debug(`Deleting cookie '${cookieName}' on '${url}'`);
|
|
39
|
+
return await this.requireRpcClient().send('Page.deleteCookie', {
|
|
40
|
+
appIdKey: this.appIdKey,
|
|
41
|
+
pageIdKey: this.pageIdKey,
|
|
42
|
+
cookieName,
|
|
43
|
+
url,
|
|
44
|
+
});
|
|
45
|
+
}
|
package/lib/mixins/events.js
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
// event emitted publically
|
|
2
|
-
const events = {
|
|
2
|
+
export const events = {
|
|
3
3
|
EVENT_PAGE_CHANGE: 'remote_debugger_page_change',
|
|
4
4
|
EVENT_FRAMES_DETACHED: 'remote_debugger_frames_detached',
|
|
5
5
|
EVENT_DISCONNECT: 'remote_debugger_disconnect',
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Keep track of the client event listeners so they can be removed
|
|
10
|
+
*
|
|
11
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
12
|
+
* @param {string} eventName
|
|
13
|
+
* @param {(event: import('@appium/types').StringRecord) => any} listener
|
|
14
|
+
* @returns {void}
|
|
15
|
+
*/
|
|
16
|
+
export function addClientEventListener (eventName, listener) {
|
|
17
|
+
this._clientEventListeners[eventName] ??= [];
|
|
18
|
+
this._clientEventListeners[eventName].push(listener);
|
|
19
|
+
this.requireRpcClient().on(eventName, listener);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @this {import('../remote-debugger').RemoteDebugger}
|
|
24
|
+
* @param {string} eventName
|
|
25
|
+
* @returns {void}
|
|
26
|
+
*/
|
|
27
|
+
export function removeClientEventListener (eventName) {
|
|
28
|
+
for (const listener of (this._clientEventListeners[eventName] || [])) {
|
|
29
|
+
this.requireRpcClient().off(eventName, listener);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
8
32
|
|
|
9
33
|
export default events;
|
package/lib/mixins/execute.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import log from '../logger';
|
|
2
1
|
import { errors } from '@appium/base-driver';
|
|
3
2
|
import { checkParams, simpleStringify, convertResult, RESPONSE_LOG_LENGTH } from '../utils';
|
|
4
3
|
import { getScriptForAtom } from '../atoms';
|
|
@@ -15,17 +14,13 @@ const RPC_RESPONSE_TIMEOUT_MS = 5000;
|
|
|
15
14
|
* @param {string} atom Name of Selenium atom (see atoms/ directory)
|
|
16
15
|
* @param {any[]} args Arguments passed to the atom
|
|
17
16
|
* @param {string[]} frames
|
|
18
|
-
* @returns {Promise<
|
|
17
|
+
* @returns {Promise<any>} The result received from the atom
|
|
19
18
|
*/
|
|
20
|
-
async function executeAtom (atom, args = [], frames = []) {
|
|
21
|
-
|
|
22
|
-
throw new Error('Remote debugger is not connected');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
log.debug(`Executing atom '${atom}' with 'args=${JSON.stringify(args)}; frames=${frames}'`);
|
|
19
|
+
export async function executeAtom (atom, args = [], frames = []) {
|
|
20
|
+
this.log.debug(`Executing atom '${atom}' with 'args=${JSON.stringify(args)}; frames=${frames}'`);
|
|
26
21
|
const script = await getScriptForAtom(atom, args, frames);
|
|
27
22
|
const value = await this.execute(script, true);
|
|
28
|
-
log.debug(`Received result for atom '${atom}' execution: ${_.truncate(simpleStringify(value), {length: RESPONSE_LOG_LENGTH})}`);
|
|
23
|
+
this.log.debug(`Received result for atom '${atom}' execution: ${_.truncate(simpleStringify(value), {length: RESPONSE_LOG_LENGTH})}`);
|
|
29
24
|
return value;
|
|
30
25
|
}
|
|
31
26
|
|
|
@@ -36,18 +31,13 @@ async function executeAtom (atom, args = [], frames = []) {
|
|
|
36
31
|
* @param {string[]} [frames]
|
|
37
32
|
* @returns {Promise<any>}
|
|
38
33
|
*/
|
|
39
|
-
async function executeAtomAsync (atom, args = [], frames = []) {
|
|
34
|
+
export async function executeAtomAsync (atom, args = [], frames = []) {
|
|
40
35
|
// helper to send directly to the web inspector
|
|
41
|
-
const evaluate = async (method, opts) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
appIdKey: this.appIdKey,
|
|
47
|
-
pageIdKey: this.pageIdKey,
|
|
48
|
-
returnByValue: false,
|
|
49
|
-
}, opts));
|
|
50
|
-
};
|
|
36
|
+
const evaluate = async (method, opts) => await this.requireRpcClient(true).send(method, Object.assign({
|
|
37
|
+
appIdKey: this.appIdKey,
|
|
38
|
+
pageIdKey: this.pageIdKey,
|
|
39
|
+
returnByValue: false,
|
|
40
|
+
}, opts));
|
|
51
41
|
|
|
52
42
|
// first create a Promise on the page, saving the resolve/reject functions
|
|
53
43
|
// as properties
|
|
@@ -94,7 +84,7 @@ async function executeAtomAsync (atom, args = [], frames = []) {
|
|
|
94
84
|
// if the timeout math turns up 0 retries, make sure it happens once
|
|
95
85
|
const retries = parseInt(`${timeout / retryWait}`, 10) || 1;
|
|
96
86
|
const timer = new timing.Timer().start();
|
|
97
|
-
log.debug(`Waiting up to ${timeout}ms for async execute to finish`);
|
|
87
|
+
this.log.debug(`Waiting up to ${timeout}ms for async execute to finish`);
|
|
98
88
|
res = await retryInterval(retries, retryWait, async () => {
|
|
99
89
|
// the atom _will_ return, either because it finished or an error
|
|
100
90
|
// including a timeout error
|
|
@@ -131,10 +121,10 @@ async function executeAtomAsync (atom, args = [], frames = []) {
|
|
|
131
121
|
* @param {boolean} [override]
|
|
132
122
|
* @returns {Promise<any>}
|
|
133
123
|
*/
|
|
134
|
-
async function execute (command, override) {
|
|
124
|
+
export async function execute (command, override) {
|
|
135
125
|
// if the page is not loaded yet, wait for it
|
|
136
126
|
if (this.pageLoading && !override) {
|
|
137
|
-
log.debug('Trying to execute but page is not loaded.');
|
|
127
|
+
this.log.debug('Trying to execute but page is not loaded.');
|
|
138
128
|
await this.waitForDom();
|
|
139
129
|
}
|
|
140
130
|
|
|
@@ -149,17 +139,13 @@ async function execute (command, override) {
|
|
|
149
139
|
await this.garbageCollect();
|
|
150
140
|
}
|
|
151
141
|
|
|
152
|
-
log.debug(`Sending javascript command: '${_.truncate(command, {length: 50})}'`);
|
|
153
|
-
|
|
154
|
-
throw new Error('Remote debugger is not connected');
|
|
155
|
-
}
|
|
156
|
-
const res = await this.rpcClient.send('Runtime.evaluate', {
|
|
142
|
+
this.log.debug(`Sending javascript command: '${_.truncate(command, {length: 50})}'`);
|
|
143
|
+
const res = await this.requireRpcClient(true).send('Runtime.evaluate', {
|
|
157
144
|
expression: command,
|
|
158
145
|
returnByValue: true,
|
|
159
146
|
appIdKey: this.appIdKey,
|
|
160
147
|
pageIdKey: this.pageIdKey,
|
|
161
148
|
});
|
|
162
|
-
|
|
163
149
|
return convertResult(res);
|
|
164
150
|
}
|
|
165
151
|
|
|
@@ -169,19 +155,15 @@ async function execute (command, override) {
|
|
|
169
155
|
* @param {any} fn
|
|
170
156
|
* @param {any[]} [args]
|
|
171
157
|
*/
|
|
172
|
-
async function callFunction (objectId, fn, args) {
|
|
173
|
-
if (!this.rpcClient?.isConnected) {
|
|
174
|
-
throw new Error('Remote debugger is not connected');
|
|
175
|
-
}
|
|
176
|
-
|
|
158
|
+
export async function callFunction (objectId, fn, args) {
|
|
177
159
|
checkParams({appIdKey: this.appIdKey, pageIdKey: this.pageIdKey});
|
|
178
160
|
|
|
179
161
|
if (this.garbageCollectOnExecute) {
|
|
180
162
|
await this.garbageCollect();
|
|
181
163
|
}
|
|
182
164
|
|
|
183
|
-
log.debug('Calling javascript function');
|
|
184
|
-
const res = await this.
|
|
165
|
+
this.log.debug('Calling javascript function');
|
|
166
|
+
const res = await this.requireRpcClient(true).send('Runtime.callFunctionOn', {
|
|
185
167
|
objectId,
|
|
186
168
|
functionDeclaration: fn,
|
|
187
169
|
arguments: args,
|
|
@@ -192,6 +174,3 @@ async function callFunction (objectId, fn, args) {
|
|
|
192
174
|
|
|
193
175
|
return convertResult(res);
|
|
194
176
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
export default { executeAtom, executeAtomAsync, execute, callFunction };
|