How to use this.nativeTap method in Appium Xcuitest Driver

Best JavaScript code snippet using appium-xcuitest-driver

Run Appium Xcuitest Driver automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Sign up Free
_

context.js

Source: context.js Github

copy
1import _ from 'lodash';
2import B from 'bluebird';
3import { RemoteDebugger, WebKitRemoteDebugger } from 'appium-remote-debugger';
4import { IOSPerformanceLog } from 'appium-ios-log';
5import { errors } from 'appium-base-driver';
6import logger from '../logger';
7
8const WEBVIEW_WIN = 'WEBVIEW';
9const WEBVIEW_BASE = `${WEBVIEW_WIN}_`;
10
11let commands = {}, helpers = {}, extensions = {};
12
13commands.getCurrentContext = async function () {
14  return `${WEBVIEW_BASE}${this.curContext}`;
15};
16
17commands.getContexts = async function () {
18  logger.debug('Getting list of available contexts');
19  let contexts = await this.getContextsAndViews();
20  return contexts.map((context) => context.id);
21};
22
23commands.setContext = async function (name, callback, skipReadyCheck) {
24  function alreadyInContext (desired, current) {
25    return (desired === current);
26  }
27
28  logger.debug(`Attempting to set context to '${name}'`);
29  if (alreadyInContext(name, this.curContext)) {
30    // already in the named context, no need to do anything
31  } else {
32    // switching into a webview context
33    let idx = name.replace(WEBVIEW_BASE, '');
34    if (idx === WEBVIEW_WIN) {
35      // allow user to pass in "WEBVIEW" without an index
36      idx = '1';
37    }
38
39    // if contexts have not already been retrieved, get them
40    if (_.isUndefined(this.contexts)) {
41      await this.getContexts();
42    }
43
44    if (!_.contains(this.contexts, idx)) {
45      throw new errors.NoSuchContextError();
46    }
47    let pageIdKey = parseInt(idx, 10);
48
49    if (!this.isRealDevice()) {
50      await this.remote.selectPage(pageIdKey, skipReadyCheck);
51      this.curContext = idx;
52    } else {
53      if (this.remote) {
54        await this.remote.disconnect();
55      }
56      this.curContext = idx;
57      await this.remote.connect(idx);
58    }
59  }
60
61  // attempt to start performance logging, if requested
62  if (this.perfLogEnabled && this.remote) {
63    logger.debug(`Starting performance log on '${this.curContext}'`);
64    this.logs.performance = new IOSPerformanceLog(this.remote);
65    this.logs.performance.startCapture();
66  }
67};
68
69commands.getWindowHandle = async function () {
70  if (!this.isWebContext()) {
71    throw new errors.NotImplementedError();
72  }
73  return this.curContext;
74};
75
76commands.getWindowHandles = async function () {
77  if (!this.isWebContext()) {
78    throw new errors.NotImplementedError();
79  }
80
81  let pageArray = await this.listWebFrames();
82  this.windowHandleCache = _.map(pageArray, this.massagePage);
83  let idArray = _.pluck(this.windowHandleCache, 'id');
84  // since we use this.contexts to manage selecting debugger pages, make
85  // sure it gets populated even if someone did not use the
86  // getContexts method
87  if (!this.contexts) {
88    this.contexts = idArray;
89  }
90  return idArray;
91};
92
93commands.setWindow = async function (name, skipReadyCheck) {
94  if (!this.isWebContext()) {
95    throw new errors.NotImplementedError();
96  }
97
98  if (!_.contains(_.pluck(this.windowHandleCache, 'id'), name)) {
99    throw new errors.NoSuchWindowError();
100  }
101  let pageIdKey = parseInt(name, 10);
102  if (!this.isRealDevice()) {
103    await this.remote.selectPage(pageIdKey, skipReadyCheck);
104    this.curContext = this.curWindowHandle = name;
105  } else {
106    if (name === this.curWindowHandle) {
107      logger.debug(`Remote debugger is already connected to window '${name}'`);
108    } else if (!_.contains(_.pluck(this.windowHandleCache, 'id'), name)) {
109      throw new errors.NoSuchWindowError();
110    } else {
111      await this.remote.disconnect();
112      this.curContext = this.curWindowHandle = name;
113      await this.remote.connect(name);
114    }
115  }
116};
117
118helpers.webContextIndex = function () {
119  return this.curContext.replace(WEBVIEW_BASE, '') - 1;
120};
121
122extensions.getContextsAndViews = async function () {
123  logger.debug('Retrieving contexts and views');
124  let webviews = await this.listWebFrames();
125  let ctxs = [];
126  this.contexts = [];
127  for (let view of webviews) {
128    ctxs.push({id: `${WEBVIEW_BASE}${view.id}`, view});
129    this.contexts.push(view.id.toString());
130  }
131  return ctxs;
132};
133
134extensions.listWebFrames = async function () {
135  if (!this.opts.bundleId) {
136    logger.errorAndThrow('Cannot enter web frame without a bundle ID');
137  }
138
139  let pageArray;
140  if (this.remote !== null && this.opts.bundleId !== null) {
141    if (this.isRealDevice()) {
142      pageArray = await this.remote.pageArrayFromJson();
143    } else {
144      pageArray = await this.remote.selectApp(this.opts.webviewConnectRetries);
145    }
146  } else {
147    if (this.isRealDevice()) {
148      this.remote = new WebKitRemoteDebugger({port: this.opts.webkitDebugProxyPort});
149      return this.remote.pageArrayFromJson();
150    }
151    this.remote = new RemoteDebugger({
152      bundleId: this.opts.bundleId,
153      useNewSafari: this.useNewSafari(),
154      pageLoadMs: this.pageLoadMs,
155      platformVersion: this.opts.platformVersion
156    });
157
158    logger.info('attempting to connect to remote debugger');
159    let appInfo = await this.remote.connect();
160    logger.info('connected to remote debugger');
161    if (!appInfo) {
162      logger.debug('Unable to connect to the remote debugger.');
163      return [];
164    }
165
166    logger.info('getting page array by calling "selectApp()"');
167    pageArray = await this.remote.selectApp(this.opts.webviewConnectRetries);
168    logger.info(`we got page array ${pageArray.length}`);
169    this.remote.on(RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
170
171    // TODO: do we need to close alerts here?
172    // let tryClosingAlert = async () => {
173    //   let didDismiss = await this.closeAlertBeforeTest();
174    //   if (!didDismiss) {
175    //     throw new Error('Close alert failed. Retry.');
176    //   }
177    // };
178    // try {
179    //   await retryInterval(3, 4000, tryClosingAlert);
180    // } catch (err) {
181    //   // if the loop to close alerts failed to dismiss, ignore,
182    //   // otherwise log and throw the error
183    //   if (err.message !== 'Close alert failed. Retry.') {
184    //     logger.errorAndThrow(err);
185    //   }
186    // }
187  }
188
189  if (pageArray.length === 0) {
190    // we have no web frames, but continue anyway
191    logger.debug('No web frames found.');
192  }
193
194  return pageArray;
195};
196
197extensions.onPageChange = async function (pageArray) {
198  logger.debug(`Remote debugger notified us of a new page listing: ${JSON.stringify(pageArray)}`);
199  if (this.selectingNewPage) {
200    logger.debug('We are in the middle of selecting a page, ignoring');
201    return;
202  }
203  let newIds = [];
204  let newPages = [];
205  let keyId = null;
206  for (let page of pageArray) {
207    let id = page.id.toString();
208    newIds.push(id);
209    if (page.isKey) {
210      keyId = id;
211    }
212    if (!_.contains(this.contexts, id)) {
213      newPages.push(id);
214      this.contexts.push(id);
215    }
216  }
217
218  let newPage = null;
219  if (this.curContext === null) {
220    logger.debug('We do not appear to have window set yet, ignoring');
221  } else if (newPages.length) {
222    logger.debug(`We have new pages, going to select page '${newPages[0]}'`);
223    newPage = newPages[0];
224  } else if (!_.contains(newIds, this.curContext.toString())) {
225    logger.debug('New page listing from remote debugger does not contain ' +
226                 'current window; assuming it is closed');
227    if (keyId !== null) {
228      logger.debug(`Debugger already selected page '${keyId}', ` +
229                   `confirming that choice.`);
230    } else {
231      logger.error('Do not have our current window anymore, and there ' +
232                   'are not any more to load! Doing nothing...');
233      return;
234    }
235    this.curContext = keyId;
236    newPage = keyId;
237  } else {
238    // If a window navigates to an anchor it doesn't always fire a page
239    // callback event. Let's check if we wound up in such a situation.
240    let needsPageLoad = (() => {
241      let item = (arr) => {
242        return _.filter(arr, function (obj) {
243          return obj.id === this.curContext;
244        }, this)[0];
245      };
246
247      return !_.isEqual(item(this.contexts), item(pageArray));
248    })();
249
250    if (needsPageLoad) {
251      await this.remote.pageLoad();
252    }
253
254    logger.debug('New page listing is same as old, doing nothing');
255  }
256
257  if (!_.isNull(newPage)) {
258    this.selectingNewPage = true;
259    await this.remote.selectPage(parseInt(newPage, 10));
260    this.selectingNewPage = false;
261    this.curContext = newPage;
262  }
263  this.windowHandleCache = _.map(pageArray, this.massagePage);
264};
265
266extensions.getLatestWebviewContextForTitle = async function (titleRegex) {
267  let contexts = await this.getContextsAndViews();
268  let matchingCtx;
269  for (let ctx of contexts) {
270    if (ctx.view && (ctx.view.title || '').match(titleRegex)) {
271      if (ctx.view.url !== 'about:blank') {
272        matchingCtx = ctx;
273      } else {
274        // in the cases of Xcode < 5 (i.e., iOS SDK Version less than 7)
275        // iOS 7.1, iOS 9.0 & iOS 9.1 in a webview (not in Safari)
276        // we can have the url be `about:blank`
277        if (parseFloat(this.iOSSDKVersion) < 7 || parseFloat(this.iOSSDKVersion) >= 9 ||
278            (this.opts.platformVersion === '7.1' && this.opts.app && this.opts.app.toLowerCase() !== 'safari')) {
279          matchingCtx = ctx;
280        }
281      }
282    }
283  }
284  return matchingCtx ? matchingCtx.id : undefined;
285};
286
287// Right now we don't necessarily wait for webview
288// and frame to load, which leads to race conditions and flakiness,
289// let's see if we can transition to something better
290extensions.useNewSafari = function () {
291  return parseFloat(this.iosSdkVersion) >= 8.1 &&
292         parseFloat(this.opts.platformVersion) >= 8.1 &&
293         !this.isRealDevice() &&
294         this.opts.safari;
295};
296
297extensions.navToInitialWebview = async function () {
298  let timeout = 0;
299  if (this.isRealDevice()) {
300    timeout = 3000;
301    logger.debug(`Waiting for ${timeout} ms before navigating to view.`);
302  }
303  await B.delay(timeout);
304  if (this.useNewSafari()) {
305    await this.typeAndNavToUrl();
306  } else if (parseInt(this.iosSdkVersion, 10) >= 7 && !this.isRealDevice() && this.opts.safari) {
307    await this.navToViewThroughFavorites();
308  } else {
309    await this.navToViewWithTitle(/.*/);
310  }
311};
312
313extensions.typeAndNavToUrl = async function () {
314  let initialUrl = this.caps.safariInitialUrl || `http://127.0.0.1:${this.opts.port}/welcome`;
315  let oldImpWait = this.implicitWaitMs;
316  this.implicitWaitMs = 7000;
317
318  // find the url bar, and tap on it
319  let el = await this.findElement('name', 'URL');
320  this.implicitWaitMs = oldImpWait;
321  await this.nativeTap(el.ELEMENT);
322
323  // get the last address element and set the url
324  let els = await this.findElements('name', 'Address');
325  let addressEl = _.last(els).ELEMENT;
326  await this.setValueImmediate(initialUrl, addressEl);
327
328  // make it happen
329  el = await this.findElement('name', 'Go');
330  await this.nativeTap(el.ELEMENT);
331  await this.navToViewWithTitle(/.*/i);
332
333  // wait for page to finish loading.
334  await this.remote.pageUnload();
335};
336
337extensions.navToViewThroughFavorites = async function () {
338  logger.debug('We are on iOS7+ simulator: clicking apple button to get into a webview');
339  let oldImpWait = this.implicitWaitMs;
340  this.implicitWaitMs = 7000; // wait 7s for apple button to exist
341
342  let el;
343  try {
344    el = await this.findElement('xpath', '//UIAScrollView[1]/UIAButton[1]');
345  } catch (err) {
346    let msg = 'Could not find button to click to get into webview. ' +
347              'Proceeding on the assumption we have a working one.';
348    logger.error(msg);
349    this.implicitWaitMs = oldImpWait;
350    return await this.navToViewWithTitle(/.*/i);
351  }
352  this.implicitWaitMs = oldImpWait;
353  try {
354    await this.nativeTap(el.ELEMENT);
355  } catch (err) {
356    let msg = 'Could not click button to get into webview. ' +
357              'Proceeding on the assumption we have a working one.';
358    logger.error(msg);
359  }
360  await this.navToViewWithTitle(/apple/i);
361};
362
363extensions.navToViewWithTitle = async function (titleRegex) {
364  logger.debug('Navigating to most recently opened webview');
365  let start = Date.now();
366  let spinTime = 500;
367  let spinHandles = async () => {
368    let res;
369    try {
370      res = await this.getLatestWebviewContextForTitle(titleRegex);
371    } catch (err) {
372      throw new Error(`Could not navigate to webview! Err: ${err.message}`);
373    }
374    if (res) {
375      let latestWindow = res;
376      logger.debug(`Picking webview '${latestWindow}'`);
377      await this.setContext(latestWindow);
378      await this.remote.cancelPageLoad();
379      return;
380    }
381
382    // no webview was found
383    if ((Date.now() - start) >= 90000) {
384      // too slow, get out
385      throw new Error('Could not navigate to webview; there are none!');
386    }
387
388    logger.warn("Could not find any webviews yet, refreshing/retrying");
389    if (this.isRealDevice() || !this.opts.safari) {
390      // on a real device, when not using Safari, we just want to try again
391      await B.delay(spinTime);
392      return await spinHandles();
393    }
394
395    // find the reload button and tap it, if possible
396    let element;
397    try {
398      element = await this.findUIElementOrElements('accessibility id', 'ReloadButton', '', false);
399      await this.nativeTap(element.ELEMENT);
400    } catch (err) {
401      logger.warn(`Error finding and tapping reload button: ${err.message}`);
402      logger.warn('Retrying.');
403      await B.delay(spinTime);
404      return await spinHandles();
405    }
406  };
407  await spinHandles();
408};
409
410helpers.closeAlertBeforeTest = async function () {
411  let present = await this.uiAutoClient.sendCommand('au.alertIsPresent()');
412  if (!present) {
413    return false;
414  }
415
416  logger.debug('Alert present before starting test, let us banish it');
417  await this.uiAutoClient.sendCommand('au.dismissAlert()');
418  logger.debug('Alert banished!');
419  return true;
420};
421
422helpers.stopRemote = async function (closeWindowBeforeDisconnecting = false) {
423  if (!this.remote) {
424    logger.errorAndThrow('Tried to leave a web frame but were not in one');
425  }
426
427  if (closeWindowBeforeDisconnecting) {
428    await this.closeWindow();
429  }
430  await this.remote.disconnect();
431  this.curContext = null;
432  this.remoteAppKey = null;
433  this.curWebFrames = [];
434  this.curWebCoords = null;
435  this.remote = null;
436};
437
438// TODO remove this stub
439helpers.isWebContext = function () {
440  return true;
441};
442
443
444Object.assign(extensions, commands, helpers);
445export { commands, helpers, WEBVIEW_WIN, WEBVIEW_BASE };
446export default extensions;
447
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Appium Xcuitest Driver on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)