How to use adb.killEmulator method in Appium Android Driver

Best JavaScript code snippet using appium-android-driver

Run Appium Android Driver automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

driver.js

Source: driver.js Github

copy
1import _ from 'lodash';
2import { BaseDriver } from 'appium-base-driver';
3import SelendroidServer from './selendroid';
4import { fs } from 'appium-support';
5import { serverExists } from './installer';
6import { retryInterval } from 'asyncbox';
7import logger from './logger';
8import commands from './commands';
9import { DEFAULT_ADB_PORT } from 'appium-adb';
10import selendroidHelpers from './helpers';
11import { androidHelpers, androidCommands, WEBVIEW_BASE } from 'appium-android-driver';
12import desiredCapConstraints from './desired-caps';
13
14
15let helpers = {};
16Object.assign(helpers, selendroidHelpers, androidHelpers);
17
18// The range of ports we can use on the system for communicating to the
19// Selendroid HTTP server on the device
20const SYSTEM_PORT_RANGE = [8200, 8299];
21
22// This is the port that Selendroid listens to on the device. We will forward
23// one of the ports above on the system to this port on the device.
24const DEVICE_PORT = 8080;
25
26// This is a set of methods and paths that we never want to proxy to Selendroid
27const NO_PROXY = [
28  ['GET', new RegExp('^/session/[^/]+/log/types$')],
29  ['POST', new RegExp('^/session/[^/]+/log')],
30  ['POST', new RegExp('^/session/[^/]+/location')],
31  ['POST', new RegExp('^/session/[^/]+/appium')],
32  ['GET', new RegExp('^/session/[^/]+/appium')],
33  ['POST', new RegExp('^/session/[^/]+/context')],
34  ['GET', new RegExp('^/session/[^/]+/context')],
35  ['GET', new RegExp('^/session/[^/]+/contexts')],
36  ['POST', new RegExp('^/session/[^/]+/element/[^/]+/value')],
37  ['GET', new RegExp('^/session/[^/]+/element/[^/]+/rect')],
38  ['GET', new RegExp('^/session/[^/]+/network_connection')],
39  ['POST', new RegExp('^/session/[^/]+/network_connection')],
40  ['POST', new RegExp('^/session/[^/]+/ime')],
41  ['GET', new RegExp('^/session/[^/]+/ime')],
42  ['POST', new RegExp('^/session/[^/]+/keys')],
43  ['POST', new RegExp('^/session/[^/]+/touch/multi/perform')],
44];
45
46const APP_EXTENSION = '.apk';
47
48
49class SelendroidDriver extends BaseDriver {
50  constructor (opts = {}, shouldValidateCaps = true) {
51    // `shell` overwrites adb.shell, so remove
52    delete opts.shell;
53
54    super(opts, shouldValidateCaps);
55
56    this.desiredCapConstraints = desiredCapConstraints;
57    this.selendroid = null;
58    this.jwpProxyActive = false;
59    this.defaultIME = null;
60    this.jwpProxyAvoid = NO_PROXY;
61    this.apkStrings = {}; // map of language -> strings obj
62
63    // handle webview mechanics from AndroidDriver
64    this.chromedriver = null;
65    this.sessionChromedrivers = {};
66
67    this.opts.systemPort = opts.selendroidPort || SYSTEM_PORT_RANGE[0];
68    this.opts.adbPort = opts.adbPort || DEFAULT_ADB_PORT;
69  }
70
71  async createSession (caps) {
72    try {
73      if (!(await serverExists())) {
74        throw new Error('Cannot start a selendroid session because the server ' +
75                        'apk does not exist. Please run `npm run-script ' +
76                        'selendroid` in the appium-selendroid-driver package');
77      }
78
79      // TODO handle otherSessionData for multiple sessions
80      let sessionId;
81      [sessionId] = await super.createSession(caps);
82      this.curContext = this.defaultContextName();
83      // fail very early if the app doesn't actually exist, since selendroid
84      // (unlike the android driver) can't run a pre-installed app based
85      // only on package name. It has to be an actual apk
86      this.opts.app = await this.helpers.configureApp(this.opts.app, APP_EXTENSION);
87      await this.checkAppPresent();
88      this.opts.systemPort = this.opts.selendroidPort || SYSTEM_PORT_RANGE[0];
89      this.opts.adbPort = this.opts.adbPort || DEFAULT_ADB_PORT;
90      await this.startSelendroidSession();
91      return [sessionId, caps];
92    } catch (e) {
93      await this.deleteSession();
94      throw e;
95    }
96  }
97
98  validateDesiredCaps (caps) {
99    // check with the base class, and return if it fails
100    let res = super.validateDesiredCaps(caps);
101    if (!res) return res; // eslint-disable-line curly
102
103    if (this.opts.reboot) {
104      this.setAvdFromCapabilities(caps);
105    }
106  }
107
108  setAvdFromCapabilities (caps) {
109    if (this.opts.avd) {
110      logger.info('avd name defined, ignoring device name and platform version');
111    } else {
112      if (!caps.deviceName) {
113        logger.errorAndThrow('avd or deviceName should be specified when reboot option is enabled');
114      }
115      if (!caps.platformVersion) {
116        logger.errorAndThrow('avd or platformVersion should be specified when reboot option is enabled');
117      }
118      let avdDevice = caps.deviceName.replace(/[^a-zA-Z0-9_.]/g, '-');
119      this.opts.avd = `${avdDevice}__${caps.platformVersion}`;
120    }
121  }
122
123  get driverData () {
124    // TODO fille out resource info here
125    return {};
126  }
127
128  isEmulator () {
129    return !!this.opts.avd;
130  }
131
132  async startSelendroidSession () {
133    if (!this.opts.javaVersion) {
134      this.opts.javaVersion = await helpers.getJavaVersion();
135    }
136
137    // get device udid for this session
138    let {udid, emPort} = await helpers.getDeviceInfoFromCaps(this.opts);
139    this.opts.udid = udid;
140    this.opts.emPort = emPort;
141
142    // now that we know our java version and device info, we can create our
143    // ADB instance
144    this.adb = await androidHelpers.createADB(this.opts);
145    // fail very early if the user's app doesn't have the appropriate perms
146    // for selendroid automation
147    await helpers.ensureInternetPermissionForApp(this.adb, this.opts.app);
148    // get appPackage et al from manifest if necessary
149    let appInfo = await helpers.getLaunchInfo(this.adb, this.opts);
150    // and get it onto our 'opts' object so we use it from now on
151    Object.assign(this.opts, appInfo);
152    // set up the modified selendroid server etc
153    await this.initSelendroidServer();
154    // start an avd, set the language/locale, pick an emulator, etc...
155    // TODO with multiple devices we'll need to parameterize this
156    await helpers.initDevice(this.adb, this.opts);
157    // Further prepare the device by forwarding the Selendroid port
158    await this.adb.forwardPort(this.opts.systemPort, DEVICE_PORT);
159    // prepare our actual AUT, get it on the device, etc...
160    await this.initAUT();
161    // unlock the device to prepare it for testing
162    await helpers.unlock(this, this.adb, this.caps);
163    // launch selendroid and wait till its online and we have a session
164    await this.selendroid.startSession(this.caps);
165    // rescue selendroid if it fails to start our AUT
166    await this.ensureAppStarts();
167    // if we want to immediately get into a webview, set our context
168    // appropriately
169    if (this.opts.autoWebview) {
170      await retryInterval(20, this.opts.autoWebviewTimeout || 2000, async () => {
171        await this.setContext(this.defaultWebviewName());
172      });
173    }
174    // now that everything has started successfully, turn on proxying so all
175    // subsequent session requests go straight to/from selendroid
176    this.jwpProxyActive = true;
177  }
178
179  async initSelendroidServer () {
180    // now that we have package and activity, we can create an instance of
181    // selendroid with the appropriate data
182    this.selendroid = new SelendroidServer({
183      host: this.opts.host || 'localhost',
184      systemPort: this.opts.systemPort,
185      devicePort: DEVICE_PORT,
186      adb: this.adb,
187      apk: this.opts.app,
188      tmpDir: this.opts.tmpDir,
189      appPackage: this.opts.appPackage,
190      appActivity: this.opts.appActivity,
191    });
192    this.proxyReqRes = this.selendroid.proxyReqRes.bind(this.selendroid);
193    // let selendroid repackage itself for our AUT
194    await this.selendroid.prepareModifiedServer();
195  }
196
197  async initAUT () {
198    logger.debug('Initializing application under test');
199    // set the localized strings for the current language from the apk
200    // TODO: incorporate changes from appium#5308 which fix a race cond-
201    // ition bug in old appium and need to be replicated here
202    this.apkStrings[this.opts.language] = await helpers.pushStrings(
203        this.opts.language, this.adb, this.opts);
204    if (!this.opts.skipUninstall) {
205      await this.adb.uninstallApk(this.opts.appPackage);
206    }
207    if (!this.opts.noSign) {
208      let signed = await this.adb.checkApkCert(this.opts.app, this.opts.appPackage);
209      if (!signed) {
210        logger.debug('Application not signed. Signing.');
211        await this.adb.sign(this.opts.app, this.opts.appPackage);
212      }
213    }
214    await helpers.installApk(this.adb, this.opts);
215    // get Selendroid on the device too
216    await this.selendroid.installModifiedServer();
217  }
218
219  async ensureAppStarts () {
220    // make sure we have an activity and package to wait for
221    let appWaitPackage = this.opts.appWaitPackage || this.opts.appPackage;
222    let appWaitActivity = this.opts.appWaitActivity || this.opts.appActivity;
223    try {
224      // wait for up to 5s for selendroid to have started the app after it is
225      // online
226      await this.adb.waitForActivity(appWaitPackage, appWaitActivity, 5000);
227    } catch (e) {
228      logger.info(`Selendroid did not start the activity we were waiting for, ` +
229                  `'${appWaitPackage}/${appWaitActivity}'. ` +
230                  `Starting it ourselves`);
231      await this.adb.startApp({
232        pkg: this.opts.appPackage,
233        activity: this.opts.appActivity,
234        action: this.opts.intentAction,
235        category: this.opts.intentCategory,
236        flags: this.opts.intentFlags,
237        waitPkg: this.opts.appWaitPackage,
238        waitActivity: this.opts.appWaitActivity,
239        optionalIntentArguments: this.opts.optionalIntentArguments,
240        stopApp: !this.opts.dontStopAppOnReset,
241        retry: false
242      });
243    }
244  }
245
246  async deleteSession () {
247    logger.debug('Deleting Selendroid session');
248    if (this.selendroid) {
249      if (this.jwpProxyActive) {
250        await this.selendroid.deleteSession();
251      }
252      this.selendroid = null;
253    }
254    this.jwpProxyActive = false;
255
256    if (this.adb) {
257      if (this.opts.unicodeKeyboard && this.opts.resetKeyboard &&
258          this.defaultIME) {
259        logger.debug(`Resetting IME to '${this.defaultIME}'`);
260        await this.adb.setIME(this.defaultIME);
261      }
262      await this.adb.forceStop(this.opts.appPackage);
263      await this.adb.stopLogcat();
264      if (this.opts.reboot) {
265        let avdName = this.opts.avd.replace('@', '');
266        logger.debug(`closing emulator '${avdName}'`);
267        await this.adb.killEmulator(avdName);
268      }
269    }
270    await super.deleteSession();
271  }
272
273  async checkAppPresent () {
274    logger.debug('Checking whether app is actually present');
275    if (!(await fs.exists(this.opts.app))) {
276      logger.errorAndThrow(`Could not find app apk at '${this.opts.app}'`);
277    }
278  }
279
280  defaultWebviewName () {
281    return `${WEBVIEW_BASE}0`;
282  }
283
284  proxyActive (sessionId) {
285    super.proxyActive(sessionId);
286
287    // we always have an active proxy to the selendroid server
288    return true;
289  }
290
291  getProxyAvoidList (sessionId) {
292    super.getProxyAvoidList(sessionId);
293
294    return this.jwpProxyAvoid;
295  }
296
297  canProxy (sessionId) {
298    super.canProxy(sessionId);
299
300    // we can always proxy to the selendroid server
301    return true;
302  }
303}
304
305// first add the android-driver commands which we will fall back to
306for (let [cmd, fn] of _.toPairs(androidCommands)) {
307  // we do some different/special things with these methods
308  if (!_.includes(['defaultWebviewName'], cmd)) {
309    SelendroidDriver.prototype[cmd] = fn;
310  }
311}
312
313// then overwrite with any selendroid-specific commands
314for (let [cmd, fn] of _.toPairs(commands)) {
315  SelendroidDriver.prototype[cmd] = fn;
316}
317
318export { SelendroidDriver, DEVICE_PORT };
319export default SelendroidDriver;
320
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Appium Android Driver on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)