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

commands.js

Source: commands.js Github

copy
1import _ from 'lodash';
2import log from './logger';
3import utf7 from 'utf7';
4import { webviewHelpers, CHROMIUM_WIN } from 'appium-android-driver';
5import { DEVICE_PORT } from './driver';
6
7const {imap} = utf7;
8
9let extensions = {},
10    commands = {},
11    helpers = {};
12
13commands.launchApp = async function launchApp () {
14  await this.startSelendroidSession();
15};
16commands.reset = async function reset () {
17  log.debug('Running generic full reset');
18  let oldImpWait = this.implicitWaitMs;
19  let oldCommandTimeoutMs = this.commandTimeoutMs;
20  let oldSessionId = this.sessionId;
21
22  await this.deleteSession();
23  log.debug('Restarting app');
24  await this.startSelendroidSession();
25  this.implicitWait(oldImpWait);
26  this.timeouts('command', oldCommandTimeoutMs);
27  this.sessionId = oldSessionId;
28};
29
30commands.performMultiAction = async function performMultiAction (elId, actions) {
31  if (elId) {
32    throw new Error('Selendroid actions do not support element id');
33  }
34  return await this.selendroid.jwproxy.command('/action', 'POST', {payload: actions});
35};
36
37function encodeString (value, unicode) {
38  for (let i = 0; i < value.length; i++) {
39    let c = value.charCodeAt(i);
40    // if we're using the unicode keyboard, and this is unicode, maybe encode
41    if (unicode && (c > 127 || c === 38)) {
42      // this is not simple ascii, or it is an ampersand (`&`)
43      if (c >= parseInt('E000', 16) && c <= parseInt('E040', 16)) {
44        // Selenium uses a Unicode PUA to cover certain special characters
45        // see https://code.google.com/p/selenium/source/browse/java/client/src/org/openqa/selenium/Keys.java
46      } else {
47        // encode the text
48        value = imap.encode(value);
49        break;
50      }
51    }
52  }
53  return value;
54}
55
56// Need to override this for correct unicode support
57commands.setValue = async function setValue (value, elementId) {
58  if (value instanceof Array) {
59    value = value.join('');
60  }
61  log.debug(`Setting text on element '${elementId}': '${value}'`);
62  value = encodeString(value, this.opts.unicodeKeyboard);
63  await this.selendroid.jwproxy.command(`/element/${elementId}/value`, 'POST', {value: [value]});
64};
65
66// This is needed to satisfy updated WebElement interface in Selenium 3
67commands.getElementRect = async function getElementRect (elementId) {
68  const location = await this.selendroid.jwproxy.command(`/element/${elementId}/location`, 'GET');
69  const size = await this.selendroid.jwproxy.command(`/element/${elementId}/size`, 'GET');
70  return Object.assign(location, size);
71};
72
73// Need to override this for correct unicode support
74commands.keys = async function keys (value) {
75  if (value instanceof Array) {
76    value = value.join('');
77  }
78  log.debug(`Setting text: '${value}'`);
79  value = encodeString(value, this.opts.unicodeKeyboard);
80  await this.selendroid.jwproxy.command('/keys', 'POST', {value: [value]});
81};
82
83// Selendroid doesn't support metastate for keyevents
84commands.keyevent = async function keyevent (keycode, metastate) {
85  log.debug(`Ignoring metastate ${metastate}`);
86  await this.adb.keyevent(keycode);
87};
88
89// Use ADB since we don't have UiAutomator
90commands.back = async function back () {
91  await this.adb.keyevent(4);
92};
93
94commands.getContexts = async function getContexts () {
95  let chromiumViews = [];
96  let webviews = await webviewHelpers.getWebviews(this.adb,
97      this.opts.androidDeviceSocket);
98  if (_.includes(webviews, CHROMIUM_WIN)) {
99    chromiumViews = [CHROMIUM_WIN];
100  } else {
101    chromiumViews = [];
102  }
103
104  log.info('Getting window handles from Selendroid');
105  let selendroidViews = await this.selendroid.jwproxy.command('/window_handles', 'GET', {});
106  this.contexts = _.union(selendroidViews, chromiumViews);
107  log.info(`Available contexts: ${JSON.stringify(this.contexts)}`);
108  return this.contexts;
109};
110
111helpers.switchContext = async function switchContext (name) {
112  // called when setting context
113  await this.selendroid.jwproxy.command('/window', 'POST', {name});
114};
115
116helpers.isChromedriverContext = function isChromedriverContext (windowName) {
117  return windowName === CHROMIUM_WIN;
118};
119
120// Need to override android-driver's version of this since we don't actually
121// have a bootstrap; instead we just restart adb and re-forward the Selendroid
122// port
123helpers.wrapBootstrapDisconnect = async function wrapBootstrapDisconnect (wrapped) {
124  await wrapped();
125  await this.adb.restart();
126  await this.adb.forwardPort(this.opts.systemPort, DEVICE_PORT);
127};
128
129Object.assign(extensions, commands, helpers);
130
131export default extensions;
132
Full Screen

