How to use adb.removePortForward 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.

adb-commands-e2e-specs.js

Source: adb-commands-e2e-specs.js Github

copy
1import chai from 'chai';
2import chaiAsPromised from 'chai-as-promised';
3import ADB from '../..';
4import path from 'path';
5import { rootDir } from '../../lib/helpers.js';
6import { apiLevel, platformVersion, MOCHA_TIMEOUT } from './setup';
7import { fs, mkdirp } from 'appium-support';
8import temp from 'temp';
9
10
11chai.should();
12chai.use(chaiAsPromised);
13let expect = chai.expect;
14
15// change according to CI
16const IME = 'com.example.android.softkeyboard/.SoftKeyboard',
17      defaultIMEs = ['com.android.inputmethod.latin/.LatinIME',
18                     'io.appium.android.ime/.UnicodeIME'],
19      contactManagerPath = path.resolve(rootDir, 'test',
20                                        'fixtures', 'ContactManager.apk'),
21      pkg = 'com.example.android.contactmanager',
22      activity = 'ContactManager';
23
24describe('adb commands', function () {
25  this.timeout(MOCHA_TIMEOUT);
26
27  let adb;
28  before(async () => {
29    adb = await ADB.createADB();
30  });
31  it('getApiLevel should get correct api level', async () => {
32    (await adb.getApiLevel()).should.equal(apiLevel);
33  });
34  it('getPlatformVersion should get correct platform version', async () => {
35    (await adb.getPlatformVersion()).should.include(platformVersion);
36  });
37  it('availableIMEs should get list of available IMEs', async () => {
38    (await adb.availableIMEs()).should.have.length.above(0);
39  });
40  it('enabledIMEs should get list of enabled IMEs', async () => {
41    (await adb.enabledIMEs()).should.have.length.above(0);
42  });
43  it('defaultIME should get default IME', async () => {
44    defaultIMEs.should.include(await adb.defaultIME());
45  });
46  it('enableIME and disableIME should enable and disble IME', async () => {
47    await adb.disableIME(IME);
48    (await adb.enabledIMEs()).should.not.include(IME);
49    await adb.enableIME(IME);
50    (await adb.enabledIMEs()).should.include(IME);
51    await adb.enabledIMEs();
52  });
53  it('processExists should be able to find ui process', async () => {
54    (await adb.processExists('com.android.systemui')).should.be.true;
55  });
56  it('ping should return true', async () => {
57    (await adb.ping()).should.be.true;
58  });
59  it('getPIDsByName should return pids', async () => {
60    (await adb.getPIDsByName('m.android.phone')).should.have.length.above(0);
61  });
62  it('killProcessesByName should kill process', async () => {
63    await adb.install(contactManagerPath);
64    await adb.startApp({pkg, activity});
65    await adb.killProcessesByName(pkg);
66    (await adb.getPIDsByName(pkg)).should.have.length(0);
67  });
68  it('killProcessByPID should kill process', async () => {
69    await adb.install(contactManagerPath);
70    await adb.startApp({pkg, activity});
71    let pids = await adb.getPIDsByName(pkg);
72    pids.should.have.length.above(0);
73    await adb.killProcessByPID(pids[0]);
74    (await adb.getPIDsByName(pkg)).length.should.equal(0);
75  });
76  it('should get device language and country', async function () {
77    if (parseInt(apiLevel, 10) >= 23) return this.skip(); // eslint-disable-line curly
78    if (process.env.TRAVIS) return this.skip(); // eslint-disable-line curly
79
80    ['en', 'fr'].should.contain(await adb.getDeviceSysLanguage());
81    ['US', 'EN_US', 'EN', 'FR'].should.contain(await adb.getDeviceSysCountry());
82  });
83  it('should set device language and country', async function () {
84    if (parseInt(apiLevel, 10) >= 23) return this.skip(); // eslint-disable-line curly
85    if (process.env.TRAVIS) return this.skip(); // eslint-disable-line curly
86
87    await adb.setDeviceSysLanguage('fr');
88    await adb.setDeviceSysCountry('fr');
89    await adb.reboot();
90    await adb.getDeviceSysLanguage().should.eventually.equal('fr');
91    await adb.getDeviceSysCountry().should.eventually.equal('FR');
92    // cleanup
93    await adb.setDeviceSysLanguage('en');
94    await adb.setDeviceSysCountry('us');
95  });
96  it('should get device locale', async function () {
97    if (parseInt(apiLevel, 10) < 23) return this.skip(); // eslint-disable-line curly
98
99    ['us', 'en', 'ca_en'].should.contain(await adb.getDeviceLocale());
100  });
101  it('should forward the port', async () => {
102    await adb.forwardPort(4724, 4724);
103  });
104  it('should remove forwarded port', async () => {
105    await adb.forwardPort(8200, 6790);
106    (await adb.adbExec([`forward`, `--list`])).should.contain('tcp:8200');
107    await adb.removePortForward(8200);
108    (await adb.adbExec([`forward`, `--list`])).should.not.contain('tcp:8200');
109
110  });
111  it('should start logcat from adb', async () => {
112    await adb.startLogcat();
113    let logs = adb.logcat.getLogs();
114    logs.should.have.length.above(0);
115    await adb.stopLogcat();
116  });
117  it('should get model', async () => {
118    (await adb.getModel()).should.not.be.null;
119  });
120  it('should get manufacturer', async () => {
121    (await adb.getManufacturer()).should.not.be.null;
122  });
123  it('should get screen size', async () => {
124    (await adb.getScreenSize()).should.not.be.null;
125  });
126  it('should be able to toggle gps location provider', async () => {
127    await adb.toggleGPSLocationProvider(true);
128    (await adb.getLocationProviders()).should.include('gps');
129    await adb.toggleGPSLocationProvider(false);
130    (await adb.getLocationProviders()).should.not.include('gps');
131  });
132  it('should be able to toogle airplane mode', async () => {
133    await adb.setAirplaneMode(true);
134    (await adb.isAirplaneModeOn()).should.be.true;
135    await adb.setAirplaneMode(false);
136    (await adb.isAirplaneModeOn()).should.be.false;
137  });
138  it('should be able to toogle wifi @skip-ci', async function () {
139    this.retries(3);
140
141    await adb.setWifiState(true);
142    (await adb.isWifiOn()).should.be.true;
143    await adb.setWifiState(false);
144    (await adb.isWifiOn()).should.be.false;
145  });
146  it('should be able to turn off animation @skip-ci', async () => {
147    await adb.setAnimationState(false);
148    (await adb.isAnimationOn()).should.be.false;
149  });
150  it('should be able to turn on animation @skip-ci', async () => {
151    await adb.setAnimationState(true);
152    (await adb.isAnimationOn()).should.be.true;
153  });
154  describe('app permissions', async () => {
155    before(async function () {
156      let deviceApiLevel = await adb.getApiLevel();
157      if (deviceApiLevel < 23) {
158        //test should skip if the device API < 23
159        this.skip();
160      }
161      let isInstalled = await adb.isAppInstalled('io.appium.android.apis');
162      if (isInstalled) {
163        await adb.uninstallApk('io.appium.android.apis');
164      }
165    });
166    it('should install and grant all permission', async () => {
167      let apiDemos = path.resolve(rootDir, 'test',
168          'fixtures', 'ApiDemos-debug.apk');
169      await adb.install(apiDemos);
170      (await adb.isAppInstalled('io.appium.android.apis')).should.be.true;
171      await adb.grantAllPermissions('io.appium.android.apis');
172      let requestedPermissions = await adb.getReqPermissions('io.appium.android.apis');
173      expect(await adb.getGrantedPermissions('io.appium.android.apis')).to.have.members(requestedPermissions);
174    });
175    it('should revoke permission', async () => {
176      await adb.revokePermission('io.appium.android.apis', 'android.permission.RECEIVE_SMS');
177      expect(await adb.getGrantedPermissions('io.appium.android.apis')).to.not.have.members(['android.permission.RECEIVE_SMS']);
178    });
179    it('should grant permission', async () => {
180      await adb.grantPermission('io.appium.android.apis', 'android.permission.RECEIVE_SMS');
181      expect(await adb.getGrantedPermissions('io.appium.android.apis')).to.include.members(['android.permission.RECEIVE_SMS']);
182    });
183  });
184
185  describe('push file', function () {
186    function getRandomDir () {
187      return `/data/local/tmp/test${Math.random()}`;
188    }
189
190    let localFile = temp.path({prefix: 'appium', suffix: '.tmp'});
191    let tempFile = temp.path({prefix: 'appium', suffix: '.tmp'});
192    const stringData = `random string data ${Math.random()}`;
193    before(async function () {
194      await mkdirp(path.dirname(localFile));
195      await mkdirp(path.dirname(tempFile));
196
197      await fs.writeFile(localFile, stringData);
198    });
199    after(async function () {
200      if (await fs.exists(localFile)) {
201        await fs.unlink(localFile);
202      }
203    });
204    afterEach(async function () {
205      if (await fs.exists(tempFile)) {
206        await fs.unlink(tempFile);
207      }
208    });
209    it('should push file to a valid location', async function () {
210      let remoteFile = `${getRandomDir()}/remote.txt`;
211
212      await adb.push(localFile, remoteFile);
213
214      // get the file and its contents, to check
215      await adb.pull(remoteFile, tempFile);
216      let remoteData = await fs.readFile(tempFile);
217      remoteData.toString().should.equal(stringData);
218    });
219    it('should throw error if it cannot write to the remote file', async function () {
220      let remoteFile = '/foo/bar/remote.txt';
221
222      await adb.push(localFile, remoteFile).should.be.rejectedWith(/\/foo\/bar\/remote.txt/);
223    });
224  });
225});
226
Full Screen

webview-helpers.js

Source: webview-helpers.js Github

copy
1import _ from 'lodash';
2import logger from './logger';
3import request from 'request-promise';
4import { asyncmap, asyncfilter } from 'asyncbox';
5
6const NATIVE_WIN = 'NATIVE_APP';
7const WEBVIEW_WIN = 'WEBVIEW';
8const WEBVIEW_BASE = `${WEBVIEW_WIN}_`;
9const WEBVIEW_REGEXP = new RegExp(`@?webview_devtools_remote_(\\d+)`);
10const WEBVIEW_PID_REGEXP = new RegExp(`${WEBVIEW_BASE}(\\d+)`);
11const CHROMIUM_WIN = 'CHROMIUM';
12const CROSSWALK_SOCKET_SUFFIX = '_devtools_remote';
13const CROSSWALK_REGEXP_STRING = `(\\S*)${CROSSWALK_SOCKET_SUFFIX}`;
14const CROSSWALK_REGEXP = new RegExp(`@${CROSSWALK_REGEXP_STRING}`);
15const CROSSWALK_PROCESS_REGEXP = new RegExp(WEBVIEW_BASE + CROSSWALK_REGEXP_STRING);
16const DEFAULT_WEBVIEW_DEVTOOLS_PORT = 9222;
17
18
19let helpers = {};
20
21/**
22 * This function gets a list of android system processes and returns ones
23 * that look like webviews
24 *
25 * @param {object} adb - an ADB instance
26 *
27 * @return {Array.<string>} - a list of webview process names (including the leading
28 * '@')
29 */
30async function getPotentialWebviewProcs (adb) {
31  const procs = [];
32  const out = await adb.shell(['cat', '/proc/net/unix']);
33  for (let line of out.split('\n')) {
34    line = line.trim();
35    let regexMatch;
36    if ((regexMatch = (line.match(WEBVIEW_REGEXP) || line.match(CROSSWALK_REGEXP)))) {
37      procs.push(regexMatch[0]);
38    }
39  }
40
41  // sometimes the webview process shows up multiple times per app
42  return _.uniq(procs);
43}
44
45/**
46 * @typedef {Object} WebviewProc
47 * @property {string} proc - The webview process name (as returned by
48 * getPotentialWebviewProcs
49 * @property {string} webview - The actual webview context name
50 */
51/**
52 * This function retrieves a list of system processes that look like webviews,
53 * and returns them along with the webview context name appropriate for it.
54 * If we pass in a deviceSocket, we only attempt to find webviews which match
55 * that socket name (this is for apps which embed Chromium, which isn't the
56 * same as chrome-backed webviews).
57 *
58 * @param {object} adb - an ADB instance
59 * @param {string} deviceSocket - the explictly-named device socket to use
60 *
61 * @return {Array.<WebviewProc>}
62 */
63// TODO: some of this function probably belongs in appium-adb?
64async function webviewsFromProcs (adb, deviceSocket) {
65  const procs = await getPotentialWebviewProcs(adb);
66  const webviews = [];
67  for (const proc of procs) {
68    if (deviceSocket === 'chrome_devtools_remote' && proc === `@${deviceSocket}`) {
69      webviews.push({proc, webview: CHROMIUM_WIN});
70      continue;
71    }
72
73    let webviewPid;
74    let crosswalkWebviewSocket;
75    if ((webviewPid = proc.match(WEBVIEW_REGEXP))) {
76      // for multiple webviews a list of 'WEBVIEW_<index>' will be returned
77      // where <index> is zero based (same is in selendroid)
78      webviews.push({proc, webview: `${WEBVIEW_BASE}${webviewPid[1]}`});
79    } else if ((crosswalkWebviewSocket = proc.match(CROSSWALK_REGEXP))) {
80      if (deviceSocket) {
81        if (crosswalkWebviewSocket[0] === `@${deviceSocket}`) {
82          webviews.push({proc, webview: `${WEBVIEW_BASE}${crosswalkWebviewSocket[1]}`});
83        }
84      } else {
85        webviews.push({proc, webview: `${WEBVIEW_BASE}${crosswalkWebviewSocket[1]}${CROSSWALK_SOCKET_SUFFIX}`});
86      }
87    }
88  }
89  return webviews;
90}
91
92/**
93 * Given a 'webview-proc' object resulting from a call to webviewsFromProcs,
94 * check whether we can detect any active pages corresponding to that webview.
95 * This is used by getWebviews to filter out any webview-looking processes
96 * which have a remote debug port open but which aren't actually running any
97 * pages, because such processes can't be automated by chromedriver anyway.
98 *
99 * @param {object} adb - an ADB instance
100 * @param {WebviewProc} wp - the webview to check
101 * @param {number} webviewDevtoolsPort - the local port to use for the check
102 *
103 * @return {boolean} - whether or not the webview has pages
104 */
105async function webviewHasPages (adb, {proc, webview}, webviewDevtoolsPort) {
106  let hasPages = false;
107  const wvPort = webviewDevtoolsPort || DEFAULT_WEBVIEW_DEVTOOLS_PORT;
108
109  // proc names come with '@', but this should not be a part of the abstract
110  // remote port, so remove it
111  const remotePort = proc.replace(/^@/, '');
112
113  // we don't want to mess with things if our wvPort is already forwarded,
114  // since who knows what is currently going on there. So determine if it is
115  // already forwarded, and just short-circuit this whole method if so.
116  const portAlreadyForwarded = (await adb.getForwardList())
117    .map((line) => line.split(' ')[1]) // the local port is the second field in the line
118    .reduce((acc, portSpec) => acc || portSpec === `tcp:${wvPort}`, false);
119  if (portAlreadyForwarded) {
120    logger.warn(`Port ${wvPort} was already forwarded when attempting webview ` +
121                `page presence check, so was unable to perform check.`);
122    return false;
123  }
124
125  // forward the specified local port to the remote debugger port on the device
126  await adb.adbExec(['forward', `tcp:${wvPort}`, `localabstract:${remotePort}`]);
127  try {
128    const remoteDebugger = `http://localhost:${wvPort}/json/list`;
129    logger.debug(`Attempting to get list of pages for webview '${webview}' ` +
130                 `from the remote debugger at ${remoteDebugger}.`);
131    // take advantage of the chrome remote debugger REST API just to get
132    // a list of pages
133    const pages = await request({
134      uri: remoteDebugger,
135      json: true
136    });
137    if (pages.length > 0) {
138      hasPages = true;
139    }
140    logger.info(`Webview '${webview}' has ${hasPages ? '' : 'no '} pages`);
141  } catch (e) {
142    logger.warn(`Got error when retrieving page list, will assume no pages: ${e}`);
143  }
144  await adb.removePortForward(wvPort); // make sure we clean up
145  return hasPages;
146}
147
148/**
149 * Take a webview name like WEBVIEW_4296 and use 'adb shell ps' to figure out
150 * which app package is associated with that webview. One of the reasons we
151 * want to do this is to make sure we're listing webviews for the actual AUT,
152 * not some other running app
153 *
154 * @param {object} adb - an ADB instance
155 * @param {string} webview - a webview process name
156 *
157 * @returns {string} - the package name of the app running the webview
158 */
159// TODO: this should probably be called procFromPid and exist in appium-adb
160helpers.procFromWebview = async function procFromWebview (adb, webview) {
161  if (webview.match(WEBVIEW_PID_REGEXP) === null) {
162    let processName = webview.match(CROSSWALK_PROCESS_REGEXP);
163    if (processName === null) {
164      throw new Error(`Could not find process name for webview ${webview}`);
165    }
166    return processName[1];
167  }
168
169  // webview_devtools_remote_4296 => 4296
170  let pid = webview.match(/\d+$/);
171  if (!pid) {
172    throw new Error(`Could not find PID for webview ${webview}`);
173  }
174  pid = pid[0];
175  logger.debug(`${webview} mapped to pid ${pid}`);
176  logger.debug('Getting process name for webview');
177  let out = await adb.shell('ps');
178  let pkg = 'unknown';
179  let lines = out.split(/\r?\n/);
180
181  /* Output of ps is like:
182   USER       PID  PPID  VSIZE  RSS   WCHAN    PC         NAME  _or_
183   USER       PID  PPID  VSZ    RSS   WCHAN    ADDR     S NAME
184   u0_a136   6248  179   946000 48144 ffffffff 4005903e R com.example.test
185   u0_a136   6249  179   946000 48144 ffffffff          R com.example.test
186  */
187  const fullHeader = lines[0].trim();
188  const header = fullHeader.split(/\s+/);
189  const pidColumn = header.indexOf('PID');
190
191  for (let line of lines) {
192    const entries = line.trim().split(/\s+/);
193    const pidEntry = entries[pidColumn];
194    if (pidEntry === pid) {
195      pkg = _.last(entries);
196      logger.debug(`Parsed pid: '${pidEntry}' pkg: '${pkg}' from`);
197      logger.debug(`    ${fullHeader}`);
198      logger.debug(`    ${line}`);
199
200      break;
201    }
202  }
203
204  logger.debug(`Returning process name: '${pkg}'`);
205  return pkg;
206};
207
208/**
209 * @typedef {Object} GetWebviewsOpts
210 * @property {string} androidDeviceSocket - device socket name
211 * @property {boolean} ensureWebviewsHavePages - whether to check for webview
212 * page presence
213 * @property {number} webviewDevtoolsPort - port to use for webview page
214 * presence check (if not the default of 9222).
215 */
216/**
217 * Get a list of available webviews by introspecting processes with adb, where
218 * webviews are listed. It's possible to pass in a 'deviceSocket' arg, which
219 * limits the webview possibilities to the one running on the Chromium devtools
220 * socket we're interested in (see note on webviewsFromProcs). We can also
221 * direct this method to verify whether a particular webview process actually
222 * has any pages (if a process exists but no pages are found, Chromedriver will
223 * not actually be able to connect to it, so this serves as a guard for that
224 * strange failure mode). The strategy for checking whether any pages are
225 * active involves sending a request to the remote debug server on the device,
226 * hence it is also possible to specify the port on the host machine which
227 * should be used for this communication.
228 *
229 * @param {object} adb - an ADB instance
230 * @param {GetWebviewOpts} opts
231 *
232 * @return {Array.<string>} - a list of webview names
233 */
234helpers.getWebviews = async function getWebviews (adb, {
235  androidDeviceSocket = null,
236  ensureWebviewsHavePages = null,
237  webviewDevtoolsPort = null
238} = {}) {
239
240  logger.debug('Getting a list of available webviews');
241  let webviewProcs = await webviewsFromProcs(adb, androidDeviceSocket);
242
243  if (ensureWebviewsHavePages) {
244    logger.info('Retrieved potential webviews; will filter out ones with no active pages');
245    webviewProcs = await asyncfilter(webviewProcs,
246      async (wp) => await webviewHasPages(adb, wp, webviewDevtoolsPort),
247      false /*ensure serial operation*/);
248  } else {
249    logger.info('Not checking whether webviews have active pages; use the ' +
250                "'ensureWebviewsHavePages' cap to turn this check on");
251  }
252
253  // webviewProcs contains procs, which we only care about for ensuring
254  // presence of pages above, so we can now discard them and rely on just the
255  // webview names
256  let webviews = webviewProcs.map((wp) => wp.webview);
257
258  if (androidDeviceSocket) {
259    return webviews;
260  }
261
262  webviews = await asyncmap(webviews, async (webviewName) => {
263    let pkg = await helpers.procFromWebview(adb, webviewName);
264    return WEBVIEW_BASE + pkg;
265  });
266  logger.debug(`Found webviews: ${JSON.stringify(webviews)}`);
267  return webviews;
268};
269
270helpers.decorateChromeOptions = function decorateChromeOptions (caps, opts, deviceId) {
271  // add options from appium session caps
272  if (opts.chromeOptions) {
273    if (opts.chromeOptions.Arguments) {
274      // merge `Arguments` and `args`
275      opts.chromeOptions.args = [...(opts.chromeOptions.args || []), ...opts.chromeOptions.Arguments];
276      delete opts.chromeOptions.Arguments;
277    }
278    for (let [opt, val] of _.toPairs(opts.chromeOptions)) {
279      if (_.isUndefined(caps.chromeOptions[opt])) {
280        caps.chromeOptions[opt] = val;
281      } else {
282        logger.warn(`Cannot pass option ${caps.chromeOptions[opt]} because ` +
283                    'Appium needs it to make chromeDriver work');
284      }
285    }
286  }
287
288  // add device id from adb
289  caps.chromeOptions.androidDeviceSerial = deviceId;
290  return caps;
291};
292
293export default helpers;
294export { helpers, NATIVE_WIN, WEBVIEW_WIN, WEBVIEW_BASE, CHROMIUM_WIN };
295
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)