UNPKG

appium-ios-simulator

Version:
1,433 lines (1,165 loc) 98 kB
'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _slicedToArray = require('babel-runtime/helpers/sliced-to-array')['default']; var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; var _getIterator = require('babel-runtime/core-js/get-iterator')['default']; var _Object$assign = require('babel-runtime/core-js/object/assign')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; var _interopRequireWildcard = require('babel-runtime/helpers/interop-require-wildcard')['default']; Object.defineProperty(exports, '__esModule', { value: true }); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _nodeSimctl = require('node-simctl'); var simctl = _interopRequireWildcard(_nodeSimctl); var _appiumXcode = require('appium-xcode'); var _logger = require('./logger'); var _logger2 = _interopRequireDefault(_logger); var _appiumSupport = require('appium-support'); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _utilsJs = require('./utils.js'); var _asyncbox = require('asyncbox'); var _settings = require('./settings'); var settings = _interopRequireWildcard(_settings); var _teen_process = require('teen_process'); var _appiumXcode2 = _interopRequireDefault(_appiumXcode); var _tailUntilJs = require('./tail-until.js'); var _extensionsIndex = require('./extensions/index'); var _extensionsIndex2 = _interopRequireDefault(_extensionsIndex); var SimulatorXcode6 = (function () { function SimulatorXcode6(udid, xcodeVersion) { _classCallCheck(this, SimulatorXcode6); this.udid = String(udid); this.xcodeVersion = xcodeVersion; // platformVersion cannot be found initially, since getting it has side effects for // our logic for figuring out if a sim has been run // it will be set when it is needed this._platformVersion = null; this.keychainPath = _path2['default'].resolve(this.getDir(), 'Library', 'Keychains'); this.simulatorApp = 'iOS Simulator.app'; this.appDataBundlePaths = {}; } _createClass(SimulatorXcode6, [{ key: 'getPlatformVersion', value: function getPlatformVersion() { var _ref, sdk; return _regeneratorRuntime.async(function getPlatformVersion$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (this._platformVersion) { context$2$0.next = 6; break; } context$2$0.next = 3; return _regeneratorRuntime.awrap(this.stat()); case 3: _ref = context$2$0.sent; sdk = _ref.sdk; this._platformVersion = sdk; case 6: return context$2$0.abrupt('return', this._platformVersion); case 7: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'getRootDir', value: function getRootDir() { var home = process.env.HOME; return _path2['default'].resolve(home, 'Library', 'Developer', 'CoreSimulator', 'Devices'); } }, { key: 'getDir', value: function getDir() { return _path2['default'].resolve(this.getRootDir(), this.udid, 'data'); } }, { key: 'getLogDir', value: function getLogDir() { var home = process.env.HOME; return _path2['default'].resolve(home, 'Library', 'Logs', 'CoreSimulator', this.udid); } /* * takes an `id`, which is either a bundleId (e.g., com.apple.mobilesafari) * or, for iOS 7.1, the app name without `.app` (e.g., MobileSafari) */ }, { key: 'getAppDir', value: function getAppDir(id) { var subDir = arguments.length <= 1 || arguments[1] === undefined ? 'Data' : arguments[1]; return _regeneratorRuntime.async(function getAppDir$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.isFresh()); case 2: if (!context$2$0.sent) { context$2$0.next = 6; break; } _logger2['default'].info('Attempted to get an app path from a fresh simulator ' + 'quickly launching the sim to populate its directories'); context$2$0.next = 6; return _regeneratorRuntime.awrap(this.launchAndQuit()); case 6: if (this.appDataBundlePaths[subDir]) { context$2$0.next = 10; break; } context$2$0.next = 9; return _regeneratorRuntime.awrap(this.buildBundlePathMap(subDir)); case 9: this.appDataBundlePaths[subDir] = context$2$0.sent; case 10: return context$2$0.abrupt('return', this.appDataBundlePaths[subDir][id]); case 11: case 'end': return context$2$0.stop(); } }, null, this); } /* * the xcode 6 simulators are really annoying, and bury the main app * directories inside directories just named with Hashes. * This function finds the proper directory by traversing all of them * and reading a metadata plist (Mobile Container Manager) to get the * bundle id. */ }, { key: 'buildBundlePathMap', value: function buildBundlePathMap() { var subDir = arguments.length <= 0 || arguments[0] === undefined ? 'Data' : arguments[0]; var applicationList, pathBundlePair, bundlePathDirs, bundlePathPairs; return _regeneratorRuntime.async(function buildBundlePathMap$(context$2$0) { var _this = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: applicationList = undefined; pathBundlePair = undefined; context$2$0.next = 4; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 4: context$2$0.t0 = context$2$0.sent; if (!(context$2$0.t0 === '7.1')) { context$2$0.next = 10; break; } // apps available // Web.app, // WebViewService.app, // MobileSafari.app, // WebContentAnalysisUI.app, // DDActionsService.app, // StoreKitUIService.app applicationList = _path2['default'].resolve(this.getDir(), 'Applications'); pathBundlePair = function callee$2$0(dir) { var appFiles, bundleId; return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: dir = _path2['default'].resolve(applicationList, dir); context$3$0.next = 3; return _regeneratorRuntime.awrap(_appiumSupport.fs.glob(dir + '/*.app')); case 3: appFiles = context$3$0.sent; bundleId = appFiles[0].match(/.*\/(.*)\.app/)[1]; return context$3$0.abrupt('return', { path: dir, bundleId: bundleId }); case 6: case 'end': return context$3$0.stop(); } }, null, _this); }; context$2$0.next = 11; break; case 10: (function () { applicationList = _path2['default'].resolve(_this.getDir(), 'Containers', subDir, 'Application'); // given a directory, find the plist file and pull the bundle id from it var readBundleId = function readBundleId(dir) { var plist, metadata; return _regeneratorRuntime.async(function readBundleId$(context$4$0) { while (1) switch (context$4$0.prev = context$4$0.next) { case 0: plist = _path2['default'].resolve(dir, '.com.apple.mobile_container_manager.metadata.plist'); context$4$0.next = 3; return _regeneratorRuntime.awrap(settings.read(plist)); case 3: metadata = context$4$0.sent; return context$4$0.abrupt('return', metadata.MCMMetadataIdentifier); case 5: case 'end': return context$4$0.stop(); } }, null, _this); }; // given a directory, return the path and bundle id associated with it pathBundlePair = function callee$3$0(dir) { var bundleId; return _regeneratorRuntime.async(function callee$3$0$(context$4$0) { while (1) switch (context$4$0.prev = context$4$0.next) { case 0: dir = _path2['default'].resolve(applicationList, dir); context$4$0.next = 3; return _regeneratorRuntime.awrap(readBundleId(dir)); case 3: bundleId = context$4$0.sent; return context$4$0.abrupt('return', { path: dir, bundleId: bundleId }); case 5: case 'end': return context$4$0.stop(); } }, null, _this); }; })(); case 11: context$2$0.next = 13; return _regeneratorRuntime.awrap(_appiumSupport.fs.readdir(applicationList)); case 13: bundlePathDirs = context$2$0.sent; context$2$0.next = 16; return _regeneratorRuntime.awrap((0, _asyncbox.asyncmap)(bundlePathDirs, function callee$2$0(dir) { return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: context$3$0.next = 2; return _regeneratorRuntime.awrap(pathBundlePair(dir)); case 2: return context$3$0.abrupt('return', context$3$0.sent); case 3: case 'end': return context$3$0.stop(); } }, null, _this); }, false)); case 16: bundlePathPairs = context$2$0.sent; return context$2$0.abrupt('return', bundlePathPairs.reduce(function (bundleMap, bundlePath) { bundleMap[bundlePath.bundleId] = bundlePath.path; return bundleMap; }, {})); case 18: case 'end': return context$2$0.stop(); } }, null, this); } // returns state and specifics of this sim. // { name: 'iPhone 4s', // udid: 'C09B34E5-7DCB-442E-B79C-AB6BC0357417', // state: 'Shutdown', // sdk: '8.3' // } }, { key: 'stat', value: function stat() { var devices, normalizedDevices, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step; return _regeneratorRuntime.async(function stat$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(simctl.getDevices()); case 2: devices = context$2$0.sent; normalizedDevices = []; _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; context$2$0.prev = 7; _loop = function () { var _step$value = _slicedToArray(_step.value, 2); var sdk = _step$value[0]; var deviceArr = _step$value[1]; deviceArr = deviceArr.map(function (device) { device.sdk = sdk; return device; }); normalizedDevices = normalizedDevices.concat(deviceArr); }; // add sdk attribute to all entries, add to normalizedDevices for (_iterator = _getIterator(_lodash2['default'].pairs(devices)); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { _loop(); } context$2$0.next = 16; break; case 12: context$2$0.prev = 12; context$2$0.t0 = context$2$0['catch'](7); _didIteratorError = true; _iteratorError = context$2$0.t0; case 16: context$2$0.prev = 16; context$2$0.prev = 17; if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } case 19: context$2$0.prev = 19; if (!_didIteratorError) { context$2$0.next = 22; break; } throw _iteratorError; case 22: return context$2$0.finish(19); case 23: return context$2$0.finish(16); case 24: return context$2$0.abrupt('return', _lodash2['default'].findWhere(normalizedDevices, { udid: this.udid })); case 25: case 'end': return context$2$0.stop(); } }, null, this, [[7, 12, 16, 24], [17,, 19, 23]]); } }, { key: 'isFresh', value: function isFresh() { var files, pv, existences, i; return _regeneratorRuntime.async(function isFresh$(context$2$0) { var _this2 = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: files = ['Library/ConfigurationProfiles', 'Library/Cookies', 'Library/Logs', 'Library/Preferences/.GlobalPreferences.plist', 'Library/Preferences/com.apple.springboard.plist', 'var/run/syslog.pid']; context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 3: pv = context$2$0.sent; if (pv !== '7.1') { files.push('Library/Preferences/com.apple.Preferences.plist'); } else { files.push('Applications'); } files = files.map(function (s) { return _path2['default'].resolve(_this2.getDir(), s); }); context$2$0.next = 8; return _regeneratorRuntime.awrap((0, _asyncbox.asyncmap)(files, function callee$2$0(f) { return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: return context$3$0.abrupt('return', _appiumSupport.fs.hasAccess(f)); case 1: case 'end': return context$3$0.stop(); } }, null, _this2); })); case 8: existences = context$2$0.sent; for (i = 0; i < files.length; i++) { if (!existences[i]) { _logger2['default'].debug('File ' + files[i] + ' not yet found'); } } return context$2$0.abrupt('return', _lodash2['default'].compact(existences).length !== files.length); case 11: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'isRunning', value: function isRunning() { var stat; return _regeneratorRuntime.async(function isRunning$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.stat()); case 2: stat = context$2$0.sent; return context$2$0.abrupt('return', stat.state === 'Booted'); case 4: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'getBootedIndicatorString', value: function getBootedIndicatorString() { var indicator, platformVersion; return _regeneratorRuntime.async(function getBootedIndicatorString$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: indicator = undefined; context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 3: platformVersion = context$2$0.sent; context$2$0.t0 = platformVersion; context$2$0.next = context$2$0.t0 === '7.1' ? 7 : context$2$0.t0 === '8.1' ? 7 : context$2$0.t0 === '8.2' ? 7 : context$2$0.t0 === '8.3' ? 7 : context$2$0.t0 === '8.4' ? 7 : context$2$0.t0 === '9.0' ? 9 : context$2$0.t0 === '9.1' ? 9 : context$2$0.t0 === '9.2' ? 9 : 11; break; case 7: indicator = 'profiled: Service starting...'; return context$2$0.abrupt('break', 13); case 9: indicator = 'System app "com.apple.springboard" finished startup'; return context$2$0.abrupt('break', 13); case 11: _logger2['default'].warn('No boot indicator case for platform version \'' + platformVersion + '\''); indicator = 'no boot indicator string available'; case 13: return context$2$0.abrupt('return', indicator); case 14: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'run', value: function run() { var OPEN_TIMEOUT, STARTUP_TIMEOUT, EXTRA_STARTUP_TIME, simulatorApp, args, startTime, bootedIndicator; return _regeneratorRuntime.async(function run$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: OPEN_TIMEOUT = 3000; STARTUP_TIMEOUT = 60 * 1000; EXTRA_STARTUP_TIME = 2000; context$2$0.t0 = _path2['default']; context$2$0.next = 6; return _regeneratorRuntime.awrap((0, _appiumXcode.getPath)()); case 6: context$2$0.t1 = context$2$0.sent; context$2$0.t2 = this.simulatorApp; simulatorApp = context$2$0.t0.resolve.call(context$2$0.t0, context$2$0.t1, 'Applications', context$2$0.t2); args = [simulatorApp, '--args', '-CurrentDeviceUDID', this.udid]; _logger2['default'].info('Starting simulator with command: open ' + args.join(' ')); startTime = Date.now(); context$2$0.next = 14; return _regeneratorRuntime.awrap((0, _teen_process.exec)('open', args, { timeout: OPEN_TIMEOUT })); case 14: context$2$0.next = 16; return _regeneratorRuntime.awrap(this.getBootedIndicatorString()); case 16: bootedIndicator = context$2$0.sent; context$2$0.next = 19; return _regeneratorRuntime.awrap(this.tailLogsUntil(bootedIndicator, STARTUP_TIMEOUT)); case 19: // so sorry, but we should wait another two seconds, just to make sure we've really started // we can't look for another magic log line, because they seem to be app-dependent (not system dependent) _logger2['default'].debug('Waiting and extra ' + EXTRA_STARTUP_TIME + 'ms for the simulator to really finish booting'); context$2$0.next = 22; return _regeneratorRuntime.awrap(_bluebird2['default'].delay(EXTRA_STARTUP_TIME)); case 22: _logger2['default'].debug('Done waiting extra time for simulator'); _logger2['default'].info('Simulator booted in ' + (Date.now() - startTime) + 'ms'); case 24: case 'end': return context$2$0.stop(); } }, null, this); } // TODO keep keychains }, { key: 'clean', value: function clean() { return _regeneratorRuntime.async(function clean$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.endSimulatorDaemon()); case 2: _logger2['default'].info('Cleaning simulator ' + this.udid); context$2$0.next = 5; return _regeneratorRuntime.awrap(simctl.eraseDevice(this.udid)); case 5: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'cleanCustomApp', value: function cleanCustomApp(appFile, appBundleId) { var appDirs, deletePromises, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, dir, relRmPath, rmPath; return _regeneratorRuntime.async(function cleanCustomApp$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: _logger2['default'].debug('Cleaning app data files for \'' + appFile + '\', \'' + appBundleId + '\''); context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getAppDirs(appFile, appBundleId)); case 3: appDirs = context$2$0.sent; if (!(appDirs.length === 0)) { context$2$0.next = 7; break; } _logger2['default'].debug("Could not find app directories to delete. It is probably not installed"); return context$2$0.abrupt('return'); case 7: deletePromises = []; _iteratorNormalCompletion2 = true; _didIteratorError2 = false; _iteratorError2 = undefined; context$2$0.prev = 11; for (_iterator2 = _getIterator(appDirs); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { dir = _step2.value; _logger2['default'].debug('Deleting directory: \'' + dir + '\''); deletePromises.push(_appiumSupport.fs.rimraf(dir)); } context$2$0.next = 19; break; case 15: context$2$0.prev = 15; context$2$0.t0 = context$2$0['catch'](11); _didIteratorError2 = true; _iteratorError2 = context$2$0.t0; case 19: context$2$0.prev = 19; context$2$0.prev = 20; if (!_iteratorNormalCompletion2 && _iterator2['return']) { _iterator2['return'](); } case 22: context$2$0.prev = 22; if (!_didIteratorError2) { context$2$0.next = 25; break; } throw _iteratorError2; case 25: return context$2$0.finish(22); case 26: return context$2$0.finish(19); case 27: context$2$0.next = 29; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 29: context$2$0.t1 = context$2$0.sent; if (!(context$2$0.t1 >= 8)) { context$2$0.next = 35; break; } relRmPath = 'Library/Preferences/' + appBundleId + '.plist'; rmPath = _path2['default'].resolve(this.getRootDir(), relRmPath); _logger2['default'].debug('Deleting file: \'' + rmPath + '\''); deletePromises.push(_appiumSupport.fs.rimraf(rmPath)); case 35: context$2$0.next = 37; return _regeneratorRuntime.awrap(_bluebird2['default'].all(deletePromises)); case 37: case 'end': return context$2$0.stop(); } }, null, this, [[11, 15, 19, 27], [20,, 22, 26]]); } }, { key: 'getAppDirs', value: function getAppDirs(appFile, appBundleId) { var dirs, data, bundle; return _regeneratorRuntime.async(function getAppDirs$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: dirs = []; context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 3: context$2$0.t0 = context$2$0.sent; if (!(context$2$0.t0 >= 8)) { context$2$0.next = 15; break; } context$2$0.next = 7; return _regeneratorRuntime.awrap(this.getAppDir(appBundleId)); case 7: data = context$2$0.sent; context$2$0.next = 10; return _regeneratorRuntime.awrap(this.getAppDir(appBundleId, 'Bundle')); case 10: bundle = context$2$0.sent; if (data) { dirs.push(data); } if (bundle) { dirs.push(bundle); } context$2$0.next = 19; break; case 15: context$2$0.next = 17; return _regeneratorRuntime.awrap(this.getAppDir(appFile)); case 17: data = context$2$0.sent; if (data) { dirs.push(data); } case 19: return context$2$0.abrupt('return', dirs); case 20: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'launchAndQuit', value: function launchAndQuit() { var safari = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0]; return _regeneratorRuntime.async(function launchAndQuit$(context$2$0) { var _this3 = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: _logger2['default'].debug('Attempting to launch and quit the simulator, to create directory structure'); _logger2['default'].debug('Will launch with Safari? ' + safari); context$2$0.next = 4; return _regeneratorRuntime.awrap(this.run()); case 4: if (!safari) { context$2$0.next = 7; break; } context$2$0.next = 7; return _regeneratorRuntime.awrap(this.openUrl('http://www.appium.io')); case 7: context$2$0.next = 9; return _regeneratorRuntime.awrap((0, _asyncbox.retryInterval)(20, 250, function callee$2$0() { var msg; return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: context$3$0.next = 2; return _regeneratorRuntime.awrap(this.isFresh()); case 2: if (!context$3$0.sent) { context$3$0.next = 6; break; } msg = 'Simulator files not fully created. Waiting a bit'; _logger2['default'].debug(msg); throw new Error(msg); case 6: case 'end': return context$3$0.stop(); } }, null, _this3); })); case 9: context$2$0.next = 11; return _regeneratorRuntime.awrap(this.shutdown()); case 11: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'endSimulatorDaemon', value: function endSimulatorDaemon() { var launchctlCmd, stopCmd, removeCmd; return _regeneratorRuntime.async(function endSimulatorDaemon$(context$2$0) { var _this4 = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: // Looks for launchd daemons corresponding to the sim udid and tries to stop them cleanly // This prevents xcrun simctl erase hangs. _logger2['default'].debug('Killing any simulator daemons for ' + this.udid); launchctlCmd = 'launchctl list | grep ' + this.udid + ' | cut -f 3 | xargs -n 1 launchctl'; context$2$0.prev = 2; stopCmd = launchctlCmd + ' stop'; context$2$0.next = 6; return _regeneratorRuntime.awrap((0, _teen_process.exec)('bash', ['-c', stopCmd])); case 6: context$2$0.next = 12; break; case 8: context$2$0.prev = 8; context$2$0.t0 = context$2$0['catch'](2); _logger2['default'].warn('Could not stop simulator daemons: ' + context$2$0.t0.message); _logger2['default'].debug('Carrying on anyway!'); case 12: context$2$0.prev = 12; removeCmd = launchctlCmd + ' remove'; context$2$0.next = 16; return _regeneratorRuntime.awrap((0, _teen_process.exec)('bash', ['-c', removeCmd])); case 16: context$2$0.next = 22; break; case 18: context$2$0.prev = 18; context$2$0.t1 = context$2$0['catch'](12); _logger2['default'].warn('Could not remove simulator daemons: ' + context$2$0.t1.message); _logger2['default'].debug('Carrying on anyway!'); case 22: context$2$0.prev = 22; context$2$0.next = 25; return _regeneratorRuntime.awrap((0, _asyncbox.waitForCondition)(function callee$2$0() { var _ref2, stdout; return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: context$3$0.next = 2; return _regeneratorRuntime.awrap((0, _teen_process.exec)('bash', ['-c', 'ps -e | grep ' + this.udid + ' | grep launchd_sim | grep -v bash | grep -v grep | awk {\'print$1\'}'])); case 2: _ref2 = context$3$0.sent; stdout = _ref2.stdout; return context$3$0.abrupt('return', stdout.trim().length === 0); case 5: case 'end': return context$3$0.stop(); } }, null, _this4); }, { waitMs: 10000, intervalMs: 500 })); case 25: context$2$0.next = 31; break; case 27: context$2$0.prev = 27; context$2$0.t2 = context$2$0['catch'](22); _logger2['default'].warn('Could not end simulator daemon for ' + this.udid + ': ' + context$2$0.t2.message); _logger2['default'].debug('Carrying on anyway!'); case 31: case 'end': return context$2$0.stop(); } }, null, this, [[2, 8], [12, 18], [22, 27]]); } }, { key: 'shutdown', value: function shutdown() { return _regeneratorRuntime.async(function shutdown$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap((0, _utilsJs.killAllSimulators)()); case 2: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'delete', value: function _delete() { return _regeneratorRuntime.async(function _delete$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(simctl.deleteDevice(this.udid)); case 2: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'updateSettings', value: function updateSettings(plist, updates) { return _regeneratorRuntime.async(function updateSettings$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(settings.updateSettings(this, plist, updates)); case 2: return context$2$0.abrupt('return', context$2$0.sent); case 3: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'updateLocationSettings', value: function updateLocationSettings(bundleId, authorized) { return _regeneratorRuntime.async(function updateLocationSettings$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(settings.updateLocationSettings(this, bundleId, authorized)); case 2: return context$2$0.abrupt('return', context$2$0.sent); case 3: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'updateSafariSettings', value: function updateSafariSettings(updates) { return _regeneratorRuntime.async(function updateSafariSettings$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(settings.updateSafariUserSettings(this, updates)); case 2: context$2$0.next = 4; return _regeneratorRuntime.awrap(settings.updateSettings(this, 'mobileSafari', updates)); case 4: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'updateLocale', value: function updateLocale(language, locale, calendarFormat) { return _regeneratorRuntime.async(function updateLocale$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(settings.updateLocale(this, language, locale, calendarFormat)); case 2: return context$2$0.abrupt('return', context$2$0.sent); case 3: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'deleteSafari', value: function deleteSafari() { var dirs, pv, deletePromises, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, dir; return _regeneratorRuntime.async(function deleteSafari$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: _logger2['default'].debug('Deleting Safari apps from simulator'); dirs = []; context$2$0.t0 = dirs; context$2$0.next = 5; return _regeneratorRuntime.awrap(this.getAppDir('com.apple.mobilesafari')); case 5: context$2$0.t1 = context$2$0.sent; context$2$0.t0.push.call(context$2$0.t0, context$2$0.t1); context$2$0.next = 9; return _regeneratorRuntime.awrap(this.getPlatformVersion()); case 9: pv = context$2$0.sent; if (!(pv >= 8)) { context$2$0.next = 16; break; } context$2$0.t2 = dirs; context$2$0.next = 14; return _regeneratorRuntime.awrap(this.getAppDir('com.apple.mobilesafari', 'Bundle')); case 14: context$2$0.t3 = context$2$0.sent; context$2$0.t2.push.call(context$2$0.t2, context$2$0.t3); case 16: deletePromises = []; _iteratorNormalCompletion3 = true; _didIteratorError3 = false; _iteratorError3 = undefined; context$2$0.prev = 20; for (_iterator3 = _getIterator(dirs); !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { dir = _step3.value; _logger2['default'].debug('Deleting directory: \'' + dir + '\''); deletePromises.push(_appiumSupport.fs.rimraf(dir)); } context$2$0.next = 28; break; case 24: context$2$0.prev = 24; context$2$0.t4 = context$2$0['catch'](20); _didIteratorError3 = true; _iteratorError3 = context$2$0.t4; case 28: context$2$0.prev = 28; context$2$0.prev = 29; if (!_iteratorNormalCompletion3 && _iterator3['return']) { _iterator3['return'](); } case 31: context$2$0.prev = 31; if (!_didIteratorError3) { context$2$0.next = 34; break; } throw _iteratorError3; case 34: return context$2$0.finish(31); case 35: return context$2$0.finish(28); case 36: context$2$0.next = 38; return _regeneratorRuntime.awrap(_bluebird2['default'].all(deletePromises)); case 38: case 'end': return context$2$0.stop(); } }, null, this, [[20, 24, 28, 36], [29,, 31, 35]]); } }, { key: 'cleanSafari', value: function cleanSafari() { var keepPrefs = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; var libraryDir, safariLibraryDir, filesToDelete, deletePromises, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, file; return _regeneratorRuntime.async(function cleanSafari$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: _logger2['default'].debug('Cleaning mobile safari data files'); if (!this.isFresh()) { context$2$0.next = 4; break; } _logger2['default'].info('Could not find Safari support directories to clean out old ' + 'data. Probably there is nothing to clean out'); return context$2$0.abrupt('return'); case 4: libraryDir = _path2['default'].resolve(this.getDir(), 'Library'); context$2$0.t0 = _path2['default']; context$2$0.next = 8; return _regeneratorRuntime.awrap(this.getAppDir('com.apple.mobilesafari')); case 8: context$2$0.t1 = context$2$0.sent; safariLibraryDir = context$2$0.t0.resolve.call(context$2$0.t0, context$2$0.t1, 'Library'); filesToDelete = ['Caches/Snapshots/com.apple.mobilesafari', 'Caches/com.apple.mobilesafari/Cache.db*', 'Caches/com.apple.WebAppCache/*.db', 'Safari', 'WebKit/LocalStorage/*.*', 'WebKit/GeolocationSites.plist', 'Cookies/*.binarycookies']; deletePromises = []; _iteratorNormalCompletion4 = true; _didIteratorError4 = false; _iteratorError4 = undefined; context$2$0.prev = 15; for (_iterator4 = _getIterator(filesToDelete); !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { file = _step4.value; deletePromises.push(_appiumSupport.fs.rimraf(_path2['default'].resolve(libraryDir, file))); deletePromises.push(_appiumSupport.fs.rimraf(_path2['default'].resolve(safariLibraryDir, file))); } context$2$0.next = 23; break; case 19: context$2$0.prev = 19; context$2$0.t2 = context$2$0['catch'](15); _didIteratorError4 = true; _iteratorError4 = context$2$0.t2; case 23: context$2$0.prev = 23; context$2$0.prev = 24; if (!_iteratorNormalCompletion4 && _iterator4['return']) { _iterator4['return'](); } case 26: context$2$0.prev = 26; if (!_didIteratorError4) { context$2$0.next = 29; break; } throw _iteratorError4; case 29: return context$2$0.finish(26); case 30: return context$2$0.finish(23); case 31: if (!keepPrefs) { deletePromises.push(_appiumSupport.fs.rimraf(_path2['default'].resolve(safariLibraryDir, 'Preferences/*.plist'))); } context$2$0.next = 34; return _regeneratorRuntime.awrap(_bluebird2['default'].all(deletePromises)); case 34: case 'end': return context$2$0.stop(); } }, null, this, [[15, 19, 23, 31], [24,, 26, 30]]); } }, { key: 'moveBuiltInApp', value: function moveBuiltInApp(appName, appPath, newAppPath) { return _regeneratorRuntime.async(function moveBuiltInApp$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap((0, _utilsJs.safeRimRaf)(newAppPath)); case 2: context$2$0.next = 4; return _regeneratorRuntime.awrap(_appiumSupport.fs.copyFile(appPath, newAppPath)); case 4: _logger2['default'].debug('Copied \'' + appName + '\' to \'' + newAppPath + '\''); context$2$0.next = 7; return _regeneratorRuntime.awrap(_appiumSupport.fs.rimraf(appPath)); case 7: _logger2['default'].debug('Temporarily deleted original app at \'' + appPath + '\''); return context$2$0.abrupt('return', [newAppPath, appPath]); case 9: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'openUrl', value: function openUrl(url) { var SAFARI_BOOTED_INDICATOR, SAFARI_STARTUP_TIMEOUT, EXTRA_STARTUP_TIME; return _regeneratorRuntime.async(function openUrl$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: SAFARI_BOOTED_INDICATOR = 'MobileSafari['; SAFARI_STARTUP_TIMEOUT = 15 * 1000; EXTRA_STARTUP_TIME = 3 * 1000; context$2$0.next = 5; return _regeneratorRuntime.awrap(this.isRunning()); case 5: if (!context$2$0.sent) { context$2$0.next = 17; break; } context$2$0.next = 8; return _regeneratorRuntime.awrap((0, _asyncbox.retry)(5000, simctl.openUrl, this.udid, url)); case 8: context$2$0.next = 10; return _regeneratorRuntime.awrap(this.tailLogsUntil(SAFARI_BOOTED_INDICATOR, SAFARI_STARTUP_TIMEOUT)); case 10: // So sorry, but the logs have nothing else for Safari starting.. just delay a little bit _logger2['default'].debug('Safari started, waiting ' + EXTRA_STARTUP_TIME + 'ms for it to fully start'); context$2$0.next = 13; return _regeneratorRuntime.awrap(_bluebird2['default'].delay(EXTRA_STARTUP_TIME)); case 13: _logger2['default'].debug('Done waiting for Safari'); return context$2$0.abrupt('return'); case 17: throw new Error('Tried to open a url, but the Simulator is not Booted'); case 18: case 'end': return context$2$0.stop(); } }, null, this); } // returns a promise that resolves when the ios simulator logs output a line matching `bootedIndicator` // times out after timeoutMs }, { key: 'tailLogsUntil', value: function tailLogsUntil(bootedIndicator, timeoutMs) { var simLog; return _regeneratorRuntime.async(function tailLogsUntil$(context$2$0) { var _this5 = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: simLog = _path2['default'].resolve(this.getLogDir(), 'system.log'); context$2$0.next = 3; return _regeneratorRuntime.awrap((0, _asyncbox.retryInterval)(200, 2000, function callee$2$0() { return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: context$3$0.next = 2; return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(simLog)); case 2: if (context$3$0.sent) { context$3$0.next = 4; break; } throw new Error('Could not find Simulator log'); case 4: case 'end': return context$3$0.stop(); } }, null, _this5); })); case 3: _logger2['default'].info('Tailing simulator logs until we encounter the string "' + bootedIndicator + '"'); _logger2['default'].info('We will time out after ' + timeoutMs + 'ms'); context$2$0.prev = 5; context$2$0.next = 8; return _regeneratorRuntime.awrap((0, _tailUntilJs.tailUntil)(simLog, bootedIndicator, timeoutMs)); case 8: context$2$0.next = 13; break; case 10: context$2$0.prev = 10; context$2$0.t0 = context$2$0['catch'](5); _logger2['default'].debug('Simulator startup timed out. Continuing anyway.'); case 13: case 'end': return context$2$0.stop(); } }, null, this, [[5, 10]]); } }], [{ key: '_getDeviceStringPlatformVersion', value: function _getDeviceStringPlatformVersion(platformVersion) { var reqVersion; return _regeneratorRuntime.async(function _getDeviceStringPlatformVersion$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: reqVersion = platformVersion; if (reqVersion) { context$2$0.next = 6; break; } context$2$0.next = 4; return _regeneratorRuntime.awrap(_appiumXcode2['default'].getMaxIOSSDK()); case 4: reqVersion = context$2$0.sent; // this will be a number, and possibly an integer (e.g., if max iOS SDK is 9) // so turn it into a string and add a .0 if necessary if (!_lodash2['default'].isString(reqVersion)) { reqVersion = reqVersion % 1 ? String(reqVersion) : reqVersion + '.0'; } case 6: return context$2$0.abrupt('return', reqVersion); case 7: case 'end': return context$2$0.stop(); } }, null, this); } // change the format in subclasses, as necessary }, { key: '_getDeviceStringVersionString', value: function _getDeviceStringVersionString(platformVersion) { var reqVersion; return _regeneratorRuntime.async(function _getDeviceStringVersionString$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this._getDeviceStringPlatformVersion(platformVersion)); case 2: reqVersion = context$2$0.sent; return context$2$0.abrupt('return', '(' + reqVersion + ' Simulator)'); case 4: case 'end': return context$2$0.stop(); } }, null, this); } // change the format in subclasses, as necessary }, { key: '_getDeviceStringConfigFix', value: function _getDeviceStringConfigFix() { // some devices need to be updated return { 'iPad Simulator (7.1 Simulator)': 'iPad 2 (7.1 Simulator)', 'iPad Simulator (8.0 Simulator)': 'iPad 2 (8.0 Simulator)', 'iPad Simulator (8.1 Simulator)': 'iPad 2 (8.1 Simulator)', 'iPad Simulator (8.2 Simulator)': 'iPad 2 (8.2 Simulator)', 'iPad Simulator (8.3 Simulator)': 'iPad 2 (8.3 Simulator)', 'iPad Simulator (8.4 Simulator)': 'iPad 2 (8.4 Simulator)', 'iPhone Simulator (7.1 Simulator)': 'iPhone 5s (7.1 Simulator)', 'iPhone Simulator (8.4 Simulator)': 'iPhone 6 (8.4 Simulator)', 'iPhone Simulator (8.3 Simulator)': 'iPhone 6 (8.3 Simulator)', 'iPhone Simulator (8.2 Simulator)': 'iPhone 6 (8.2 Simulator)', 'iPhone Simulator (8.1 Simulator)': 'iPhone 6 (8.1 Simulator)', 'iPhone Simulator (8.0 Simulator)': 'iPhone 6 (8.0 Simulator)' }; } }, { key: 'getDeviceString', value: function getDeviceString(opts) { var isiPhone, device, iosDeviceString, CONFIG_FIX, configFix; return _regeneratorRuntime.async(function getDeviceString$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: opts = _Object$assign({}, { deviceName: null, platformVersion: null, forceIphone: false, forceIpad: false }, opts); _logger2['default'].debug('Getting device string: ' + JSON.stringify(opts)); // short circuit if we already have a device name if (!((opts.deviceName || '')[0] === '=')) { context$2$0.next = 4; break; } return context$2$0.abrupt('return', opts.deviceName.substring(1)); case 4: isiPhone = !!opts.forceIphone || !opts.forceIpad; if (opts.deviceName) { device = opts.deviceName.toLowerCase(); if (device.indexOf('iphone') !== -1