bootstrap.js

Source: bootstrap.js Github

copy
1import UiAutomator from './uiautomator';
2import net from 'net';
3import path from 'path';
4import _ from 'lodash';
5import { errorFromCode } from 'appium-base-driver';
6import B from 'bluebird';
7import { logger } from 'appium-support';
8
9
10const log = logger.getLogger('AndroidBootstrap');
11const COMMAND_TYPES = {
12  ACTION: 'action',
13  SHUTDOWN: 'shutdown'
14};
15const SEND_COMMAND_TIMEOUT = 1 * 60 * 1000;
16
17class AndroidBootstrap {
18  constructor (adb, systemPort = 4724, webSocket = undefined) {
19    this.adb = adb;
20    this.systemPort = systemPort;
21    this.webSocket = webSocket;
22    this.ignoreUnexpectedShutdown = false;
23  }
24
25  get onUnexpectedShutdown () {
26    if (!this._onUnexpectedShutdownPromise) {
27      let reject;
28      this._onUnexpectedShutdownPromise = new B(function _onUnexpectedShutdownPromise (_resolve, _reject) {
29        reject = _reject;
30      });
31      this._onUnexpectedShutdownPromise.cancel = reject;
32    }
33    return this._onUnexpectedShutdownPromise;
34  }
35
36  async start (appPackage, disableAndroidWatchers = false, acceptSslCerts = false) {
37    try {
38      const rootDir = path.resolve(__dirname, '..', '..');
39      const startDetector = (s) => { return /Appium Socket Server Ready/.test(s); };
40      const bootstrapJar = path.resolve(rootDir, 'bootstrap', 'bin', 'AppiumBootstrap.jar');
41
42      await this.init();
43      await this.adb.forwardPort(this.systemPort, 4724);
44      this.process = await this.uiAutomator.start(
45                       bootstrapJar, 'io.appium.android.bootstrap.Bootstrap',
46                       startDetector, '-e', 'pkg', appPackage,
47                       '-e', 'disableAndroidWatchers', disableAndroidWatchers,
48                       '-e', 'acceptSslCerts', acceptSslCerts);
49
50      // process the output
51      this.process.on('output', (stdout, stderr) => {
52        const alertRe = /Emitting system alert message/;
53        if (alertRe.test(stdout)) {
54          log.debug('Emitting alert message...');
55          if (this.webSocket) {
56            this.webSocket.sockets.emit('alert', {message: stdout});
57          }
58        }
59
60        // the bootstrap logger wraps its own log lines with
61        // [APPIUM-UIAUTO] ... [APPIUM-UIAUTO]
62        // and leaves actual UiAutomator logs as they are
63        let stdoutLines = (stdout || '').split('\n');
64        const uiautoLog = /\[APPIUM-UIAUTO\](.+)\[\/APPIUM-UIAUTO\]/;
65        for (let line of stdoutLines) {
66          if (line.trim()) {
67            if (uiautoLog.test(line)) {
68              let innerLine = uiautoLog.exec(line)[1].trim();
69              let logMethod = log.info.bind(log);
70              // if the bootstrap log considers something debug, log that as
71              // debug and not info
72              if (/\[debug\]/.test(innerLine)) {
73                logMethod = log.debug.bind(log);
74              }
75              logMethod(`[BOOTSTRAP LOG] ${innerLine}`);
76            } else {
77              log.debug(`[UIAUTO STDOUT] ${line}`);
78            }
79          }
80        }
81
82        let stderrLines = (stderr || '').split('\n');
83        for (let line of stderrLines) {
84          if (line.trim()) {
85            log.debug(`[UIAUTO STDERR] ${line}`);
86          }
87        }
88      });
89
90      // only return when the socket client has connected
91      return await new B((resolve, reject) => {
92        try {
93          this.socketClient = net.connect(this.systemPort);
94          // Windows: the socket errors out when ADB restarts. Let's catch it to avoid crashing.
95          this.socketClient.on('error', (err) => {
96            if (!this.ignoreUnexpectedShutdown) {
97              throw new Error(`Android bootstrap socket crashed: ${err}`);
98            }
99          });
100          this.socketClient.once('connect', () => {
101            log.info('Android bootstrap socket is now connected');
102            resolve();
103          });
104        } catch (err) {
105          reject(err);
106        }
107      });
108    } catch (err) {
109      log.errorAndThrow(`Error occured while starting AndroidBootstrap. Original error: ${err}`);
110    }
111  }
112
113  async sendCommand (type, extra = {}) {
114    if (!this.socketClient) {
115      throw new Error('Socket connection closed unexpectedly');
116    }
117
118    return await new B((resolve, reject) => {
119      let cmd = Object.assign({cmd: type}, extra);
120      let cmdJson = `${JSON.stringify(cmd)} \n`;
121      log.debug(`Sending command to android: ${_.truncate(cmdJson, {length: 1000}).trim()}`);
122      this.socketClient.write(cmdJson);
123      this.socketClient.setEncoding('utf8');
124      let streamData = '';
125      let sendCommandTimeoutHandler = null;
126      this.socketClient.on('data', (data) => {
127        if (sendCommandTimeoutHandler) {
128          clearTimeout(sendCommandTimeoutHandler);
129        }
130        log.debug('Received command result from bootstrap');
131        try {
132          streamData = JSON.parse(streamData + data);
133          // we successfully parsed JSON so we've got all the data,
134          // remove the socket listener and evaluate
135          this.socketClient.removeAllListeners('data');
136          if (streamData.status === 0) {
137            return resolve(streamData.value);
138          }
139          reject(errorFromCode(streamData.status, streamData.value));
140        } catch (err) {
141          if (!_.isString(streamData)) {
142            log.error('Got an unexpected error inside socket listener');
143            log.error(err.stack);
144            return reject(errorFromCode(13, err.message));
145          }
146          log.debug(`Stream still not complete, waiting up to ${SEND_COMMAND_TIMEOUT}ms for the data to arrive`);
147          streamData += data;
148          sendCommandTimeoutHandler = setTimeout(() => {
149            const errMsg = `Server socket stopped responding. The recent response was '${streamData}'`;
150            log.error(errMsg);
151            this.socketClient.removeAllListeners('data');
152            reject(errorFromCode(13, errMsg));
153          }, SEND_COMMAND_TIMEOUT);
154        }
155      });
156    });
157  }
158
159  async sendAction (action, params = {}) {
160    let extra = {action, params};
161    return await this.sendCommand(COMMAND_TYPES.ACTION, extra);
162  }
163
164  async shutdown () {
165    if (!this.uiAutomator) {
166      log.warn('Cannot shut down Android bootstrap; it has already shut down');
167      return;
168    }
169
170    // remove listners so we don't trigger unexpected shutdown
171    this.uiAutomator.removeAllListeners(UiAutomator.EVENT_CHANGED);
172    if (this.socketClient) {
173      await this.sendCommand(COMMAND_TYPES.SHUTDOWN);
174    }
175    await this.uiAutomator.shutdown();
176    this.uiAutomator = null;
177  }
178
179  // this helper function makes unit testing easier.
180  async init () { // eslint-disable-line require-await
181    this.uiAutomator = new UiAutomator(this.adb);
182
183    // Handle unexpected UiAutomator shutdown
184    this.uiAutomator.on(UiAutomator.EVENT_CHANGED, (msg) => {
185      if (msg.state === UiAutomator.STATE_STOPPED) {
186        this.uiAutomator = null;
187        this.onUnexpectedShutdown.cancel(new Error('UiAUtomator shut down unexpectedly'));
188      }
189    });
190  }
191
192  set ignoreUnexpectedShutdown (ignore) {
193    log.debug(`${ignore ? 'Ignoring' : 'Watching for'} bootstrap disconnect`);
194    this._ignoreUnexpectedShutdown = ignore;
195  }
196
197  get ignoreUnexpectedShutdown () {
198    return this._ignoreUnexpectedShutdown;
199  }
200}
201
202export { AndroidBootstrap, COMMAND_TYPES };
203export default AndroidBootstrap;
204
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)