appium-remote-debugger 15.2.9 → 15.2.11
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 +47 -31
- package/build/lib/mixins/connect.d.ts.map +1 -1
- package/build/lib/mixins/connect.js +105 -86
- package/build/lib/mixins/connect.js.map +1 -1
- package/build/lib/mixins/cookies.d.ts +17 -13
- package/build/lib/mixins/cookies.d.ts.map +1 -1
- package/build/lib/mixins/cookies.js +12 -12
- package/build/lib/mixins/cookies.js.map +1 -1
- package/build/lib/mixins/events.d.ts +32 -31
- package/build/lib/mixins/events.d.ts.map +1 -1
- package/build/lib/mixins/events.js +21 -24
- package/build/lib/mixins/events.js.map +1 -1
- package/build/lib/mixins/execute.d.ts +35 -24
- package/build/lib/mixins/execute.d.ts.map +1 -1
- package/build/lib/mixins/execute.js +34 -26
- package/build/lib/mixins/execute.js.map +1 -1
- package/build/lib/mixins/message-handlers.d.ts +63 -43
- package/build/lib/mixins/message-handlers.d.ts.map +1 -1
- package/build/lib/mixins/message-handlers.js +74 -57
- package/build/lib/mixins/message-handlers.js.map +1 -1
- package/build/lib/mixins/misc.d.ts +34 -24
- package/build/lib/mixins/misc.d.ts.map +1 -1
- package/build/lib/mixins/misc.js +27 -21
- package/build/lib/mixins/misc.js.map +1 -1
- package/build/lib/mixins/navigate.d.ts +39 -27
- package/build/lib/mixins/navigate.d.ts.map +1 -1
- package/build/lib/mixins/navigate.js +31 -31
- package/build/lib/mixins/navigate.js.map +1 -1
- package/build/lib/mixins/screenshot.d.ts +21 -11
- package/build/lib/mixins/screenshot.d.ts.map +1 -1
- package/build/lib/mixins/screenshot.js +10 -14
- package/build/lib/mixins/screenshot.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/mixins/{connect.js → connect.ts} +153 -113
- package/lib/mixins/cookies.ts +61 -0
- package/lib/mixins/events.ts +91 -0
- package/lib/mixins/{execute.js → execute.ts} +59 -33
- package/lib/mixins/message-handlers.ts +272 -0
- package/lib/mixins/misc.ts +136 -0
- package/lib/mixins/{navigate.js → navigate.ts} +44 -41
- package/lib/mixins/screenshot.ts +52 -0
- package/package.json +1 -1
- package/lib/mixins/cookies.js +0 -53
- package/lib/mixins/events.js +0 -81
- package/lib/mixins/message-handlers.js +0 -224
- package/lib/mixins/misc.js +0 -121
- package/lib/mixins/screenshot.js +0 -43
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
getAdditionalBundleIds,
|
|
20
20
|
} from './property-accessors';
|
|
21
21
|
import { NEW_APP_CONNECTED_ERROR, EMPTY_PAGE_DICTIONARY_ERROR } from '../rpc/rpc-client';
|
|
22
|
+
import type { RemoteDebugger } from '../remote-debugger';
|
|
23
|
+
import type { AppDict, Page, AppIdKey, PageIdKey, AppPage } from '../types';
|
|
22
24
|
|
|
23
25
|
const APP_CONNECT_TIMEOUT_MS = 0;
|
|
24
26
|
const APP_CONNECT_INTERVAL_MS = 100;
|
|
@@ -32,11 +34,11 @@ const SAFARI_VIEW_BUNDLE_ID = 'com.apple.SafariViewService';
|
|
|
32
34
|
const WILDCARD_BUNDLE_ID = '*';
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
37
|
+
* Sends a connection key request to the Web Inspector.
|
|
38
|
+
* This method only waits to ensure the socket connection works, as the response
|
|
39
|
+
* from Web Inspector can take a long time.
|
|
38
40
|
*/
|
|
39
|
-
export async function setConnectionKey
|
|
41
|
+
export async function setConnectionKey(this: RemoteDebugger): Promise<void> {
|
|
40
42
|
this.log.debug('Sending connection key request');
|
|
41
43
|
|
|
42
44
|
// send but only wait to make sure the socket worked
|
|
@@ -45,12 +47,17 @@ export async function setConnectionKey () {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/**
|
|
50
|
+
* Establishes a connection to the remote debugger and initializes the RPC client.
|
|
51
|
+
* Sets up event listeners for debugger-level events and waits for applications
|
|
52
|
+
* to be reported if a timeout is specified.
|
|
48
53
|
*
|
|
49
|
-
* @
|
|
50
|
-
*
|
|
51
|
-
*
|
|
54
|
+
* @param timeout - Maximum time in milliseconds to wait for applications to be reported.
|
|
55
|
+
* Defaults to 0 (no waiting). If provided, the method will wait up to
|
|
56
|
+
* this duration for applications to appear in the app dictionary.
|
|
57
|
+
* @returns A promise that resolves to the application dictionary containing all
|
|
58
|
+
* connected applications.
|
|
52
59
|
*/
|
|
53
|
-
export async function connect
|
|
60
|
+
export async function connect(this: RemoteDebugger, timeout: number = APP_CONNECT_TIMEOUT_MS): Promise<AppDict> {
|
|
54
61
|
this.setup();
|
|
55
62
|
|
|
56
63
|
// initialize the rpc client
|
|
@@ -91,7 +98,7 @@ export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
|
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
return this.appDict;
|
|
94
|
-
} catch (err) {
|
|
101
|
+
} catch (err: any) {
|
|
95
102
|
this.log.error(`Error setting connection key: ${err.message}`);
|
|
96
103
|
await this.disconnect();
|
|
97
104
|
throw err;
|
|
@@ -99,25 +106,36 @@ export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
|
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* @returns {Promise<void>}
|
|
109
|
+
* Disconnects from the remote debugger by closing the RPC client connection,
|
|
110
|
+
* emitting a disconnect event, and performing cleanup via teardown.
|
|
105
111
|
*/
|
|
106
|
-
export async function disconnect
|
|
112
|
+
export async function disconnect(this: RemoteDebugger): Promise<void> {
|
|
107
113
|
await getRcpClient(this)?.disconnect();
|
|
108
114
|
this.emit(events.EVENT_DISCONNECT, true);
|
|
109
115
|
this.teardown();
|
|
110
116
|
}
|
|
111
117
|
|
|
112
118
|
/**
|
|
119
|
+
* Selects an application from the available connected applications.
|
|
120
|
+
* Searches for an app matching the provided URL and bundle IDs, then returns
|
|
121
|
+
* all pages from the selected application.
|
|
113
122
|
*
|
|
114
|
-
* @
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* @param
|
|
118
|
-
*
|
|
123
|
+
* @param currentUrl - Optional URL to match when selecting an application.
|
|
124
|
+
* If provided, the method will try to find an app containing
|
|
125
|
+
* a page with this URL.
|
|
126
|
+
* @param maxTries - Maximum number of retry attempts when searching for an app.
|
|
127
|
+
* Defaults to SELECT_APP_RETRIES (20).
|
|
128
|
+
* @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be
|
|
129
|
+
* excluded from the results. Defaults to false.
|
|
130
|
+
* @returns A promise that resolves to an array of Page objects from the selected
|
|
131
|
+
* application. Returns an empty array if no applications are connected.
|
|
119
132
|
*/
|
|
120
|
-
export async function selectApp
|
|
133
|
+
export async function selectApp(
|
|
134
|
+
this: RemoteDebugger,
|
|
135
|
+
currentUrl: string | null = null,
|
|
136
|
+
maxTries: number = SELECT_APP_RETRIES,
|
|
137
|
+
ignoreAboutBlankUrl: boolean = false
|
|
138
|
+
): Promise<Page[]> {
|
|
121
139
|
this.log.debug('Selecting application');
|
|
122
140
|
|
|
123
141
|
const timer = new timing.Timer().start();
|
|
@@ -135,8 +153,7 @@ export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIE
|
|
|
135
153
|
// translate the dictionary into a useful form, and return to sender
|
|
136
154
|
this.log.debug(`Finally selecting app ${getAppIdKey(this)}`);
|
|
137
155
|
|
|
138
|
-
|
|
139
|
-
const fullPageArray = [];
|
|
156
|
+
const fullPageArray: Page[] = [];
|
|
140
157
|
for (const [app, info] of _.toPairs(getAppDict(this))) {
|
|
141
158
|
if (!_.isArray(info.pageArray) || !info.isActive) {
|
|
142
159
|
continue;
|
|
@@ -157,14 +174,22 @@ export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIE
|
|
|
157
174
|
}
|
|
158
175
|
|
|
159
176
|
/**
|
|
177
|
+
* Selects a specific page within an application and forwards socket setup.
|
|
178
|
+
* Optionally waits for the page to be ready based on the page load strategy.
|
|
160
179
|
*
|
|
161
|
-
* @
|
|
162
|
-
*
|
|
163
|
-
* @param
|
|
164
|
-
* @param
|
|
165
|
-
*
|
|
180
|
+
* @param appIdKey - The application identifier key. Will be prefixed with 'PID:'
|
|
181
|
+
* if not already present.
|
|
182
|
+
* @param pageIdKey - The page identifier key to select.
|
|
183
|
+
* @param skipReadyCheck - If true, skips the page readiness check. Defaults to false.
|
|
184
|
+
* When false, the method will wait for the page to be ready
|
|
185
|
+
* according to the configured page load strategy.
|
|
166
186
|
*/
|
|
167
|
-
export async function selectPage
|
|
187
|
+
export async function selectPage(
|
|
188
|
+
this: RemoteDebugger,
|
|
189
|
+
appIdKey: AppIdKey,
|
|
190
|
+
pageIdKey: PageIdKey,
|
|
191
|
+
skipReadyCheck: boolean = false
|
|
192
|
+
): Promise<void> {
|
|
168
193
|
const fullAppIdKey = _.startsWith(`${appIdKey}`, 'PID:') ? `${appIdKey}` : `PID:${appIdKey}`;
|
|
169
194
|
setAppIdKey(this, fullAppIdKey);
|
|
170
195
|
setPageIdKey(this, pageIdKey);
|
|
@@ -175,7 +200,7 @@ export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
|
|
|
175
200
|
|
|
176
201
|
const pageReadinessDetector = skipReadyCheck ? undefined : {
|
|
177
202
|
timeoutMs: this.pageLoadMs,
|
|
178
|
-
readinessDetector: (
|
|
203
|
+
readinessDetector: (readyState: string) => this.isPageLoadingCompleted(readyState),
|
|
179
204
|
};
|
|
180
205
|
await this.requireRpcClient().selectPage(fullAppIdKey, pageIdKey, pageReadinessDetector);
|
|
181
206
|
|
|
@@ -183,16 +208,87 @@ export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
|
|
|
183
208
|
}
|
|
184
209
|
|
|
185
210
|
/**
|
|
211
|
+
* Finds app keys based on assigned bundle IDs from the app dictionary.
|
|
212
|
+
* When bundleIds includes a wildcard ('*'), returns all app keys in the app dictionary.
|
|
213
|
+
* Also handles proxy applications that may act on behalf of other bundle IDs.
|
|
186
214
|
*
|
|
187
|
-
* @
|
|
188
|
-
*
|
|
189
|
-
* @
|
|
190
|
-
* @param {boolean} ignoreAboutBlankUrl
|
|
191
|
-
* @returns {Promise<import('../types').AppPage>}
|
|
215
|
+
* @param bundleIds - Array of bundle identifiers to match against. If the array
|
|
216
|
+
* contains a wildcard ('*'), all apps will be returned.
|
|
217
|
+
* @returns Array of application identifier keys that match the provided bundle IDs.
|
|
192
218
|
*/
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
export function getPossibleDebuggerAppKeys(this: RemoteDebugger, bundleIds: string[]): string[] {
|
|
220
|
+
const appDict = getAppDict(this);
|
|
221
|
+
|
|
222
|
+
if (bundleIds.includes(WILDCARD_BUNDLE_ID)) {
|
|
223
|
+
this.log.info(
|
|
224
|
+
'Returning all apps because the list of matching bundle identifiers includes a wildcard'
|
|
225
|
+
);
|
|
226
|
+
return _.keys(appDict);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// go through the possible bundle identifiers
|
|
230
|
+
const possibleBundleIds = _.uniq([
|
|
231
|
+
WEB_CONTENT_BUNDLE_ID,
|
|
232
|
+
WEB_CONTENT_PROCESS_BUNDLE_ID,
|
|
233
|
+
SAFARI_VIEW_PROCESS_BUNDLE_ID,
|
|
234
|
+
SAFARI_VIEW_BUNDLE_ID,
|
|
235
|
+
...bundleIds,
|
|
236
|
+
]);
|
|
237
|
+
this.log.debug(
|
|
238
|
+
`Checking for apps with matching bundle identifiers: ${possibleBundleIds.join(', ')}`
|
|
239
|
+
);
|
|
240
|
+
const proxiedAppIds: string[] = [];
|
|
241
|
+
for (const bundleId of possibleBundleIds) {
|
|
242
|
+
// now we need to determine if we should pick a proxy for this instead
|
|
243
|
+
for (const appId of appIdsForBundle(bundleId, appDict)) {
|
|
244
|
+
if (proxiedAppIds.includes(appId)) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
proxiedAppIds.push(appId);
|
|
249
|
+
this.log.debug(`Found app id key '${appId}' for bundle '${bundleId}'`);
|
|
250
|
+
for (const [key, data] of _.toPairs(appDict)) {
|
|
251
|
+
if (data.isProxy && data.hostId === appId && !proxiedAppIds.includes(key)) {
|
|
252
|
+
this.log.debug(
|
|
253
|
+
`Found separate bundleId '${data.bundleId}' ` +
|
|
254
|
+
`acting as proxy for '${bundleId}', with app id '${key}'`
|
|
255
|
+
);
|
|
256
|
+
proxiedAppIds.push(key);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
this.log.debug(
|
|
263
|
+
`You may also consider providing more values to 'additionalWebviewBundleIds' ` +
|
|
264
|
+
`capability to match other applications. Add a wildcard ('*') to match all apps.`
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
return _.uniq(proxiedAppIds);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Searches for an application matching the given criteria by retrying with
|
|
272
|
+
* exponential backoff. Attempts to connect to apps matching the bundle IDs
|
|
273
|
+
* and optionally filters by URL.
|
|
274
|
+
*
|
|
275
|
+
* @param currentUrl - Optional URL to match when searching for a page.
|
|
276
|
+
* If provided, only apps containing a page with this URL
|
|
277
|
+
* will be considered.
|
|
278
|
+
* @param maxTries - Maximum number of retry attempts.
|
|
279
|
+
* @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be
|
|
280
|
+
* ignored during the search.
|
|
281
|
+
* @returns A promise that resolves to an AppPage object containing the matched
|
|
282
|
+
* app ID key and page dictionary.
|
|
283
|
+
* @throws Error if no valid webapp can be connected after all retry attempts.
|
|
284
|
+
*/
|
|
285
|
+
async function searchForApp(
|
|
286
|
+
this: RemoteDebugger,
|
|
287
|
+
currentUrl: string | null,
|
|
288
|
+
maxTries: number,
|
|
289
|
+
ignoreAboutBlankUrl: boolean
|
|
290
|
+
): Promise<AppPage> {
|
|
291
|
+
const bundleIds: string[] = _.compact(
|
|
196
292
|
[
|
|
197
293
|
getBundleId(this),
|
|
198
294
|
...(getAdditionalBundleIds(this) ?? []),
|
|
@@ -200,9 +296,9 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
|
200
296
|
]
|
|
201
297
|
);
|
|
202
298
|
let retryCount = 0;
|
|
203
|
-
return
|
|
299
|
+
return await retryInterval(maxTries, SELECT_APP_RETRY_SLEEP_MS, async () => {
|
|
204
300
|
logApplicationDictionary.bind(this)();
|
|
205
|
-
const possibleAppIds = getPossibleDebuggerAppKeys.bind(this)(
|
|
301
|
+
const possibleAppIds = getPossibleDebuggerAppKeys.bind(this)(bundleIds);
|
|
206
302
|
this.log.debug(`Trying out the possible app ids: ${possibleAppIds.join(', ')} (try #${retryCount + 1} of ${maxTries})`);
|
|
207
303
|
for (const attemptedAppIdKey of possibleAppIds) {
|
|
208
304
|
const appInfo = getAppDict(this)[attemptedAppIdKey];
|
|
@@ -236,7 +332,7 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
|
236
332
|
} else {
|
|
237
333
|
this.log.debug('Received app, but no match was found. Trying again.');
|
|
238
334
|
}
|
|
239
|
-
} catch (err) {
|
|
335
|
+
} catch (err: any) {
|
|
240
336
|
if (![NEW_APP_CONNECTED_ERROR, EMPTY_PAGE_DICTIONARY_ERROR].some((msg) => msg === err.message)) {
|
|
241
337
|
this.log.debug(err.stack);
|
|
242
338
|
}
|
|
@@ -247,18 +343,25 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
|
|
|
247
343
|
throw new Error(
|
|
248
344
|
`Could not connect to a valid webapp. Make sure it is debuggable and has at least one active page.`
|
|
249
345
|
);
|
|
250
|
-
})
|
|
346
|
+
}) as Promise<AppPage>;
|
|
251
347
|
}
|
|
252
348
|
|
|
253
349
|
/**
|
|
350
|
+
* Searches through the application dictionary to find a page matching the given URL.
|
|
351
|
+
* Only considers active applications with non-empty page arrays.
|
|
254
352
|
*
|
|
255
|
-
* @
|
|
256
|
-
* @param
|
|
257
|
-
*
|
|
258
|
-
* @param
|
|
259
|
-
* @returns
|
|
353
|
+
* @param appsDict - The application dictionary to search through.
|
|
354
|
+
* @param currentUrl - Optional URL to match. If provided, only pages with this exact
|
|
355
|
+
* URL or with this URL followed by '/' will be considered.
|
|
356
|
+
* @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be ignored.
|
|
357
|
+
* @returns An AppPage object if a matching page is found, null otherwise.
|
|
260
358
|
*/
|
|
261
|
-
function searchForPage
|
|
359
|
+
function searchForPage(
|
|
360
|
+
this: RemoteDebugger,
|
|
361
|
+
appsDict: AppDict,
|
|
362
|
+
currentUrl: string | null = null,
|
|
363
|
+
ignoreAboutBlankUrl: boolean = false
|
|
364
|
+
): AppPage | null {
|
|
262
365
|
for (const appDict of _.values(appsDict)) {
|
|
263
366
|
if (!appDict || !appDict.isActive || !appDict.pageArray || _.isEmpty(appDict.pageArray)) {
|
|
264
367
|
continue;
|
|
@@ -278,10 +381,11 @@ function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false
|
|
|
278
381
|
}
|
|
279
382
|
|
|
280
383
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
384
|
+
* Logs the current application dictionary to the debug log.
|
|
385
|
+
* Displays all applications, their properties, and their associated pages
|
|
386
|
+
* in a formatted structure.
|
|
283
387
|
*/
|
|
284
|
-
function logApplicationDictionary
|
|
388
|
+
function logApplicationDictionary(this: RemoteDebugger): void {
|
|
285
389
|
this.log.debug('Current applications available:');
|
|
286
390
|
for (const [app, info] of _.toPairs(getAppDict(this))) {
|
|
287
391
|
this.log.debug(` Application: "${app}"`);
|
|
@@ -302,67 +406,3 @@ function logApplicationDictionary () {
|
|
|
302
406
|
}
|
|
303
407
|
}
|
|
304
408
|
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Find app keys based on assigned bundleIds from appDict
|
|
308
|
-
* When bundleIds includes a wildcard ('*'), returns all appKeys in appDict.
|
|
309
|
-
*
|
|
310
|
-
* @this {RemoteDebugger}
|
|
311
|
-
* @param {string[]} bundleIds
|
|
312
|
-
* @returns {string[]}
|
|
313
|
-
*/
|
|
314
|
-
export function getPossibleDebuggerAppKeys(bundleIds) {
|
|
315
|
-
const appDict = getAppDict(this);
|
|
316
|
-
|
|
317
|
-
if (bundleIds.includes(WILDCARD_BUNDLE_ID)) {
|
|
318
|
-
this.log.info(
|
|
319
|
-
'Returning all apps because the list of matching bundle identifiers includes a wildcard'
|
|
320
|
-
);
|
|
321
|
-
return _.keys(appDict);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// go through the possible bundle identifiers
|
|
325
|
-
const possibleBundleIds = _.uniq([
|
|
326
|
-
WEB_CONTENT_BUNDLE_ID,
|
|
327
|
-
WEB_CONTENT_PROCESS_BUNDLE_ID,
|
|
328
|
-
SAFARI_VIEW_PROCESS_BUNDLE_ID,
|
|
329
|
-
SAFARI_VIEW_BUNDLE_ID,
|
|
330
|
-
...bundleIds,
|
|
331
|
-
]);
|
|
332
|
-
this.log.debug(
|
|
333
|
-
`Checking for apps with matching bundle identifiers: ${possibleBundleIds.join(', ')}`
|
|
334
|
-
);
|
|
335
|
-
/** @type {string[]} */
|
|
336
|
-
const proxiedAppIds = [];
|
|
337
|
-
for (const bundleId of possibleBundleIds) {
|
|
338
|
-
// now we need to determine if we should pick a proxy for this instead
|
|
339
|
-
for (const appId of appIdsForBundle(bundleId, appDict)) {
|
|
340
|
-
if (proxiedAppIds.includes(appId)) {
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
proxiedAppIds.push(appId);
|
|
345
|
-
this.log.debug(`Found app id key '${appId}' for bundle '${bundleId}'`);
|
|
346
|
-
for (const [key, data] of _.toPairs(appDict)) {
|
|
347
|
-
if (data.isProxy && data.hostId === appId && !proxiedAppIds.includes(key)) {
|
|
348
|
-
this.log.debug(
|
|
349
|
-
`Found separate bundleId '${data.bundleId}' ` +
|
|
350
|
-
`acting as proxy for '${bundleId}', with app id '${key}'`
|
|
351
|
-
);
|
|
352
|
-
proxiedAppIds.push(key);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
this.log.debug(
|
|
359
|
-
`You may also consider providing more values to 'additionalWebviewBundleIds' ` +
|
|
360
|
-
`capability to match other applications. Add a wildcard ('*') to match all apps.`
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
return _.uniq(proxiedAppIds);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* @typedef {import('../remote-debugger').RemoteDebugger} RemoteDebugger
|
|
368
|
-
*/
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAppIdKey,
|
|
3
|
+
getPageIdKey,
|
|
4
|
+
} from './property-accessors';
|
|
5
|
+
import type { RemoteDebugger } from '../remote-debugger';
|
|
6
|
+
import type { StringRecord } from '@appium/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves all cookies for the current page by sending a Page.getCookies
|
|
10
|
+
* command to the remote debugger.
|
|
11
|
+
*
|
|
12
|
+
* @returns A promise that resolves to a dictionary containing the cookies.
|
|
13
|
+
*/
|
|
14
|
+
export async function getCookies(this: RemoteDebugger): Promise<StringRecord> {
|
|
15
|
+
this.log.debug('Getting cookies');
|
|
16
|
+
return await this.requireRpcClient().send('Page.getCookies', {
|
|
17
|
+
appIdKey: getAppIdKey(this),
|
|
18
|
+
pageIdKey: getPageIdKey(this),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sets a cookie on the current page by sending a Page.setCookie command
|
|
24
|
+
* to the remote debugger.
|
|
25
|
+
*
|
|
26
|
+
* @param cookie - Dictionary containing the cookie properties to set.
|
|
27
|
+
* @returns A promise that resolves when the cookie has been set.
|
|
28
|
+
*/
|
|
29
|
+
export async function setCookie(
|
|
30
|
+
this: RemoteDebugger,
|
|
31
|
+
cookie: StringRecord
|
|
32
|
+
): Promise<any> {
|
|
33
|
+
this.log.debug('Setting cookie');
|
|
34
|
+
return await this.requireRpcClient().send('Page.setCookie', {
|
|
35
|
+
appIdKey: getAppIdKey(this),
|
|
36
|
+
pageIdKey: getPageIdKey(this),
|
|
37
|
+
cookie,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Deletes a cookie from the current page by sending a Page.deleteCookie
|
|
43
|
+
* command to the remote debugger.
|
|
44
|
+
*
|
|
45
|
+
* @param cookieName - The name of the cookie to delete.
|
|
46
|
+
* @param url - The URL associated with the cookie to delete.
|
|
47
|
+
* @returns A promise that resolves when the cookie has been deleted.
|
|
48
|
+
*/
|
|
49
|
+
export async function deleteCookie(
|
|
50
|
+
this: RemoteDebugger,
|
|
51
|
+
cookieName: string,
|
|
52
|
+
url: string
|
|
53
|
+
): Promise<any> {
|
|
54
|
+
this.log.debug(`Deleting cookie '${cookieName}' on '${url}'`);
|
|
55
|
+
return await this.requireRpcClient().send('Page.deleteCookie', {
|
|
56
|
+
appIdKey: getAppIdKey(this),
|
|
57
|
+
pageIdKey: getPageIdKey(this),
|
|
58
|
+
cookieName,
|
|
59
|
+
url,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClientEventListeners,
|
|
3
|
+
} from './property-accessors';
|
|
4
|
+
import type { RemoteDebugger } from '../remote-debugger';
|
|
5
|
+
import type { EventListener } from '../types';
|
|
6
|
+
|
|
7
|
+
// event emitted publically
|
|
8
|
+
export const events = {
|
|
9
|
+
EVENT_PAGE_CHANGE: 'remote_debugger_page_change',
|
|
10
|
+
EVENT_FRAMES_DETACHED: 'remote_debugger_frames_detached',
|
|
11
|
+
EVENT_DISCONNECT: 'remote_debugger_disconnect',
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Adds a client event listener to the RPC client and tracks it for later removal.
|
|
16
|
+
* The listener will be called when the specified event is emitted by the remote debugger.
|
|
17
|
+
*
|
|
18
|
+
* @param eventName - The name of the event to listen for.
|
|
19
|
+
* @param listener - The event listener function to call when the event is emitted.
|
|
20
|
+
*/
|
|
21
|
+
export function addClientEventListener(
|
|
22
|
+
this: RemoteDebugger,
|
|
23
|
+
eventName: string,
|
|
24
|
+
listener: EventListener
|
|
25
|
+
): void {
|
|
26
|
+
getClientEventListeners(this)[eventName] ??= [];
|
|
27
|
+
getClientEventListeners(this)[eventName].push(listener);
|
|
28
|
+
this.requireRpcClient().on(eventName, listener);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Removes all client event listeners for the specified event name from the RPC client.
|
|
33
|
+
* This will stop listening for the event and clean up the tracked listeners.
|
|
34
|
+
*
|
|
35
|
+
* @param eventName - The name of the event to stop listening for.
|
|
36
|
+
*/
|
|
37
|
+
export function removeClientEventListener(
|
|
38
|
+
this: RemoteDebugger,
|
|
39
|
+
eventName: string
|
|
40
|
+
): void {
|
|
41
|
+
for (const listener of (getClientEventListeners(this)[eventName] || [])) {
|
|
42
|
+
this.requireRpcClient().off(eventName, listener);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Starts listening for JavaScript console messages by registering listeners
|
|
48
|
+
* for Console.messageAdded and Console.messageRepeatCountUpdated events.
|
|
49
|
+
*
|
|
50
|
+
* @param listener - The event listener function to call when console messages are received.
|
|
51
|
+
*/
|
|
52
|
+
export function startConsole(
|
|
53
|
+
this: RemoteDebugger,
|
|
54
|
+
listener: EventListener
|
|
55
|
+
): void {
|
|
56
|
+
this.log.debug('Starting to listen for JavaScript console');
|
|
57
|
+
this.addClientEventListener('Console.messageAdded', listener);
|
|
58
|
+
this.addClientEventListener('Console.messageRepeatCountUpdated', listener);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Stops listening for JavaScript console messages by removing listeners
|
|
63
|
+
* for Console.messageAdded and Console.messageRepeatCountUpdated events.
|
|
64
|
+
*/
|
|
65
|
+
export function stopConsole(this: RemoteDebugger): void {
|
|
66
|
+
this.log.debug('Stopping to listen for JavaScript console');
|
|
67
|
+
this.removeClientEventListener('Console.messageAdded');
|
|
68
|
+
this.removeClientEventListener('Console.messageRepeatCountUpdated');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Starts listening for network events by registering a listener for NetworkEvent.
|
|
73
|
+
* This aggregates all Network.* events into a single NetworkEvent.
|
|
74
|
+
*
|
|
75
|
+
* @param listener - The event listener function to call when network events are received.
|
|
76
|
+
*/
|
|
77
|
+
export function startNetwork(
|
|
78
|
+
this: RemoteDebugger,
|
|
79
|
+
listener: EventListener
|
|
80
|
+
): void {
|
|
81
|
+
this.log.debug('Starting to listen for network events');
|
|
82
|
+
this.addClientEventListener('NetworkEvent', listener);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Stops listening for network events by removing the listener for NetworkEvent.
|
|
87
|
+
*/
|
|
88
|
+
export function stopNetwork(this: RemoteDebugger): void {
|
|
89
|
+
this.log.debug('Stopping to listen for network events');
|
|
90
|
+
this.removeClientEventListener('NetworkEvent');
|
|
91
|
+
}
|