appium-doctor
Version:
Test environment for fitness to run Appium
242 lines (212 loc) • 8.24 kB
JavaScript
import { ok, nok, okOptional, nokOptional, authorizeIos, resolveExecutablePath } from './utils'; // eslint-disable-line
import { fs, util } from 'appium-support';
import { exec } from 'teen_process';
import { DoctorCheck, FixSkippedError } from './doctor';
import log from './logger';
import CarthageDetector from './carthage-detector';
import { fixIt } from './prompt';
import EnvVarAndPathCheck from './env';
import _ from 'lodash';
import '@colors/colors';
let checks = [];
let fixes = {};
// Check for Xcode.
class XcodeCheck extends DoctorCheck {
async diagnose () {
let xcodePath;
try {
// https://github.com/appium/appium/issues/12093#issuecomment-459358120 can happen
await exec('xcrun', ['simctl', 'help']);
} catch (err) {
return nok('Error running xcrun simctl');
}
try {
const {stdout} = await exec('xcode-select', ['-p']);
xcodePath = (stdout || '').replace('\n', '');
} catch (err) {
return nok('Xcode is NOT installed!');
}
return xcodePath && await fs.exists(xcodePath) ? ok(`Xcode is installed at: ${xcodePath}`) :
nok(`Xcode cannot be found at '${xcodePath}'!`);
}
async fix () { // eslint-disable-line require-await
return `Manually install ${'Xcode'.bold}, and make sure 'xcode-select -p' command shows proper path like '/Applications/Xcode.app/Contents/Developer'`;
}
}
checks.push(new XcodeCheck());
// Check for Xcode Command Line Tools.
class XcodeCmdLineToolsCheck extends DoctorCheck {
constructor () {
super({autofix: true});
}
async diagnose () {
const errMess = 'Xcode Command Line Tools are NOT installed!';
try {
// https://stackoverflow.com/questions/15371925/how-to-check-if-command-line-tools-is-installed
const stdout = (await exec('xcode-select', ['-p'])).stdout;
return ok(`Xcode Command Line Tools are installed in: ${stdout.trim()}`);
} catch (err) {
log.debug(err);
return nok(errMess);
}
}
async fix () {
log.info(`The following command need be executed: xcode-select --install`);
let yesno = await fixIt();
if (yesno === 'yes') {
await exec('xcode-select', ['--install']);
} else {
log.info(`Skipping you will need to install ${'Xcode'.bold} manually.`);
throw new FixSkippedError();
}
}
}
checks.push(new XcodeCmdLineToolsCheck());
// Automatically run authorize iOS if requested
fixes.authorizeIosFix = async function () {
log.info(`The authorize iOS script need to be run.`);
let yesno = await fixIt();
if (yesno === 'yes') {
await authorizeIos();
} else {
log.info(`Skipping you will need to run ${'the authorize iOS'.bold} manually.`);
throw new FixSkippedError();
}
};
// Dev Tools Security
class DevToolsSecurityCheck extends DoctorCheck {
constructor () {
super({autofix: true});
}
async diagnose () {
const errMess = 'DevToolsSecurity is NOT enabled!';
let stdout;
try {
stdout = (await exec('DevToolsSecurity', [])).stdout;
} catch (err) {
log.debug(err);
return nok(errMess);
}
return stdout && stdout.match(/enabled/) ? ok('DevToolsSecurity is enabled.')
: nok(errMess);
}
async fix () {
return await fixes.authorizeIosFix();
}
}
checks.push(new DevToolsSecurityCheck());
// Authorization DB
class AuthorizationDbCheck extends DoctorCheck {
constructor () {
super({autofix: true});
}
async diagnose () {
const successMess = 'The Authorization DB is set up properly.';
const errMess = 'The Authorization DB is NOT set up properly.';
let stdout;
try {
({stdout} = await exec('security', ['authorizationdb', 'read', 'system.privilege.taskport']));
} catch (err) {
log.warn(err);
return nok(errMess);
}
return stdout && (stdout.match(/is-developer/) || stdout.match(/allow/)) ?
ok(successMess) : nok(errMess);
}
async fix () {
return await fixes.authorizeIosFix();
}
}
checks.push(new AuthorizationDbCheck());
// Check for Carthage (for WDA)
class CarthageCheck extends DoctorCheck {
async diagnose () {
let carthagePath = await CarthageDetector.detect();
let version;
if (carthagePath) {
try {
const {stdout} = await exec(carthagePath, ['version']);
// 'Please update to the latest Carthage version: 0.33.0. You currently are on 0.32.0\n0.32.0\n' or '0.32.0\n'
// 0.32.0 is the current version. 0.33.0 is an available newer version.
version = _.last(stdout.match(/(\d+\.\d+\.\d+)/g));
if (!util.coerceVersion(version, false)) {
log.warn(`Cannot parse Carthage version from ${stdout}`);
}
} catch (err) {
log.warn(err);
}
}
return carthagePath
? ok(`Carthage was found at: ${carthagePath}${ version ? `. Installed version is: ${version}` : ''}`)
: nok(`Carthage was NOT found!`);
}
async fix () { // eslint-disable-line require-await
return `${'[For lower than Appium 1.20.0]'.bold} Please install ${'Carthage'.bold}. Visit https://github.com/Carthage` +
'/Carthage#installing-carthage for more information.';
}
}
checks.push(new CarthageCheck());
checks.push(new EnvVarAndPathCheck('HOME'));
class OptionalLyftCommandCheck extends DoctorCheck {
async diagnose () {
const lyftCmd = await resolveExecutablePath('set-simulator-location');
if (lyftCmd) {
return okOptional('set-simulator-location is installed');
}
return nokOptional('set-simulator-location is not installed');
}
async fix () { // eslint-disable-line require-await
return `${'set-simulator-location'.bold} is needed to set location for Simulator. ` +
'Please read https://github.com/lyft/set-simulator-location to install it';
}
}
checks.push(new OptionalLyftCommandCheck());
class OptionalIdbCommandCheck extends DoctorCheck {
async diagnose () {
const fbIdbPath = await resolveExecutablePath('idb');
const fbCompanionIdbPath = await resolveExecutablePath('idb_companion');
if (fbIdbPath && fbCompanionIdbPath) {
return okOptional('idb and idb_companion are installed');
}
if (!fbIdbPath && fbCompanionIdbPath) {
return nokOptional('idb is not installed');
} else if (fbIdbPath && !fbCompanionIdbPath) {
return nokOptional('idb_companion is not installed');
}
return nokOptional('idb and idb_companion are not installed');
}
async fix () { // eslint-disable-line require-await
return `Why ${'idb'.bold} is needed and how to install it: https://github.com/appium/appium-idb`;
}
}
checks.push(new OptionalIdbCommandCheck());
class OptionalApplesimutilsCommandCheck extends DoctorCheck {
async diagnose () {
const applesimutilsPath = await resolveExecutablePath('applesimutils');
return applesimutilsPath
? okOptional(`applesimutils is installed at: ${applesimutilsPath}. Installed versions are: ${(await exec('brew', ['list', '--versions', 'applesimutils'])).stdout.trim()}`)
: nokOptional('applesimutils cannot be found');
}
async fix () { // eslint-disable-line require-await
return `Why ${'applesimutils'.bold} is needed and how to install it: http://appium.io/docs/en/drivers/ios-xcuitest/`;
}
}
checks.push(new OptionalApplesimutilsCommandCheck());
class OptionalIOSDeployCommandCheck extends DoctorCheck {
async diagnose () {
const iosDeployPath = await resolveExecutablePath('ios-deploy');
return iosDeployPath
? okOptional(`ios-deploy is installed at: ${iosDeployPath}. Installed version is: ${(await exec(iosDeployPath, ['-V'])).stdout.trim()}`)
: nokOptional('ios-deploy cannot be found');
}
async fix () { // eslint-disable-line require-await
return `${'ios-deploy'.bold} is used as a fallback command to install iOS applications to real device. Please read https://github.com/ios-control/ios-deploy/ to install it`;
}
}
checks.push(new OptionalIOSDeployCommandCheck());
export {
fixes, XcodeCheck, XcodeCmdLineToolsCheck, DevToolsSecurityCheck,
AuthorizationDbCheck, CarthageCheck, OptionalIdbCommandCheck, OptionalApplesimutilsCommandCheck,
OptionalIOSDeployCommandCheck, OptionalLyftCommandCheck
};
export default checks;