UNPKG

appium-ios-simulator

Version:
212 lines 8.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MIN_SUPPORTED_XCODE_VERSION = exports.SIMULATOR_APP_NAME = exports.MOBILE_SAFARI_BUNDLE_ID = exports.SAFARI_STARTUP_TIMEOUT_MS = void 0; exports.killAllSimulators = killAllSimulators; exports.getSimulatorInfo = getSimulatorInfo; exports.simExists = simExists; exports.getDeveloperRoot = getDeveloperRoot; exports.assertXcodeVersion = assertXcodeVersion; exports.getDevices = getDevices; const logger_1 = require("./logger"); const lodash_1 = __importDefault(require("lodash")); const teen_process_1 = require("teen_process"); const asyncbox_1 = require("asyncbox"); const appium_xcode_1 = require("appium-xcode"); const path_1 = __importDefault(require("path")); const node_simctl_1 = require("node-simctl"); // it's a hack needed to stub getDevices in tests const utilsModule = __importStar(require("./utils")); const DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS = 30000; exports.SAFARI_STARTUP_TIMEOUT_MS = 25 * 1000; exports.MOBILE_SAFARI_BUNDLE_ID = 'com.apple.mobilesafari'; exports.SIMULATOR_APP_NAME = 'Simulator.app'; exports.MIN_SUPPORTED_XCODE_VERSION = 14; /** * @param appName - The application name to kill. * @param forceKill - Whether to force kill the process. * @returns Promise that resolves to 0 on success. */ async function pkill(appName, forceKill = false) { const args = forceKill ? ['-9'] : []; args.push('-x', appName); try { await (0, teen_process_1.exec)('pkill', args); return 0; } catch (err) { // pgrep/pkill exit codes: // 0 One or more processes were matched. // 1 No processes were matched. // 2 Invalid options were specified on the command line. // 3 An internal error occurred. if (!lodash_1.default.isUndefined(err.code)) { throw new Error(`Cannot forcefully terminate ${appName}. pkill error code: ${err.code}`); } logger_1.log.error(`Received unexpected error while trying to kill ${appName}: ${err.message}`); throw err; } } /** * @param timeout - Timeout in milliseconds (default: DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS). * @returns Promise that resolves when all simulators are killed. */ async function killAllSimulators(timeout = DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS) { logger_1.log.debug('Killing all iOS Simulators'); const xcodeVersion = await (0, appium_xcode_1.getVersion)(true); if (lodash_1.default.isString(xcodeVersion)) { return; } const appName = path_1.default.parse(exports.SIMULATOR_APP_NAME).name; const version = xcodeVersion; // later versions are slower to close timeout = timeout * (version.major >= 8 ? 2 : 1); try { await (0, teen_process_1.exec)('xcrun', ['simctl', 'shutdown', version.major > 8 ? 'all' : 'booted'], { timeout }); } catch { } const pids = []; try { const { stdout } = await (0, teen_process_1.exec)('pgrep', ['-f', `${appName}.app/Contents/MacOS/`]); if (stdout.trim()) { pids.push(...(stdout.trim().split(/\s+/))); } } catch (e) { if (e.code === 1) { logger_1.log.debug(`${appName} is not running. Continuing...`); return; } if (lodash_1.default.isEmpty(pids)) { logger_1.log.warn(`pgrep error ${e.code} while detecting whether ${appName} is running. Trying to kill anyway.`); } } if (!lodash_1.default.isEmpty(pids)) { logger_1.log.debug(`Killing processes: ${pids.join(', ')}`); try { await (0, teen_process_1.exec)('kill', ['-9', ...(pids.map((pid) => `${pid}`))]); } catch { } } logger_1.log.debug(`Using pkill to kill application: ${appName}`); try { await pkill(appName, true); } catch { } // wait for all the devices to be shutdown before Continuing // but only print out the failed ones when they are actually fully failed let remainingDevices = []; async function allSimsAreDown() { remainingDevices = []; const devicesRecord = await utilsModule.getDevices(); const devices = lodash_1.default.flatten(lodash_1.default.values(devicesRecord)); return lodash_1.default.every(devices, (sim) => { const state = sim.state.toLowerCase(); const done = ['shutdown', 'unavailable', 'disconnected'].includes(state); if (!done) { remainingDevices.push(`${sim.name} (${sim.sdk}, udid: ${sim.udid}) is still in state '${state}'`); } return done; }); } try { await (0, asyncbox_1.waitForCondition)(allSimsAreDown, { waitMs: timeout, intervalMs: 200 }); } catch (err) { if (remainingDevices.length > 0) { logger_1.log.warn(`The following devices are still not in the correct state after ${timeout} ms:`); for (const device of remainingDevices) { logger_1.log.warn(` ${device}`); } } throw err; } } /** * @param udid - The simulator UDID. * @param opts - Options including devicesSetPath. * @returns Promise that resolves to simulator info or undefined if not found. */ async function getSimulatorInfo(udid, opts = {}) { const { devicesSetPath } = opts; // see the README for github.com/appium/node-simctl for example output of getDevices() const devices = lodash_1.default.toPairs(await utilsModule.getDevices({ devicesSetPath })) .map((pair) => pair[1]) .reduce((a, b) => a.concat(b), []); return lodash_1.default.find(devices, (sim) => sim.udid === udid); } /** * @param udid - The simulator UDID. * @returns Promise that resolves to true if simulator exists, false otherwise. */ async function simExists(udid) { return !!(await getSimulatorInfo(udid)); } /** * @returns Promise that resolves to the developer root path. */ async function getDeveloperRoot() { const { stdout } = await (0, teen_process_1.exec)('xcode-select', ['-p']); return stdout.trim(); } /** * Asserts that the Xcode version meets the minimum supported version requirement. * * @template V - The Xcode version type. * @param xcodeVersion - The Xcode version to check. * @returns The same Xcode version if it meets the requirement. * @throws {Error} If the Xcode version is below the minimum supported version. */ function assertXcodeVersion(xcodeVersion) { if (xcodeVersion.major < exports.MIN_SUPPORTED_XCODE_VERSION) { throw new Error(`Tried to use an iOS simulator with xcode version ${xcodeVersion.versionString} but only Xcode version ` + `${exports.MIN_SUPPORTED_XCODE_VERSION} and up are supported`); } return xcodeVersion; } /** * @param simctlOpts - Optional simctl options * @returns Promise that resolves to a record of devices grouped by SDK version */ async function getDevices(simctlOpts) { return await new node_simctl_1.Simctl(simctlOpts).getDevices(); } //# sourceMappingURL=utils.js.map