How to use this.setInitialOrientation method in Appium Xcuitest Driver

Best JavaScript code snippet using appium-xcuitest-driver

ios.js

Source:ios.js Github

copy

Full Screen

1"use strict";2var path = require('path')3  , rimraf = require('rimraf')4  , ncp = require('ncp').ncp5  , fs = require('fs')6  , _ = require('underscore')7  , which = require('which')8  , logger = require('../../server/logger.js').get('appium')9  , exec = require('child_process').exec10  , spawn = require('child_process').spawn11  , bplistCreate = require('bplist-creator')12  , bplistParse = require('bplist-parser')13  , xmlplist = require('plist')14  , Device = require('../device.js')15  , Instruments = require('./instruments.js')16  , xcode = require('../../future.js').xcode17  , errors = require('../../server/errors.js')18  , deviceCommon = require('../common.js')19  , iOSLog = require('./ios-log.js')20  , iOSCrashLog = require('./ios-crash-log.js')21  , status = require("../../server/status.js")22  , iDevice = require('node-idevice')23  , async = require('async')24  , iOSController = require('./ios-controller.js')25  , iOSHybrid = require('./ios-hybrid.js')26  , settings = require('./settings.js')27  , Simulator = require('./simulator.js')28  , prepareBootstrap = require('./uiauto').prepareBootstrap29  , CommandProxy = require('./uiauto').CommandProxy30  , UnknownError = errors.UnknownError31  , binaryPlist = true32  , Args = require("vargs").Constructor33  , logCustomDeprecationWarning = require('../../helpers.js').logCustomDeprecationWarning;34// XML Plist library helper35var parseXmlPlistFile = function (plistFilename, cb) {36  try {37    var xmlContent = fs.readFileSync(plistFilename, 'utf8');38    var result = xmlplist.parse(xmlContent);39    return cb(null, result);40  } catch (ex) {41    return cb(ex);42  }43};44var parsePlistFile = function (plist, cb) {45  bplistParse.parseFile(plist, function (err, obj) {46    if (err) {47      logger.debug("Could not parse plist file (as binary) at " + plist);48      logger.info("Will try to parse the plist file as XML");49      parseXmlPlistFile(plist, function (err, obj) {50        if (err) {51          logger.debug("Could not parse plist file (as XML) at " + plist);52          return cb(err, null);53        } else {54          logger.debug("Parsed app Info.plist (as XML)");55          binaryPlist = false;56          cb(null, obj);57        }58      });59    } else {60      binaryPlist = true;61      if (obj.length) {62        logger.debug("Parsed app Info.plist (as binary)");63        cb(null, obj[0]);64      } else {65        cb(new Error("Binary Info.plist appears to be empty"));66      }67    }68  });69};70var IOS = function () {71  this.init();72};73_.extend(IOS.prototype, Device.prototype);74IOS.prototype._deviceInit = Device.prototype.init;75IOS.prototype.init = function () {76  this._deviceInit();77  this.appExt = ".app";78  this.capabilities = {79    webStorageEnabled: false80  , locationContextEnabled: false81  , browserName: 'iOS'82  , platform: 'MAC'83  , javascriptEnabled: true84  , databaseEnabled: false85  , takesScreenshot: true86  , networkConnectionEnabled: false87  };88  this.xcodeVersion = null;89  this.iOSSDKVersion = null;90  this.iosSimProcess = null;91  this.iOSSimUdid = null;92  this.logs = {};93  this.instruments = null;94  this.commandProxy = null;95  this.initQueue();96  this.onInstrumentsDie = function () {};97  this.stopping = false;98  this.cbForCurrentCmd = null;99  this.remote = null;100  this.curContext = null;101  this.curWebFrames = [];102  this.selectingNewPage = false;103  this.processingRemoteCmd = false;104  this.remoteAppKey = null;105  this.windowHandleCache = [];106  this.webElementIds = [];107  this.implicitWaitMs = 0;108  this.asyncWaitMs = 0;109  this.pageLoadMs = 60000;110  this.asyncResponseCb = null;111  this.returnedFromExecuteAtom = {};112  this.executedAtomsCounter = 0;113  this.curCoords = null;114  this.curWebCoords = null;115  this.onPageChangeCb = null;116  this.supportedStrategies = ["name", "xpath", "id", "-ios uiautomation",117                              "class name", "accessibility id"];118  this.landscapeWebCoordsOffset = 0;119  this.localizableStrings = {};120  this.keepAppToRetainPrefs = false;121  this.isShuttingDown = false;122};123IOS.prototype._deviceConfigure = Device.prototype.configure;124IOS.prototype.configure = function (args, caps, cb) {125  var msg;126  this._deviceConfigure(args, caps);127  this.setIOSArgs();128  if (this.args.locationServicesAuthorized && !this.args.bundleId) {129    msg = "You must set the bundleId cap if using locationServicesEnabled";130    logger.error(msg);131    return cb(new Error(msg));132  }133  // on iOS8 we can use a bundleId to launch an app on the simulator, but134  // on previous versions we can only do so on a real device, so we need135  // to do a check of which situation we're in136  var ios8 = caps.platformVersion &&137             parseFloat(caps.platformVersion) >= 8;138  if (!this.args.app &&139      !((ios8 || this.args.udid) && this.args.bundleId)) {140    msg = "Please provide the 'app' or 'browserName' capability or start " +141          "appium with the --app or --browser-name argument. Alternatively, " +142          "you may provide the 'bundleId' and 'udid' capabilities for an app " +143          "under test on a real device.";144    logger.error(msg);145    return cb(new Error(msg));146  }147  if (parseFloat(caps.platformVersion) < 7.1) {148    logCustomDeprecationWarning('iOS version', caps.platformVersion,149                                'iOS ' + caps.platformVersion + ' support has ' +150                                'been deprecated and will be removed in a ' +151                                'future version of Appium.');152  }153  return this.configureApp(cb);154};155IOS.prototype.setIOSArgs = function () {156  this.args.withoutDelay = !this.args.nativeInstrumentsLib;157  this.args.reset = !this.args.noReset;158  this.args.initialOrientation = this.capabilities.deviceOrientation ||159                                 this.args.orientation ||160                                 "PORTRAIT";161  this.useRobot = this.args.robotPort > 0;162  this.args.robotUrl = this.useRobot ?163    "http://" + this.args.robotAddress + ":" + this.args.robotPort + "" :164    null;165  this.curOrientation = this.args.initialOrientation;166  this.sock = path.resolve(this.args.tmpDir || '/tmp', 'instruments_sock');167  this.perfLogEnabled = !!(typeof this.args.loggingPrefs === 'object' && this.args.loggingPrefs.performance);168};169IOS.prototype.configureApp = function (cb) {170  var _cb = cb;171  cb = function (err) {172    if (err) {173      err = new Error("Bad app: " + this.args.app + ". App paths need to " +174                      "be absolute, or relative to the appium server " +175                      "install dir, or a URL to compressed file, or a " +176                      "special app name. cause: " + err);177    }178    _cb(err);179  }.bind(this);180  var app = this.appString();181  // if the app name is a bundleId assign it to the bundleId property182  if (!this.args.bundleId && this.appIsPackageOrBundle(app)) {183    this.args.bundleId = app;184  }185  if (app !== "" && app.toLowerCase() === "settings") {186    if (parseFloat(this.args.platformVersion) >= 8) {187      logger.debug("We're on iOS8+ so not copying preferences app");188      this.args.bundleId = "com.apple.Preferences";189      this.args.app = null;190    }191    cb();192  } else if (this.args.bundleId &&193             this.appIsPackageOrBundle(this.args.bundleId) &&194             (app === "" || this.appIsPackageOrBundle(app))) {195    // we have a bundle ID, but no app, or app is also a bundle196    logger.debug("App is an iOS bundle, will attempt to run as pre-existing");197    cb();198  } else {199    Device.prototype.configureApp.call(this, cb);200  }201};202IOS.prototype.removeInstrumentsSocket = function (cb) {203  var removeSocket = function (innerCb) {204    logger.debug("Removing any remaining instruments sockets");205    rimraf(this.sock, function (err) {206      if (err) return innerCb(err);207      logger.debug("Cleaned up instruments socket " + this.sock);208      innerCb();209    }.bind(this));210  }.bind(this);211  removeSocket(cb);212};213IOS.prototype.getNumericVersion = function () {214  return parseFloat(this.args.platformVersion);215};216IOS.prototype.startRealDevice = function (cb) {217  async.series([218    this.removeInstrumentsSocket.bind(this),219    this.detectUdid.bind(this),220    this.parseLocalizableStrings.bind(this),221    this.setBundleIdFromApp.bind(this),222    this.createInstruments.bind(this),223    this.startLogCapture.bind(this),224    this.installToRealDevice.bind(this),225    this.startInstruments.bind(this),226    this.onInstrumentsLaunch.bind(this),227    this.configureBootstrap.bind(this),228    this.setBundleId.bind(this),229    this.setInitialOrientation.bind(this),230    this.initAutoWebview.bind(this),231    this.waitForAppLaunched.bind(this),232  ], function (err) {233    cb(err);234  });235};236IOS.prototype.startSimulator = function (cb) {237  async.series([238    this.removeInstrumentsSocket.bind(this),239    this.setXcodeVersion.bind(this),240    this.setiOSSDKVersion.bind(this),241    this.checkSimAvailable.bind(this),242    this.createSimulator.bind(this),243    this.moveBuiltInApp.bind(this),244    this.detectUdid.bind(this),245    this.parseLocalizableStrings.bind(this),246    this.setBundleIdFromApp.bind(this),247    this.createInstruments.bind(this),248    this.setDeviceInfo.bind(this),249    this.checkPreferences.bind(this),250    this.runSimReset.bind(this),251    this.isolateSimDevice.bind(this),252    this.setLocale.bind(this),253    this.setPreferences.bind(this),254    this.startLogCapture.bind(this),255    this.prelaunchSimulator.bind(this),256    this.startInstruments.bind(this),257    this.onInstrumentsLaunch.bind(this),258    this.configureBootstrap.bind(this),259    this.setBundleId.bind(this),260    this.setInitialOrientation.bind(this),261    this.initAutoWebview.bind(this),262    this.waitForAppLaunched.bind(this),263  ], function (err) {264    cb(err);265  });266};267IOS.prototype.start = function (cb, onDie) {268  if (this.instruments !== null) {269    var msg = "Trying to start a session but instruments is still around";270    logger.error(msg);271    return cb(new Error(msg));272  }273  if (typeof onDie === "function") {274    this.onInstrumentsDie = onDie;275  }276  if (this.args.udid) {277    this.startRealDevice(cb);278  } else {279    this.startSimulator(cb);280  }281};282IOS.prototype.createInstruments = function (cb) {283  logger.debug("Creating instruments");284  this.commandProxy = new CommandProxy({ sock: this.sock });285  this.makeInstruments(function (err, instruments) {286    if (err) return cb(err);287    this.instruments = instruments;288    cb();289  }.bind(this));290};291IOS.prototype.startInstruments = function (cb) {292  cb = _.once(cb);293  var treatError = function (err, cb) {294    if (!_.isEmpty(this.logs)) {295      this.logs.syslog.stopCapture();296      this.logs = {};297    }298    this.postCleanup(function () {299      cb(err);300    });301  }.bind(this);302  logger.debug("Starting command proxy.");303  this.commandProxy.start(304    function onFirstConnection(err) {305      // first let instruments know so that it does not restart itself306      this.instruments.launchHandler(err);307      // then we call the callback308      cb(err);309    }.bind(this)310  , function regularCallback(err) {311      if (err) return treatError(err, cb);312      logger.debug("Starting instruments");313      this.instruments.start(314        function (err) {315          if (err) return treatError(err, cb);316          // we don't call cb here, waiting for first connection or error317        }.bind(this)318      , function (code) {319          if (!this.shouldIgnoreInstrumentsExit()) {320            this.onUnexpectedInstrumentsExit(code);321          }322        }.bind(this)323      );324    }.bind(this)325  );326};327IOS.prototype.makeInstruments = function (cb) {328  // at the moment all the logging in uiauto is at debug level329  // TODO: be able to use info in appium-uiauto330  var bootstrap = prepareBootstrap({331    sock: this.sock,332    interKeyDelay: this.args.interKeyDelay,333    justLoopInfinitely: false,334    autoAcceptAlerts: !(!this.args.autoAcceptAlerts || this.args.autoAcceptAlerts === 'false'),335    autoDismissAlerts: !(!this.args.autoDismissAlerts || this.args.autoDismissAlerts === 'false'),336    sendKeyStrategy: this.args.sendKeyStrategy || (this.args.udid ? 'grouped' : 'oneByOne')337  });338  bootstrap.then(function (bootstrapPath) {339      var instruments = new Instruments({340        // on real devices bundleId is always used341        app: (!this.args.udid ? this.args.app : null) || this.args.bundleId342      , udid: this.args.udid343      , processArguments: this.args.processArguments344      , ignoreStartupExit: this.shouldIgnoreInstrumentsExit()345      , bootstrap: bootstrapPath346      , template: this.args.automationTraceTemplatePath347      , instrumentsPath: this.args.instrumentsPath348      , withoutDelay: this.args.withoutDelay349      , platformVersion: this.args.platformVersion350      , webSocket: this.args.webSocket351      , launchTimeout: this.args.launchTimeout352      , flakeyRetries: this.args.backendRetries353      , simulatorSdkAndDevice: this.iOSSDKVersion >= 7.1 ? this.getDeviceString() : null354      , tmpDir: path.resolve(this.args.tmpDir , 'appium-instruments')355      , traceDir: this.args.traceDir356      });357      cb(null, instruments);358    }.bind(this), cb).fail(cb);359};360IOS.prototype.shouldIgnoreInstrumentsExit = function () {361  return false;362};363IOS.prototype.onInstrumentsLaunch = function (cb) {364  logger.debug('Instruments launched. Starting poll loop for new commands.');365  this.instruments.setDebug(true);366  if (this.args.origAppPath) {367    logger.debug("Copying app back to its original place");368    return ncp(this.args.app, this.args.origAppPath, cb);369  }370  cb();371};372IOS.prototype.setBundleId = function (cb) {373  if (this.args.bundleId) {374    // We already have a bundle Id375    cb();376  } else {377    this.proxy('au.bundleId()', function (err, bId) {378      if (err) return cb(err);379      logger.debug('Bundle ID for open app is ' + bId.value);380      this.args.bundleId = bId.value;381      cb();382    }.bind(this));383  }384};385IOS.prototype.setInitialOrientation = function (cb) {386  if (typeof this.args.initialOrientation === "string" &&387      _.contains(["LANDSCAPE", "PORTRAIT"],388                 this.args.initialOrientation.toUpperCase())389      ) {390    logger.debug("Setting initial orientation to " + this.args.initialOrientation);391    var command = ["au.setScreenOrientation('",392      this.args.initialOrientation.toUpperCase(), "')"].join('');393    this.proxy(command, function (err, res) {394      if (err || res.status !== status.codes.Success.code) {395        logger.warn("Setting initial orientation did not work!");396      } else {397        this.curOrientation = this.args.initialOrientation;398      }399      cb();400    }.bind(this));401  } else {402    cb();403  }404};405IOS.isSpringBoard = function (uiAppObj) {406// Test for iOS homescreen (SpringBoard). AUT occassionally start the sim, but fails to load407// the app. If that occurs, getSourceForElementFoXML will return a doc object that meets our408// app-check conditions, resulting in a false positive. This function tests the UiApplication409// property's meta data to ensure that the Appium doesn't confuse SpringBoard with the app410// under test.411  return _.propertyOf(uiAppObj['@'])('name') === 'SpringBoard';412};413IOS.prototype.waitForAppLaunched = function (cb) {414  // on iOS8 in particular, we can get a working session before the app415  // is ready to respond to commands; in that case the source will be empty416  // so we just spin until it's not417  var condFn;418  if (this.args.waitForAppScript) {419    // the default getSourceForElementForXML does not fit some use case, so making this customizable.420    // TODO: collect script from customer and propose several options, please comment in issue #4190.421    logger.debug("Using custom script to wait for app start:" + this.args.waitForAppScript);422    condFn = function (cb) {423      this.proxy('try{\n' + this.args.waitForAppScript +424                 '\n} catch(err) { $.log("waitForAppScript err: " + error); false; };',425        function (err, res) {426          cb(!!res.value, err);427        });428    }.bind(this);429  } else {430    logger.debug("Waiting for app source to contain elements");431    condFn = function (cb) {432      this.getSourceForElementForXML(null, function (err, res) {433        if (err || !res || res.status !== status.codes.Success.code) {434          return cb(false, err);435        }436        var sourceObj, appEls;437        try {438          sourceObj = JSON.parse(res.value);439          appEls = sourceObj.UIAApplication['>'];440          if (appEls.length > 0 && !IOS.isSpringBoard(sourceObj.UIAApplication)) {441            return cb(true);442          } else {443            return cb(false, new Error("App did not have elements"));444          }445        } catch (e) {446          return cb(false, new Error("Couldn't parse JSON source"));447        }448        return cb(true, err);449      });450    }.bind(this);451  }452  this.waitForCondition(10000, condFn, cb, 500);453};454IOS.prototype.configureBootstrap = function (cb) {455  logger.debug("Setting bootstrap config keys/values");456  var isVerbose = logger.transports.console.level === 'debug';457  var cmd = '';458  cmd += 'target = $.target();\n';459  cmd += 'au = $;\n';460  cmd += '$.isVerbose = ' + isVerbose + ';\n';461  // Not using uiauto grace period because of bug.462  // cmd += '$.target().setTimeout(1);\n';463  this.proxy(cmd, cb);464};465IOS.prototype.onUnexpectedInstrumentsExit = function (code) {466  logger.debug("Instruments exited unexpectedly");467  this.isShuttingDown = true;468  var postShutdown = function () {469    if (typeof this.cbForCurrentCmd === "function") {470      logger.debug("We were in the middle of processing a command when " +471                   "instruments died; responding with a generic error");472      var error = new UnknownError("Instruments died while responding to " +473                                   "command, please check appium logs");474      this.onInstrumentsDie(error, this.cbForCurrentCmd);475    } else {476      this.onInstrumentsDie();477    }478  }.bind(this);479  if (this.commandProxy) {480    this.commandProxy.safeShutdown(function () {481      this.shutdown(code, postShutdown);482    }.bind(this));483  } else {484    this.shutdown(code, postShutdown);485  }486};487IOS.prototype.setXcodeVersion = function (cb) {488  logger.debug("Setting Xcode version");489  xcode.getVersion(function (err, versionNumber) {490    if (err) {491      logger.error("Could not determine Xcode version:" + err.message);492    } else {493      var minorVersion = parseFloat(versionNumber.slice(0, 3));494      var pv = parseFloat(this.args.platformVersion);495      // we deprecate Xcodes < 6.3, except for iOS 8.0 in which case we496      // support Xcode 6.0 as well497      if (minorVersion < 6.3 && (!(minorVersion === 6.0 && pv === 8.0))) {498        logCustomDeprecationWarning('Xcode version', versionNumber,499                                    'Support for Xcode ' + versionNumber + ' ' +500                                    'has been deprecated and will be removed ' +501                                    'in a future version. Please upgrade ' +502                                    'to version 6.3 or higher (or version ' +503                                    '6.0.1 for iOS 8.0)');504      }505    }506    this.xcodeVersion = versionNumber;507    logger.debug("Xcode version set to " + versionNumber);508    cb();509  }.bind(this));510};511IOS.prototype.setiOSSDKVersion = function (cb) {512  logger.debug("Setting iOS SDK Version");513  xcode.getMaxIOSSDK(function (err, versionNumber) {514    if (err) {515      logger.error("Could not determine iOS SDK version");516      return cb(err);517    }518    this.iOSSDKVersion = versionNumber;519    logger.debug("iOS SDK Version set to " + this.iOSSDKVersion);520    cb();521  }.bind(this));522};523IOS.prototype.setLocale = function (cb) {524  var msg;525  var setLoc = function (err) {526    logger.debug("Setting locale information");527    if (err) return cb(err);528    var needSimRestart = false;529    this.localeConfig = this.localeConfig || {};530    _(['language', 'locale', 'calendarFormat']).each(function (key) {531      needSimRestart = needSimRestart ||532                      (this.args[key] &&533                       this.args[key] !== this.localeConfig[key]);534    }, this);535    this.localeConfig = {536      language: this.args.language,537      locale: this.args.locale,538      calendarFormat: this.args.calendarFormat539    };540    var simRoots = this.sim.getDirs();541    if (simRoots.length < 1) {542      msg = "Cannot set locale information because the iOS Simulator directory could not be determined.";543      logger.error(msg);544      return cb(new Error(msg));545    }546    try {547      this.sim.setLocale(this.args.language, this.args.locale, this.args.calendarFormat);548    } catch (e) {549      msg = "Appium was unable to set locale info: " + e;550      logger.error(msg);551      return cb(new Error(msg));552    }553    logger.debug("Locale was set");554    if (needSimRestart) {555      logger.debug("First time setting locale, or locale changed, killing existing Instruments and Sim procs.");556      Instruments.killAllSim();557      Instruments.killAll();558      setTimeout(cb, 250);559    } else {560      cb();561    }562  }.bind(this);563  if ((this.args.language || this.args.locale || this.args.calendarFormat) && this.args.udid === null) {564    if (this.args.fullReset && this.args.platformVersion <= 6.1) {565      msg = "Cannot set locale information because a full-reset was requested. full-reset interferes with the language/locale caps on iOS 6.1 and older";566      logger.error(msg);567      return cb(new Error(msg));568    }569    if (!this.sim.dirsExist()) {570      this.instantLaunchAndQuit(false, setLoc);571    } else {572      setLoc();573    }574  } else if (this.args.udid) {575    logger.debug("Not setting locale because we're using a real device");576    cb();577  } else {578    logger.debug("Not setting locale");579    cb();580  }581};582IOS.prototype.checkPreferences = function (cb) {583  logger.debug("Checking whether we need to set app preferences");584  if (this.args.udid !== null) {585    logger.debug("Not setting iOS and app preferences since we're on a real " +586                "device");587    return cb();588  }589  var settingsCaps = [590    'locationServicesEnabled',591    'locationServicesAuthorized',592    'safariAllowPopups',593    'safariIgnoreFraudWarning',594    'safariOpenLinksInBackground'595  ];596  var safariSettingsCaps = settingsCaps.slice(2, 5);597  this.needToSetPrefs = false;598  this.needToSetSafariPrefs = false;599  _.each(settingsCaps, function (cap) {600    if (_.has(this.capabilities, cap)) {601      this.needToSetPrefs = true;602      if (_.contains(safariSettingsCaps, cap)) {603        this.needToSetSafariPrefs = true;604      }605    }606  }.bind(this));607  this.keepAppToRetainPrefs = this.needToSetPrefs;608  cb();609};610IOS.prototype.setPreferences = function (cb) {611  if (!this.needToSetPrefs) {612    logger.debug("No iOS / app preferences to set");613    return cb();614  } else if (this.args.fullReset) {615    var msg = "Cannot set preferences because a full-reset was requested";616    logger.debug(msg);617    logger.error(msg);618    return cb(new Error(msg));619  }620  var setPrefs = function (err) {621    if (err) return cb(err);622    try {623      this.setLocServicesPrefs();624    } catch (e) {625      logger.error("Error setting location services preferences, prefs will not work");626      logger.error(e);627      logger.error(e.stack);628    }629    try {630      this.setSafariPrefs();631    } catch (e) {632      logger.error("Error setting safari preferences, prefs will not work");633      logger.error(e);634      logger.error(e.stack);635    }636    cb();637  }.bind(this);638  logger.debug("Setting iOS and app preferences");639  if (!this.sim.dirsExist() ||640      !settings.locServicesDirsExist(this.sim) ||641      (this.needToSetSafariPrefs && !this.sim.safariDirsExist())) {642    this.instantLaunchAndQuit(this.needToSetSafariPrefs, setPrefs);643  } else {644    setPrefs();645  }646};647IOS.prototype.instantLaunchAndQuit = function (needSafariDirs, cb) {648  logger.debug("Sim files for the " + this.iOSSDKVersion + " SDK do not yet exist, launching the sim " +649      "to populate the applications and preference dirs");650  var condition = function () {651    var simDirsExist = this.sim.dirsExist();652    var locServicesExist = settings.locServicesDirsExist(this.sim);653    var safariDirsExist = this.args.platformVersion < 7.0 ||654                          (this.sim.safariDirsExist() &&655                           (this.args.platformVersion < 8.0 ||656                            this.sim.userSettingsPlistExists())657                          );658    var okToGo = simDirsExist && locServicesExist &&659                 (!needSafariDirs || safariDirsExist);660    if (!okToGo) {661      logger.debug("We launched the simulator but the required dirs don't " +662                   "yet exist. Waiting some more...");663    }664    return okToGo;665  }.bind(this);666  this.prelaunchSimulator(function (err) {667    if (err) return cb(err);668    this.makeInstruments(function (err, instruments) {669      instruments.launchAndKill(condition, function (err) {670        if (err) return cb(err);671        this.endSimulator(cb);672      }.bind(this));673    }.bind(this));674  }.bind(this));675};676IOS.prototype.setLocServicesPrefs = function () {677  if (typeof this.capabilities.locationServicesEnabled !== "undefined" ||678      this.capabilities.locationServicesAuthorized) {679    var locServ = this.capabilities.locationServicesEnabled;680    locServ = locServ || this.capabilities.locationServicesAuthorized;681    locServ = locServ ? 1 : 0;682    logger.debug("Setting location services to " + locServ);683    settings.updateSettings(this.sim, 'locationServices', {684         LocationServicesEnabled: locServ,685        'LocationServicesEnabledIn7.0': locServ,686        'LocationServicesEnabledIn8.0': locServ687       }688    );689  }690  if (typeof this.capabilities.locationServicesAuthorized !== "undefined") {691    if (!this.args.bundleId) {692      var msg = "Can't set location services for app without bundle ID";693      logger.error(msg);694      throw new Error(msg);695    }696    var locAuth = !!this.capabilities.locationServicesAuthorized;697    if (locAuth) {698      logger.debug("Authorizing location services for app");699    } else {700      logger.debug("De-authorizing location services for app");701    }702    settings.updateLocationSettings(this.sim, this.args.bundleId, locAuth);703  }704};705IOS.prototype.setSafariPrefs = function () {706  var safariSettings = {};707  var val;708  if (_.has(this.capabilities, 'safariAllowPopups')) {709    val = !!this.capabilities.safariAllowPopups;710    logger.debug("Setting javascript window opening to " + val);711    safariSettings.WebKitJavaScriptCanOpenWindowsAutomatically = val;712    safariSettings.JavaScriptCanOpenWindowsAutomatically = val;713  }714  if (_.has(this.capabilities, 'safariIgnoreFraudWarning')) {715    val = !this.capabilities.safariIgnoreFraudWarning;716    logger.debug("Setting fraudulent website warning to " + val);717    safariSettings.WarnAboutFraudulentWebsites = val;718  }719  if (_.has(this.capabilities, 'safariOpenLinksInBackground')) {720    val = this.capabilities.safariOpenLinksInBackground ? 1 : 0;721    logger.debug("Setting opening links in background to " + !!val);722    safariSettings.OpenLinksInBackground = val;723  }724  if (_.size(safariSettings) > 0) {725    settings.updateSafariSettings(this.sim, safariSettings);726  }727};728IOS.prototype.detectUdid = function (cb) {729  var msg;730  logger.debug("Auto-detecting iOS udid...");731  if (this.args.udid !== null && this.args.udid === "auto") {732    which('idevice_id', function (notFound, cmdPath) {733      var udidetectPath;734      if (notFound) {735        udidetectPath = require.resolve('udidetect');736      } else {737        udidetectPath = cmdPath + " -l";738      }739      exec(udidetectPath, { maxBuffer: 524288, timeout: 3000 }, function (err, stdout) {740        if (err) {741          msg = "Error detecting udid: " + err.message;742          logger.error(msg);743          cb(err);744        }745        if (stdout && stdout.length > 2) {746          this.args.udid = stdout.split("\n")[0];747          logger.debug("Detected udid as " + this.args.udid);748          cb();749        } else {750          msg = "Could not detect udid.";751          logger.error(msg);752          cb(new Error(msg));753        }754      }.bind(this));755    }.bind(this));756  } else {757    logger.debug("Not auto-detecting udid, running on sim");758    cb();759  }760};761IOS.prototype.setBundleIdFromApp = function (cb) {762  // This method will try to extract the bundleId from the app763  if (this.args.bundleId) {764    // We aleady have a bundle Id765    cb();766  } else {767    this.getBundleIdFromApp(function (err, bundleId) {768      if (err) {769        logger.error("Could not set the bundleId from app.");770        return cb(err);771      }772      this.args.bundleId = bundleId;773      cb();774    }.bind(this));775  }776};777IOS.prototype.installToRealDevice = function (cb) {778  // if user has passed in desiredCaps.autoLaunch = false779  // meaning they will manage app install / launching780  if (this.args.autoLaunch === false) {781    cb();782  } else {783    if (this.args.udid) {784      try {785        this.realDevice = this.getIDeviceObj();786      } catch (e) {787        return cb(e);788      }789      this.isAppInstalled(this.args.bundleId, function (err, installed) {790        if (err || !installed) {791          logger.debug("App is not installed. Will try to install the app.");792        } else {793          logger.debug("App is installed.");794          if (this.args.fullReset) {795            logger.debug("fullReset requested. Forcing app install.");796          } else {797            logger.debug("fullReset not requested. No need to install.");798            return cb();799          }800        }801        if (this.args.ipa && this.args.bundleId) {802          this.installIpa(cb);803        } else if (this.args.ipa) {804          var msg = "You specified a UDID and ipa but did not include the bundle " +805            "id";806          logger.error(msg);807          cb(new Error(msg));808        } else if (this.args.app) {809          this.installApp(this.args.app, cb);810        } else {811          logger.debug("Real device specified but no ipa or app path, assuming bundle ID is " +812                       "on device");813          cb();814        }815      }.bind(this));816    } else {817      logger.debug("No device id or app, not installing to real device.");818      cb();819    }820  }821};822IOS.prototype.getIDeviceObj = function () {823  var idiPath = path.resolve(__dirname, "../../../build/",824                             "libimobiledevice-macosx/ideviceinstaller");825  logger.debug("Creating iDevice object with udid " + this.args.udid);826  try {827    return iDevice(this.args.udid);828  } catch (e1) {829    logger.debug("Couldn't find ideviceinstaller, trying built-in at " +830                idiPath);831    try {832      return iDevice(this.args.udid, {cmd: idiPath});833    } catch (e2) {834      var msg = "Could not initialize ideviceinstaller; make sure it is " +835                "installed and works on your system";836      logger.error(msg);837      throw new Error(msg);838    }839  }840};841IOS.prototype.installIpa = function (cb) {842  logger.debug("Installing ipa found at " + this.args.ipa);843  if (!this.realDevice) {844    this.realDevice = this.getIDeviceObj();845  }846  var d = this.realDevice;847  async.waterfall([848    function (cb) { d.isInstalled(this.args.bundleId, cb); }.bind(this),849    function (installed, cb) {850      if (installed) {851        logger.debug("Bundle found on device, removing before reinstalling.");852        d.remove(this.args.bundleId, cb);853      } else {854        logger.debug("Nothing found on device, going ahead and installing.");855        cb();856      }857    }.bind(this),858    function (cb) { d.installAndWait(this.args.ipa, this.args.bundleId, cb); }.bind(this)859  ], cb);860};861IOS.getDeviceStringFromOpts = function (opts) {862  logger.debug("Getting device string from opts: " + JSON.stringify({863    forceIphone: opts.forceIphone,864    forceIpad: opts.forceIpad,865    xcodeVersion: opts.xcodeVersion,866    iOSSDKVersion: opts.iOSSDKVersion,867    deviceName: opts.deviceName,868    platformVersion: opts.platformVersion869  }));870  var xcodeMajorVer = parseInt(opts.xcodeVersion.substr(0,871        opts.xcodeVersion.indexOf('.')), 10);872  var isiPhone = opts.forceIphone || opts.forceIpad === null || (opts.forceIpad !== null && !opts.forceIpad);873  var isTall = isiPhone;874  var isRetina = opts.xcodeVersion[0] !== '4';875  var is64bit = false;876  var deviceName = opts.deviceName;877  var fixDevice = true;878  if (deviceName && deviceName[0] === '=') {879    return deviceName.substring(1);880  }881  logger.debug("fixDevice is " + (fixDevice ? "on" : "off"));882  if (deviceName) {883    var device = deviceName.toLowerCase();884    if (device.indexOf("iphone") !== -1) {885      isiPhone = true;886    } else if (device.indexOf("ipad") !== -1) {887      isiPhone = false;888    }889    if (deviceName !== opts.platformName) {890      isTall = isiPhone && (device.indexOf("4-inch") !== -1);891      isRetina =  (device.indexOf("retina") !== -1);892      is64bit = (device.indexOf("64-bit") !== -1);893    }894  }895  var iosDeviceString = isiPhone ? "iPhone" : "iPad";896  if (xcodeMajorVer === 4) {897    if (isiPhone && isRetina) {898      iosDeviceString += isTall ? " (Retina 4-inch)" : " (Retina 3.5-inch)";899    } else {900      iosDeviceString += isRetina ? " (Retina)" : "";901    }902  } else if (xcodeMajorVer === 5) {903    iosDeviceString += isRetina ? " Retina" : "";904    if (isiPhone) {905      if (isRetina && isTall) {906        iosDeviceString += is64bit ? " (4-inch 64-bit)" : " (4-inch)";907      } else if (deviceName.toLowerCase().indexOf("3.5") !== -1) {908        iosDeviceString += " (3.5-inch)";909      }910    } else {911      iosDeviceString += is64bit ? " (64-bit)" : "";912    }913  } else if (_.contains([6, 7], xcodeMajorVer)) {914    iosDeviceString = opts.deviceName ||915      (isiPhone ? "iPhone Simulator" : "iPad Simulator");916  }917  var reqVersion = opts.platformVersion || opts.iOSSDKVersion;918  if (opts.iOSSDKVersion >= 8 && xcodeMajorVer === 7) {919    iosDeviceString += " (" + reqVersion + ")";920  } else if (opts.iOSSDKVersion >= 8) {921    iosDeviceString += " (" + reqVersion + " Simulator)";922  } else if (opts.iOSSDKVersion >= 7.1) {923    iosDeviceString += " - Simulator - iOS " + reqVersion;924  }925  if (fixDevice) {926    // Some device config are broken in 5.1927    var CONFIG_FIX = {928      'iPhone - Simulator - iOS 7.1': 'iPhone Retina (4-inch 64-bit) - ' +929                                      'Simulator - iOS 7.1',930      'iPad - Simulator - iOS 7.1': 'iPad Retina (64-bit) - Simulator - ' +931                                    'iOS 7.1',932      'iPad Simulator (8.0 Simulator)': 'iPad 2 (8.0 Simulator)',933      'iPad Simulator (8.1 Simulator)': 'iPad 2 (8.1 Simulator)',934      'iPad Simulator (8.2 Simulator)': 'iPad 2 (8.2 Simulator)',935      'iPad Simulator (8.3 Simulator)': 'iPad 2 (8.3 Simulator)',936      'iPad Simulator (8.4 Simulator)': 'iPad 2 (8.4 Simulator)',937      'iPad Simulator (7.1 Simulator)': 'iPad 2 (7.1 Simulator)',938      'iPhone Simulator (8.4 Simulator)': 'iPhone 6 (8.4 Simulator)',939      'iPhone Simulator (8.3 Simulator)': 'iPhone 6 (8.3 Simulator)',940      'iPhone Simulator (8.2 Simulator)': 'iPhone 6 (8.2 Simulator)',941      'iPhone Simulator (8.1 Simulator)': 'iPhone 6 (8.1 Simulator)',942      'iPhone Simulator (8.0 Simulator)': 'iPhone 6 (8.0 Simulator)',943      'iPhone Simulator (7.1 Simulator)': 'iPhone 5s (7.1 Simulator)'944    };945    // For xcode major version 7946    var CONFIG_FIX__XCODE_7 = {947      'iPad Simulator (8.1)': 'iPad 2 (8.1)',948      'iPad Simulator (8.2)': 'iPad 2 (8.2)',949      'iPad Simulator (8.3)': 'iPad 2 (8.3)',950      'iPad Simulator (8.4)': 'iPad 2 (8.4)',951      'iPhone Simulator (8.1)': 'iPhone 6 (8.1)',952      'iPhone Simulator (8.2)': 'iPhone 6 (8.2)',953      'iPhone Simulator (8.3)': 'iPhone 6 (8.3)',954      'iPhone Simulator (8.4)': 'iPhone 6 (8.4)',955      'iPad Simulator (9.0)': 'iPad 2 (9.0)',956      'iPad Simulator (9.1)': 'iPad 2 (9.1)',957      // Fixing ambiguous device name by adding '[' at the end so intruments958      // correctly starts iPhone 6 [udid] and not the iPhone 6 (9.0) + Apple Watch959      // for ios9.0 and above; see #5619960      'iPhone Simulator (9.0)': 'iPhone 6 (9.0) [',961      'iPhone Simulator (9.1)': 'iPhone 6 (9.1) [',962      'iPhone 6 (9.0)': 'iPhone 6 (9.0) [',963      'iPhone 6 (9.1)': 'iPhone 6 (9.1) ['964    };965    var configFix = xcodeMajorVer === 7 ? CONFIG_FIX__XCODE_7 : CONFIG_FIX;966    if (configFix[iosDeviceString]) {967      var oldDeviceString = iosDeviceString;968      iosDeviceString = configFix[iosDeviceString];969      logger.debug("Fixing device. Changed from: \"" + oldDeviceString +970                   "\" to: \"" + iosDeviceString + "\"");971    }972  }973  logger.debug("Final device string is: '" + iosDeviceString + "'");974  return iosDeviceString;975};976IOS.prototype.getDeviceString = function () {977  var opts = _.clone(this.args);978  _.extend(opts, {979    xcodeVersion: this.xcodeVersion,980    iOSSDKVersion: this.iOSSDKVersion981  });982  return IOS.getDeviceStringFromOpts(opts);983};984IOS.prototype.setDeviceTypeInInfoPlist = function (cb) {985  var plist = path.resolve(this.args.app, "Info.plist");986  var dString = this.getDeviceString();987  var isiPhone = dString.toLowerCase().indexOf("ipad") === -1;988  var deviceTypeCode = isiPhone ? 1 : 2;989  parsePlistFile(plist, function (err, obj) {990    if (err) {991      logger.error("Could not set the device type in Info.plist");992      return cb(err, null);993    } else {994      var newPlist;995      obj.UIDeviceFamily = [deviceTypeCode];996      if (binaryPlist) {997        newPlist = bplistCreate(obj);998      } else {999        newPlist = xmlplist.build(obj);1000      }1001      fs.writeFile(plist, newPlist, function (err) {1002        if (err) {1003          logger.error("Could not save new Info.plist");1004          cb(err);1005        } else {1006          logger.debug("Wrote new app Info.plist with device type");1007          cb();1008        }1009      }.bind(this));1010    }1011  }.bind(this));1012};1013IOS.prototype.getBundleIdFromApp = function (cb) {1014  logger.debug("Getting bundle ID from app");1015  var plist = path.resolve(this.args.app, "Info.plist");1016  parsePlistFile(plist, function (err, obj) {1017    if (err) {1018      logger.error("Could not get the bundleId from app.");1019      cb(err, null);1020    } else {1021      cb(null, obj.CFBundleIdentifier);1022    }1023  }.bind(this));1024};1025IOS.getSimForDeviceString = function (dString, availDevices) {1026  var matchedDevice = null;1027  var matchedUdid = null;1028  _.each(availDevices, function (device) {1029    if (device.indexOf(dString) !== -1) {1030      matchedDevice = device;1031      try {1032        matchedUdid = /.+\[([^\]]+)\]/.exec(device)[1];1033      } catch (e) {1034        matchedUdid = null;1035      }1036    }1037  });1038  return [matchedDevice, matchedUdid];1039};1040IOS.prototype.checkSimAvailable = function (cb) {1041  if (this.args.udid) {1042    logger.debug("Not checking whether simulator is available since we're on " +1043                 "a real device");1044    return cb();1045  }1046  if (this.iOSSDKVersion < 7.1) {1047    logger.debug("Instruments v < 7.1, not checking device string support");1048    return cb();1049  }1050  logger.debug("Checking whether instruments supports our device string");1051  Instruments.getAvailableDevicesWithRetry(3, function (err, availDevices) {1052    if (err) return cb(err);1053    var noDevicesError = function () {1054      var msg = "Could not find a device to launch. You requested '" +1055                dString + "', but the available devices were: " +1056                JSON.stringify(availDevices);1057      logger.error(msg);1058      cb(new Error(msg));1059    };1060    var dString = this.getDeviceString();1061    if (this.iOSSDKVersion >= 8) {1062      var sim = IOS.getSimForDeviceString(dString, availDevices);1063      if (sim[0] === null || sim[1] === null) {1064        return noDevicesError();1065      }1066      this.iOSSimUdid = sim[1];1067      logger.debug("iOS sim UDID is " + this.iOSSimUdid);1068      return cb();1069    } else if (!_.contains(availDevices, dString)) {1070      return noDevicesError();1071    }1072    cb();1073  }.bind(this));1074};1075IOS.prototype.setDeviceInfo = function (cb) {1076  this.shouldPrelaunchSimulator = false;1077  if (this.args.udid) {1078    logger.debug("Not setting device type since we're on a real device");1079    return cb();1080  }1081  if (!this.args.app && this.args.bundleId) {1082    logger.debug("Not setting device type since we're using bundle ID and " +1083                "assuming app is already installed");1084    return cb();1085  }1086  if (!this.args.deviceName &&1087      this.args.forceIphone === null &&1088      this.args.forceIpad === null) {1089    logger.debug("No device specified, current device in the iOS " +1090                 "simulator will be used.");1091    return cb();1092  }1093  if (this.args.defaultDevice || this.iOSSDKVersion >= 7.1) {1094    if (this.iOSSDKVersion >= 7.1) {1095      logger.debug("We're on iOS7.1+ so forcing defaultDevice on");1096    } else {1097      logger.debug("User specified default device, letting instruments launch it");1098    }1099  } else {1100    this.shouldPrelaunchSimulator = true;1101  }1102  this.setDeviceTypeInInfoPlist(cb);1103};1104IOS.prototype.createSimulator = function (cb) {1105  this.sim = new Simulator({1106    platformVer: this.args.platformVersion,1107    sdkVer: this.iOSSDKVersion,1108    udid: this.iOSSimUdid1109  });1110  cb();1111};1112IOS.prototype.moveBuiltInApp = function (cb) {1113  if (this.appString().toLowerCase() === "settings") {1114    logger.debug("Trying to use settings app, version " +1115                 this.args.platformVersion);1116    this.sim.preparePreferencesApp(this.args.tmpDir, function (err, attemptedApp, origApp) {1117      if (err) {1118        logger.error("Could not prepare settings app: " + err);1119        return cb(err);1120      }1121      logger.debug("Using settings app at " + attemptedApp);1122      this.args.app = attemptedApp;1123      this.args.origAppPath = origApp;1124      cb();1125    }.bind(this));1126  } else {1127    cb();1128  }1129};1130IOS.prototype.prelaunchSimulator = function (cb) {1131  var msg;1132  if (!this.shouldPrelaunchSimulator) {1133    logger.debug("Not pre-launching simulator");1134    return cb();1135  }1136  xcode.getPath(function (err, xcodePath) {1137    if (err) {1138      return cb(new Error('Could not find xcode folder. Needed to start simulator. ' + err.message));1139    }1140    logger.debug("Pre-launching simulator");1141    var iosSimPath = path.resolve(xcodePath,1142        "Platforms/iPhoneSimulator.platform/Developer/Applications" +1143        "/iPhone Simulator.app/Contents/MacOS/iPhone Simulator");1144    if (!fs.existsSync(iosSimPath)) {1145      msg = "Could not find ios simulator binary at " + iosSimPath;1146      logger.error(msg);1147      return cb(new Error(msg));1148    }1149    this.endSimulator(function (err) {1150      if (err) return cb(err);1151      logger.debug("Launching device: " + this.getDeviceString());1152      var iosSimArgs = ["-SimulateDevice", this.getDeviceString()];1153      this.iosSimProcess = spawn(iosSimPath, iosSimArgs);1154      var waitForSimulatorLogs = function (countdown) {1155        if (countdown <= 0 ||1156          (this.logs.syslog && (this.logs.syslog.getAllLogs().length > 0 ||1157          (this.logs.crashlog && this.logs.crashlog.getAllLogs().length > 0)))) {1158          logger.debug(countdown > 0 ? "Simulator is now ready." :1159                       "Waited 10 seconds for simulator to start.");1160          cb();1161        } else {1162          setTimeout(function () {1163            waitForSimulatorLogs(countdown - 1);1164          }, 1000);1165        }1166      }.bind(this);1167      waitForSimulatorLogs(10);1168    }.bind(this));1169  }.bind(this));1170};1171IOS.prototype.parseLocalizableStrings = function (/* language, stringFile, cb */) {1172  var args = new Args(arguments);1173  var cb = args.callback;1174  if (this.args.app === null) {1175    logger.debug("Localizable.strings is not currently supported when using real devices.");1176    return cb();1177  }1178  var language = args.all[0] || this.args.language1179    , stringFile = args.all[1] || "Localizable.strings"1180    , strings = null;1181  if (language) {1182    strings = path.resolve(this.args.app, language + ".lproj", stringFile);1183  }1184  if (!fs.existsSync(strings)) {1185    if (language) {1186      logger.debug("No strings file '" + stringFile + "' for language '" + language + "', getting default strings");1187    }1188    strings = path.resolve(this.args.app, stringFile);1189  }1190  if (!fs.existsSync(strings)) {1191    strings = path.resolve(this.args.app, this.args.localizableStringsDir, stringFile);1192  }1193  parsePlistFile(strings, function (err, obj) {1194    if (err) {1195      logger.warn("Could not parse app " + stringFile +" assuming it " +1196                  "doesn't exist");1197    } else {1198      logger.debug("Parsed app " + stringFile);1199      this.localizableStrings = obj;1200    }1201    cb();1202  }.bind(this));1203};1204IOS.prototype.deleteSim = function (cb) {1205  this.sim.deleteSim(cb);1206};1207IOS.prototype.clearAppData = function (cb) {1208  if (!this.keepAppToRetainPrefs && this.args.app && this.args.bundleId) {1209    this.sim.cleanCustomApp(path.basename(this.args.app), this.args.bundleId);1210  }1211  cb();1212};1213IOS.prototype.cleanupSimState = function (cb) {1214  if (this.realDevice && this.args.bundleId && this.args.fullReset) {1215    logger.debug("fullReset requested. Will try to uninstall the app.");1216    var bundleId = this.args.bundleId;1217    this.realDevice.remove(bundleId, function (err) {1218      if (err) {1219        this.removeApp(bundleId, function (err) {1220          if (err) {1221            logger.error("Could not remove " + bundleId + " from device");1222            cb(err);1223          } else {1224            logger.debug("Removed " + bundleId);1225            cb();1226          }1227        }.bind(this));1228      } else {1229        logger.debug("Removed " + bundleId);1230        cb();1231      }1232    }.bind(this));1233  } else if (!this.args.udid) {1234    this.sim.cleanSim(this.args.keepKeyChains, this.args.tmpDir, function (err) {1235      if (err) {1236        logger.error("Could not reset simulator. Leaving as is. Error: " + err.message);1237      }1238      this.clearAppData(cb);1239    }.bind(this));1240  } else {1241    logger.debug("On a real device; cannot clean device state");1242    cb();1243  }1244};1245IOS.prototype.runSimReset = function (cb) {1246  if (this.args.reset || this.args.fullReset) {1247    logger.debug("Running ios sim reset flow");1248    // The simulator process must be ended before we delete applications.1249    async.series([1250      this.endSimulator.bind(this),1251      function (cb) {1252        if (this.args.reset) {1253          this.cleanupSimState(cb);1254        } else {1255          cb();1256        }1257      }.bind(this),1258      function (cb) {1259        if (this.args.fullReset && !this.args.udid) {1260          this.deleteSim(cb);1261        } else {1262          cb();1263        }1264      }.bind(this)1265    ], cb);1266  } else {1267    logger.debug("Reset not set, not ending sim or cleaning up app state");1268    cb();1269  }1270};1271IOS.prototype.isolateSimDevice = function (cb) {1272  if (!this.args.udid && this.args.isolateSimDevice &&1273      this.iOSSDKVersion >= 8) {1274    this.sim.deleteOtherSims(cb);1275  } else {1276    cb();1277  }1278};1279IOS.prototype.postCleanup = function (cb) {1280  this.curCoords = null;1281  this.curOrientation = null;1282  if (!_.isEmpty(this.logs)) {1283    this.logs.syslog.stopCapture();1284    this.logs = {};1285  }1286  if (this.remote) {1287    this.stopRemote();1288  }1289  this.runSimReset(function () {1290    // ignore any errors during reset and continue shutting down1291    this.isShuttingDown = false;1292    cb();1293  }.bind(this));1294};1295IOS.prototype.endSimulator = function (cb) {1296  logger.debug("Killing the simulator process");1297  if (this.iosSimProcess) {1298    this.iosSimProcess.kill("SIGHUP");1299    this.iosSimProcess = null;1300  } else {1301    Instruments.killAllSim();1302  }1303  this.endSimulatorDaemons(cb);1304};1305IOS.prototype.endSimulatorDaemons = function (cb) {1306  logger.debug("Killing any other simulator daemons");1307  var stopCmd = 'launchctl list | grep com.apple.iphonesimulator | cut -f 3 | xargs -n 1 launchctl stop';1308  exec(stopCmd, { maxBuffer: 524288 }, function () {1309    var removeCmd = 'launchctl list | grep com.apple.iphonesimulator | cut -f 3 | xargs -n 1 launchctl remove';1310    exec(removeCmd, { maxBuffer: 524288 }, function () {1311      cb();1312    });1313  });1314};1315IOS.prototype.stop = function (cb) {1316  logger.debug("Stopping ios");1317  if (this.instruments === null) {1318    logger.debug("Trying to stop instruments but it already exited");1319    this.postCleanup(cb);1320  } else {1321    this.commandProxy.shutdown(function (err) {1322      if (err) logger.warn("Got warning when trying to close command proxy:", err);1323      this.instruments.shutdown(function (code) {1324        this.shutdown(code, cb);1325      }.bind(this));1326    }.bind(this));1327  }1328};1329IOS.prototype.shutdown = function (code, cb) {1330  this.commandProxy = null;1331  this.instruments = null;1332  this.postCleanup(cb);1333};1334IOS.prototype.resetTimeout = deviceCommon.resetTimeout;1335IOS.prototype.waitForCondition = deviceCommon.waitForCondition;1336IOS.prototype.implicitWaitForCondition = deviceCommon.implicitWaitForCondition;1337IOS.prototype.proxy = deviceCommon.proxy;1338IOS.prototype.proxyWithMinTime = deviceCommon.proxyWithMinTime;1339IOS.prototype.respond = deviceCommon.respond;1340IOS.prototype.getSettings = deviceCommon.getSettings;1341IOS.prototype.updateSettings = deviceCommon.updateSettings;1342IOS.prototype.initQueue = function () {1343  this.queue = async.queue(function (command, cb) {1344    if (!this.commandProxy) return cb();1345    async.series([1346      function (cb) {1347        async.whilst(1348          function () { return this.selectingNewPage && this.curContext; }.bind(this),1349          function (cb) {1350            logger.debug("We're in the middle of selecting a new page, " +1351                        "waiting to run next command until done");1352            setTimeout(cb, 100);1353          },1354          cb1355        );1356      }.bind(this),1357      function (cb) {1358        var matched = false;1359        var matches = ["au.alertIsPresent", "au.getAlertText", "au.acceptAlert",1360                       "au.dismissAlert", "au.setAlertText",1361                       "au.waitForAlertToClose"];1362        _.each(matches, function (match) {1363          if (command.indexOf(match) === 0) {1364            matched = true;1365          }1366        });1367        async.whilst(1368          function () { return !matched && this.curContext && this.processingRemoteCmd; }.bind(this),1369          function (cb) {1370            logger.debug("We're in the middle of processing a remote debugger " +1371                        "command, waiting to run next command until done");1372            setTimeout(cb, 100);1373          },1374          cb1375        );1376      }.bind(this)1377    ], function (err) {1378      if (err) return cb(err);1379      this.cbForCurrentCmd = cb;1380      if (this.commandProxy) {1381        this.commandProxy.sendCommand(command, function (response) {1382          this.cbForCurrentCmd = null;1383          if (typeof cb === 'function') {1384            this.respond(response, cb);1385          }1386        }.bind(this));1387      }1388    }.bind(this));1389  }.bind(this), 1);1390};1391IOS.prototype.push = function (elem) {1392  this.queue.push(elem[0], elem[1]);1393};1394IOS.prototype.isAppInstalled = function (bundleId, cb) {1395  if (this.args.udid) {1396    this.realDevice.isInstalled(bundleId, cb);1397  } else {1398    cb(new Error("You can not call isInstalled for the iOS simulator!"));1399  }1400};1401IOS.prototype.removeApp = function (bundleId, cb) {1402  if (this.args.udid) {1403    this.realDevice.remove(bundleId, cb);1404  } else {1405    cb(new Error("You can not call removeApp for the iOS simulator!"));1406  }1407};1408IOS.prototype.installApp = function (unzippedAppPath, cb) {1409  if (this.args.udid) {1410    this.realDevice.install(unzippedAppPath, cb);1411  } else {1412    cb(new Error("You can not call installApp for the iOS simulator!"));1413  }1414};1415IOS.prototype.unpackApp = function (req, cb) {1416  deviceCommon.unpackApp(req, '.app', cb);1417};1418IOS.prototype.startLogCapture = function (cb) {1419  if (!_.isEmpty(this.logs)) {1420    cb(new Error("Trying to start iOS log capture but it's already started!"));1421    return;1422  }1423  this.logs.crashlog = new iOSCrashLog();1424  this.logs.syslog = new iOSLog({1425    udid: this.args.udid1426  , simUdid: this.iOSSimUdid1427  , showLogs: this.args.showSimulatorLog || this.args.showIOSLog1428  });1429  this.logs.syslog.startCapture(function (err) {1430    if (err) {1431      logger.warn("Could not capture logs from device. Continuing without capturing logs.");1432      return cb();1433    }1434    this.logs.crashlog.startCapture(cb);1435  }.bind(this));1436};1437IOS.prototype.initAutoWebview = function (cb) {1438  if (this.args.autoWebview) {1439    logger.debug('Setting auto webview');1440    this.navToInitialWebview(cb);1441  } else {1442    cb();1443  }1444};1445IOS.prototype.getContextsAndViews = function (cb) {1446  this.listWebFrames(function (err, webviews) {1447    if (err) return cb(err);1448    var ctxs = [{id: this.NATIVE_WIN}];1449    this.contexts = [this.NATIVE_WIN];1450    _.each(webviews, function (view) {1451      ctxs.push({id: this.WEBVIEW_BASE + view.id, view: view});1452      this.contexts.push(view.id.toString());1453    }.bind(this));1454    cb(null, ctxs);1455  }.bind(this));1456};1457IOS.prototype.getLatestWebviewContextForTitle = function (titleRegex, cb) {1458  this.getContextsAndViews(function (err, contexts) {1459    if (err) return cb(err);1460    var matchingCtx;1461    _(contexts).each(function (ctx) {1462      if (ctx.view && (ctx.view.title || "").match(titleRegex)) {1463        if (ctx.view.url === "about:blank") {1464          // in the cases of Xcode < 5 (i.e., iOS SDK Version less than 7)1465          // iOS 7.1, iOS 9.0 & iOS 9.1 in a webview (not in Safari)1466          // we can have the url be `about:blank`1467          if (parseFloat(this.iOSSDKVersion) < 7 || parseFloat(this.iOSSDKVersion) >= 9 ||1468              (this.args.platformVersion === '7.1' && this.args.app && this.args.app.toLowerCase() !== 'safari')) {1469            matchingCtx = ctx;1470          }1471        } else {1472          matchingCtx = ctx;1473        }1474      }1475    }.bind(this));1476    cb(null, matchingCtx ? matchingCtx.id : undefined);1477  }.bind(this));1478};1479// Right now we don't necessarily wait for webview1480// and frame to load, which leads to race conditions and flakiness1481// , let see if we can transition to something better1482IOS.prototype.useNewSafari = function () {1483  return parseFloat(this.iOSSDKVersion) >= 8.1 &&1484         parseFloat(this.args.platformVersion) >= 8.1 &&1485         !this.args.udid &&1486         this.capabilities.safari;1487};1488IOS.prototype.navToInitialWebview = function (cb) {1489  var timeout = 0;1490  if (this.args.udid) timeout = parseInt(this.iOSSDKVersion, 10) >= 8 ? 4000 : 6000;1491  if (timeout > 0) logger.debug('Waiting for ' + timeout + ' ms before navigating to view.');1492  setTimeout(function () {1493    if (this.useNewSafari()) {1494      return this.typeAndNavToUrl(cb);1495    } else if (parseInt(this.iOSSDKVersion, 10) >= 7 && !this.args.udid && this.capabilities.safari) {1496      this.navToViewThroughFavorites(cb);1497    } else {1498      this.navToViewWithTitle(/.*/, cb);1499    }1500  }.bind(this), timeout);1501};1502IOS.prototype.typeAndNavToUrl = function (cb) {1503  var initialUrl = this.args.safariInitialUrl || 'http://127.0.0.1:' + this.args.port + '/welcome';1504  var oldImpWait = this.implicitWaitMs;1505  this.implicitWaitMs = 7000;1506  function noArgsCb(cb) { return function (err) { cb(err); }; }1507  async.waterfall([1508    this.findElement.bind(this, 'name', 'URL'),1509    function (res, cb) {1510      this.implicitWaitMs = oldImpWait;1511      this.nativeTap(res.value.ELEMENT, noArgsCb(cb));1512    }.bind(this),1513    this.findElements.bind(this, 'name', 'Address'),1514    function (res, cb) {1515      var addressEl = res.value[res.value.length -1].ELEMENT;1516      this.setValueImmediate(addressEl, initialUrl, noArgsCb(cb));1517    }.bind(this),1518    this.findElement.bind(this, 'name', 'Go'),1519    function (res, cb) {1520      this.nativeTap(res.value.ELEMENT, noArgsCb(cb));1521    }.bind(this)1522  ], function () {1523    this.navToViewWithTitle(/.*/i, function (err) {1524      if (err) return cb(err);1525      // Waits for page to finish loading.1526      this.remote.pageUnload(cb);1527    }.bind(this));1528  }.bind(this));1529};1530IOS.prototype.navToViewThroughFavorites = function (cb) {1531  logger.debug("We're on iOS7+ simulator: clicking apple button to get into " +1532              "a webview");1533  var oldImpWait = this.implicitWaitMs;1534  this.implicitWaitMs = 7000; // wait 7s for apple button to exist1535  this.findElement('xpath', '//UIAScrollView[1]/UIAButton[1]', function (err, res) {1536    this.implicitWaitMs = oldImpWait;1537    if (err || res.status !== status.codes.Success.code) {1538      var msg = "Could not find button to click to get into webview. " +1539                "Proceeding on the assumption we have a working one.";1540      logger.error(msg);1541      return this.navToViewWithTitle(/.*/i, cb);1542    }1543    this.nativeTap(res.value.ELEMENT, function (err, res) {1544      if (err || res.status !== status.codes.Success.code) {1545        var msg = "Could not click button to get into webview. " +1546                  "Proceeding on the assumption we have a working one.";1547        logger.error(msg);1548      }1549      this.navToViewWithTitle(/apple/i, cb);1550    }.bind(this));1551  }.bind(this));1552};1553IOS.prototype.navToViewWithTitle = function (titleRegex, cb) {1554  logger.debug("Navigating to most recently opened webview");1555  var start = Date.now();1556  var spinTime = 500;1557  var spinHandles = function () {1558    this.getLatestWebviewContextForTitle(titleRegex, function (err, res) {1559      if (err) {1560        cb(new Error("Could not navigate to webview! Err: " + err));1561      } else if (!res) {1562        if ((Date.now() - start) < 90000) {1563          logger.warn("Could not find any webviews yet, refreshing/retrying");1564          if (this.args.udid || !this.capabilities.safari) {1565            return setTimeout(spinHandles, spinTime);1566          }1567          this.findUIElementOrElements('accessibility id', 'ReloadButton',1568              '', false, function (err, res) {1569            if (err || !res || !res.value || !res.value.ELEMENT) {1570              logger.warn("Could not find reload button, continuing");1571              setTimeout(spinHandles, spinTime);1572            } else {1573              this.nativeTap(res.value.ELEMENT, function (err, res) {1574                if (err || !res) {1575                  logger.warn("Could not click reload button, continuing");1576                }1577                setTimeout(spinHandles, spinTime);1578              }.bind(this));1579            }1580          }.bind(this));1581        } else {1582          cb(new Error("Could not navigate to webview; there aren't any!"));1583        }1584      } else {1585        var latestWindow = res;1586        logger.debug("Picking webview " + latestWindow);1587        this.setContext(latestWindow, function (err) {1588          if (err) return cb(err);1589          this.remote.cancelPageLoad();1590          cb();1591        }.bind(this), true);1592      }1593    }.bind(this));1594  }.bind(this);1595  spinHandles();1596};1597_.extend(IOS.prototype, iOSHybrid);1598_.extend(IOS.prototype, iOSController);...

