appium-ios-simulator
Version:
iOS Simulator interface for Appium.
1,433 lines (1,165 loc) • 98 kB
JavaScript
'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