webdriverio 9.6.3 → 9.7.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/build/index.js CHANGED
@@ -23,7 +23,7 @@ var __privateWrapper = (obj, member, setter, getter) => ({
23
23
  });
24
24
 
25
25
  // src/index.ts
26
- import logger24 from "@wdio/logger";
26
+ import logger27 from "@wdio/logger";
27
27
  import WebDriver, { DEFAULTS } from "webdriver";
28
28
  import { validateConfig } from "@wdio/config";
29
29
  import { enableFileLogging, wrapCommand as wrapCommand3 } from "@wdio/utils";
@@ -97,7 +97,7 @@ async function refetchElement(currentElement, commandName) {
97
97
  import cssValue from "css-value";
98
98
  import rgb2hex from "rgb2hex";
99
99
  import GraphemeSplitter from "grapheme-splitter";
100
- import logger23 from "@wdio/logger";
100
+ import logger26 from "@wdio/logger";
101
101
  import isPlainObject from "is-plain-obj";
102
102
  import { ELEMENT_KEY as ELEMENT_KEY18 } from "webdriver";
103
103
  import { UNICODE_CHARACTERS as UNICODE_CHARACTERS2, asyncIterators, getBrowserObject as getBrowserObject34 } from "@wdio/utils";
@@ -120,6 +120,8 @@ __export(browser_exports, {
120
120
  emulate: () => emulate,
121
121
  execute: () => execute,
122
122
  executeAsync: () => executeAsync,
123
+ getContext: () => getContext,
124
+ getContexts: () => getContexts,
123
125
  getCookies: () => getCookies,
124
126
  getPuppeteer: () => getPuppeteer,
125
127
  getWindowSize: () => getWindowSize,
@@ -142,6 +144,7 @@ __export(browser_exports, {
142
144
  setViewport: () => setViewport,
143
145
  setWindowSize: () => setWindowSize,
144
146
  swipe: () => swipe,
147
+ switchContext: () => switchContext,
145
148
  switchFrame: () => switchFrame,
146
149
  switchWindow: () => switchWindow,
147
150
  tap: () => tap,
@@ -3134,7 +3137,7 @@ var _ContextManager = class _ContextManager extends SessionManager {
3134
3137
  isNativeContext: __privateGet(this, _isNativeContext)
3135
3138
  }));
3136
3139
  __privateGet(this, _browser3).on("result", __privateMethod(this, _ContextManager_instances, onCommandResultBidiAndClassic_fn).bind(this));
3137
- if (!this.isEnabled()) {
3140
+ if (!this.isEnabled() && !__privateGet(this, _browser3).isMobile) {
3138
3141
  return;
3139
3142
  }
3140
3143
  __privateGet(this, _browser3).on("command", __privateMethod(this, _ContextManager_instances, onCommand_fn2).bind(this));
@@ -3288,15 +3291,15 @@ onCommand_fn2 = function(event) {
3288
3291
  if (COMMANDS_REQUIRING_RESET.includes(event.command)) {
3289
3292
  __privateSet(this, _currentContext, void 0);
3290
3293
  }
3291
- if (__privateGet(this, _browser3).isMobile && event.command === "switchContext") {
3294
+ if (__privateGet(this, _browser3).isMobile && event.command === "switchAppiumContext") {
3292
3295
  __privateSet(this, _mobileContext, event.body.name);
3293
3296
  }
3294
3297
  };
3295
3298
  onCommandResultMobile_fn = function(event) {
3296
- if (event.command === "getContext") {
3299
+ if (event.command === "getAppiumContext") {
3297
3300
  this.setCurrentContext(event.result.value);
3298
3301
  }
3299
- if (event.command === "switchContext" && event.result.value === null && __privateGet(this, _mobileContext)) {
3302
+ if (event.command === "switchAppiumContext" && event.result.value === null && __privateGet(this, _mobileContext)) {
3300
3303
  this.setCurrentContext(__privateGet(this, _mobileContext));
3301
3304
  }
3302
3305
  };
@@ -4692,16 +4695,16 @@ _initialize3 = new WeakMap();
4692
4695
  _requests = new WeakMap();
4693
4696
  _lastNetworkId = new WeakMap();
4694
4697
  _NetworkManager_instances = new WeakSet();
4695
- beforeRequestSent_fn = function(log24) {
4698
+ beforeRequestSent_fn = function(log27) {
4696
4699
  var _a;
4697
- if (log24.navigation) {
4700
+ if (log27.navigation) {
4698
4701
  return;
4699
4702
  }
4700
- const request = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log24.navigation);
4703
+ const request = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log27.navigation);
4701
4704
  if (!request) {
4702
4705
  return;
4703
4706
  }
4704
- const { request: id, headers, cookies, url: url2 } = log24.request;
4707
+ const { request: id, headers, cookies, url: url2 } = log27.request;
4705
4708
  (_a = request.children) == null ? void 0 : _a.push({
4706
4709
  id,
4707
4710
  url: url2,
@@ -4717,52 +4720,52 @@ beforeRequestSent_fn = function(log24) {
4717
4720
  sameSite: cookie.sameSite,
4718
4721
  expiry: cookie.expiry
4719
4722
  })),
4720
- timestamp: log24.timestamp
4723
+ timestamp: log27.timestamp
4721
4724
  });
4722
4725
  };
4723
- navigationStarted_fn = function(log24) {
4726
+ navigationStarted_fn = function(log27) {
4724
4727
  if (
4725
4728
  /**
4726
4729
  * we need a navigation id to identify the request
4727
4730
  */
4728
- !log24.navigation || /**
4731
+ !log27.navigation || /**
4729
4732
  * ignore urls that users wouldn't navigate to
4730
4733
  */
4731
- !SUPPORTED_NAVIGATION_PROTOCOLS.some((protocol) => log24.url.startsWith(protocol))
4734
+ !SUPPORTED_NAVIGATION_PROTOCOLS.some((protocol) => log27.url.startsWith(protocol))
4732
4735
  ) {
4733
- if (log24.navigation === null && log24.url === "") {
4736
+ if (log27.navigation === null && log27.url === "") {
4734
4737
  __privateSet(this, _lastNetworkId, UNKNOWN_NAVIGATION_ID);
4735
4738
  return __privateGet(this, _requests).set(UNKNOWN_NAVIGATION_ID, {
4736
4739
  url: "",
4737
4740
  headers: {},
4738
- timestamp: log24.timestamp,
4741
+ timestamp: log27.timestamp,
4739
4742
  redirectChain: [],
4740
4743
  children: []
4741
4744
  });
4742
4745
  }
4743
4746
  return;
4744
4747
  }
4745
- __privateSet(this, _lastNetworkId, log24.navigation);
4746
- __privateGet(this, _requests).set(log24.navigation, {
4747
- url: log24.url,
4748
+ __privateSet(this, _lastNetworkId, log27.navigation);
4749
+ __privateGet(this, _requests).set(log27.navigation, {
4750
+ url: log27.url,
4748
4751
  headers: {},
4749
- timestamp: log24.timestamp,
4750
- navigation: log24.navigation,
4752
+ timestamp: log27.timestamp,
4753
+ navigation: log27.navigation,
4751
4754
  redirectChain: [],
4752
4755
  children: []
4753
4756
  });
4754
4757
  };
4755
- fetchError_fn = function(log24) {
4758
+ fetchError_fn = function(log27) {
4756
4759
  var _a;
4757
- const response = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log24.navigation);
4760
+ const response = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log27.navigation);
4758
4761
  if (!response) {
4759
4762
  return;
4760
4763
  }
4761
- const request = (_a = response.children) == null ? void 0 : _a.find((child) => child.id === log24.request.request);
4764
+ const request = (_a = response.children) == null ? void 0 : _a.find((child) => child.id === log27.request.request);
4762
4765
  if (!request) {
4763
4766
  return;
4764
4767
  }
4765
- request.error = log24.errorText;
4768
+ request.error = log27.errorText;
4766
4769
  };
4767
4770
  findRootRequest_fn = function(navigationId) {
4768
4771
  const response = __privateGet(this, _requests).get(navigationId || UNKNOWN_NAVIGATION_ID);
@@ -4772,23 +4775,23 @@ findRootRequest_fn = function(navigationId) {
4772
4775
  const firstRequest = __privateGet(this, _requests).values().next().value;
4773
4776
  return __privateGet(this, _lastNetworkId) ? __privateGet(this, _requests).get(__privateGet(this, _lastNetworkId)) || firstRequest : firstRequest;
4774
4777
  };
4775
- responseCompleted_fn = function(log24) {
4778
+ responseCompleted_fn = function(log27) {
4776
4779
  var _a, _b, _c;
4777
- const response = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log24.navigation);
4780
+ const response = __privateMethod(this, _NetworkManager_instances, findRootRequest_fn).call(this, log27.navigation);
4778
4781
  if (!response) {
4779
4782
  return;
4780
4783
  }
4781
4784
  if (!response.navigation && response.url === "") {
4782
- response.url = log24.request.url;
4783
- response.navigation = log24.navigation;
4785
+ response.url = log27.request.url;
4786
+ response.navigation = log27.navigation;
4784
4787
  }
4785
- if (log24.navigation === response.navigation) {
4786
- if (response.url !== log24.response.url) {
4788
+ if (log27.navigation === response.navigation) {
4789
+ if (response.url !== log27.response.url) {
4787
4790
  (_a = response.redirectChain) == null ? void 0 : _a.push(response.url);
4788
4791
  }
4789
- response.url = log24.response.url;
4790
- const { headers: requestHeaders } = log24.request;
4791
- const { fromCache, headers: responseHeaders, mimeType, status } = log24.response;
4792
+ response.url = log27.response.url;
4793
+ const { headers: requestHeaders } = log27.request;
4794
+ const { fromCache, headers: responseHeaders, mimeType, status } = log27.response;
4792
4795
  response.headers = headerListToObject(requestHeaders), response.response = {
4793
4796
  fromCache,
4794
4797
  headers: headerListToObject(responseHeaders),
@@ -4797,15 +4800,15 @@ responseCompleted_fn = function(log24) {
4797
4800
  };
4798
4801
  return;
4799
4802
  }
4800
- const request = (_b = response.children) == null ? void 0 : _b.find((child) => child.id === log24.request.request);
4803
+ const request = (_b = response.children) == null ? void 0 : _b.find((child) => child.id === log27.request.request);
4801
4804
  if (!request) {
4802
4805
  return;
4803
4806
  }
4804
4807
  request.response = {
4805
- fromCache: log24.response.fromCache,
4806
- headers: headerListToObject(log24.response.headers),
4807
- mimeType: log24.response.mimeType,
4808
- status: log24.response.status
4808
+ fromCache: log27.response.fromCache,
4809
+ headers: headerListToObject(log27.response.headers),
4810
+ mimeType: log27.response.mimeType,
4811
+ status: log27.response.status
4809
4812
  };
4810
4813
  (_c = response.children) == null ? void 0 : _c.push(request);
4811
4814
  };
@@ -4855,14 +4858,14 @@ _browser8 = new WeakMap();
4855
4858
  _initialize4 = new WeakMap();
4856
4859
  _autoHandleDialog = new WeakMap();
4857
4860
  _DialogManager_instances = new WeakSet();
4858
- handleUserPrompt_fn = async function(log24) {
4861
+ handleUserPrompt_fn = async function(log27) {
4859
4862
  if (__privateGet(this, _autoHandleDialog)) {
4860
4863
  return __privateGet(this, _browser8).browsingContextHandleUserPrompt({
4861
4864
  accept: false,
4862
- context: log24.context
4865
+ context: log27.context
4863
4866
  });
4864
4867
  }
4865
- const dialog = new Dialog(log24, __privateGet(this, _browser8));
4868
+ const dialog = new Dialog(log27, __privateGet(this, _browser8));
4866
4869
  __privateGet(this, _browser8).emit("dialog", dialog);
4867
4870
  };
4868
4871
  /**
@@ -5797,6 +5800,263 @@ async function screenTap(browser, options) {
5797
5800
  ).move({ x, y }).down({ button: 0 }).pause(10).up({ button: 0 }).perform();
5798
5801
  }
5799
5802
 
5803
+ // src/commands/mobile/getContext.ts
5804
+ import logger18 from "@wdio/logger";
5805
+ var log18 = logger18("webdriver");
5806
+ async function getContext(options) {
5807
+ const browser = this;
5808
+ if (!browser.isMobile) {
5809
+ throw new Error("The `getContext` command is only available for mobile platforms.");
5810
+ }
5811
+ const currentAppiumContext = await browser.getAppiumContext();
5812
+ if (!options || !(options == null ? void 0 : options.returnDetailedContext) || currentAppiumContext === "NATIVE_APP") {
5813
+ return currentAppiumContext;
5814
+ }
5815
+ delete options.returnDetailedContext;
5816
+ return getDetailedContext(browser, currentAppiumContext, options);
5817
+ }
5818
+ async function getDetailedContext(browser, currentAppiumContext, options) {
5819
+ const detailedContexts = await browser.getContexts({
5820
+ ...{ options },
5821
+ // Defaults
5822
+ returnDetailedContexts: true,
5823
+ // We want to get back the detailed context information
5824
+ isAndroidWebviewVisible: true,
5825
+ // We only want to get back the visible webviews
5826
+ filterByCurrentAndroidApp: true,
5827
+ // We only want to get back the webviews that are attached to the current app
5828
+ returnAndroidDescriptionData: false
5829
+ // We don't want to get back the Android Webview description data
5830
+ });
5831
+ const parsedContexts = detailedContexts.filter((context) => context.id === currentAppiumContext);
5832
+ if (parsedContexts.length > 1) {
5833
+ log18.warn("We found more than 1 detailed context for the current context '".concat(currentAppiumContext, "'. We will return the first context."));
5834
+ return parsedContexts[0];
5835
+ } else if (parsedContexts.length === 0) {
5836
+ log18.warn("We did not get back any detailed context for the current context '".concat(currentAppiumContext, "'. We will return the current context as a string."));
5837
+ return currentAppiumContext;
5838
+ }
5839
+ return parsedContexts[0];
5840
+ }
5841
+
5842
+ // src/commands/mobile/getContexts.ts
5843
+ import logger19 from "@wdio/logger";
5844
+ var log19 = logger19("webdriver");
5845
+ async function getContexts(options) {
5846
+ const browser = this;
5847
+ if (!browser.isMobile) {
5848
+ throw new Error("The `getContexts` command is only available for mobile platforms.");
5849
+ }
5850
+ if (!options || !options.returnDetailedContexts) {
5851
+ log19.info("The standard Appium `contexts` method is used. If you want to get more detailed data, you can set `returnDetailedContexts` to `true`.");
5852
+ return browser.getAppiumContexts();
5853
+ }
5854
+ const defaultOptions = {
5855
+ androidWebviewConnectionRetryTime: 500,
5856
+ androidWebviewConnectTimeout: 5e3,
5857
+ filterByCurrentAndroidApp: false,
5858
+ isAndroidWebviewVisible: true,
5859
+ returnAndroidDescriptionData: false
5860
+ };
5861
+ return getCurrentContexts({ browser, ...{ ...defaultOptions, ...options } });
5862
+ }
5863
+ var CHROME_PACKAGE_NAME = "com.android.chrome";
5864
+ async function parsedAndroidContexts({
5865
+ contexts,
5866
+ filterByCurrentAndroidApp,
5867
+ isAttachedAndVisible,
5868
+ packageName
5869
+ }) {
5870
+ const currentWebviewName = "WEBVIEW_".concat(packageName);
5871
+ let parsedContexts = contexts;
5872
+ if (filterByCurrentAndroidApp) {
5873
+ parsedContexts = contexts.filter((context) => context.webviewName === currentWebviewName);
5874
+ }
5875
+ const result = [{ id: "NATIVE_APP" }];
5876
+ if (!parsedContexts || parsedContexts.length < 1) {
5877
+ return result;
5878
+ }
5879
+ parsedContexts.forEach(
5880
+ (context) => {
5881
+ var _a;
5882
+ return (_a = context.pages) == null ? void 0 : _a.filter((page) => {
5883
+ if (packageName === CHROME_PACKAGE_NAME) {
5884
+ return true;
5885
+ }
5886
+ if (page.type === "page" && page.description) {
5887
+ let descriptionObj;
5888
+ try {
5889
+ descriptionObj = JSON.parse(page.description);
5890
+ } catch (e) {
5891
+ return false;
5892
+ }
5893
+ return isAttachedAndVisible ? descriptionObj.attached === true && descriptionObj.visible === true : true;
5894
+ }
5895
+ return !isAttachedAndVisible;
5896
+ }).forEach((page) => {
5897
+ const {
5898
+ attached = false,
5899
+ empty = false,
5900
+ height = 0,
5901
+ never_attached: neverAttached = false,
5902
+ screenX = 0,
5903
+ screenY = 0,
5904
+ visible = false,
5905
+ width = 0
5906
+ } = JSON.parse(page.description || "{}");
5907
+ const pageData = {
5908
+ androidWebviewData: {
5909
+ attached,
5910
+ empty,
5911
+ height,
5912
+ neverAttached,
5913
+ screenX,
5914
+ screenY,
5915
+ visible,
5916
+ width
5917
+ },
5918
+ id: context.webviewName,
5919
+ title: page.title,
5920
+ url: page.url,
5921
+ packageName: context.info["Android-Package"],
5922
+ webviewPageId: page.id
5923
+ };
5924
+ result.push(pageData);
5925
+ });
5926
+ }
5927
+ );
5928
+ return result;
5929
+ }
5930
+ async function getCurrentContexts({
5931
+ browser,
5932
+ androidWebviewConnectionRetryTime,
5933
+ androidWebviewConnectTimeout,
5934
+ filterByCurrentAndroidApp,
5935
+ isAndroidWebviewVisible,
5936
+ returnAndroidDescriptionData
5937
+ }) {
5938
+ var _a;
5939
+ const contexts = await browser.execute("mobile: getContexts");
5940
+ if (browser.isIOS) {
5941
+ return contexts;
5942
+ }
5943
+ const packageName = await browser.getCurrentPackage();
5944
+ const startTime = Date.now();
5945
+ const retryInterval = androidWebviewConnectionRetryTime;
5946
+ let isPackageNameMissing = false;
5947
+ while (Date.now() - startTime < androidWebviewConnectTimeout) {
5948
+ const parsedContexts = await parsedAndroidContexts({
5949
+ contexts,
5950
+ filterByCurrentAndroidApp,
5951
+ isAttachedAndVisible: isAndroidWebviewVisible,
5952
+ packageName
5953
+ });
5954
+ const androidContext = parsedContexts.find((context) => context.packageName === packageName);
5955
+ isPackageNameMissing = !(androidContext == null ? void 0 : androidContext.packageName);
5956
+ const isAndroidWebviewDataMissing = androidContext && !("androidWebviewData" in androidContext);
5957
+ const isAndroidWebviewDataEmpty = androidContext && ((_a = androidContext.androidWebviewData) == null ? void 0 : _a.empty);
5958
+ if (packageName === CHROME_PACKAGE_NAME) {
5959
+ return parsedContexts;
5960
+ }
5961
+ if (!isPackageNameMissing && !isAndroidWebviewDataMissing && !isAndroidWebviewDataEmpty) {
5962
+ if (!returnAndroidDescriptionData) {
5963
+ parsedContexts.forEach((context) => {
5964
+ if ("androidWebviewData" in context) {
5965
+ delete context.androidWebviewData;
5966
+ }
5967
+ });
5968
+ }
5969
+ return parsedContexts;
5970
+ }
5971
+ await new Promise((resolve2) => setTimeout(resolve2, retryInterval));
5972
+ }
5973
+ throw new Error(
5974
+ "The packageName '".concat(packageName, "' ").concat(isPackageNameMissing ? "could not be found!" : "matches, but no webview with pages was loaded in this response: " + JSON.stringify(contexts) + "'")
5975
+ );
5976
+ }
5977
+
5978
+ // src/commands/mobile/switchContext.ts
5979
+ import logger20 from "@wdio/logger";
5980
+ var log20 = logger20("webdriver");
5981
+ async function switchContext(options) {
5982
+ const browser = this;
5983
+ if (!browser.isMobile) {
5984
+ throw new Error("The `switchContext` command is only available for mobile platforms.");
5985
+ }
5986
+ if (!options) {
5987
+ throw new Error("You need to provide at least a context name to switch to. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
5988
+ }
5989
+ if (typeof options === "string") {
5990
+ log20.info("The standard Appium `context`-method is used. If you want to switch to a webview with a specific title or url, please provide an object with the `title` or `url` property. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
5991
+ return browser.switchAppiumContext(options);
5992
+ }
5993
+ if (!options.title && !options.url) {
5994
+ throw new Error("You need to provide at least a `title` or `url` property to use full potential of the `switchContext` command. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
5995
+ }
5996
+ return switchToContext({ browser, options });
5997
+ }
5998
+ async function switchToContext({ browser, options }) {
5999
+ var _a;
6000
+ const getContextsOptions = {
6001
+ returnDetailedContexts: true,
6002
+ filterByCurrentAndroidApp: false,
6003
+ isAndroidWebviewVisible: false,
6004
+ returnAndroidDescriptionData: true,
6005
+ ...(options == null ? void 0 : options.androidWebviewConnectionRetryTime) && { androidWebviewConnectionRetryTime: options.androidWebviewConnectionRetryTime },
6006
+ ...(options == null ? void 0 : options.androidWebviewConnectTimeout) && { androidWebviewConnectTimeout: options.androidWebviewConnectTimeout }
6007
+ };
6008
+ const contexts = await browser.getContexts(getContextsOptions);
6009
+ const identifier = browser.isIOS ? (_a = await browser.execute("mobile: activeAppInfo")) == null ? void 0 : _a.bundleId : await browser.getCurrentPackage();
6010
+ const { matchingContext, reasons } = findMatchingContext({ browser, contexts, identifier, ...(options == null ? void 0 : options.title) && { title: options.title }, ...(options == null ? void 0 : options.url) && { url: options.url } });
6011
+ if (!matchingContext) {
6012
+ throw new Error(reasons.join("\n"));
6013
+ }
6014
+ log20.info("WebdriverIO found a matching context:", JSON.stringify(matchingContext, null, 2));
6015
+ if (!browser.isIOS) {
6016
+ const webviewName = "WEBVIEW_".concat(identifier);
6017
+ await browser.switchAppiumContext(webviewName);
6018
+ }
6019
+ const switchFunction = browser.isIOS ? browser.switchAppiumContext.bind(browser) : browser.switchToWindow.bind(browser);
6020
+ const matchingContextId = browser.isIOS ? matchingContext.id : matchingContext.webviewPageId;
6021
+ return switchFunction(matchingContextId);
6022
+ }
6023
+ function findMatchingContext({
6024
+ browser: { isIOS },
6025
+ contexts,
6026
+ identifier,
6027
+ title,
6028
+ url: url2
6029
+ }) {
6030
+ const reasons = [];
6031
+ reasons.push("We parsed a total of ".concat(contexts.length, " Webviews but did not find a matching context. The reasons are:"));
6032
+ const matchingContext = contexts.find((context, index) => {
6033
+ var _a, _b, _c, _d;
6034
+ reasons.push("- Webview ".concat(index + 1, ": '").concat(context.id, "'"));
6035
+ if (context.id === "NATIVE_APP") {
6036
+ reasons.push(" - Skipped context because it is NATIVE_APP");
6037
+ return false;
6038
+ }
6039
+ const idMatch = isIOS ? context.bundleId === identifier : context.packageName === identifier;
6040
+ const titleMatches = title ? title instanceof RegExp ? title.test(context.title || "") : (_a = context.title) == null ? void 0 : _a.includes(title) : true;
6041
+ const urlMatches = url2 ? url2 instanceof RegExp ? url2.test(context.url || "") : (_b = context.url) == null ? void 0 : _b.includes(url2) : true;
6042
+ const additionalAndroidChecks = isIOS ? true : ((_c = context.androidWebviewData) == null ? void 0 : _c.attached) && ((_d = context.androidWebviewData) == null ? void 0 : _d.visible);
6043
+ if (!idMatch) {
6044
+ reasons.push(" - App ".concat(isIOS ? "bundleId" : "packageName", " '").concat(identifier, "' did not match: '").concat(context.id, "'"));
6045
+ }
6046
+ if (!titleMatches) {
6047
+ reasons.push(" - Title '".concat(title, "' did not match: '").concat(context.title, "'"));
6048
+ }
6049
+ if (!urlMatches) {
6050
+ reasons.push(" - URL '".concat(url2, "' did not match: '").concat(context.url, "'"));
6051
+ }
6052
+ if (!additionalAndroidChecks) {
6053
+ reasons.push(" - Additional Android checks failed");
6054
+ }
6055
+ return idMatch && titleMatches && urlMatches && additionalAndroidChecks;
6056
+ });
6057
+ return { matchingContext, reasons };
6058
+ }
6059
+
5800
6060
  // src/commands/element.ts
5801
6061
  var element_exports = {};
5802
6062
  __export(element_exports, {
@@ -5881,9 +6141,9 @@ function clearValue() {
5881
6141
  }
5882
6142
 
5883
6143
  // src/commands/element/click.ts
5884
- import logger18 from "@wdio/logger";
6144
+ import logger21 from "@wdio/logger";
5885
6145
  import { getBrowserObject as getBrowserObject11 } from "@wdio/utils";
5886
- var log18 = logger18("webdriver");
6146
+ var log21 = logger21("webdriver");
5887
6147
  function click(options) {
5888
6148
  if (typeof options !== "undefined") {
5889
6149
  if (typeof options !== "object" || Array.isArray(options)) {
@@ -5930,10 +6190,10 @@ async function actionClick(element, options) {
5930
6190
  if (x || y) {
5931
6191
  const { width, height } = await browser.getElementRect(element.elementId);
5932
6192
  if (x && x < -Math.floor(width / 2) || x && x > Math.floor(width / 2)) {
5933
- log18.warn("x would cause a out of bounds error as it goes outside of element");
6193
+ log21.warn("x would cause a out of bounds error as it goes outside of element");
5934
6194
  }
5935
6195
  if (y && y < -Math.floor(height / 2) || y && y > Math.floor(height / 2)) {
5936
- log18.warn("y would cause a out of bounds error as it goes outside of element");
6196
+ log21.warn("y would cause a out of bounds error as it goes outside of element");
5937
6197
  }
5938
6198
  }
5939
6199
  const clickNested = async () => {
@@ -6437,7 +6697,7 @@ async function isClickable() {
6437
6697
  if (!await this.isDisplayed()) {
6438
6698
  return false;
6439
6699
  }
6440
- if (this.isMobile && await this.getContext().catch(() => void 0) === "NATIVE_APP") {
6700
+ if (this.isMobile && this.isNativeContext) {
6441
6701
  throw new Error("Method not supported in mobile native environment. It is unlikely that you need to use this command.");
6442
6702
  }
6443
6703
  const browser = getBrowserObject20(this);
@@ -6789,18 +7049,18 @@ async function isStable() {
6789
7049
  }
6790
7050
 
6791
7051
  // src/commands/element/moveTo.ts
6792
- import logger19 from "@wdio/logger";
7052
+ import logger22 from "@wdio/logger";
6793
7053
  import { getBrowserObject as getBrowserObject25 } from "@wdio/utils";
6794
- var log19 = logger19("webdriver");
7054
+ var log22 = logger22("webdriver");
6795
7055
  async function moveTo({ xOffset, yOffset } = {}) {
6796
7056
  const browser = getBrowserObject25(this);
6797
7057
  if (xOffset || yOffset) {
6798
7058
  const { width, height } = await browser.getElementRect(this.elementId);
6799
7059
  if (xOffset && xOffset < -Math.floor(width / 2) || xOffset && xOffset > Math.floor(width / 2)) {
6800
- log19.warn("xOffset would cause a out of bounds error as it goes outside of element");
7060
+ log22.warn("xOffset would cause a out of bounds error as it goes outside of element");
6801
7061
  }
6802
7062
  if (yOffset && yOffset < -Math.floor(height / 2) || yOffset && yOffset > Math.floor(height / 2)) {
6803
- log19.warn("yOffset would cause a out of bounds error as it goes outside of element");
7063
+ log22.warn("yOffset would cause a out of bounds error as it goes outside of element");
6804
7064
  }
6805
7065
  }
6806
7066
  const moveToNested = async () => {
@@ -6884,10 +7144,10 @@ async function saveScreenshot2(filepath) {
6884
7144
  }
6885
7145
 
6886
7146
  // src/commands/element/scrollIntoView.ts
6887
- import logger20 from "@wdio/logger";
7147
+ import logger23 from "@wdio/logger";
6888
7148
  import { ELEMENT_KEY as ELEMENT_KEY17 } from "webdriver";
6889
7149
  import { getBrowserObject as getBrowserObject28 } from "@wdio/utils";
6890
- var log20 = logger20("webdriverio");
7150
+ var log23 = logger23("webdriverio");
6891
7151
  async function scrollIntoView(options = { block: "start", inline: "nearest" }) {
6892
7152
  const browser = getBrowserObject28(this);
6893
7153
  if (browser.isMobile) {
@@ -6940,7 +7200,7 @@ async function scrollIntoView(options = { block: "start", inline: "nearest" }) {
6940
7200
  deltaY = Math.round(deltaY - scrollY2);
6941
7201
  await browser.action("wheel").scroll({ duration: 0, x: deltaX, y: deltaY, origin: this }).perform();
6942
7202
  } catch (err) {
6943
- log20.warn(
7203
+ log23.warn(
6944
7204
  'Failed to execute "scrollIntoView" using WebDriver Actions API: '.concat(err.message, "!\n") + "Re-attempting using `Element.scrollIntoView` via Web API."
6945
7205
  );
6946
7206
  await scrollIntoViewWeb.call(this, options);
@@ -7078,7 +7338,7 @@ async function setValue(value) {
7078
7338
  }
7079
7339
 
7080
7340
  // src/commands/element/shadow$$.ts
7081
- import logger21 from "@wdio/logger";
7341
+ import logger24 from "@wdio/logger";
7082
7342
  import { getBrowserObject as getBrowserObject29 } from "@wdio/utils";
7083
7343
  import { SHADOW_ELEMENT_KEY } from "webdriver";
7084
7344
 
@@ -7414,7 +7674,7 @@ var createRoleBaseXpathSelector = (role) => {
7414
7674
  };
7415
7675
 
7416
7676
  // src/commands/element/shadow$$.ts
7417
- var log21 = logger21("webdriverio");
7677
+ var log24 = logger24("webdriverio");
7418
7678
  async function shadow$$(selector) {
7419
7679
  const browser = getBrowserObject29(this);
7420
7680
  try {
@@ -7424,7 +7684,7 @@ async function shadow$$(selector) {
7424
7684
  const elements = await getElements.call(this, selector, res, { isShadowElement: true });
7425
7685
  return enhanceElementsArray(elements, this, selector);
7426
7686
  } catch (err) {
7427
- log21.warn(
7687
+ log24.warn(
7428
7688
  "Failed to fetch element within shadow DOM using WebDriver command: ".concat(err.message, "!\n") + "Falling back to JavaScript shim."
7429
7689
  );
7430
7690
  return await this.$$(shadowFnFactory(selector, true));
@@ -7432,10 +7692,10 @@ async function shadow$$(selector) {
7432
7692
  }
7433
7693
 
7434
7694
  // src/commands/element/shadow$.ts
7435
- import logger22 from "@wdio/logger";
7695
+ import logger25 from "@wdio/logger";
7436
7696
  import { SHADOW_ELEMENT_KEY as SHADOW_ELEMENT_KEY2 } from "webdriver";
7437
7697
  import { getBrowserObject as getBrowserObject30 } from "@wdio/utils";
7438
- var log22 = logger22("webdriverio");
7698
+ var log25 = logger25("webdriverio");
7439
7699
  async function shadow$(selector) {
7440
7700
  const browser = getBrowserObject30(this);
7441
7701
  try {
@@ -7444,7 +7704,7 @@ async function shadow$(selector) {
7444
7704
  const res = await browser.findElementFromShadowRoot(shadowRoot[SHADOW_ELEMENT_KEY2], using, value);
7445
7705
  return getElement.call(this, selector, res, { isShadowElement: true });
7446
7706
  } catch (err) {
7447
- log22.warn(
7707
+ log25.warn(
7448
7708
  "Failed to fetch element within shadow DOM using WebDriver command: ".concat(err.message, "!\n") + "Falling back to JavaScript shim."
7449
7709
  );
7450
7710
  return this.$(shadowFnFactory(selector));
@@ -7818,7 +8078,7 @@ function querySelectorAllDeep(findMany, s, r) {
7818
8078
  }
7819
8079
 
7820
8080
  // src/utils/index.ts
7821
- var log23 = logger23("webdriverio");
8081
+ var log26 = logger26("webdriverio");
7822
8082
  var INVALID_SELECTOR_ERROR = "selector needs to be typeof `string` or `function`";
7823
8083
  var IGNORED_COMMAND_FILE_EXPORTS = ["SESSION_MOCKS", "CDP_SESSIONS"];
7824
8084
  var scopes = {
@@ -7987,7 +8247,7 @@ async function findDeepElement(selector) {
7987
8247
  })).then((elems) => elems.filter(([isIn]) => isIn).map(([, elem]) => elem));
7988
8248
  return scopedNodes[0];
7989
8249
  }, (err) => {
7990
- log23.warn("Failed to execute browser.browsingContextLocateNodes({ ... }) due to ".concat(err, ", falling back to regular WebDriver Classic command"));
8250
+ log26.warn("Failed to execute browser.browsingContextLocateNodes({ ... }) due to ".concat(err, ", falling back to regular WebDriver Classic command"));
7991
8251
  return this && "elementId" in this && this.elementId ? this.findElementFromElement(this.elementId, using, value) : browser.findElement(using, value);
7992
8252
  });
7993
8253
  if (!deepElementResult) {
@@ -8025,7 +8285,7 @@ async function findDeepElements(selector) {
8025
8285
  })).then((elems) => elems.filter(([isIn]) => isIn).map(([, elem]) => elem));
8026
8286
  return scopedNodes;
8027
8287
  }, (err) => {
8028
- log23.warn("Failed to execute browser.browsingContextLocateNodes({ ... }) due to ".concat(err, ", falling back to regular WebDriver Classic command"));
8288
+ log26.warn("Failed to execute browser.browsingContextLocateNodes({ ... }) due to ".concat(err, ", falling back to regular WebDriver Classic command"));
8029
8289
  return this && "elementId" in this && this.elementId ? this.findElementsFromElement(this.elementId, using, value) : browser.findElements(using, value);
8030
8290
  });
8031
8291
  return deepElementResult;
@@ -8153,7 +8413,7 @@ async function getElementRect(scope) {
8153
8413
  if (rectJs && typeof rectJs[key] === "number") {
8154
8414
  rect[key] = Math.floor(rectJs[key]);
8155
8415
  } else {
8156
- log23.error("getElementRect", { rect, rectJs, key });
8416
+ log26.error("getElementRect", { rect, rectJs, key });
8157
8417
  throw new Error("Failed to receive element rects via execute command");
8158
8418
  }
8159
8419
  });
@@ -8599,7 +8859,7 @@ var remote = async function(params, remoteModifier) {
8599
8859
  const keysToKeep = Object.keys(process.env.WDIO_WORKER_ID ? params : DEFAULTS);
8600
8860
  const config = validateConfig(WDIO_DEFAULTS, params, keysToKeep);
8601
8861
  await enableFileLogging(config.outputDir);
8602
- logger24.setLogLevelsConfig(config.logLevels, config.logLevel);
8862
+ logger27.setLogLevelsConfig(config.logLevels, config.logLevel);
8603
8863
  const modifier = (client, options2) => {
8604
8864
  Object.assign(options2, Object.entries(config).reduce((a, [k, v]) => typeof v === "undefined" ? a : { ...a, [k]: v }, {}));
8605
8865
  if (typeof remoteModifier === "function") {