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!!