Full Screen

Full Screen

driver.js

Source:driver.js Github

copy

Full Screen

...301    await this.startInstruments();302    await this.onInstrumentsLaunch();303    await this.configureBootstrap();304    await this.setBundleId();305    await this.setInitialOrientation();306    await this.initAutoWebview();307    await this.waitForAppLaunched();308  }309  async startRealDevice () {310    await utils.removeInstrumentsSocket(this.sock);311    this.opts.localizableStrings = await utils.parseLocalizableStrings(this.opts);312    await utils.setBundleIdFromApp(this.opts);313    await this.createInstruments();314    await runRealDeviceReset(this.realDevice, this.opts);315    await this.setUpLogCapture();316    await this.installToRealDevice();317    await this.startInstruments();318    await this.onInstrumentsLaunch();319    await this.configureBootstrap();320    await this.setBundleId();321    await this.setInitialOrientation();322    await this.initAutoWebview();323    await this.waitForAppLaunched();324  }325  async installToRealDevice () {326    // if user has passed in desiredCaps.autoLaunch = false327    // meaning they will manage app install / launching328    if (this.opts.autoLaunch === false) {329      return;330    }331    // if we have an ipa file, set it in opts332    if (this.opts.app) {333      let ext = this.opts.app.substring(this.opts.app.length - 3).toLowerCase();334      if (ext === 'ipa') {335        this.opts.ipa = this.opts.app;...

Full Screen

Full Screen

DeviceOrientationControls.js

Source:DeviceOrientationControls.js Github

copy

Full Screen

1/**2 * @author richt / http://richt.me3 * @author WestLangley / http://github.com/WestLangley4 *5 * W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)6 */7THREE.DeviceOrientationControls = function ( object ) {8	var scope = this;9	this.object = object;10	this.object.rotation.reorder( 'YXZ' );11	this.enabled = true;12	this.deviceOrientation = {};13	this.screenOrientation = 0;14	this.alphaOffset = 0; // radians15	this.enableScreenOrientation = false;16	this._initialX = 0;17	this._initialY = 0;18	this._initialZ = 0;19	var onDeviceOrientationChangeEvent = function ( event ) {20		scope.deviceOrientation = event;21	};22	var onScreenOrientationChangeEvent = function () {23		if (scope.enableScreenOrientation) {24			scope.screenOrientation = window.orientation || 0;25		}26	};27	// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''28	var setObjectQuaternion = function () {29		var zee = new THREE.Vector3( 0, 0, 1 );30		var euler = new THREE.Euler();31		var q0 = new THREE.Quaternion();32		var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis33		return function ( quaternion, alpha, beta, gamma, orient ) {34			euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us35			// euler.set( 36			// 	(beta - this._initialY),37			// 	(alpha - this._initialX),38			// 	-(gamma - this._initialZ),39			// 	'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us40			quaternion.setFromEuler( euler ); // orient the device41			quaternion.multiply( q1 ); // camera looks out the back of the device, not the top42			quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation43		};44	}();45	this.connect = function () {46		onScreenOrientationChangeEvent(); // run once on load47		window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );48		window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );49		scope.enabled = true;50	};51	this.disconnect = function () {52		window.removeEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );53		window.removeEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );54		scope.enabled = false;55	};56	this.setInitialOrientation = function(x, y, z) {57		this._initialX = x;58		this._initialY = y;59		this._initialZ = z;60	}61	this.update = function () {62		if ( scope.enabled === false ) return;63		var device = scope.deviceOrientation;64		if ( device ) {65			var alpha = device.alpha ? THREE.Math.degToRad( device.alpha ) + scope.alphaOffset : 0; // Z66			var beta = device.beta ? THREE.Math.degToRad( device.beta ) : 0; // X'67			var gamma = device.gamma ? THREE.Math.degToRad( device.gamma ) : 0; // Y''68			var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O69			setObjectQuaternion( scope.object.quaternion, alpha, beta, gamma, orient );70		}71	};72	this.dispose = function () {73		scope.disconnect();74	};75	this.connect();...

Full Screen

Full Screen

lightsaberControls.js

Source:lightsaberControls.js Github

copy

Full Screen

1function lightsaberControls(lightsaberMesh) {2  // public properties3  // private variables4  let _orientationData = { x: 0, y: 0, z: 0 };5  let _initialOrientationData = { x: 0, y: 0, z: 0 };6  let _controls = null;7  let _lightsaberMesh = lightsaberMesh;8  // public methods9  this.orientation = orientation;10  this.setInitialOrientation = setInitialOrientation;11  this.setOrientation = setOrientation;12  this.update = update;13  14  // method definitions15  _init()16  function _init() {17    _controls = new THREE.DeviceOrientationControls( _lightsaberMesh, true );18  }19  function orientation() {20    return _orientationData;21  }22  function setInitialOrientation() {23    console.log('calibrating...');24    // controls.setInitialOrientation(cube.rotation.x, cube.rotation.y, cube.rotation.z);25    _initialOrientationData.x = _lightsaberMesh.rotation.x;26    _initialOrientationData.y = _lightsaberMesh.rotation.y;27    _initialOrientationData.z = _lightsaberMesh.rotation.z;28    // screen.orientation.lock();29    // screen.lockOrientation("portrait-primary");30  }31  function setOrientation(orientation) {32    _lightsaberMesh.rotation.x = orientation.x;33    _lightsaberMesh.rotation.y = orientation.y;34    _lightsaberMesh.rotation.z = orientation.z;35  }36  function update() {37    _controls.update();38    // console.log('cube: \n' + JSON.stringify(cube));39    _orientationData.x = _lightsaberMesh.rotation.x - _initialOrientationData.x;40    _orientationData.y = _lightsaberMesh.rotation.y - _initialOrientationData.y;41    _orientationData.z = _lightsaberMesh.rotation.z - _initialOrientationData.z;42    console.log('orientation: \n' + JSON.stringify(_orientationData));43    // socket.emit('peer-msg', _orientationData);44  }45  46}...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1this.setInitialOrientation('LANDSCAPE');2this.getOrientation();3this.rotate('LANDSCAPE');4this.hideKeyboard();5this.isKeyboardShown();6this.getAlertText();7this.setAlertText('Hello');8this.acceptAlert();9this.dismissAlert();10this.getGeoLocation();11this.setGeoLocation(45.123, -122.123);12this.getNetworkConnection();13this.setNetworkConnection(0);14this.getPerformanceData('com.apple.mobilesafari', 'cpu', 3);15this.getPerformanceDataTypes();16this.getPerformanceDataTypes();17this.touchId(true);18this.toggleTouchIdEnrollment(true);19this.getSettings();20this.updateSettings({});21this.getClipboard();

Full Screen

Using AI Code Generation

copy

Full Screen

1var webdriver = require('selenium-webdriver');2var driver = new webdriver.Builder()3    .forBrowser('chrome')4    .build();5driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');6driver.findElement(webdriver.By.name('btnG')).click();7driver.wait(function() {8  return driver.getTitle().then(function(title) {9    return title === 'webdriver - Google Search';10  });11}, 1000);12driver.quit();13appium --webdriveragent-port 8100 --default-capabilities '{"udid":"00008020-001F9C1C0E80002E", "bundleId":"com.apple.mobilesafari"}'

Full Screen

Using AI Code Generation

copy

Full Screen

1const { remote } = require('webdriverio')2async function main() {3    const client = await remote({4        capabilities: {5        }6    })7    await client.setInitialOrientation('LANDSCAPE')8    await client.pause(1000)9    await client.setInitialOrientation('PORTRAIT')10    await client.pause(1000)11    await client.deleteSession()12}13main()

Full Screen

Using AI Code Generation

copy

Full Screen

1var assert = require('assert');2var webdriverio = require('webdriverio');3var desiredCaps = {4};5var client = webdriverio.remote({6});7client.init()8  .then(function() {9    return client.setInitialOrientation('LANDSCAPE');10  })11  .then(function() {12    return client.orientation();13  })14  .then(function(orientation) {15    assert.equal(orientation, 'LANDSCAPE');16  })17  .then(function() {18    return client.end();19  })20  .catch(function(err) {21    console.log(err);22  });23var assert = require('assert');24var webdriverio = require('webdriverio');25var desiredCaps = {26};27var client = webdriverio.remote({28});29client.init()30  .then(function() {31    return client.setInitialOrientation('LANDSCAPE');32  })33  .then(function() {34    return client.orientation();35  })36  .then(function(orientation) {37    assert.equal(orientation, 'LANDSCAPE');38  })39  .then(function() {40    return client.end();41  })42  .catch(function(err) {43    console.log(err);44  });45var assert = require('assert');46var webdriverio = require('webdriverio');47var desiredCaps = {48};49var client = webdriverio.remote({50});

Full Screen

Using AI Code Generation

copy

Full Screen

1const wd = require('wd');2async function main() {3  const driver = await wd.promiseChainRemote({4  });5  await driver.init({6  });7  await driver.setInitialOrientation('LANDSCAPE');8}9main();10const wd = require('wd');11async function main() {12  const driver = await wd.promiseChainRemote({13  });14  await driver.init({15  });16  await driver.setInitialOrientation('PORTRAIT');17}18main();19const wd = require('wd');20async function main() {21  const driver = await wd.promiseChainRemote({22  });23  await driver.init({24  });25  await driver.setInitialOrientation('LANDSCAPE');26}27main();28const wd = require('wd');29async function main() {30  const driver = await wd.promiseChainRemote({31  });32  await driver.init({

Full Screen

Using AI Code Generation

copy

Full Screen

1const wdio = require('webdriverio');2const opts = {3  capabilities: {4  },5};6async function main() {7  const client = await wdio.remote(opts);8  await client.setInitialOrientation('LANDSCAPE');9  await client.pause(5000);10  await client.setInitialOrientation('PORTRAIT');11  await client.pause(5000);12  await client.deleteSession();13}14main();15const wdio = require('webdriverio');16const opts = {17  capabilities: {18  },19};20async function main() {21  const client = await wdio.remote(opts);22  await client.pause(5000);23  await client.setInitialOrientation('PORTRAIT');

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Appium Xcuitest Driver automation tests on LambdaTest cloud grid

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

Sign up Free
_

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful