detox
Version:
E2E tests and automation for mobile
251 lines (197 loc) • 7.15 kB
JavaScript
const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
const path = require('path');
const exec = require('child-process-promise').exec;
const ini = require('ini');
const _ = require('lodash');
const _which = require('which');
const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
const appdatapath = require('./appdatapath');
const fsext = require('./fsext');
function which(executable, path) {
return _which.sync(executable, { path, nothrow: true });
}
const DETOX_LIBRARY_ROOT_PATH = path.join(appdatapath.appDataPath(), 'Detox');
const MISSING_SDK_ERROR = `$ANDROID_SDK_ROOT is not defined, set the path to the SDK installation directory into $ANDROID_SDK_ROOT,
Go to https://developer.android.com/studio/command-line/variables.html for more details`;
const DETOX_LOCK_FILE_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'global-context.json');
const DEVICE_REGISTRY_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'device.registry.json');
const LAST_FAILED_TESTS_PATH = path.join(DETOX_LIBRARY_ROOT_PATH, 'last-failed.txt');
function getAndroidSDKPath() {
return process.env.ANDROID_SDK_ROOT || process.env.ANDROID_HOME || '';
}
function getAndroidSDKHome() {
return process.env['ANDROID_SDK_HOME'] || os.homedir();
}
function getEmulatorHome() {
return process.env['ANDROID_EMULATOR_HOME'] || path.join(getAndroidSDKHome(), '.android');
}
function getAvdHome() {
return process.env['ANDROID_AVD_HOME'] || path.join(getEmulatorHome(), 'avd');
}
function getAvdDir(avdName) {
const avdIniPath = path.join(getAvdHome(), `${avdName}.ini`);
if (!fs.existsSync(avdIniPath)) {
throwMissingAvdINIError(avdName, avdIniPath);
}
const avdIni = ini.parse(fs.readFileSync(avdIniPath, 'utf-8'));
if (!fs.existsSync(avdIni.path)) {
throwMissingAvdError(avdName, avdIni.path, avdIniPath);
}
return avdIni.path;
}
function getAvdManagerPath() {
return path.join(getAndroidSDKPath(), 'cmdline-tools', 'latest', 'bin', 'avdmanager');
}
function getAndroidSdkManagerPath() {
return path.join(getAndroidSDKPath(), 'cmdline-tools', 'latest', 'bin', 'sdkmanager');
}
function getAndroidEmulatorPath() {
const sdkRoot = getAndroidSDKPath();
if (!sdkRoot) {
return which('emulator') || throwMissingSdkError();
}
const defaultPath = which('emulator', path.join(sdkRoot, 'emulator'));
if (defaultPath) {
return defaultPath;
}
const legacyPath = which('emulator', path.join(sdkRoot, 'tools'));
if (legacyPath) {
return legacyPath;
}
throwSdkBinIntegrityError(sdkRoot, 'emulator/emulator');
}
async function getAaptPath() {
const sdkRoot = getAndroidSDKPath();
if (!sdkRoot) {
return which('aapt') || throwMissingSdkError();
}
const latestBuildTools = await getLatestBuildToolsPath(sdkRoot);
if (!latestBuildTools) {
throwSdkIntegrityError('Failed to find the "aapt" tool under the Android SDK: No build-tools are installed!');
}
const defaultPath = which('aapt', latestBuildTools);
if (defaultPath) {
return defaultPath;
}
throwSdkToolPathError(`${latestBuildTools}/aapt`);
}
async function getLatestBuildToolsPath(sdkRoot) {
if (!sdkRoot) {
return '';
}
const buildToolsDir = path.join(sdkRoot, 'build-tools');
if (!fs.existsSync(buildToolsDir)) {
return '';
}
const buildToolsVersions = await fsext.getDirectories(buildToolsDir);
const latestBuildToolsVersion = _.last(buildToolsVersions);
if (!latestBuildToolsVersion) {
return '';
}
return path.join(buildToolsDir, latestBuildToolsVersion);
}
function getAdbPath() {
const sdkRoot = getAndroidSDKPath();
if (!sdkRoot) {
return which('adb') || throwMissingSdkError();
}
const defaultPath = which('adb', path.join(sdkRoot, 'platform-tools'));
if (defaultPath) {
return defaultPath;
}
throwSdkBinIntegrityError(sdkRoot, 'platform-tools/adb');
}
function getGmsaasPath() {
return which('gmsaas') || throwMissingGmsaasError();
}
function throwMissingSdkError() {
throw new DetoxRuntimeError(MISSING_SDK_ERROR);
}
function throwMissingAvdINIError(avdName, avdIniPath) {
throw new DetoxRuntimeError(`Failed to find INI file for ${avdName} at path: ${avdIniPath}`);
}
function throwMissingAvdError(avdName, avdPath, avdIniPath) {
throw new DetoxRuntimeError(
`Failed to find AVD ${avdName} directory at path: ${avdPath}\n` +
`Please verify "path" property in the INI file: ${avdIniPath}`
);
}
function throwSdkBinIntegrityError(sdkRoot, relativeBinPath) {
const executablePath = path.join(sdkRoot, relativeBinPath);
throwSdkToolPathError(executablePath);
}
function throwSdkToolPathError(sdkToolPath) {
const name = path.basename(sdkToolPath);
const dir = path.dirname(sdkToolPath);
throwSdkIntegrityError(`There was no "${name}" executable file in directory: ${dir}`);
}
function throwSdkIntegrityError(errMessage) {
throw new DetoxRuntimeError(`${errMessage}\nCheck the integrity of your Android SDK.`);
}
function throwMissingGmsaasError() {
throw new DetoxRuntimeError(`Failed to locate Genymotion's gmsaas executable. Please add it to your $PATH variable!\nPATH is currently set to: ${process.env.PATH}`);
}
const getDetoxVersion = _.once(() => {
return require(path.join(__dirname, '../../package.json')).version;
});
const getBuildFolderName = _.once(async () => {
const detoxVersion = getDetoxVersion();
const xcodeVersion = await exec('xcodebuild -version').then(result => result.stdout.trim());
return crypto.createHash('sha1')
.update(`${detoxVersion}\n${xcodeVersion}\n`)
.digest('hex');
});
const getFrameworkDirPath = `${DETOX_LIBRARY_ROOT_PATH}/ios/framework`;
const getFrameworkPath = _.once(async () => {
const buildFolder = await getBuildFolderName();
return `${getFrameworkDirPath}/${buildFolder}/Detox.framework`;
});
const getXCUITestRunnerDirPath = `${DETOX_LIBRARY_ROOT_PATH}/ios/xcuitest-runner`;
const getXCUITestRunnerPath = _.once(async () => {
const buildFolder = await getBuildFolderName();
const derivedDataPath = `${getXCUITestRunnerDirPath}/${buildFolder}`;
const xctestrunPath = await exec(`find ${derivedDataPath} -name "*.xctestrun" -print -quit`)
.then(result => result.stdout.trim());
if (!xctestrunPath) {
throw new DetoxRuntimeError(`Failed to find .xctestrun file in ${derivedDataPath}`);
}
return xctestrunPath;
});
function getDetoxLibraryRootPath() {
return DETOX_LIBRARY_ROOT_PATH;
}
function getDetoxLockFilePath() {
return DETOX_LOCK_FILE_PATH;
}
function getDeviceRegistryPath() {
return DEVICE_REGISTRY_PATH;
}
function getLastFailedTestsPath() {
return LAST_FAILED_TESTS_PATH;
}
function getHomeDir() {
return os.homedir();
}
module.exports = {
getAaptPath,
getAdbPath,
getAvdHome,
getAvdDir,
getAvdManagerPath,
getAndroidSdkManagerPath,
getGmsaasPath,
getDetoxVersion,
getFrameworkDirPath,
getFrameworkPath,
getXCUITestRunnerDirPath,
getXCUITestRunnerPath,
getAndroidSDKPath,
getAndroidEmulatorPath,
getDetoxLibraryRootPath,
getDetoxLockFilePath,
getDeviceRegistryPath,
getLastFailedTestsPath,
getHomeDir,
};