ti-appium
Version:
An Appium wrapper to test Titanium applications
326 lines (258 loc) • 10.9 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: src/device.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: src/device.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>'use strict';
const
ps = require('ps-list'),
output = require('./output.js'),
childProcess = require('child_process');
/**
* @class Device_Helper
* @desc
* Devices handling class, used to make shortcuts around the launching and
* shutting down of emulators. Also has functions for finding iOS certificates
* and provisioning profiles.
*/
class Device_Helper {
/**
* Kill the iOS simulator using it's UDID, and then repeatedly check whether
* it has fully shut down
*
* @param {String} simName - The name of the iOS device to find
* @param {String} simVersion - The version of the iOS device to find
* @param {Object} opts - Optional arguments
* @param {Int} opts.initialWait - How long to wait for the first boot check
* @param {Int} opts.intervalWait - How long to wait between each check following the first
*/
static async killSim(simName, simVersion, { initialWait = 10000, intervalWait = 5000 } = {}) {
if (!simName) { throw new Error('Empty simulator name argument passed'); }
if (!simVersion) { throw new Error('Empty simulator version passed'); }
output.debug(`Shutting Down the iOS Simulator: ${simName} (${simVersion})`);
const udid = getUdid(simName, simVersion);
output.debug(`Found UDID for Simulator: ${udid}`);
childProcess.execSync(`xcrun simctl shutdown ${udid}`);
await isShutdown(simName, simVersion, initialWait, intervalWait);
// The simulator process hangs around even after the sim itself is shut down
childProcess.spawn('killall', [ 'Simulator' ]);
}
/**
* Get the boot status of an iOS simulator via its UDID
*
* @param {String} simName - The name of the iOS device to find
* @param {String} simVersion - The version of the iOS device to find
*/
static getSimState(simName, simVersion) {
if (!simName) { throw new Error('Empty simulator name argument passed'); }
if (!simVersion) { throw new Error('Empty simulator version passed'); }
return getState(simName, simVersion);
}
/**
* Kill all the Android emulators.
*
* @param {String} deviceName - The name of the Android device to kill
*/
static async killEmu(deviceName) {
const devicePID = await getAndroidPID(deviceName);
output.debug(`Found Android emulator PID: ${devicePID}`);
if (process.platform === 'win32') {
output.debug('Detected Windows, killing emulator with taskkill command');
await childProcess.execSync(`taskkill /F /PID ${devicePID}`);
} else {
output.debug('Presuming UNIX, killing emulator with kill command');
await childProcess.execSync(`kill -9 ${devicePID}`);
}
}
/**
* Use ioslib to probe the machine for a particular iOS certificate, then
* return the certificate object.
*
* @param {String} type - The type of operation the cert is defined for
* @param {String} search - Part of the cert name, used to help locate it
*/
static async getCert(type, search) {
if (process.platform !== 'darwin') {
return undefined;
}
const ioslib = require('ioslib');
const
certs = await ioslib.certs.getCerts(),
subCerts = certs[type],
valid = [ 'developer', 'distribution' ];
if (!valid.includes(type)) {
throw Error(`Argument '${type}' is not a valid type of certificate`);
}
let foundCert;
subCerts.forEach(cert => {
if (cert.name.includes(search)) {
foundCert = cert;
}
});
if (!foundCert) {
throw Error(`No certificate found with a name including '${search}'`);
}
return foundCert;
}
/**
* Use ioslib to probe the machine for a particular iOS provisioning profile,
* then return the provisioning profile object.
*
* @param {String} type - The type of operation the pp is defined for
* @param {String} search - Part of the pp name, used to help locate it
*/
static async getProfile(type, search) {
if (process.platform !== 'darwin') {
return undefined;
}
const ioslib = require('ioslib');
const
profiles = await ioslib.provisioning.getProvisioningProfiles(),
subProfiles = profiles[type],
valid = [ 'adhoc', 'development', 'distribution' ];
if (!valid.includes(type)) {
throw Error(`Argument '${type}' is not a valid type of provisioning profile`);
}
let foundProfile;
subProfiles.forEach(profile => {
if (profile.name === search) {
foundProfile = profile;
}
});
if (!foundProfile) {
throw Error(`No provisioning profile found with a name matching '${search}'`);
}
return foundProfile;
}
}
/**
* Use the status of the simulator to determine whether the device is shutdown. The
* initial wait value is used because a simulator will sometimes show as shutdown
* before it really is and then change it's mind back to booted. So we use a long
* wait to allow it to get past this phase
* @private
*
* @param {String} simName - The name of the iOS device to find
* @param {String} simVersion - The version of the iOS device to find
* @param {Int} initialWait - How long to wait for the first boot check
* @param {Int} intervalWait - How long to wait between each check following the first
*/
function isShutdown(simName, simVersion, initialWait, intervalWait) {
return new Promise((resolve, reject) => {
output.debug(`Starting Check for Simulator Shutdown, Waiting ${initialWait}ms for First Check Then Every ${intervalWait}ms`);
setTimeout(() => {
let count = 0;
const interval = setInterval(() => {
let state = getState(simName, simVersion);
count++;
output.debug(`${simName} (${simVersion}) is Currently ${state}`);
if (state === 'Shutdown') {
clearInterval(interval);
return resolve();
} else if (count >= 20) {
clearInterval(interval);
return reject('iOS simulator didn\'t shutdown in expected time, you may expierience instability');
}
}, intervalWait);
}, initialWait);
});
}
/**
* Get the boot status of an iOS simulator via its UDID
* @private
*
* @param {String} simName - The name of the iOS device to find
* @param {String} simVersion - The version of the iOS device to find
*/
function getState(simName, simVersion) {
const
versionParts = simVersion.split('.'),
major = versionParts[0],
minor = versionParts[1];
const udid = getUdid(simName, simVersion);
const xcrunOut = childProcess.execSync('xcrun simctl list --json');
const xcrunSims = JSON.parse(xcrunOut).devices[`com.apple.CoreSimulator.SimRuntime.iOS-${major}-${minor}`];
try {
for (const xcrunSim of xcrunSims) {
if (xcrunSim.udid === udid) {
return xcrunSim.state;
}
}
} catch (e) {
throw new Error(`An issue occured trying to get the boot status of iOS simulator "${simName} (${simVersion})", do you have this simulator configured?`);
}
throw new Error(`Cannot retrieve a status for simulator ${simName} (${simVersion})`);
}
/**
* Get the UDID of an iOS simulator using the Titanium CLI
* @private
*
* @param {String} simName - The name of the iOS device to find
* @param {String} simVersion - The version of the iOS device to find
*/
function getUdid(simName, simVersion) {
const tiOut = childProcess.execSync('ti info -t ios -o json');
const tiSims = JSON.parse(tiOut).ios.simulators.ios[simVersion];
try {
for (const tiSim of tiSims) {
if (tiSim.name === simName) {
return tiSim.udid;
}
}
} catch (e) {
throw new Error(`An issue occured trying to find the UDID of iOS simulator "${simName} (${simVersion})", do you have this simulator configured?`);
}
throw new Error(`Cannot find a UDID for simulator ${simName} (${simVersion})`);
}
/**
* Search the running processes on the system, and look for one with the
* Android device name that we booted for testing.
* @private
*
* @param {String} deviceName - The name of the Android device to find
*/
async function getAndroidPID(deviceName) {
try {
const list = await ps();
let pid;
if (process.platform === 'win32') {
const proc = list.find(x => x.name.includes('qemu-system-x86_64'));
pid = proc.pid;
} else {
const proc = list.find(x => x.cmd.includes(deviceName));
pid = proc.pid;
}
return pid;
} catch (err) {
throw Error(`Cannot find an Android PID for ${deviceName}`);
}
}
module.exports = Device_Helper;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="WebDriverCommands.html">WebDriverCommands</a></li></ul><h3>Classes</h3><ul><li><a href="Appc_Helper.html">Appc_Helper</a></li><li><a href="Appium_Helper.html">Appium_Helper</a></li><li><a href="Device_Helper.html">Device_Helper</a></li><li><a href="Mocha_Helper.html">Mocha_Helper</a></li><li><a href="Output_Helper.html">Output_Helper</a></li><li><a href="Webdriver_Helper.html">Webdriver_Helper</a></li></ul><h3>Global</h3><ul><li><a href="global.html#appcRun">appcRun</a></li><li><a href="global.html#appcSetup">appcSetup</a></li><li><a href="global.html#banner">banner</a></li><li><a href="global.html#buildApp">buildApp</a></li><li><a href="global.html#createAppPath">createAppPath</a></li><li><a href="global.html#debug">debug</a></li><li><a href="global.html#error">error</a></li><li><a href="global.html#finish">finish</a></li><li><a href="global.html#getCert">getCert</a></li><li><a href="global.html#getProfile">getProfile</a></li><li><a href="global.html#getSimState">getSimState</a></li><li><a href="global.html#info">info</a></li><li><a href="global.html#killEmulator">killEmulator</a></li><li><a href="global.html#killSimulator">killSimulator</a></li><li><a href="global.html#parseSDK">parseSDK</a></li><li><a href="global.html#skip">skip</a></li><li><a href="global.html#startAppium">startAppium</a></li><li><a href="global.html#startClient">startClient</a></li><li><a href="global.html#step">step</a></li><li><a href="global.html#stopAppium">stopAppium</a></li><li><a href="global.html#stopClient">stopClient</a></li><li><a href="global.html#test">test</a></li><li><a href="global.html#warn">warn</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Fri Aug 28 2020 10:09:07 GMT+0100 (British Summer Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>