Best JavaScript code snippet using appium-android-driver
android-helper-specs.js
Source:android-helper-specs.js  
...304    it('should throw error if remote file does not exist', async () => {305      mocks.fs.expects('md5').withExactArgs(localApkPath).returns('apkmd5');306      mocks.adb.expects('fileExists').returns(false);307      mocks.helpers.expects('reinstallRemoteApk').never();308      await helpers.resetApp(adb, localApkPath, pkg, false, androidInstallTimeout).should.eventually309        .be.rejectedWith('slow');310      mocks.adb.verify();311      mocks.fs.verify();312      mocks.helpers.verify();313    });314    it('should reinstall apk', async () => {315      mocks.fs.expects('md5').withExactArgs(localApkPath).returns('apkmd5');316      mocks.adb.expects('fileExists').returns(true);317      mocks.helpers.expects('reinstallRemoteApk').once().returns('');318      await helpers.resetApp(adb, localApkPath, pkg, false, androidInstallTimeout);319      mocks.adb.verify();320      mocks.fs.verify();321      mocks.helpers.verify();322    });323    it('should be able to do fast reset', async () => {324      mocks.adb.expects('stopAndClear').withExactArgs(pkg).once();325      await helpers.resetApp(adb, localApkPath, pkg, true);326      mocks.adb.verify();327    });328    it('should use default timeout and remote temp path', async () => {329      mocks.fs.expects('md5').withExactArgs(localApkPath).returns('apkmd5');330      mocks.adb.expects('fileExists').returns(true);331      mocks.helpers.expects('getRemoteApkPath')332        .withExactArgs('apkmd5', REMOTE_TEMP_PATH).returns('remote_path');333      mocks.helpers.expects('reinstallRemoteApk')334        .withExactArgs(adb, localApkPath, pkg, 'remote_path', REMOTE_INSTALL_TIMEOUT).returns('');335      await helpers.resetApp(adb, localApkPath, pkg, false);336      mocks.adb.verify();337      mocks.fs.verify();338      mocks.helpers.verify();339    });340  }));341  describe('reinstallRemoteApk', withMocks({adb, helpers}, (mocks) => {342    const localApkPath = 'local';343    const pkg = 'pkg';344    const remotePath = 'remote';345    const androidInstallTimeout = 90000;346    it('should throw error if remote file does not exist', async () => {347      mocks.adb.expects('uninstallApk').withExactArgs(pkg).returns('');348      // install remote is not defines do we mean installApkRemotely?349      mocks.adb.expects('installFromDevicePath').withExactArgs(remotePath, {timeout: 90000})...ah1.js
Source:ah1.js  
1import _ from 'lodash';2import path from 'path';3import { exec } from 'teen_process';4import { retry, retryInterval } from 'asyncbox';5import logger from './logger';6import { fs } from 'appium-support';7import { path as unicodeIMEPath } from 'appium-android-ime';8import { path as settingsApkPath } from 'io.appium.settings';9import { path as unlockApkPath } from 'appium-unlock';10import Bootstrap from 'appium-android-bootstrap';11import B from 'bluebird';12import ADB from 'appium-adb';13import { default as unlocker, PIN_UNLOCK, PASSWORD_UNLOCK,14  PATTERN_UNLOCK, FINGERPRINT_UNLOCK } from './unlock-helpers';15const PACKAGE_INSTALL_TIMEOUT = 90000; // milliseconds16const CHROME_BROWSER_PACKAGE_ACTIVITY = {17  chrome: {18    pkg: 'com.android.chrome',19    activity: 'com.google.android.apps.chrome.Main',20  },21  chromium: {22    pkg: 'org.chromium.chrome.shell',23    activity: '.ChromeShellActivity',24  },25  chromebeta: {26    pkg: 'com.chrome.beta',27    activity: 'com.google.android.apps.chrome.Main',28  },29  browser: {30    pkg: 'com.android.browser',31    activity: 'com.android.browser.BrowserActivity',32  },33  'chromium-browser': {34    pkg: 'org.chromium.chrome',35    activity: 'com.google.android.apps.chrome.Main',36  },37  'chromium-webview': {38    pkg: 'org.chromium.webview_shell',39    activity: 'org.chromium.webview_shell.WebViewBrowserActivity',40  },41  default: {42    pkg: 'com.android.chrome',43    activity: 'com.google.android.apps.chrome.Main',44  },45};46const SETTINGS_HELPER_PKG_ID = 'io.appium.settings';47const SETTINGS_HELPER_PKG_ACTIVITY = ".Settings";48const UNLOCK_HELPER_PKG_ID = 'io.appium.unlock';49const UNLOCK_HELPER_PKG_ACTIVITY = ".Unlock";50const UNICODE_IME_PKG_ID = 'io.appium.android.ime';51let helpers = {};52helpers.createBaseADB = async function (opts = {}) {53  // filter out any unwanted options sent in54  // this list should be updated as ADB takes more arguments55  const {56    javaVersion,57    adbPort,58    suppressKillServer,59    remoteAdbHost,60    clearDeviceLogsOnStart,61    adbExecTimeout,62  } = opts;63  return await ADB.createADB({64    javaVersion,65    adbPort,66    suppressKillServer,67    remoteAdbHost,68    clearDeviceLogsOnStart,69    adbExecTimeout,70  });71};72helpers.parseJavaVersion = function (stderr) {73  let lines = stderr.split("\n");74  for (let line of lines) {75    if (new RegExp(/(java|openjdk) version/).test(line)) {76      return line.split(" ")[2].replace(/"/g, '');77    }78  }79  return null;80};81helpers.getJavaVersion = async function (logVersion = true) {82  let {stderr} = await exec('java', ['-version']);83  let javaVer = helpers.parseJavaVersion(stderr);84  if (javaVer === null) {85    throw new Error("Could not get the Java version. Is Java installed?");86  }87  if (logVersion) {88    logger.info(`Java version is: ${javaVer}`);89  }90  return javaVer;91};92helpers.prepareEmulator = async function (adb, opts) {93  let {avd, avdArgs, language, locale, avdLaunchTimeout,94       avdReadyTimeout} = opts;95  if (!avd) {96    throw new Error("Cannot launch AVD without AVD name");97  }98  let avdName = avd.replace('@', '');99  let runningAVD = await adb.getRunningAVD(avdName);100  if (runningAVD !== null) {101    if (avdArgs && avdArgs.toLowerCase().indexOf("-wipe-data") > -1) {102      logger.debug(`Killing '${avdName}' because it needs to be wiped at start.`);103      await adb.killEmulator(avdName);104    } else {105      logger.debug("Not launching AVD because it is already running.");106      return;107    }108  }109  avdArgs = this.prepareAVDArgs(opts, adb, avdArgs);110  await adb.launchAVD(avd, avdArgs, language, locale, avdLaunchTimeout,111                      avdReadyTimeout);112};113helpers.prepareAVDArgs = function (opts, adb, avdArgs) {114  let args = avdArgs ? [avdArgs] : [];115  if (!_.isUndefined(opts.networkSpeed)) {116    let networkSpeed = this.ensureNetworkSpeed(adb, opts.networkSpeed);117    args.push('-netspeed', networkSpeed);118  }119  if (opts.isHeadless) {120    args.push('-no-window');121  }122  return args.join(' ');123};124helpers.ensureNetworkSpeed = function (adb, networkSpeed) {125  if (_.values(adb.NETWORK_SPEED).indexOf(networkSpeed) !== -1) {126    return networkSpeed;127  }128  logger.warn(`Wrong network speed param ${networkSpeed}, using default: full. Supported values: ${_.values(adb.NETWORK_SPEED)}`);129  return adb.NETWORK_SPEED.FULL;130};131helpers.ensureDeviceLocale = async function (adb, language, country) {132  if (!_.isString(language) && !_.isString(country)) {133    logger.warn(`setDeviceLanguageCountry requires language or country.`);134    logger.warn(`Got language: '${language}' and country: '${country}'`);135    return;136  }137  await adb.setDeviceLanguageCountry(language, country);138  if (!await adb.ensureCurrentLocale(language, country)) {139    throw new Error(`Failed to set language: ${language} and country: ${country}`);140  }141};142helpers.getDeviceInfoFromCaps = async function (opts = {}) {143  // we can create a throwaway ADB instance here, so there is no dependency144  // on instantiating on earlier (at this point, we have no udid)145  // we can only use this ADB object for commands that would not be confused146  // if multiple devices are connected147  const adb = await helpers.createBaseADB(opts);148  let udid = opts.udid;149  let emPort = null;150  // a specific avd name was given. try to initialize with that151  if (opts.avd) {152    await helpers.prepareEmulator(adb, opts);153    udid = adb.curDeviceId;154    emPort = adb.emulatorPort;155  } else {156    // no avd given. lets try whatever's plugged in devices/emulators157    logger.info("Retrieving device list");158    let devices = await adb.getDevicesWithRetry();159    // udid was given, lets try to init with that device160    if (udid) {161      if (!_.includes(_.map(devices, 'udid'), udid)) {162        logger.errorAndThrow(`Device ${udid} was not in the list ` +163                             `of connected devices`);164      }165      emPort = adb.getPortFromEmulatorString(udid);166    } else if (opts.platformVersion) {167      opts.platformVersion = `${opts.platformVersion}`.trim();168      // a platform version was given. lets try to find a device with the same os169      logger.info(`Looking for a device with Android '${opts.platformVersion}'`);170      // in case we fail to find something, give the user a useful log that has171      // the device udids and os versions so they know what's available172      let availDevicesStr = [];173      // first try started devices/emulators174      for (let device of devices) {175        // direct adb calls to the specific device176        await adb.setDeviceId(device.udid);177        let deviceOS = await adb.getPlatformVersion();178        // build up our info string of available devices as we iterate179        availDevicesStr.push(`${device.udid} (${deviceOS})`);180        // we do a begins with check for implied wildcard matching181        // eg: 4 matches 4.1, 4.0, 4.1.3-samsung, etc182        if (deviceOS.indexOf(opts.platformVersion) === 0) {183          udid = device.udid;184          break;185        }186      }187      // we couldn't find anything! quit188      if (!udid) {189        logger.errorAndThrow(`Unable to find an active device or emulator ` +190                             `with OS ${opts.platformVersion}. The following ` +191                             `are available: ` + availDevicesStr.join(', '));192      }193      emPort = adb.getPortFromEmulatorString(udid);194    } else {195      // a udid was not given, grab the first device we see196      udid = devices[0].udid;197      emPort = adb.getPortFromEmulatorString(udid);198    }199  }200  logger.info(`Using device: ${udid}`);201  return {udid, emPort};202};203// returns a new adb instance with deviceId set204helpers.createADB = async function (opts = {}) {205  const {udid, emPort} = opts;206  const adb = await helpers.createBaseADB(opts);207  adb.setDeviceId(udid);208  if (emPort) {209    adb.setEmulatorPort(emPort);210  }211  return adb;212};213helpers.validatePackageActivityNames = function (opts) {214  for (const key of ['appPackage', 'appActivity', 'appWaitPackage', 'appWaitActivity']) {215    const name = opts[key];216    if (!name) {217      continue;218    }219    const match = /([^\w.*,])+/.exec(name);220    if (!match) {221      continue;222    }223    logger.warn(`Capability '${key}' is expected to only include latin letters, digits, underscore, dot, comma and asterisk characters.`);224    logger.warn(`Current value '${name}' has non-matching character at index ${match.index}: '${name.substring(0, match.index + 1)}'`);225  }226};227helpers.getLaunchInfo = async function (adb, opts) {228  let {app, appPackage, appActivity, appWaitPackage, appWaitActivity} = opts;229  if (!app) {230    logger.warn("No app sent in, not parsing package/activity");231    return;232  }233  this.validatePackageActivityNames(opts);234  if (appPackage && appActivity) {235    return;236  }237  logger.debug("Parsing package and activity from app manifest");238  let {apkPackage, apkActivity} =239    await adb.packageAndLaunchActivityFromManifest(app);240  if (apkPackage && !appPackage) {241    appPackage = apkPackage;242  }243  if (!appWaitPackage) {244    appWaitPackage = appPackage;245  }246  if (apkActivity && !appActivity) {247    appActivity = apkActivity;248  }249  if (!appWaitActivity) {250    appWaitActivity = appActivity;251  }252  logger.debug(`Parsed package and activity are: ${apkPackage}/${apkActivity}`);253  return {appPackage, appWaitPackage, appActivity, appWaitActivity};254};255helpers.resetApp = async function (adb, opts = {}) {256  const {257    app,258    appPackage,259    fastReset,260    fullReset,261    androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT,262    autoGrantPermissions,263    allowTestPackages264  } = opts;265  if (!appPackage) {266    throw new Error("'appPackage' option is required");267  }268  const isInstalled = await adb.isAppInstalled(appPackage);269  if (isInstalled) {270    try {271      await adb.forceStop(appPackage);272    } catch (ign) {}273    // fullReset has priority over fastReset274    if (!fullReset && fastReset) {275      const output = await adb.clear(appPackage);276      if (_.isString(output) && output.toLowerCase().includes('failed')) {277        throw new Error(`Cannot clear the application data of '${appPackage}'. Original error: ${output}`);278      }279      // executing `shell pm clear` resets previously assigned application permissions as well280      if (autoGrantPermissions) {281        try {282          await adb.grantAllPermissions(appPackage);283        } catch (error) {284          logger.error(`Unable to grant permissions requested. Original error: ${error.message}`);285        }286      }287      logger.debug(`Performed fast reset on the installed '${appPackage}' application (stop and clear)`);288      return;289    }290  }291  if (!app) {292    throw new Error("'app' option is required for reinstall");293  }294  logger.debug(`Running full reset on '${appPackage}' (reinstall)`);295  if (isInstalled) {296    await adb.uninstallApk(appPackage);297  }298  await adb.install(app, {299    grantPermissions: autoGrantPermissions,300    timeout: androidInstallTimeout,301    allowTestPackages,302  });303};304helpers.installApk = async function (adb, opts = {}) {305  const {306    app,307    appPackage,308    fastReset,309    fullReset,310    androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT,311    autoGrantPermissions,312    allowTestPackages313  } = opts;314  if (!app || !appPackage) {315    throw new Error("'app' and 'appPackage' options are required");316  }317  if (fullReset) {318    await this.resetApp(adb, opts);319    return;320  }321  // There is no need to reset the newly installed app322  const shouldPerformFastReset = fastReset && await adb.isAppInstalled(appPackage);323  await adb.installOrUpgrade(app, appPackage, {324    grantPermissions: autoGrantPermissions,325    timeout: androidInstallTimeout,326    allowTestPackages,327  });328  if (shouldPerformFastReset) {329    logger.info(`Performing fast reset on '${appPackage}'`);330    await this.resetApp(adb, opts);331  }332};333/**334 * Installs an array of apks335 * @param {ADB} adb Instance of Appium ADB object336 * @param {Object} opts Opts defined in driver.js337 */338helpers.installOtherApks = async function (otherApps, adb, opts) {339  let {340    androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT,341    autoGrantPermissions,342    allowTestPackages343  } = opts;344  // Install all of the APK's asynchronously345  await B.all(otherApps.map((otherApp) => {346    logger.debug(`Installing app: ${otherApp}`);347    return adb.installOrUpgrade(otherApp, null, {348      grantPermissions: autoGrantPermissions,349      timeout: androidInstallTimeout,350      allowTestPackages,351    });352  }));353};354helpers.initUnicodeKeyboard = async function (adb) {355  logger.debug('Enabling Unicode keyboard support');356  logger.debug("Pushing unicode ime to device...");357  try {358    await adb.install(unicodeIMEPath, {replace: false});359  } catch (err) {360    logger.info(`Performing full reinstall of ${UNICODE_IME_PKG_ID} as a possible fix for: ${err.message}`);361    await adb.uninstallApk(UNICODE_IME_PKG_ID);362    await adb.install(unicodeIMEPath, {replace: false});363  }364  // get the default IME so we can return back to it later if we want365  let defaultIME = await adb.defaultIME();366  logger.debug(`Unsetting previous IME ${defaultIME}`);367  const appiumIME = `${UNICODE_IME_PKG_ID}/.UnicodeIME`;368  logger.debug(`Setting IME to '${appiumIME}'`);369  await adb.enableIME(appiumIME);370  await adb.setIME(appiumIME);371  return defaultIME;372};373helpers.setMockLocationApp = async function (adb, app) {374  try {375    if (await adb.getApiLevel() < 23) {376      await adb.shell(['settings', 'put', 'secure', 'mock_location', '1']);377    } else {378      await adb.shell(['appops', 'set', app, 'android:mock_location', 'allow']);379    }380  } catch (err) {381    logger.warn(`Unable to set mock location for app '${app}': ${err.message}`);382  }383};384helpers.installHelperApp = async function (adb, apkPath, packageId, appName) {385  try {386    await adb.installOrUpgrade(apkPath, packageId, {grantPermissions: true});387  } catch (err) {388    logger.warn(`Ignored error while installing Appium ${appName} helper: ` +389                `'${err.message}'. Manually uninstalling the application ` +390                `with package id '${packageId}' may help. Expect some Appium ` +391                `features may not work as expected unless this problem is ` +392                `fixed.`);393  }394};395helpers.pushSettingsApp = async function (adb, throwError = false) {396  logger.debug("Pushing settings apk to device...");397  await helpers.installHelperApp(adb, settingsApkPath, SETTINGS_HELPER_PKG_ID, 'Settings');398  // Reinstall will stop the settings helper process anyway, so399  // there is no need to continue if the application is still running400  if (await adb.processExists(SETTINGS_HELPER_PKG_ID)) {401    logger.debug(`${SETTINGS_HELPER_PKG_ID} is already running. ` +402                 `There is no need to reset its permissions.`);403    return;404  }405  // lauch io.appium.settings app due to settings failing to be set406  // if the app is not launched prior to start the session on android 7+407  // see https://github.com/appium/appium/issues/8957408  try {409    await adb.startApp({410      pkg: SETTINGS_HELPER_PKG_ID,411      activity: SETTINGS_HELPER_PKG_ACTIVITY,412      action: "android.intent.action.MAIN",413      category: "android.intent.category.LAUNCHER",414      flags: "0x10200000",415      stopApp: false,416    });417  } catch (err) {418    logger.warn(`Failed to launch settings app: ${err.message}`);419    if (throwError) {420      throw err;421    }422  }423};424helpers.pushUnlock = async function (adb) {425  logger.debug("Pushing unlock helper app to device...");426  await helpers.installHelperApp(adb, unlockApkPath, UNLOCK_HELPER_PKG_ID, 'Unlock');427};428/**429 * Extracts string.xml and converts it to string.json and pushes430 * it to /data/local/tmp/string.json on for use of bootstrap431 * If app is not present to extract string.xml it deletes remote strings.json432 * If app does not have strings.xml we push an empty json object to remote433 *434 * @param {?string} language - Language abbreviation, for example 'fr'. The default language435 * is used if this argument is not defined.436 * @param {Object} adb - The adb mofdule instance.437 * @param {Object} opts - Driver options dictionary.438 * @returns {Object} The dictionary, where string resourtces identifiers are keys439 * along with their corresponding values for the given language or an empty object440 * if no matching resources were extracted.441 */442helpers.pushStrings = async function (language, adb, opts) {443  const remoteDir = '/data/local/tmp';444  const stringsJson = 'strings.json';445  const remoteFile = `${remoteDir}/${stringsJson}`;446  // clean up remote string.json if present447  await adb.rimraf(remoteFile);448  if (_.isEmpty(opts.appPackage) || !(await fs.exists(opts.app))) {449    return {};450  }451  const stringsTmpDir = path.resolve(opts.tmpDir, opts.appPackage);452  try {453    logger.debug('Extracting strings from apk', opts.app, language, stringsTmpDir);454    const {apkStrings, localPath} = await adb.extractStringsFromApk(opts.app, language, stringsTmpDir);455    await adb.push(localPath, remoteDir);456    return apkStrings;457  } catch (err) {458    logger.warn(`Could not get strings, continuing anyway. Original error: ${err.message}`);459    await adb.shell('echo', [`'{}' > ${remoteFile}`]);460  } finally {461    await fs.rimraf(stringsTmpDir);462  }463  return {};464};465helpers.unlockWithUIAutomation = async function (driver, adb, unlockCapabilities) {466  let unlockType = unlockCapabilities.unlockType;467  if (!unlocker.isValidUnlockType(unlockType)) {468    throw new Error(`Invalid unlock type ${unlockType}`);469  }470  let unlockKey = unlockCapabilities.unlockKey;471  if (!unlocker.isValidKey(unlockType, unlockKey)) {472    throw new Error(`Missing unlockKey ${unlockKey} capability for unlockType ${unlockType}`);473  }474  const unlockMethod = {475    [PIN_UNLOCK]: unlocker.pinUnlock,476    [PASSWORD_UNLOCK]: unlocker.passwordUnlock,477    [PATTERN_UNLOCK]: unlocker.patternUnlock,478    [FINGERPRINT_UNLOCK]: unlocker.fingerprintUnlock479  }[unlockType];480  await unlockMethod(adb, driver, unlockCapabilities);481};482helpers.unlockWithHelperApp = async function (adb) {483  logger.info("Unlocking screen");484  try {485    await adb.forceStop(UNLOCK_HELPER_PKG_ID);486  } catch (e) {487    // Sometimes we can see the below error, but we can ignore it.488    // [W3C] Encountered internal error running command: Error: Error executing adbExec. Original error: 'Command 'adb -P 5037 -s emulator-5554 shell am force-stop io.appium.unlock' timed out after 20000ms'; Stderr: ''; Code: 'null'489    logger.warn(`An error in unlockWithHelperApp: ${e.message}`);490  }491  let startOpts = {492    pkg: UNLOCK_HELPER_PKG_ID,493    activity: UNLOCK_HELPER_PKG_ACTIVITY,494    action: "android.intent.action.MAIN",495    category: "android.intent.category.LAUNCHER",496    flags: "0x10200000",497    stopApp: false,498    retry: false,499    waitDuration: 1000500  };501  // Unlock succeed with a couple of retries.502  let firstRun = true;503  await retry(3, async function () {504    // To reduce a time to call adb.isScreenLocked() since `adb shell dumpsys window` is easy to hang adb commands505    if (firstRun) {506      firstRun = false;507    } else {508      try {509        if (!(await adb.isScreenLocked())) {510          return;511        }512      } catch (e) {513        logger.warn(`Error in isScreenLocked: ${e.message}`);514        logger.warn("\"adb shell dumpsys window\" command has timed out.");515        logger.warn("The reason of this timeout is the delayed adb response. Resetting adb server can improve it.");516      }517    }518    logger.info(`Launching ${UNLOCK_HELPER_PKG_ID}`);519    // The command takes too much time so we should not call the command over twice continuously.520    await adb.startApp(startOpts);521  });522};523helpers.unlock = async function (driver, adb, capabilities) {524  if (!(await adb.isScreenLocked())) {525    logger.info("Screen already unlocked, doing nothing");526    return;527  }528  logger.debug("Screen is locked, trying to unlock");529  if (_.isUndefined(capabilities.unlockType)) {530    logger.warn("Using app unlock, this is going to be deprecated!");531    await helpers.unlockWithHelperApp(adb);532  } else {533    await helpers.unlockWithUIAutomation(driver, adb, {unlockType: capabilities.unlockType, unlockKey: capabilities.unlockKey});534    await helpers.verifyUnlock(adb);535  }536};537helpers.verifyUnlock = async function (adb) {538  await retryInterval(2, 1000, async () => {539    if (await adb.isScreenLocked()) {540      throw new Error("Screen did not unlock successfully, retrying");541    }542    logger.debug("Screen unlocked successfully");543  });544};545helpers.initDevice = async function (adb, opts) {546  await adb.waitForDevice();547  // pushSettingsApp required before calling ensureDeviceLocale for API Level 24+548  await helpers.pushSettingsApp(adb);549  if (!opts.avd) {550    await helpers.setMockLocationApp(adb, SETTINGS_HELPER_PKG_ID);551  }552  await helpers.ensureDeviceLocale(adb, opts.language, opts.locale);553  await adb.startLogcat();554  let defaultIME;555  if (opts.unicodeKeyboard) {556    defaultIME = await helpers.initUnicodeKeyboard(adb);557  }558  if (_.isUndefined(opts.unlockType)) {559    await helpers.pushUnlock(adb);560  }561  return defaultIME;562};563helpers.removeNullProperties = function (obj) {564  for (let key of _.keys(obj)) {565    if (_.isNull(obj[key]) || _.isUndefined(obj[key])) {566      delete obj[key];567    }568  }569};570helpers.truncateDecimals = function (number, digits) {571  let multiplier = Math.pow(10, digits),572      adjustedNum = number * multiplier,573      truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);574  return truncatedNum / multiplier;575};576helpers.isChromeBrowser = function (browser) {577  return _.includes(Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY), (browser || '').toLowerCase());578};579helpers.getChromePkg = function (browser) {580  return CHROME_BROWSER_PACKAGE_ACTIVITY[browser.toLowerCase()] ||581         CHROME_BROWSER_PACKAGE_ACTIVITY.default;582};583helpers.removeAllSessionWebSocketHandlers = async function (server, sessionId) {584  if (!server || !_.isFunction(server.getWebSocketHandlers)) {585    return;586  }587  const activeHandlers = await server.getWebSocketHandlers(sessionId);588  for (const pathname of _.keys(activeHandlers)) {589    await server.removeWebSocketHandler(pathname);590  }591};592/**593 * Takes a desired capability and tries to JSON.parse it as an array,594 * and either returns the parsed array or a singleton array.595 *596 * @param {any} cap A desired capability597 */598helpers.parseArray = function (cap) {599  let parsedCaps;600  try {601    parsedCaps = JSON.parse(cap);602  } catch (ign) { }603  if (_.isArray(parsedCaps)) {604    return parsedCaps;605  } else if (_.isString(cap)) {606    return [cap];607  }608  throw new Error(`must provide a string or JSON Array; received ${cap}`);609};610helpers.validateDesiredCaps = function (caps) {611  // make sure that the capabilities have one of `app`, `appPackage` or `browser`612  if ((!caps.browserName || !this.isChromeBrowser(caps.browserName)) && !caps.app && !caps.appPackage) {613    logger.errorAndThrow('The desired capabilities must include either an app, appPackage or browserName');614  }615  if (caps.browserName) {616    if (caps.app) {617      // warn if the capabilities have both `app` and `browser, although this is common with selenium grid618      logger.warn('The desired capabilities should generally not include both an app and a browserName');619    }620    if (caps.appPackage) {621      logger.errorAndThrow(`The desired capabilities must include either 'appPackage' or 'browserName'`);622    }623  }624  return true;625};626helpers.bootstrap = Bootstrap;627helpers.unlocker = unlocker;...general-specs.js
Source:general-specs.js  
1import chai from 'chai';2import chaiAsPromised from 'chai-as-promised';3import sinon from 'sinon';4import AndroidDriver from '../../..';5import { parseSurfaceLine, parseWindows } from '../../../lib/commands/general';6import helpers from '../../../lib/android-helpers';7import { withMocks } from 'appium-test-support';8import { fs } from 'appium-support';9import Bootstrap from '../../../lib/bootstrap';10import B from 'bluebird';11import ADB from 'appium-adb';12chai.should();13chai.use(chaiAsPromised);14let driver;15let sandbox = sinon.createSandbox();16let expect = chai.expect;17describe('General', function () {18  beforeEach(function () {19    driver = new AndroidDriver();20    driver.bootstrap = new Bootstrap();21    driver.adb = new ADB();22    driver.caps = {};23    driver.opts = {};24  });25  afterEach(function () {26    sandbox.restore();27  });28  describe('keys', function () {29    it('should send keys via setText bootstrap command', async function () {30      sandbox.stub(driver.bootstrap, 'sendAction');31      driver.opts.unicodeKeyboard = true;32      await driver.keys('keys');33      driver.bootstrap.sendAction34        .calledWithExactly('setText',35          {text: 'keys', replace: false, unicodeKeyboard: true})36        .should.be.true;37    });38    it('should join keys if keys is array', async function () {39      sandbox.stub(driver.bootstrap, 'sendAction');40      driver.opts.unicodeKeyboard = false;41      await driver.keys(['k', 'e', 'y', 's']);42      driver.bootstrap.sendAction43        .calledWithExactly('setText', {text: 'keys', replace: false})44        .should.be.true;45    });46  });47  describe('getDeviceTime', function () {48    it('should return device time', async function () {49      sandbox.stub(driver.adb, 'shell');50      driver.adb.shell.returns(' 2018-06-09T16:21:54+0900 ');51      await driver.getDeviceTime().should.become('2018-06-09T16:21:54+09:00');52      driver.adb.shell.calledWithExactly(['date', '+%Y-%m-%dT%T%z']).should.be.true;53    });54    it('should return device time with custom format', async function () {55      sandbox.stub(driver.adb, 'shell');56      driver.adb.shell.returns(' 2018-06-09T16:21:54+0900 ');57      await driver.getDeviceTime('YYYY-MM-DD').should.become('2018-06-09');58      driver.adb.shell.calledWithExactly(['date', '+%Y-%m-%dT%T%z']).should.be.true;59    });60    it('should throw error if shell command failed', async function () {61      sandbox.stub(driver.adb, 'shell').throws();62      await driver.getDeviceTime().should.be.rejected;63    });64  });65  describe('getPageSource', function () {66    it('should return page source', async function () {67      sandbox.stub(driver.bootstrap, 'sendAction').withArgs('source').returns('sources');68      (await driver.getPageSource()).should.be.equal('sources');69    });70  });71  describe('back', function () {72    it('should press back', async function () {73      sandbox.stub(driver.bootstrap, 'sendAction');74      await driver.back();75      driver.bootstrap.sendAction.calledWithExactly('pressBack').should.be.true;76    });77  });78  describe('isKeyboardShown', function () {79    it('should return true if the keyboard is shown', async function () {80      driver.adb.isSoftKeyboardPresent = function isSoftKeyboardPresent () {81        return {isKeyboardShown: true, canCloseKeyboard: true};82      };83      (await driver.isKeyboardShown()).should.equal(true);84    });85    it('should return false if the keyboard is not shown', async function () {86      driver.adb.isSoftKeyboardPresent = function isSoftKeyboardPresent () {87        return {isKeyboardShown: false, canCloseKeyboard: true};88      };89      (await driver.isKeyboardShown()).should.equal(false);90    });91  });92  describe('hideKeyboard', function () {93    it('should hide keyboard with ESC command', async function () {94      sandbox.stub(driver.adb, 'keyevent');95      let callIdx = 0;96      driver.adb.isSoftKeyboardPresent = function isSoftKeyboardPresent () {97        callIdx++;98        return {99          isKeyboardShown: callIdx <= 1,100          canCloseKeyboard: callIdx <= 1,101        };102      };103      await driver.hideKeyboard().should.eventually.be.fulfilled;104      driver.adb.keyevent.calledWithExactly(111).should.be.true;105    });106    it('should throw if cannot close keyboard', async function () {107      this.timeout(10000);108      sandbox.stub(driver.adb, 'keyevent');109      driver.adb.isSoftKeyboardPresent = function isSoftKeyboardPresent () {110        return {111          isKeyboardShown: true,112          canCloseKeyboard: false,113        };114      };115      await driver.hideKeyboard().should.eventually.be.rejected;116      driver.adb.keyevent.notCalled.should.be.true;117    });118    it('should not throw if no keyboard is present', async function () {119      driver.adb.isSoftKeyboardPresent = function isSoftKeyboardPresent () {120        return {121          isKeyboardShown: false,122          canCloseKeyboard: false,123        };124      };125      await driver.hideKeyboard().should.eventually.be.fulfilled;126    });127  });128  describe('openSettingsActivity', function () {129    it('should open settings activity', async function () {130      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')131        .returns({appPackage: 'pkg', appActivity: 'act'});132      sandbox.stub(driver.adb, 'shell');133      sandbox.stub(driver.adb, 'waitForNotActivity');134      await driver.openSettingsActivity('set1');135      driver.adb.shell.calledWithExactly(['am', 'start', '-a', 'android.settings.set1'])136        .should.be.true;137      driver.adb.waitForNotActivity.calledWithExactly('pkg', 'act', 5000)138        .should.be.true;139    });140  });141  describe('getWindowSize', function () {142    it('should get window size', async function () {143      sandbox.stub(driver.bootstrap, 'sendAction')144        .withArgs('getDeviceSize').returns('size');145      (await driver.getWindowSize()).should.be.equal('size');146    });147  });148  describe('getWindowRect', function () {149    it('should get window size', async function () {150      sandbox.stub(driver.bootstrap, 'sendAction')151        .withArgs('getDeviceSize').returns({width: 300, height: 400});152      const rect = await driver.getWindowRect();153      rect.width.should.be.equal(300);154      rect.height.should.be.equal(400);155      rect.x.should.be.equal(0);156      rect.y.should.be.equal(0);157    });158  });159  describe('getCurrentActivity', function () {160    it('should get current activity', async function () {161      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')162        .returns({appActivity: 'act'});163      await driver.getCurrentActivity().should.eventually.be.equal('act');164    });165  });166  describe('getCurrentPackage', function () {167    it('should get current activity', async function () {168      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')169        .returns({appPackage: 'pkg'});170      await driver.getCurrentPackage().should.eventually.equal('pkg');171    });172  });173  describe('isAppInstalled', function () {174    it('should return true if app is installed', async function () {175      sandbox.stub(driver.adb, 'isAppInstalled').withArgs('pkg').returns(true);176      (await driver.isAppInstalled('pkg')).should.be.true;177    });178  });179  describe('removeApp', function () {180    it('should remove app', async function () {181      sandbox.stub(driver.adb, 'uninstallApk').withArgs('pkg').returns(true);182      (await driver.removeApp('pkg')).should.be.true;183    });184  });185  describe('installApp', function () {186    it('should install app', async function () {187      let app = 'app.apk';188      sandbox.stub(driver.helpers, 'configureApp').withArgs(app, '.apk')189        .returns(app);190      sandbox.stub(fs, 'rimraf').returns();191      sandbox.stub(driver.adb, 'install').returns(true);192      await driver.installApp(app);193      driver.helpers.configureApp.calledOnce.should.be.true;194      fs.rimraf.notCalled.should.be.true;195      driver.adb.install.calledOnce.should.be.true;196    });197    it('should throw an error if APK does not exist', async function () {198      await driver.installApp('non/existent/app.apk').should.be199        .rejectedWith(/does not exist or is not accessible/);200    });201  });202  describe('background', function () {203    it('should bring app to background and back', async function () {204      const appPackage = 'wpkg';205      const appActivity = 'wacv';206      driver.opts = {appPackage, appActivity, intentAction: 'act',207                     intentCategory: 'cat', intentFlags: 'flgs',208                     optionalIntentArguments: 'opt'};209      sandbox.stub(driver.adb, 'goToHome');210      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')211        .returns({appPackage, appActivity});212      sandbox.stub(B, 'delay');213      sandbox.stub(driver.adb, 'startApp');214      sandbox.stub(driver, 'activateApp');215      await driver.background(10);216      driver.adb.getFocusedPackageAndActivity.calledOnce.should.be.true;217      driver.adb.goToHome.calledOnce.should.be.true;218      B.delay.calledWithExactly(10000).should.be.true;219      driver.activateApp.calledWithExactly(appPackage).should.be.true;220      driver.adb.startApp.notCalled.should.be.true;221    });222    it('should bring app to background and back if started after session init', async function () {223      const appPackage = 'newpkg';224      const appActivity = 'newacv';225      driver.opts = {appPackage: 'pkg', appActivity: 'acv', intentAction: 'act',226                     intentCategory: 'cat', intentFlags: 'flgs',227                     optionalIntentArguments: 'opt'};228      let params = {pkg: appPackage, activity: appActivity, action: 'act', category: 'cat',229                    flags: 'flgs', waitPkg: 'wpkg', waitActivity: 'wacv',230                    optionalIntentArguments: 'opt', stopApp: false};231      driver._cachedActivityArgs = {[`${appPackage}/${appActivity}`]: params};232      sandbox.stub(driver.adb, 'goToHome');233      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')234        .returns({appPackage, appActivity});235      sandbox.stub(B, 'delay');236      sandbox.stub(driver.adb, 'startApp');237      sandbox.stub(driver, 'activateApp');238      await driver.background(10);239      driver.adb.getFocusedPackageAndActivity.calledOnce.should.be.true;240      driver.adb.goToHome.calledOnce.should.be.true;241      B.delay.calledWithExactly(10000).should.be.true;242      driver.adb.startApp.calledWithExactly(params).should.be.true;243      driver.activateApp.notCalled.should.be.true;244    });245    it('should bring app to background and back if waiting for other pkg / activity', async function () { //eslint-disable-line246      const appPackage = 'somepkg';247      const appActivity = 'someacv';248      const appWaitPackage = 'somewaitpkg';249      const appWaitActivity = 'somewaitacv';250      driver.opts = {appPackage, appActivity, appWaitPackage, appWaitActivity,251                     intentAction: 'act', intentCategory: 'cat',252                     intentFlags: 'flgs', optionalIntentArguments: 'opt',253                     stopApp: false};254      sandbox.stub(driver.adb, 'goToHome');255      sandbox.stub(driver.adb, 'getFocusedPackageAndActivity')256        .returns({appPackage: appWaitPackage, appActivity: appWaitActivity});257      sandbox.stub(B, 'delay');258      sandbox.stub(driver.adb, 'startApp');259      sandbox.stub(driver, 'activateApp');260      await driver.background(10);261      driver.adb.getFocusedPackageAndActivity.calledOnce.should.be.true;262      driver.adb.goToHome.calledOnce.should.be.true;263      B.delay.calledWithExactly(10000).should.be.true;264      driver.activateApp.calledWithExactly(appWaitPackage).should.be.true;265      driver.adb.startApp.notCalled.should.be.true;266    });267    it('should not bring app back if seconds are negative', async function () {268      sandbox.stub(driver.adb, 'goToHome');269      sandbox.stub(driver.adb, 'startApp');270      await driver.background(-1);271      driver.adb.goToHome.calledOnce.should.be.true;272      driver.adb.startApp.notCalled.should.be.true;273    });274  });275  describe('getStrings', withMocks({helpers}, (mocks) => {276    it('should return app strings', async function () {277      driver.bootstrap.sendAction = () => '';278      mocks.helpers.expects('pushStrings')279          .returns({test: 'en_value'});280      let strings = await driver.getStrings('en');281      strings.test.should.equal('en_value');282      mocks.helpers.verify();283    });284    it('should return cached app strings for the specified language', async function () {285      driver.adb.getDeviceLanguage = () => 'en';286      driver.apkStrings.en = {test: 'en_value'};287      driver.apkStrings.fr = {test: 'fr_value'};288      let strings = await driver.getStrings('fr');289      strings.test.should.equal('fr_value');290    });291    it('should return cached app strings for the device language', async function () {292      driver.adb.getDeviceLanguage = () => 'en';293      driver.apkStrings.en = {test: 'en_value'};294      driver.apkStrings.fr = {test: 'fr_value'};295      let strings = await driver.getStrings();296      strings.test.should.equal('en_value');297    });298  }));299  describe('launchApp', function () {300    it('should init and start app', async function () {301      sandbox.stub(driver, 'initAUT');302      sandbox.stub(driver, 'startAUT');303      await driver.launchApp();304      driver.initAUT.calledOnce.should.be.true;305      driver.startAUT.calledOnce.should.be.true;306    });307  });308  describe('startActivity', function () {309    let params;310    beforeEach(function () {311      params = {pkg: 'pkg', activity: 'act', waitPkg: 'wpkg', waitActivity: 'wact',312                action: 'act', category: 'cat', flags: 'flgs', optionalIntentArguments: 'opt'};313      sandbox.stub(driver.adb, 'startApp');314    });315    it('should start activity', async function () {316      params.optionalIntentArguments = 'opt';317      params.stopApp = false;318      await driver.startActivity('pkg', 'act', 'wpkg', 'wact', 'act',319        'cat', 'flgs', 'opt', true);320      driver.adb.startApp.calledWithExactly(params).should.be.true;321    });322    it('should use dontStopAppOnReset from opts if it is not passed as param', async function () {323      driver.opts.dontStopAppOnReset = true;324      params.stopApp = false;325      await driver.startActivity('pkg', 'act', 'wpkg', 'wact', 'act', 'cat', 'flgs', 'opt');326      driver.adb.startApp.calledWithExactly(params).should.be.true;327    });328    it('should use appPackage and appActivity if appWaitPackage and appWaitActivity are undefined', async function () {329      params.waitPkg = 'pkg';330      params.waitActivity = 'act';331      params.stopApp = true;332      await driver.startActivity('pkg', 'act', null, null, 'act', 'cat', 'flgs', 'opt', false);333      driver.adb.startApp.calledWithExactly(params).should.be.true;334    });335  });336  describe('reset', function () {337    it('should reset app via reinstall if fullReset is true', async function () {338      driver.opts.fullReset = true;339      driver.opts.appPackage = 'pkg';340      sandbox.stub(driver, 'startAUT').returns('aut');341      sandbox.stub(helpers, 'resetApp').returns(undefined);342      await driver.reset().should.eventually.be.equal('aut');343      helpers.resetApp.calledWith(driver.adb).should.be.true;344      driver.startAUT.calledOnce.should.be.true;345    });346    it('should do fast reset if fullReset is false', async function () {347      driver.opts.fullReset = false;348      driver.opts.appPackage = 'pkg';349      sandbox.stub(helpers, 'resetApp').returns(undefined);350      sandbox.stub(driver, 'startAUT').returns('aut');351      await driver.reset().should.eventually.be.equal('aut');352      helpers.resetApp.calledWith(driver.adb).should.be.true;353      driver.startAUT.calledOnce.should.be.true;354      expect(driver.curContext).to.eql('NATIVE_APP');355    });356  });357  describe('startAUT', function () {358    it('should start AUT', async function () {359      driver.opts = {360        appPackage: 'pkg',361        appActivity: 'act',362        intentAction: 'actn',363        intentCategory: 'cat',364        intentFlags: 'flgs',365        appWaitPackage: 'wpkg',366        appWaitActivity: 'wact',367        appWaitForLaunch: true,368        appWaitDuration: 'wdur',369        optionalIntentArguments: 'opt',370        userProfile: 1371      };372      let params = {373        pkg: 'pkg',374        activity: 'act',375        action: 'actn',376        category: 'cat',377        flags: 'flgs',378        waitPkg: 'wpkg',379        waitActivity: 'wact',380        waitForLaunch: true,381        waitDuration: 'wdur',382        optionalIntentArguments: 'opt',383        stopApp: false,384        user: 1385      };386      driver.opts.dontStopAppOnReset = true;387      params.stopApp = false;388      sandbox.stub(driver.adb, 'startApp');389      await driver.startAUT();390      driver.adb.startApp.calledWithExactly(params).should.be.true;391    });392  });393  describe('setUrl', function () {394    it('should set url', async function () {395      driver.opts = {appPackage: 'pkg'};396      sandbox.stub(driver.adb, 'startUri');397      await driver.setUrl('url');398      driver.adb.startUri.calledWithExactly('url', 'pkg').should.be.true;399    });400  });401  describe('closeApp', function () {402    it('should close app', async function () {403      driver.opts = {appPackage: 'pkg'};404      sandbox.stub(driver.adb, 'forceStop');405      await driver.closeApp();406      driver.adb.forceStop.calledWithExactly('pkg').should.be.true;407    });408  });409  describe('getDisplayDensity', function () {410    it('should return the display density of a device', async function () {411      driver.adb.shell = () => '123';412      (await driver.getDisplayDensity()).should.equal(123);413    });414    it('should return the display density of an emulator', async function () {415      driver.adb.shell = (cmd) => {416        let joinedCmd = cmd.join(' ');417        if (joinedCmd.indexOf('ro.sf') !== -1) {418          // device property look up419          return '';420        } else if (joinedCmd.indexOf('qemu.sf') !== -1) {421          // emulator property look up422          return '456';423        }424        return '';425      };426      (await driver.getDisplayDensity()).should.equal(456);427    });428    it('should throw an error if the display density property can\'t be found', async function () {429      driver.adb.shell = () => '';430      await driver.getDisplayDensity().should.be.rejectedWith(/Failed to get display density property/);431    });432    it('should throw and error if the display density is not a number', async function () {433      driver.adb.shell = () => 'abc';434      await driver.getDisplayDensity().should.be.rejectedWith(/Failed to get display density property/);435    });436  });437  describe('parseSurfaceLine', function () {438    it('should return visible true if the surface is visible', function () {439      parseSurfaceLine('shown=true rect=1 1 1 1').should.be.eql({440        visible: true,441        x: 1,442        y: 1,443        width: 1,444        height: 1445      });446    });447    it('should return visible false if the surface is not visible', function () {448      parseSurfaceLine('shown=false rect=1 1 1 1').should.be.eql({449        visible: false,450        x: 1,451        y: 1,452        width: 1,453        height: 1454      });455    });456    it('should return the parsed surface bounds', function () {457      parseSurfaceLine('shown=true rect=(1.0,2.0) 3.0 x 4.0').should.be.eql({458        visible: true,459        x: 1,460        y: 2,461        width: 3,462        height: 4463      });464    });465  });466  // these are used for both parseWindows and getSystemBars tests467  let validWindowOutput = [468    '  Window #1 Derp',469    '    stuff',470    '      Surface: derp shown=false lalalala rect=(9.0,8.0) 7.0 x 6.0',471    '    more stuff',472    '  Window #2 StatusBar',473    '    blah blah blah',474    '      Surface: blah blah shown=true blah blah rect=(1.0,2.0) 3.0 x 4.0',475    '    blah blah blah',476    '  Window #3 NavigationBar',477    '    womp womp',478    '      Surface: blah blah shown=false womp womp rect=(5.0,6.0) 50.0 x 60.0',479    '    qwerty asd zxc'480  ].join('\n');481  let validSystemBars = {482    statusBar: {visible: true, x: 1, y: 2, width: 3, height: 4},483    navigationBar: {visible: false, x: 5, y: 6, width: 50, height: 60}484  };485  describe('parseWindows', function () {486    it('should throw an error if the status bar info wasn\'t found', function () {487      expect(() => { parseWindows(''); })488        .to.throw(Error, /Failed to parse status bar information./);489    });490    it('should throw an error if the navigation bar info wasn\'t found', function () {491      let windowOutput = [492        '  Window #1 StatusBar',493        '    blah blah blah',494        '      Surface: blah blah shown=true blah blah rect=(1.0,2.0) 3.0 x 4.0',495        '    blah blah blah'496      ].join('\n');497      expect(() => { parseWindows(windowOutput); })498        .to.throw(Error, /Failed to parse navigation bar information./);499    });500    it('should return status and navigation bar info when both are given', function () {501      parseWindows(validWindowOutput).should.be.eql(validSystemBars);502    });503  });504  describe('getSystemBars', function () {505    it('should throw an error if there\'s no window manager output', async function () {506      driver = new AndroidDriver();507      driver.adb = {};508      driver.adb.shell = () => '';509      await driver.getSystemBars().should.be.rejectedWith(/Did not get window manager output./);510    });511    it('should return the parsed system bar info', async function () {512      driver = new AndroidDriver();513      driver.adb = {};514      driver.adb.shell = () => validWindowOutput;515      (await driver.getSystemBars()).should.be.eql(validSystemBars);516    });517  });...android-helpers.js
Source:android-helpers.js  
...250  logger.debug("Checking if app is installed");251  let installed = await adb.isAppInstalled(appPackage);252  if (installed && remoteApkExists && fastReset) {253    logger.info("Apk is already on remote and installed, resetting");254    await helpers.resetApp(adb, app, appPackage, fastReset, androidInstallTimeout);255  } else if (!installed || (!remoteApkExists && fastReset)) {256    if (!installed) {257      logger.info("Apk is not yet installed");258    } else {259      logger.info("Apk was already installed but not from our remote path");260    }261    logger.info(`${installed ? 'Re' : ''}installing apk from remote`);262    await adb.mkdir(REMOTE_TEMP_PATH);263    logger.info("Clearing out any existing remote apks with the same hash");264    await helpers.removeRemoteApks(adb, [apkMd5]);265    if (!remoteApkExists) {266      // push from local to remote267      logger.info(`Pushing ${appPackage} to device. Will wait up to ${androidInstallTimeout} ` +268                  `milliseconds before aborting`);...driver.js
Source:driver.js  
...339        logger.errorAndThrow('Full reset requires an app capability, use fastReset if app is not provided');340      }341      logger.debug('No app capability. Assuming it is already on the device');342      if (this.opts.fastReset) {343        await helpers.resetApp(this.adb, this.opts);344      }345    }346    if (!this.opts.skipUninstall) {347      await this.adb.uninstallApk(this.opts.appPackage);348    }349    if (this.opts.app) {350      if (this.opts.noSign) {351        logger.info('Skipping application signing because noSign capability is set to true. ' +352          'Having the application under test with improper signature/non-signed will cause ' +353          'Espresso automation startup failure.');354      } else if (!await this.adb.checkApkCert(this.opts.app, this.opts.appPackage)) {355        await this.adb.sign(this.opts.app, this.opts.appPackage);356      }357      await helpers.installApk(this.adb, this.opts);...general.js
Source:general.js  
1import _ from 'lodash';2import { util } from 'appium-support';3import logger from '../logger';4import validate from 'validate.js';5import { errors } from 'appium-base-driver';6import { qualifyActivityName } from '../utils';7import { androidHelpers } from 'appium-android-driver';8let commands = {}, helpers = {}, extensions = {};9function assertRequiredOptions (options, requiredOptionNames) {10  if (!_.isArray(requiredOptionNames)) {11    requiredOptionNames = [requiredOptionNames];12  }13  const presentOptionNames = _.keys(options);14  const missingOptionNames = _.difference(requiredOptionNames, presentOptionNames);15  if (_.isEmpty(missingOptionNames)) {16    return options;17  }18  throw new Error(`The following options are required: ${JSON.stringify(missingOptionNames)}. ` +19    `You have only provided: ${JSON.stringify(presentOptionNames)}`);20}21// eslint-disable-next-line require-await22commands.launchApp = async function launchApp () {23  throw new errors.UnsupportedOperationError('Please create a new session in order to launch the application under test');24};25// eslint-disable-next-line require-await26commands.closeApp = async function closeApp () {27  throw new errors.UnsupportedOperationError('Please quit the session in order to close the application under test');28};29// eslint-disable-next-line require-await30commands.reset = async function reset () {31  throw new errors.UnsupportedOperationError('Please quit the session and create a new session in order to close and launch the application under test');32};33commands.getClipboard = async function getClipboard () {34  return (await this.adb.getApiLevel() < 29)35    ? (await this.espresso.jwproxy.command('/appium/device/get_clipboard', 'POST', {}))36    : (await this.adb.getClipboard());37};38commands.mobilePerformEditorAction = async function mobilePerformEditorAction (opts = {}) {39  const {action} = assertRequiredOptions(opts, ['action']);40  return await this.espresso.jwproxy.command('/appium/device/perform_editor_action', 'POST', {action});41};42commands.mobileSwipe = async function mobileSwipe (opts = {}) {43  const {direction, element, swiper, startCoordinates, endCoordinates, precisionDescriber} = assertRequiredOptions(opts, ['element']);44  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/swipe`, 'POST', {45    direction, element, swiper, startCoordinates, endCoordinates, precisionDescriber46  });47};48commands.mobileGetDeviceInfo = async function mobileGetDeviceInfo () {49  return await this.espresso.jwproxy.command('/appium/device/info', 'GET');50};51commands.mobileIsToastVisible = async function mobileIsToastVisible (opts = {}) {52  const {text, isRegexp} = opts;53  if (!util.hasValue(text)) {54    logger.errorAndThrow(`'text' argument is mandatory`);55  }56  return await this.espresso.jwproxy.command('/appium/execute_mobile/is_toast_displayed', 'POST', {57    text,58    isRegexp,59  });60};61commands.mobileOpenDrawer = async function mobileOpenDrawer (opts = {}) {62  const {element, gravity} = assertRequiredOptions(opts, ['element']);63  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/open_drawer`, 'POST', {64    gravity65  });66};67commands.mobileCloseDrawer = async function mobileCloseDrawer (opts = {}) {68  const {element, gravity} = assertRequiredOptions(opts, ['element']);69  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/close_drawer`, 'POST', {70    gravity71  });72};73commands.mobileSetDate = async function mobileSetDate (opts = {}) {74  const {element, year, monthOfYear, dayOfMonth} = assertRequiredOptions(opts, ['element', 'year', 'monthOfYear', 'dayOfMonth']);75  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/set_date`, 'POST', {76    year,77    monthOfYear,78    dayOfMonth,79  });80};81commands.mobileSetTime = async function mobileSetTime (opts = {}) {82  const {element, hours, minutes} = assertRequiredOptions(opts, ['element', 'hours', 'minutes']);83  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/set_time`, 'POST', {84    hours,85    minutes,86  });87};88commands.mobileNavigateTo = async function mobileNavigateTo (opts = {}) {89  let {element, menuItemId} = assertRequiredOptions(opts, ['menuItemId', 'element']);90  let menuItemIdAsNumber = parseInt(menuItemId, 10);91  if (_.isNaN(menuItemIdAsNumber) || menuItemIdAsNumber < 0) {92    logger.errorAndThrow(`'menuItemId' must be a non-negative number. Found ${menuItemId}`);93    menuItemId = menuItemIdAsNumber;94  }95  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/navigate_to`, 'POST', {96    menuItemId97  });98};99/**100 * Runs a chain of Espresso web atoms (see https://developer.android.com/training/testing/espresso/web for reference)101 *102 * Takes JSON of the form103 *104 * {105 *   "webviewEl": "<ELEMENT_ID>", // optional webview element to operate on106 *   "forceJavascriptEnabled": true|false, // if webview disables javascript, webatoms won't work, this forces it107 *   "methodChain": [108 *     {"name": "methodName", "atom": {"name": "atomName", "args": ["arg1", "arg2", ...]}},109 *     ...110 *   ]111 * }112 *113 */114commands.mobileWebAtoms = async function mobileWebAtoms (opts = {}) {115  opts = assertRequiredOptions(opts, ['methodChain']);116  return await this.espresso.jwproxy.command(`/appium/execute_mobile/web_atoms`, 'POST', opts);117};118commands.mobileScrollToPage = async function mobileScrollToPage (opts = {}) {119  // Validate the parameters120  const scrollToTypes = ['first', 'last', 'left', 'right'];121  const res = validate(opts, {122    element: {presence: true},123    scrollTo: {124      inclusion: {125        within: scrollToTypes,126        message: `"scrollTo" must be one of "${scrollToTypes.join(', ')}" found '%{value}'`,127      }128    },129    scrollToPage: {130      numericality: {131        onlyInteger: true,132        greaterThanOrEqualTo: 0,133        message: `"scrollToPage" must be a non-negative integer. Found '%{value}'`134      },135    },136  });137  if (util.hasValue(res)) {138    logger.errorAndThrow(`Invalid scrollTo parameters: ${JSON.stringify(res)}`);139  }140  const {element, scrollTo, scrollToPage, smoothScroll} = opts;141  if (util.hasValue(scrollTo) && util.hasValue(scrollToPage)) {142    logger.warn(`'scrollTo' and 'scrollToPage' where both provided. Defaulting to 'scrollTo'`);143  }144  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/scroll_to_page`, 'POST', {145    scrollTo,146    scrollToPage,147    smoothScroll,148  });149};150/**151 *  API to invoke methods defined in Android app.152 *153 *  Example data154 *  {155 *   target: 'activity',156 *   methods:157 *         [158 *           {159 *               name: "someMethod",160 *           },161 *           {162 *               name: "anotherMethod",163 *               args:164 *                   [165 *                       {value: "Lol", type: 'java.lang.CharSequence'},166 *                       {value: 1, type: 'int'}167 *                   ]168 *           }169 *         ]170 * }171 *172 * In above example, method "someMethod" will be invoked on 'activity'. On the result, "anotherMethod" will be invoked173 *  "target" can be either 'activity', 'application' or 'element'174 *  If target is set to 'application', methods will be invoked on application class175 *  If target is set to 'activity', methods will be invoked on current activity176 *  If target is set to 'element', 'elementId' must be specified177 *178 * - Only 'Public' methods can be invoked. ('open' modifire is necessary in Kotlin)179 * - following primitive types are supported: "int", "boolean", "byte", "short", "long", "float", "char"180 * -  Non-primitive types with fully qualified name "java.lang.*" is also supported:181 *                              Eg. "java.lang.CharSequence", "java.lang.String", "java.lang.Integer", "java.lang.Float",182 *                              "java.lang.Double", "java.lang.Boolean", "java.lang.Long", "java.lang.Short",183 *                              "java.lang.Character" etc...184 *185 *186 * @throws  {Error} if target is not 'activity' or 'application'187 * @throws  {Error} if a method is not found with given argument types188 *189 * @return {*} the result of the last method in the invocation chain. If method return type is void, then "<VOID>" will be returned190 *191 */192commands.mobileBackdoor = async function mobileBackdoor (opts = {}) {193  assertRequiredOptions(opts, ['target', 'methods']);194  const {target, methods} = opts;195  if (target === 'element') {196    assertRequiredOptions(opts, ['elementId']);197  }198  const {elementId: targetElement} = opts;199  return await this.espresso.jwproxy.command(`/appium/execute_mobile/backdoor`, 'POST', {target, methods, targetElement});200};201/**202 *  Execute UiAutomator2 commands to drive out of app areas.203 *  strategy can be one of: "clazz", "res", "text", "textContains", "textEndsWith", "textStartsWith",204 *                          "desc", "descContains", "descEndsWith", "descStartsWith", "pkg"205 *206 *  action can be one of: "click", "longClick", "getText", "getContentDescription", "getClassName",207 *                        "getResourceName", "getVisibleBounds", "getVisibleCenter", "getApplicationPackage",208 *                        "getChildCount", "clear", "isCheckable", "isChecked", "isClickable", "isEnabled",209 *                        "isFocusable", "isFocused", "isLongClickable", "isScrollable", "isSelected"210 */211commands.mobileUiautomator = async function mobileUiautomator (opts = {}) {212  const {strategy, locator, action, index} = assertRequiredOptions(opts, ['strategy', 'locator', 'action']);213  return await this.espresso.jwproxy.command(`/appium/execute_mobile/uiautomator`, 'POST', {strategy, locator, index, action});214};215/**216 *  Flash the element with given id.217 *  durationMillis and repeatCount are optional218 *219 */220commands.mobileFlashElement = async function mobileFlashElement (opts = {}) {221  const {element} = assertRequiredOptions(opts, ['element']);222  const {durationMillis, repeatCount} = opts;223  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/flash`, 'POST', {224    durationMillis,225    repeatCount226  });227};228/**229 * Perform a 'GeneralClickAction' (https://developer.android.com/reference/androidx/test/espresso/action/GeneralClickAction)230 */231commands.mobileClickAction = async function mobileClickAction (opts = {}) {232  const {element, tapper, coordinatesProvider, precisionDescriber,233         inputDevice, buttonState} = assertRequiredOptions(opts, ['element']);234  return await this.espresso.jwproxy.command(`/appium/execute_mobile/${util.unwrapElement(element)}/click_action`, 'POST', {235    tapper, coordinatesProvider, precisionDescriber, inputDevice, buttonState236  });237};238// eslint-disable-next-line require-await,no-unused-vars239commands.updateSettings = async function updateSettings (settings) {240  throw new errors.NotYetImplementedError();241};242// eslint-disable-next-line require-await243commands.getSettings = async function getSettings () {244  throw new errors.NotYetImplementedError();245};246// Stop proxying to any Chromedriver and redirect to Espresso247helpers.suspendChromedriverProxy = function suspendChromedriverProxy () {248  this.chromedriver = null;249  this.proxyReqRes = this.espresso.proxyReqRes.bind(this.espresso);250  this.jwpProxyActive = true;251};252commands.startActivity = async function startActivity (appPackage, appActivity,253  appWaitPackage, appWaitActivity) {254  // intentAction, intentCategory, intentFlags, optionalIntentArguments, dontStopAppOnReset255  // parameters are not supported by Espresso256  appPackage = appPackage || this.caps.appPackage;257  appWaitPackage = appWaitPackage || appPackage;258  appActivity = qualifyActivityName(appActivity, appPackage);259  appWaitActivity = qualifyActivityName(appWaitActivity || appActivity, appWaitPackage);260  logger.debug(`Starting activity '${appActivity}' for package '${appPackage}'`);261  await this.espresso.jwproxy.command(`/appium/device/start_activity`, 'POST', {262    appPackage,263    appActivity,264  });265  await this.adb.waitForActivity(appWaitPackage, appWaitActivity);266};267commands.reset = async function reset () {268  await androidHelpers.resetApp(this.adb, Object.assign({}, this.opts, {fastReset: true}));269  await this.espresso.startSession(this.caps);270  await this.adb.waitForActivity(this.caps.appWaitPackage, this.caps.appWaitActivity, this.opts.appWaitDuration);271  if (this.opts.autoWebview) {272    await this.initWebview();273  }274};275commands.mobileDismissAutofill = async function mobileDismissAutofill (opts = {}) {276  const {element} = assertRequiredOptions(opts, ['element']);277  await this.espresso.jwproxy.command(278    `/session/:sessionId/appium/execute_mobile/${util.unwrapElement(element)}/dismiss_autofill`, 'POST', {});279};280Object.assign(extensions, commands, helpers);281export { commands, helpers };...Using AI Code Generation
1var wd = require('wd');2var asserters = wd.asserters;3var chai = require('chai');4var chaiAsPromised = require('chai-as-promised');5var should = chai.should();6var expect = chai.expect;Using AI Code Generation
1var webdriver = require('selenium-webdriver');2    withCapabilities({3    build();4var helpers = require('../../lib/helpers.js');5  .executeAsyncScript(helpers.resetApp)6  .then(function() {7    console.log('App reset.');8  })9  .quit();10var resetApp = function(cb) {11  var self = this;12  self.resetApp(function(err) {13    if (err) {14      cb(err);15    } else {16      cb(null);17    }18  });19};20module.exports.resetApp = resetApp;Using AI Code Generation
1var wd = require('wd');2var assert = require('assert');3var chai = require('chai');4var chaiAsPromised = require('chai-as-promised');5var should = chai.should();6var expect = chai.expect;7var asserters = wd.asserters;8chai.use(chaiAsPromised);9var desiredCapabilities = {10};11var driver = wd.promiseChainRemote('localhost', 4723);12driver.init(desiredCapabilities);13    .elementById('io.appium.android.apis:id/text')14    .click()15    .sleep(3000)16    .then(function (text) {17        console.log('Clicked Text');18    });19    .elementById('io.appium.android.apis:id/edit')20    .sendKeys('Hello World')21    .sleep(3000)22    .then(function (text) {23        console.log('Entered Text');24    });25    .elementById('io.appium.android.apis:id/button')26    .click()27    .sleep(3000)28    .then(function (text) {29        console.log('Clicked Button');30    });31    .elementById('io.appium.android.apis:id/edit')32    .text()33    .then(function (text) {34        console.log('Text is: ' + text);35    });36    .elementById('io.appium.android.apis:id/text')37    .text()38    .then(function (text) {39        console.log('Text is: ' + text);40    });41    .elementById('io.appium.android.apis:id/button')42    .click()43    .sleep(3000)44    .then(function (text) {45        console.log('Clicked Button');46    });47    .elementById('io.appium.android.apis:id/edit')48    .clear()49    .sendKeys('Hello World')50    .sleep(3000)51    .then(function (text) {52        console.log('Entered Text');53    });54    .elementById('Using AI Code Generation
1var assert = require('assert');2var wd = require('wd');3var Q = require('q');4var androidHelpers = require('appium-android-driver').androidHelpers;5describe('test', function () {6  var driver;7  before(function () {8    driver = wd.promiseChainRemote('localhost', 4723);9    return driver.init({Using AI Code Generation
1var wd = require('wd');2var assert = require('assert');3var helpers = require('appium-android-driver').androidHelpers;4var desiredCaps = {5};6driver.init(desiredCaps)7    .then(function () {8        return helpers.resetApp(driver);9    })10    .then(function () {11        console.log('App reset successfully');12    })13    .catch(function (err) {14        console.error('Error occurred! ', err);15    })16    .fin(function () {17        driver.quit();18    });Using AI Code Generation
1const wd = require('wd');2const chai = require('chai');3const chaiAsPromised = require('chai-as-promised');4chai.use(chaiAsPromised);5chai.should();6const desired = {7};8describe('Android Driver', () => {9  before(async () => {10    await driver.init(desired);11  });12  after(async () => {13    await driver.quit();14  });15  it('should reset app', async () => {16    await driver.resetApp();17  });18});Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
