appium-remote-debugger 15.0.1 → 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.
@@ -144,7 +144,7 @@ export async function execute (command, override) {
144
144
  }
145
145
 
146
146
  const rpcClient = this.requireRpcClient(true);
147
- await rpcClient.waitForPageInitialization(
147
+ await rpcClient.waitForPage(
148
148
  /** @type {import('../types').AppIdKey} */ (appIdKey),
149
149
  /** @type {import('../types').PageIdKey} */ (pageIdKey)
150
150
  );
@@ -182,7 +182,7 @@ export async function navToUrl (url) {
182
182
 
183
183
  this.log.debug(`Navigating to new URL: '${url}'`);
184
184
  setNavigatingToPage(this, true);
185
- await rpcClient.waitForPageInitialization(
185
+ await rpcClient.waitForPage(
186
186
  /** @type {import('../types').AppIdKey} */ (appIdKey),
187
187
  /** @type {import('../types').PageIdKey} */ (pageIdKey)
188
188
  );
@@ -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
 
@@ -24,6 +24,7 @@ const NO_TARGET_PRESENT_YET_ERRORS = [
24
24
  ];
25
25
  export const NEW_APP_CONNECTED_ERROR = 'New application has connected';
26
26
  export const EMPTY_PAGE_DICTIONARY_ERROR = 'Empty page dictionary received';
27
+ const ON_PAGE_INITIALIZED_EVENT = 'onPageInitialized';
27
28
 
28
29
 
29
30
  export class RpcClient {
@@ -129,6 +130,8 @@ export class RpcClient {
129
130
  this._targets = {};
130
131
  this._targetSubscriptions = new EventEmitter();
131
132
  this._provisionedPages = new Set();
133
+ this._pageSelectionLock = new AsyncLock();
134
+ this._pageSelectionMonitor = new EventEmitter();
132
135
 
133
136
  this.remoteMessages = new RemoteMessages();
134
137
 
@@ -568,6 +571,11 @@ export class RpcClient {
568
571
  });
569
572
  } catch (e) {
570
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);
571
579
  }
572
580
  }
573
581
 
@@ -668,29 +676,69 @@ export class RpcClient {
668
676
  * @returns {Promise<void>}
669
677
  */
670
678
  async selectPage (appIdKey, pageIdKey, pageReadinessDetector) {
671
- this._pendingTargetNotification = [appIdKey, pageIdKey, pageReadinessDetector];
672
- this._provisionedPages.clear();
679
+ await this._pageSelectionLock.acquire(toPageSelectionKey(appIdKey, pageIdKey), async () => {
680
+ this._pendingTargetNotification = [appIdKey, pageIdKey, pageReadinessDetector];
681
+ this._provisionedPages.clear();
673
682
 
674
- // go through the steps that the Desktop Safari system
675
- // goes through to initialize the Web Inspector session
683
+ // go through the steps that the Desktop Safari system
684
+ // goes through to initialize the Web Inspector session
676
685
 
677
- const sendOpts = {
678
- appIdKey,
679
- pageIdKey,
680
- };
686
+ const sendOpts = {
687
+ appIdKey,
688
+ pageIdKey,
689
+ };
681
690
 
682
- // highlight and then un-highlight the webview
683
- for (const enabled of [true, false]) {
684
- await this.send('indicateWebView', Object.assign({
685
- enabled,
686
- }, sendOpts), false);
687
- }
691
+ const timeoutMs = Math.trunc(Math.max(this.pageLoadTimeoutMs ?? 0, PAGE_INIT_TIMEOUT_MS) * 1.2);
692
+ const timer = new timing.Timer().start();
693
+
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`);
688
705
 
689
- await this.send('setSenderKey', sendOpts);
690
- log.debug('Sender key set');
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
+ };
691
738
 
692
- await this.waitForTarget(appIdKey, pageIdKey);
693
- await this.waitForPageInitialization(appIdKey, pageIdKey);
739
+ this._pageSelectionMonitor.on(ON_PAGE_INITIALIZED_EVENT, onPageInitialized);
740
+ });
741
+ });
694
742
  }
695
743
 
696
744
  /**
@@ -986,15 +1034,19 @@ export class RpcClient {
986
1034
  *
987
1035
  * @param {import('../types').AppIdKey} appIdKey
988
1036
  * @param {import('../types').PageIdKey} pageIdKey
1037
+ * @returns {Promise<void>}
989
1038
  */
990
- async waitForPageInitialization (appIdKey, pageIdKey) {
1039
+ async waitForPage (appIdKey, pageIdKey) {
991
1040
  const appTargetsMap = this.targets[appIdKey];
992
1041
  if (!appTargetsMap) {
993
1042
  throw new Error(`No targets found for app '${appIdKey}'`);
994
1043
  }
995
1044
  const lock = appTargetsMap.lock;
996
1045
  const timer = new timing.Timer().start();
997
- await lock.acquire(pageIdKey, async () => await B.delay(0));
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
+ ]);
998
1050
  const durationMs = timer.getDuration().asMilliSeconds;
999
1051
  if (durationMs > 10) {
1000
1052
  log.debug(`Waited ${durationMs}ms until the page ${pageIdKey}@${appIdKey} is initialized`);
@@ -1002,6 +1054,16 @@ export class RpcClient {
1002
1054
  }
1003
1055
  }
1004
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
+
1005
1067
  export default RpcClient;
1006
1068
 
1007
1069
  /**
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
- /** for web inspector, whether this is a new Safari instance */
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/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "appium"
6
6
  ],
7
- "version": "15.0.1",
7
+ "version": "15.0.2",
8
8
  "author": "Appium Contributors",
9
9
  "license": "Apache-2.0",
10
10
  "repository": {