appium-remote-debugger 15.0.0 → 15.0.2
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.js +5 -4
- package/build/lib/mixins/connect.js.map +1 -1
- package/build/lib/mixins/events.js +1 -2
- package/build/lib/mixins/events.js.map +1 -1
- package/build/lib/mixins/execute.js +4 -4
- package/build/lib/mixins/execute.js.map +1 -1
- package/build/lib/mixins/navigate.d.ts.map +1 -1
- package/build/lib/mixins/navigate.js +13 -12
- package/build/lib/mixins/navigate.js.map +1 -1
- package/build/lib/remote-debugger-real-device.js +1 -0
- package/build/lib/remote-debugger-real-device.js.map +1 -1
- package/build/lib/remote-debugger.d.ts +0 -1
- package/build/lib/remote-debugger.d.ts.map +1 -1
- package/build/lib/remote-debugger.js +75 -42
- package/build/lib/remote-debugger.js.map +1 -1
- package/build/lib/rpc/rpc-client-simulator.js +10 -0
- package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
- package/build/lib/rpc/rpc-client.d.ts +22 -4
- package/build/lib/rpc/rpc-client.d.ts.map +1 -1
- package/build/lib/rpc/rpc-client.js +191 -25
- package/build/lib/rpc/rpc-client.js.map +1 -1
- package/build/lib/types.d.ts +1 -1
- package/build/lib/types.d.ts.map +1 -1
- package/build/lib/utils.d.ts +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +2 -2
- package/build/lib/utils.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/mixins/connect.js +5 -5
- package/lib/mixins/execute.js +5 -5
- package/lib/mixins/navigate.js +13 -14
- package/lib/remote-debugger.ts +0 -4
- package/lib/rpc/rpc-client.js +181 -26
- package/lib/types.ts +1 -1
- package/lib/utils.js +1 -1
- package/package.json +1 -1
package/lib/mixins/connect.js
CHANGED
|
@@ -173,11 +173,11 @@ export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
|
|
|
173
173
|
|
|
174
174
|
const timer = new timing.Timer().start();
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
const pageReadinessDetector = skipReadyCheck ? undefined : {
|
|
177
|
+
timeoutMs: this.pageLoadMs,
|
|
178
|
+
readinessDetector: (/** @type {string} */ readyState) => this.isPageLoadingCompleted(readyState),
|
|
179
|
+
};
|
|
180
|
+
await this.requireRpcClient().selectPage(fullAppIdKey, pageIdKey, pageReadinessDetector);
|
|
181
181
|
|
|
182
182
|
this.log.debug(`Selected page after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
183
183
|
}
|
package/lib/mixins/execute.js
CHANGED
|
@@ -2,7 +2,7 @@ import { errors } from '@appium/base-driver';
|
|
|
2
2
|
import {
|
|
3
3
|
checkParams,
|
|
4
4
|
simpleStringify,
|
|
5
|
-
|
|
5
|
+
convertJavascriptEvaluationResult,
|
|
6
6
|
RESPONSE_LOG_LENGTH,
|
|
7
7
|
} from '../utils';
|
|
8
8
|
import { getScriptForAtom } from '../atoms';
|
|
@@ -123,7 +123,7 @@ export async function executeAtomAsync (atom, args = [], frames = []) {
|
|
|
123
123
|
);
|
|
124
124
|
} catch {}
|
|
125
125
|
}
|
|
126
|
-
return
|
|
126
|
+
return convertJavascriptEvaluationResult(res);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -144,7 +144,7 @@ export async function execute (command, override) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const rpcClient = this.requireRpcClient(true);
|
|
147
|
-
await rpcClient.
|
|
147
|
+
await rpcClient.waitForPage(
|
|
148
148
|
/** @type {import('../types').AppIdKey} */ (appIdKey),
|
|
149
149
|
/** @type {import('../types').PageIdKey} */ (pageIdKey)
|
|
150
150
|
);
|
|
@@ -155,7 +155,7 @@ export async function execute (command, override) {
|
|
|
155
155
|
appIdKey,
|
|
156
156
|
pageIdKey,
|
|
157
157
|
});
|
|
158
|
-
return
|
|
158
|
+
return convertJavascriptEvaluationResult(res);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/**
|
|
@@ -184,7 +184,7 @@ export async function callFunction (objectId, fn, args) {
|
|
|
184
184
|
pageIdKey,
|
|
185
185
|
});
|
|
186
186
|
|
|
187
|
-
return
|
|
187
|
+
return convertJavascriptEvaluationResult(res);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
package/lib/mixins/navigate.js
CHANGED
|
@@ -20,11 +20,11 @@ const PAGE_READINESS_CHECK_INTERVAL_MS = 50;
|
|
|
20
20
|
/**
|
|
21
21
|
* pageLoadStrategy in WebDriver definitions.
|
|
22
22
|
*/
|
|
23
|
-
const PAGE_LOAD_STRATEGY = {
|
|
23
|
+
const PAGE_LOAD_STRATEGY = Object.freeze({
|
|
24
24
|
EAGER: 'eager',
|
|
25
25
|
NONE: 'none',
|
|
26
26
|
NORMAL: 'normal'
|
|
27
|
-
};
|
|
27
|
+
});
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* @this {RemoteDebugger}
|
|
@@ -53,18 +53,17 @@ export function cancelPageLoad () {
|
|
|
53
53
|
* @returns {boolean}
|
|
54
54
|
*/
|
|
55
55
|
export function isPageLoadingCompleted (readyState) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
const pageLoadStrategy = _.toLower(getPageLoadStartegy(this));
|
|
57
|
+
switch (pageLoadStrategy) {
|
|
58
|
+
case PAGE_LOAD_STRATEGY.EAGER:
|
|
59
|
+
// This could include 'interactive' or 'complete'
|
|
60
|
+
return readyState !== 'loading';
|
|
61
|
+
case PAGE_LOAD_STRATEGY.NONE:
|
|
62
|
+
return true;
|
|
63
|
+
case PAGE_LOAD_STRATEGY.NORMAL:
|
|
64
|
+
default:
|
|
65
|
+
return readyState === 'complete';
|
|
59
66
|
}
|
|
60
|
-
|
|
61
|
-
if (_pageLoadStrategy === PAGE_LOAD_STRATEGY.EAGER) {
|
|
62
|
-
// This could include 'interactive' or 'complete'
|
|
63
|
-
return readyState !== 'loading';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Default behavior. It includes pageLoadStrategy is 'normal' as well.
|
|
67
|
-
return readyState === 'complete';
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
/**
|
|
@@ -183,7 +182,7 @@ export async function navToUrl (url) {
|
|
|
183
182
|
|
|
184
183
|
this.log.debug(`Navigating to new URL: '${url}'`);
|
|
185
184
|
setNavigatingToPage(this, true);
|
|
186
|
-
await rpcClient.
|
|
185
|
+
await rpcClient.waitForPage(
|
|
187
186
|
/** @type {import('../types').AppIdKey} */ (appIdKey),
|
|
188
187
|
/** @type {import('../types').PageIdKey} */ (pageIdKey)
|
|
189
188
|
);
|
package/lib/remote-debugger.ts
CHANGED
|
@@ -49,7 +49,6 @@ export class RemoteDebugger extends EventEmitter {
|
|
|
49
49
|
protected readonly _platformVersion?: string;
|
|
50
50
|
protected readonly _isSafari: boolean;
|
|
51
51
|
protected readonly _includeSafari: boolean;
|
|
52
|
-
protected readonly _useNewSafari: boolean;
|
|
53
52
|
protected readonly _garbageCollectOnExecute: boolean;
|
|
54
53
|
protected readonly _host?: string;
|
|
55
54
|
protected readonly _port?: number;
|
|
@@ -120,7 +119,6 @@ export class RemoteDebugger extends EventEmitter {
|
|
|
120
119
|
platformVersion,
|
|
121
120
|
isSafari = true,
|
|
122
121
|
includeSafari = false,
|
|
123
|
-
useNewSafari = false,
|
|
124
122
|
pageLoadMs,
|
|
125
123
|
host,
|
|
126
124
|
port = REMOTE_DEBUGGER_PORT,
|
|
@@ -142,10 +140,8 @@ export class RemoteDebugger extends EventEmitter {
|
|
|
142
140
|
this._platformVersion = platformVersion;
|
|
143
141
|
this._isSafari = isSafari;
|
|
144
142
|
this._includeSafari = includeSafari;
|
|
145
|
-
this._useNewSafari = useNewSafari;
|
|
146
143
|
this._pageLoadMs = pageLoadMs;
|
|
147
144
|
this._allowNavigationWithoutReload = false;
|
|
148
|
-
this.log.debug(`useNewSafari --> ${this._useNewSafari}`);
|
|
149
145
|
|
|
150
146
|
this._garbageCollectOnExecute = garbageCollectOnExecute;
|
|
151
147
|
|
package/lib/rpc/rpc-client.js
CHANGED
|
@@ -7,6 +7,7 @@ import RpcMessageHandler from './rpc-message-handler';
|
|
|
7
7
|
import { util, timing } from '@appium/support';
|
|
8
8
|
import { EventEmitter } from 'node:events';
|
|
9
9
|
import AsyncLock from 'async-lock';
|
|
10
|
+
import { convertJavascriptEvaluationResult } from '../utils';
|
|
10
11
|
|
|
11
12
|
const DATA_LOG_LENGTH = {length: 200};
|
|
12
13
|
const MIN_WAIT_FOR_TARGET_TIMEOUT_MS = 30000;
|
|
@@ -23,6 +24,7 @@ const NO_TARGET_PRESENT_YET_ERRORS = [
|
|
|
23
24
|
];
|
|
24
25
|
export const NEW_APP_CONNECTED_ERROR = 'New application has connected';
|
|
25
26
|
export const EMPTY_PAGE_DICTIONARY_ERROR = 'Empty page dictionary received';
|
|
27
|
+
const ON_PAGE_INITIALIZED_EVENT = 'onPageInitialized';
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
export class RpcClient {
|
|
@@ -83,7 +85,7 @@ export class RpcClient {
|
|
|
83
85
|
/** @type {EventEmitter} */
|
|
84
86
|
_targetSubscriptions;
|
|
85
87
|
|
|
86
|
-
/** @type {
|
|
88
|
+
/** @type {PendingTargetNotification | undefined} */
|
|
87
89
|
_pendingTargetNotification;
|
|
88
90
|
|
|
89
91
|
/**
|
|
@@ -128,6 +130,8 @@ export class RpcClient {
|
|
|
128
130
|
this._targets = {};
|
|
129
131
|
this._targetSubscriptions = new EventEmitter();
|
|
130
132
|
this._provisionedPages = new Set();
|
|
133
|
+
this._pageSelectionLock = new AsyncLock();
|
|
134
|
+
this._pageSelectionMonitor = new EventEmitter();
|
|
131
135
|
|
|
132
136
|
this.remoteMessages = new RemoteMessages();
|
|
133
137
|
|
|
@@ -454,7 +458,7 @@ export class RpcClient {
|
|
|
454
458
|
return;
|
|
455
459
|
}
|
|
456
460
|
|
|
457
|
-
const [appIdKey, pageIdKey] = this._pendingTargetNotification;
|
|
461
|
+
const [appIdKey, pageIdKey, pageReadinessDetector] = this._pendingTargetNotification;
|
|
458
462
|
if (appIdKey !== app) {
|
|
459
463
|
log.info(
|
|
460
464
|
`Received 'Target.targetCreated' event for app '${app}' with no pending request: ${JSON.stringify(targetInfo)}`
|
|
@@ -470,6 +474,24 @@ export class RpcClient {
|
|
|
470
474
|
}
|
|
471
475
|
const timer = new timing.Timer().start();
|
|
472
476
|
|
|
477
|
+
const adjustPageReadinessDetector = () => {
|
|
478
|
+
if (!pageReadinessDetector) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const elapsedMs = timer.getDuration().asMilliSeconds;
|
|
483
|
+
if (elapsedMs >= pageReadinessDetector.timeoutMs) {
|
|
484
|
+
log.warn(
|
|
485
|
+
`Page '${pageIdKey}' took too long to initialize, skipping readiness check`
|
|
486
|
+
);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
timeoutMs: pageReadinessDetector.timeoutMs - elapsedMs,
|
|
491
|
+
readinessDetector: pageReadinessDetector.readinessDetector,
|
|
492
|
+
};
|
|
493
|
+
};
|
|
494
|
+
|
|
473
495
|
if (targetInfo.isProvisional) {
|
|
474
496
|
log.debug(
|
|
475
497
|
`Provisional target created for app '${appIdKey}' and page '${pageIdKey}': '${JSON.stringify(targetInfo)}'`
|
|
@@ -478,8 +500,9 @@ export class RpcClient {
|
|
|
478
500
|
this._provisionedPages.add(pageIdKey);
|
|
479
501
|
try {
|
|
480
502
|
await this.targets[appIdKey].lock.acquire(pageIdKey, async () => {
|
|
503
|
+
let wasInitialized = false;
|
|
481
504
|
try {
|
|
482
|
-
await this._initializePage(appIdKey, pageIdKey, targetInfo.targetId);
|
|
505
|
+
wasInitialized = await this._initializePage(appIdKey, pageIdKey, targetInfo.targetId);
|
|
483
506
|
} finally {
|
|
484
507
|
if (targetInfo.isPaused) {
|
|
485
508
|
await this._resumeTarget(appIdKey, pageIdKey, targetInfo.targetId);
|
|
@@ -489,6 +512,11 @@ export class RpcClient {
|
|
|
489
512
|
);
|
|
490
513
|
}
|
|
491
514
|
}
|
|
515
|
+
if (wasInitialized) {
|
|
516
|
+
await this._waitForPageReadiness(
|
|
517
|
+
appIdKey, pageIdKey, targetInfo.targetId, adjustPageReadinessDetector()
|
|
518
|
+
);
|
|
519
|
+
}
|
|
492
520
|
});
|
|
493
521
|
} catch (e) {
|
|
494
522
|
log.warn(
|
|
@@ -522,21 +550,32 @@ export class RpcClient {
|
|
|
522
550
|
|
|
523
551
|
try {
|
|
524
552
|
await this.targets[appIdKey].lock.acquire(pageIdKey, async () => {
|
|
553
|
+
let wasInitialized = false;
|
|
525
554
|
try {
|
|
526
555
|
if (this._provisionedPages.has(pageIdKey)) {
|
|
527
556
|
log.debug(`Page '${pageIdKey}' has been already provisioned`);
|
|
528
557
|
this._provisionedPages.delete(pageIdKey);
|
|
529
558
|
} else {
|
|
530
|
-
await this._initializePage(appIdKey, pageIdKey);
|
|
559
|
+
wasInitialized = await this._initializePage(appIdKey, pageIdKey);
|
|
531
560
|
}
|
|
532
561
|
} finally {
|
|
533
562
|
if (targetInfo.isPaused) {
|
|
534
563
|
await this._resumeTarget(appIdKey, pageIdKey, targetInfo.targetId);
|
|
535
564
|
}
|
|
536
565
|
}
|
|
566
|
+
if (wasInitialized) {
|
|
567
|
+
await this._waitForPageReadiness(
|
|
568
|
+
appIdKey, pageIdKey, targetInfo.targetId, adjustPageReadinessDetector()
|
|
569
|
+
);
|
|
570
|
+
}
|
|
537
571
|
});
|
|
538
572
|
} catch (e) {
|
|
539
573
|
log.warn(e.message);
|
|
574
|
+
} finally {
|
|
575
|
+
// Target creation is happening after provisioning,
|
|
576
|
+
// which means the above lock would be already released
|
|
577
|
+
// after provisioning is completed.
|
|
578
|
+
this._pageSelectionMonitor.emit(ON_PAGE_INITIALIZED_EVENT, appIdKey, pageIdKey);
|
|
540
579
|
}
|
|
541
580
|
}
|
|
542
581
|
|
|
@@ -633,32 +672,73 @@ export class RpcClient {
|
|
|
633
672
|
/**
|
|
634
673
|
* @param {import('../types').AppIdKey} appIdKey
|
|
635
674
|
* @param {import('../types').PageIdKey} pageIdKey
|
|
675
|
+
* @param {PageReadinessDetector} [pageReadinessDetector]
|
|
636
676
|
* @returns {Promise<void>}
|
|
637
677
|
*/
|
|
638
|
-
async selectPage (appIdKey, pageIdKey) {
|
|
639
|
-
this.
|
|
640
|
-
|
|
678
|
+
async selectPage (appIdKey, pageIdKey, pageReadinessDetector) {
|
|
679
|
+
await this._pageSelectionLock.acquire(toPageSelectionKey(appIdKey, pageIdKey), async () => {
|
|
680
|
+
this._pendingTargetNotification = [appIdKey, pageIdKey, pageReadinessDetector];
|
|
681
|
+
this._provisionedPages.clear();
|
|
641
682
|
|
|
642
|
-
|
|
643
|
-
|
|
683
|
+
// go through the steps that the Desktop Safari system
|
|
684
|
+
// goes through to initialize the Web Inspector session
|
|
644
685
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
686
|
+
const sendOpts = {
|
|
687
|
+
appIdKey,
|
|
688
|
+
pageIdKey,
|
|
689
|
+
};
|
|
649
690
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
await this.send('indicateWebView', Object.assign({
|
|
653
|
-
enabled,
|
|
654
|
-
}, sendOpts), false);
|
|
655
|
-
}
|
|
691
|
+
const timeoutMs = Math.trunc(Math.max(this.pageLoadTimeoutMs ?? 0, PAGE_INIT_TIMEOUT_MS) * 1.2);
|
|
692
|
+
const timer = new timing.Timer().start();
|
|
656
693
|
|
|
657
|
-
|
|
658
|
-
|
|
694
|
+
const setupWebview = async () => {
|
|
695
|
+
// highlight and then un-highlight the webview
|
|
696
|
+
for (const enabled of [true, false]) {
|
|
697
|
+
await this.send('indicateWebView', Object.assign({
|
|
698
|
+
enabled,
|
|
699
|
+
}, sendOpts), false);
|
|
700
|
+
}
|
|
701
|
+
await this.send('setSenderKey', sendOpts);
|
|
702
|
+
};
|
|
703
|
+
await B.resolve(setupWebview())
|
|
704
|
+
.timeout(timeoutMs, `Cannot set up page '${pageIdKey}' for app '${appIdKey}' within ${timeoutMs}ms`);
|
|
659
705
|
|
|
660
|
-
|
|
661
|
-
|
|
706
|
+
const msLeft = Math.max(timeoutMs - Math.trunc(timer.getDuration().asMilliSeconds), 1000);
|
|
707
|
+
log.debug(
|
|
708
|
+
`Waiting up to ${msLeft}ms for page '${pageIdKey}' of app '${appIdKey}' to be selected`
|
|
709
|
+
);
|
|
710
|
+
await new Promise((resolve) => {
|
|
711
|
+
const onPageInitialized = (
|
|
712
|
+
/** @type {import("../types").AppIdKey} */ notifiedAppIdKey,
|
|
713
|
+
/** @type {import("../types").PageIdKey} */ notifiedPageIdKey
|
|
714
|
+
) => {
|
|
715
|
+
const timeoutHandler = setTimeout(() => {
|
|
716
|
+
this._pageSelectionMonitor.off(ON_PAGE_INITIALIZED_EVENT, onPageInitialized);
|
|
717
|
+
log.warn(
|
|
718
|
+
`Page '${pageIdKey}' for app '${appIdKey}' has not been selected ` +
|
|
719
|
+
`within ${timer.getDuration().asMilliSeconds}ms. Continuing anyway`
|
|
720
|
+
);
|
|
721
|
+
resolve(false);
|
|
722
|
+
}, msLeft);
|
|
723
|
+
|
|
724
|
+
if (notifiedAppIdKey === appIdKey && notifiedPageIdKey === pageIdKey) {
|
|
725
|
+
clearTimeout(timeoutHandler);
|
|
726
|
+
this._pageSelectionMonitor.off(ON_PAGE_INITIALIZED_EVENT, onPageInitialized);
|
|
727
|
+
log.debug(
|
|
728
|
+
`Selected the page ${pageIdKey}@${appIdKey} after ${timer.getDuration().asMilliSeconds}ms`
|
|
729
|
+
);
|
|
730
|
+
resolve(true);
|
|
731
|
+
} else {
|
|
732
|
+
log.debug(
|
|
733
|
+
`Got notified that page ${notifiedPageIdKey}@${notifiedAppIdKey} is initialized, ` +
|
|
734
|
+
`but we are waiting for ${pageIdKey}@${appIdKey}. Continuing to wait`
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
this._pageSelectionMonitor.on(ON_PAGE_INITIALIZED_EVENT, onPageInitialized);
|
|
740
|
+
});
|
|
741
|
+
});
|
|
662
742
|
}
|
|
663
743
|
|
|
664
744
|
/**
|
|
@@ -904,15 +984,69 @@ export class RpcClient {
|
|
|
904
984
|
*
|
|
905
985
|
* @param {import('../types').AppIdKey} appIdKey
|
|
906
986
|
* @param {import('../types').PageIdKey} pageIdKey
|
|
987
|
+
* @param {import('../types').TargetId} targetId
|
|
988
|
+
* @param {PageReadinessDetector} [pageReadinessDetector]
|
|
989
|
+
* @returns {Promise<void>}
|
|
907
990
|
*/
|
|
908
|
-
async
|
|
991
|
+
async _waitForPageReadiness(appIdKey, pageIdKey, targetId, pageReadinessDetector) {
|
|
992
|
+
if (!pageReadinessDetector) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
log.debug(`Waiting up to ${pageReadinessDetector.timeoutMs}ms for page readiness`);
|
|
997
|
+
const timer = new timing.Timer().start();
|
|
998
|
+
while (pageReadinessDetector.timeoutMs - timer.getDuration().asMilliSeconds > 0) {
|
|
999
|
+
/** @type {string} */
|
|
1000
|
+
let readyState;
|
|
1001
|
+
try {
|
|
1002
|
+
const commandTimeoutMs = Math.max(
|
|
1003
|
+
100,
|
|
1004
|
+
Math.trunc((pageReadinessDetector.timeoutMs - timer.getDuration().asMilliSeconds) * 0.8)
|
|
1005
|
+
);
|
|
1006
|
+
const rawResult = await B.resolve(this.send('Runtime.evaluate', {
|
|
1007
|
+
expression: 'document.readyState;',
|
|
1008
|
+
returnByValue: true,
|
|
1009
|
+
appIdKey,
|
|
1010
|
+
pageIdKey,
|
|
1011
|
+
targetId,
|
|
1012
|
+
})).timeout(commandTimeoutMs);
|
|
1013
|
+
readyState = convertJavascriptEvaluationResult(rawResult);
|
|
1014
|
+
} catch (e) {
|
|
1015
|
+
log.debug(`Cannot determine page readiness: ${e.message}`);
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
if (pageReadinessDetector.readinessDetector(readyState)) {
|
|
1019
|
+
log.info(
|
|
1020
|
+
`Page '${pageIdKey}' for app '${appIdKey}' is ready after ` +
|
|
1021
|
+
`${timer.getDuration().asMilliSeconds}ms`
|
|
1022
|
+
);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
await B.delay(100);
|
|
1026
|
+
}
|
|
1027
|
+
log.warn(
|
|
1028
|
+
`Page '${pageIdKey}' for app '${appIdKey}' is not ready after ` +
|
|
1029
|
+
`${timer.getDuration().asMilliSeconds}ms. Continuing anyway`
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
*
|
|
1035
|
+
* @param {import('../types').AppIdKey} appIdKey
|
|
1036
|
+
* @param {import('../types').PageIdKey} pageIdKey
|
|
1037
|
+
* @returns {Promise<void>}
|
|
1038
|
+
*/
|
|
1039
|
+
async waitForPage (appIdKey, pageIdKey) {
|
|
909
1040
|
const appTargetsMap = this.targets[appIdKey];
|
|
910
1041
|
if (!appTargetsMap) {
|
|
911
1042
|
throw new Error(`No targets found for app '${appIdKey}'`);
|
|
912
1043
|
}
|
|
913
1044
|
const lock = appTargetsMap.lock;
|
|
914
1045
|
const timer = new timing.Timer().start();
|
|
915
|
-
await
|
|
1046
|
+
await Promise.all([
|
|
1047
|
+
lock.acquire(pageIdKey, async () => await B.delay(0)),
|
|
1048
|
+
this._pageSelectionLock.acquire(toPageSelectionKey(appIdKey, pageIdKey), async () => await B.delay(0))
|
|
1049
|
+
]);
|
|
916
1050
|
const durationMs = timer.getDuration().asMilliSeconds;
|
|
917
1051
|
if (durationMs > 10) {
|
|
918
1052
|
log.debug(`Waited ${durationMs}ms until the page ${pageIdKey}@${appIdKey} is initialized`);
|
|
@@ -920,6 +1054,16 @@ export class RpcClient {
|
|
|
920
1054
|
}
|
|
921
1055
|
}
|
|
922
1056
|
|
|
1057
|
+
/**
|
|
1058
|
+
*
|
|
1059
|
+
* @param {import('../types').AppIdKey} appIdKey
|
|
1060
|
+
* @param {import('../types').PageIdKey} pageIdKey
|
|
1061
|
+
* @returns {string}
|
|
1062
|
+
*/
|
|
1063
|
+
function toPageSelectionKey(appIdKey, pageIdKey) {
|
|
1064
|
+
return `${appIdKey}:${pageIdKey}`;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
923
1067
|
export default RpcClient;
|
|
924
1068
|
|
|
925
1069
|
/**
|
|
@@ -943,4 +1087,15 @@ export default RpcClient;
|
|
|
943
1087
|
/**
|
|
944
1088
|
* @typedef {PageDict & {provisional?: import('../types').ProvisionalTargetInfo, lock: AsyncLock}} PagesToTargets
|
|
945
1089
|
* @typedef {{[key: import('../types').AppIdKey]: PagesToTargets}} AppToTargetsMap
|
|
946
|
-
*/
|
|
1090
|
+
*/
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* @typedef {Object} PageReadinessDetector
|
|
1094
|
+
* @property {number} timeoutMs
|
|
1095
|
+
* @property {(readyState: string) => boolean} readinessDetector
|
|
1096
|
+
*/
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* @typedef {[import('../types').AppIdKey, import('../types').PageIdKey, PageReadinessDetector | undefined]} PendingTargetNotification
|
|
1100
|
+
*/
|
|
1101
|
+
|
package/lib/types.ts
CHANGED
|
@@ -49,7 +49,7 @@ export interface RemoteDebuggerOptions {
|
|
|
49
49
|
platformVersion?: string;
|
|
50
50
|
isSafari?: boolean;
|
|
51
51
|
includeSafari?: boolean;
|
|
52
|
-
/**
|
|
52
|
+
/** @deprecated - deprecated for removal, not used anywhere */
|
|
53
53
|
useNewSafari?: boolean;
|
|
54
54
|
/** the time, in ms, that should be waited for page loading */
|
|
55
55
|
pageLoadMs?: number;
|
package/lib/utils.js
CHANGED
|
@@ -157,7 +157,7 @@ export function deferredPromise () {
|
|
|
157
157
|
* @param {any} res
|
|
158
158
|
* @returns {any}
|
|
159
159
|
*/
|
|
160
|
-
export function
|
|
160
|
+
export function convertJavascriptEvaluationResult (res) {
|
|
161
161
|
if (_.isUndefined(res)) {
|
|
162
162
|
throw new Error(`Did not get OK result from remote debugger. Result was: ${_.truncate(simpleStringify(res), {length: RESPONSE_LOG_LENGTH})}`);
|
|
163
163
|
} else if (_.isString(res)) {
|