appium-espresso-driver 2.1.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,5 @@
1
1
  import { JWProxy, errors } from '@appium/base-driver';
2
2
  import { waitForCondition } from 'asyncbox';
3
- import logger from './logger';
4
3
  import { ServerBuilder, buildServerSigningConfig } from './server-builder';
5
4
  import path from 'path';
6
5
  import { fs, util, mkdirp, timing } from '@appium/support';
@@ -38,14 +37,16 @@ class EspressoProxy extends JWProxy {
38
37
  }
39
38
 
40
39
  class EspressoRunner {
41
- constructor (opts = {}) {
40
+ constructor (log, opts = {}) {
42
41
  for (let req of REQUIRED_PARAMS) {
43
42
  if (!opts || !util.hasValue(opts[req])) {
44
43
  throw new Error(`Option '${req}' is required!`);
45
44
  }
46
45
  this[req] = opts[req];
47
46
  }
47
+ this.log = log;
48
48
  this.jwproxy = new EspressoProxy({
49
+ log,
49
50
  server: this.host,
50
51
  port: this.systemPort,
51
52
  base: '',
@@ -85,11 +86,11 @@ class EspressoRunner {
85
86
 
86
87
  async isAppPackageChanged () {
87
88
  if (!await this.adb.fileExists(TARGET_PACKAGE_CONTAINER)) {
88
- logger.debug('The previous target application package is unknown');
89
+ this.log.debug('The previous target application package is unknown');
89
90
  return true;
90
91
  }
91
92
  const previousAppPackage = (await this.adb.shell(['cat', TARGET_PACKAGE_CONTAINER])).trim();
92
- logger.debug(`The previous target application package was '${previousAppPackage}'. ` +
93
+ this.log.debug(`The previous target application package was '${previousAppPackage}'. ` +
93
94
  `The current package is '${this.appPackage}'`);
94
95
  return previousAppPackage !== this.appPackage;
95
96
  }
@@ -110,21 +111,21 @@ class EspressoRunner {
110
111
  ].includes(appState);
111
112
 
112
113
  if (shouldUninstallApp) {
113
- logger.info(`Uninstalling Espresso Test Server apk from the target device (pkg: '${TEST_APK_PKG}')`);
114
+ this.log.info(`Uninstalling Espresso Test Server apk from the target device (pkg: '${TEST_APK_PKG}')`);
114
115
  try {
115
116
  await this.adb.uninstallApk(TEST_APK_PKG);
116
117
  } catch (err) {
117
- logger.warn(`Error uninstalling '${TEST_APK_PKG}': ${err.message}`);
118
+ this.log.warn(`Error uninstalling '${TEST_APK_PKG}': ${err.message}`);
118
119
  }
119
120
  }
120
121
 
121
122
  if (shouldInstallApp) {
122
- logger.info(`Installing Espresso Test Server apk from the target device (path: '${this.modServerPath}')`);
123
+ this.log.info(`Installing Espresso Test Server apk from the target device (path: '${this.modServerPath}')`);
123
124
  try {
124
125
  await this.adb.install(this.modServerPath, { replace: false, timeout: this.androidInstallTimeout });
125
- logger.info(`Installed Espresso Test Server apk '${this.modServerPath}' (pkg: '${TEST_APK_PKG}')`);
126
+ this.log.info(`Installed Espresso Test Server apk '${this.modServerPath}' (pkg: '${TEST_APK_PKG}')`);
126
127
  } catch (err) {
127
- logger.errorAndThrow(`Cannot install '${this.modServerPath}' because of '${err.message}'`);
128
+ this.log.errorAndThrow(`Cannot install '${this.modServerPath}' because of '${err.message}'`);
128
129
  }
129
130
  }
130
131
  }
@@ -132,14 +133,14 @@ class EspressoRunner {
132
133
  async installTestApk () {
133
134
  let rebuild = this.forceEspressoRebuild;
134
135
  if (rebuild) {
135
- logger.debug(`'forceEspressoRebuild' capability is enabled`);
136
+ this.log.debug(`'forceEspressoRebuild' capability is enabled`);
136
137
  } else if (await this.isAppPackageChanged()) {
137
- logger.info(`Forcing Espresso server rebuild because of changed application package`);
138
+ this.log.info(`Forcing Espresso server rebuild because of changed application package`);
138
139
  rebuild = true;
139
140
  }
140
141
 
141
142
  if (rebuild && await fs.exists(this.modServerPath)) {
142
- logger.debug(`Deleting the obsolete Espresso server package '${this.modServerPath}'`);
143
+ this.log.debug(`Deleting the obsolete Espresso server package '${this.modServerPath}'`);
143
144
  await fs.unlink(this.modServerPath);
144
145
  }
145
146
  if (!(await fs.exists(this.modServerPath))) {
@@ -150,7 +151,7 @@ class EspressoRunner {
150
151
  await this.adb.sign(this.modServerPath);
151
152
  }
152
153
  if ((rebuild || !isSigned) && await this.adb.uninstallApk(TEST_APK_PKG)) {
153
- logger.info('Uninstalled the obsolete Espresso server package from the device under test');
154
+ this.log.info('Uninstalled the obsolete Espresso server package from the device under test');
154
155
  }
155
156
 
156
157
  await this.installServer();
@@ -161,16 +162,16 @@ class EspressoRunner {
161
162
  if (this.espressoBuildConfig) {
162
163
  let buildConfigurationStr;
163
164
  if (await fs.exists(this.espressoBuildConfig)) {
164
- logger.info(`Loading the build configuration from '${this.espressoBuildConfig}'`);
165
+ this.log.info(`Loading the build configuration from '${this.espressoBuildConfig}'`);
165
166
  buildConfigurationStr = await fs.readFile(this.espressoBuildConfig, 'utf8');
166
167
  } else {
167
- logger.info(`Loading the build configuration from 'espressoBuildConfig' capability`);
168
+ this.log.info(`Loading the build configuration from 'espressoBuildConfig' capability`);
168
169
  buildConfigurationStr = this.espressoBuildConfig;
169
170
  }
170
171
  try {
171
172
  buildConfiguration = JSON.parse(buildConfigurationStr);
172
173
  } catch (e) {
173
- logger.error('Cannot parse the build configuration JSON', e);
174
+ this.log.error('Cannot parse the build configuration JSON', e);
174
175
  throw e;
175
176
  }
176
177
  }
@@ -178,26 +179,26 @@ class EspressoRunner {
178
179
  replacement: '-',
179
180
  });
180
181
  const serverPath = path.resolve(this.tmpDir, dirName);
181
- logger.info(`Building espresso server in '${serverPath}'`);
182
- logger.debug(`The build folder root could be customized by changing the 'tmpDir' capability`);
182
+ this.log.info(`Building espresso server in '${serverPath}'`);
183
+ this.log.debug(`The build folder root could be customized by changing the 'tmpDir' capability`);
183
184
  await fs.rimraf(serverPath);
184
185
  await mkdirp(serverPath);
185
- logger.debug(`Copying espresso server template from ('${TEST_SERVER_ROOT}' to '${serverPath}')`);
186
+ this.log.debug(`Copying espresso server template from ('${TEST_SERVER_ROOT}' to '${serverPath}')`);
186
187
  await copyGradleProjectRecursively(TEST_SERVER_ROOT, serverPath);
187
- logger.debug('Bulding espresso server');
188
- await new ServerBuilder({
188
+ this.log.debug('Bulding espresso server');
189
+ await new ServerBuilder(this.log, {
189
190
  serverPath, buildConfiguration,
190
191
  showGradleLog: this.showGradleLog,
191
192
  testAppPackage: this.appPackage,
192
193
  signingConfig: this.signingConfig
193
194
  }).build();
194
195
  const apkPath = path.resolve(serverPath, 'app', 'build', 'outputs', 'apk', 'androidTest', 'debug', 'app-debug-androidTest.apk');
195
- logger.debug(`Copying built apk from '${apkPath}' to '${this.modServerPath}'`);
196
+ this.log.debug(`Copying built apk from '${apkPath}' to '${this.modServerPath}'`);
196
197
  await fs.copyFile(apkPath, this.modServerPath);
197
198
  }
198
199
 
199
200
  async cleanupSessionLeftovers () {
200
- logger.debug('Performing cleanup of automation leftovers');
201
+ this.log.debug('Performing cleanup of automation leftovers');
201
202
 
202
203
  try {
203
204
  const {value} = (await axios({
@@ -206,8 +207,8 @@ class EspressoRunner {
206
207
  })).data;
207
208
  const activeSessionIds = value.map((sess) => sess.id);
208
209
  if (activeSessionIds.length) {
209
- logger.debug(`The following obsolete sessions are still running: ${JSON.stringify(activeSessionIds)}`);
210
- logger.debug('Cleaning up the obsolete sessions');
210
+ this.log.debug(`The following obsolete sessions are still running: ${JSON.stringify(activeSessionIds)}`);
211
+ this.log.debug('Cleaning up the obsolete sessions');
211
212
  await B.all(activeSessionIds.map((id) =>
212
213
  axios({
213
214
  url: `http://${this.host}:${this.systemPort}/session/${id}`,
@@ -217,10 +218,10 @@ class EspressoRunner {
217
218
  // Let all sessions to be properly terminated before continuing
218
219
  await B.delay(1000);
219
220
  } else {
220
- logger.debug('No obsolete sessions have been detected');
221
+ this.log.debug('No obsolete sessions have been detected');
221
222
  }
222
223
  } catch (e) {
223
- logger.debug(`No obsolete sessions have been detected (${e.message})`);
224
+ this.log.debug(`No obsolete sessions have been detected (${e.message})`);
224
225
  }
225
226
  }
226
227
 
@@ -241,7 +242,7 @@ class EspressoRunner {
241
242
 
242
243
  cmd.push(`${TEST_APK_PKG}/androidx.test.runner.AndroidJUnitRunner`);
243
244
 
244
- logger.info(`Starting Espresso Server v${version} with cmd: adb ${cmd.join(' ')}`);
245
+ this.log.info(`Starting Espresso Server v${version} with cmd: adb ${cmd.join(' ')}`);
245
246
 
246
247
  let hasSocketError = false;
247
248
  // start the instrumentation process
@@ -251,7 +252,7 @@ class EspressoRunner {
251
252
  };
252
253
  this.instProcess = this.adb.createSubProcess(cmd);
253
254
  this.instProcess.on('exit', (code, signal) => {
254
- logger.info(`Instrumentation process exited with code ${code} from signal ${signal}`);
255
+ this.log.info(`Instrumentation process exited with code ${code} from signal ${signal}`);
255
256
  this.jwproxy.instrumentationState.exited = true;
256
257
  });
257
258
  this.instProcess.on('output', (stdout, stderr) => {
@@ -261,7 +262,7 @@ class EspressoRunner {
261
262
  return;
262
263
  }
263
264
 
264
- logger.debug(`[Instrumentation] ${line.trim()}`);
265
+ this.log.debug(`[Instrumentation] ${line.trim()}`);
265
266
  // A 'SocketException' indicates that we couldn't connect to the Espresso server,
266
267
  // because the INTERNET permission is not set
267
268
  if (line.toLowerCase().includes('java.net.socketexception')) {
@@ -273,15 +274,15 @@ class EspressoRunner {
273
274
 
274
275
  const timer = new timing.Timer().start();
275
276
  await this.instProcess.start(0);
276
- logger.info(`Waiting up to ${this.serverLaunchTimeout}ms for Espresso server to be online`);
277
+ this.log.info(`Waiting up to ${this.serverLaunchTimeout}ms for Espresso server to be online`);
277
278
  try {
278
279
  await waitForCondition(async () => {
279
280
  if (hasSocketError) {
280
- logger.errorAndThrow(`Espresso server has failed to start due to an unexpected exception. ` +
281
+ this.log.errorAndThrow(`Espresso server has failed to start due to an unexpected exception. ` +
281
282
  `Make sure the 'INTERNET' permission is requested in the Android manifest of your ` +
282
283
  `application under test (<uses-permission android:name="android.permission.INTERNET" />)`);
283
284
  } else if (this.jwproxy.instrumentationState.exited) {
284
- logger.errorAndThrow(`Espresso server process has been unexpectedly terminated. ` +
285
+ this.log.errorAndThrow(`Espresso server process has been unexpectedly terminated. ` +
285
286
  `Check the Appium server log and the logcat output for more details`);
286
287
  }
287
288
  try {
@@ -296,15 +297,15 @@ class EspressoRunner {
296
297
  });
297
298
  } catch (e) {
298
299
  if (/Condition unmet/.test(e.message)) {
299
- logger.errorAndThrow(`Timed out waiting for Espresso server to be ` +
300
+ this.log.errorAndThrow(`Timed out waiting for Espresso server to be ` +
300
301
  `online within ${this.serverLaunchTimeout}ms. The timeout value could be ` +
301
302
  `customized using 'espressoServerLaunchTimeout' capability`);
302
303
  }
303
304
  throw e;
304
305
  }
305
- logger.info(`Espresso server is online. ` +
306
+ this.log.info(`Espresso server is online. ` +
306
307
  `The initialization process took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
307
- logger.info('Starting the session');
308
+ this.log.info('Starting the session');
308
309
 
309
310
  await this.jwproxy.command('/session', 'POST', {
310
311
  capabilities: {
@@ -317,17 +318,17 @@ class EspressoRunner {
317
318
 
318
319
  async recordTargetAppPackage () {
319
320
  await this.adb.shell([`echo "${this.appPackage}" > "${TARGET_PACKAGE_CONTAINER}"`]);
320
- logger.info(`Recorded the target application package '${this.appPackage}' to ${TARGET_PACKAGE_CONTAINER}`);
321
+ this.log.info(`Recorded the target application package '${this.appPackage}' to ${TARGET_PACKAGE_CONTAINER}`);
321
322
  }
322
323
 
323
324
  async deleteSession () {
324
- logger.debug('Deleting Espresso server session');
325
+ this.log.debug('Deleting Espresso server session');
325
326
  // rely on jwproxy's intelligence to know what we're talking about and
326
327
  // delete the current session
327
328
  try {
328
329
  await this.jwproxy.command('/', 'DELETE');
329
330
  } catch (err) {
330
- logger.warn(`Did not get confirmation Espresso deleteSession worked; ` +
331
+ this.log.warn(`Did not get confirmation Espresso deleteSession worked; ` +
331
332
  `Error was: ${err}`);
332
333
  }
333
334
 
@@ -1,7 +1,6 @@
1
1
  import { SubProcess } from 'teen_process';
2
- import { fs, logger, system } from '@appium/support';
2
+ import { fs, system } from '@appium/support';
3
3
  import _ from 'lodash';
4
- import log from './logger';
5
4
  import path from 'path';
6
5
  import { EOL } from 'os';
7
6
  import { updateDependencyLines } from './utils';
@@ -22,11 +21,10 @@ const VERSION_KEYS = [
22
21
  'kotlin',
23
22
  'sourceCompatibility',
24
23
  'targetCompatibility',
25
- 'jvmTarget'
24
+ 'jvmTarget',
25
+ 'composeVersion'
26
26
  ];
27
27
 
28
- const gradleLog = logger.getLogger('Gradle');
29
-
30
28
  function buildServerSigningConfig (args) {
31
29
  return {
32
30
  zipAlign: true,
@@ -38,7 +36,8 @@ function buildServerSigningConfig (args) {
38
36
  }
39
37
 
40
38
  class ServerBuilder {
41
- constructor (args = {}) {
39
+ constructor (log, args = {}) {
40
+ this.log = log;
42
41
  this.serverPath = args.serverPath;
43
42
  this.showGradleLog = args.showGradleLog;
44
43
 
@@ -73,7 +72,7 @@ class ServerBuilder {
73
72
  }
74
73
 
75
74
  getCommand () {
76
- const cmd = system.isWindows() ? 'gradlew.bat' : './gradlew';
75
+ const cmd = system.isWindows() ? 'gradlew.bat' : path.resolve(this.serverPath, 'gradlew');
77
76
  const buildProperty = (key, value) => value ? `-P${key}=${value}` : null;
78
77
  let args = VERSION_KEYS
79
78
  .filter((key) => key !== GRADLE_VERSION_KEY)
@@ -150,7 +149,7 @@ class ServerBuilder {
150
149
  continue;
151
150
  }
152
151
 
153
- log.info(`Adding the following ${propName} to build.gradle.kts: ${deps}`);
152
+ this.log.info(`Adding the following ${propName} to build.gradle.kts: ${deps}`);
154
153
  configuration = updateDependencyLines(configuration, propName, deps);
155
154
  }
156
155
  await fs.writeFile(buildPath, configuration, 'utf8');
@@ -158,7 +157,7 @@ class ServerBuilder {
158
157
 
159
158
  async runBuildProcess () {
160
159
  const {cmd, args} = this.getCommand();
161
- log.debug(`Beginning build with command '${cmd} ${args.join(' ')}' ` +
160
+ this.log.debug(`Beginning build with command '${cmd} ${args.join(' ')}' ` +
162
161
  `in directory '${this.serverPath}'`);
163
162
  const gradlebuild = new SubProcess(cmd, args, {
164
163
  cwd: this.serverPath,
@@ -168,13 +167,13 @@ class ServerBuilder {
168
167
  let buildLastLines = [];
169
168
 
170
169
  const logMsg = `Output from Gradle ${this.showGradleLog ? 'will' : 'will not'} be logged`;
171
- log.debug(`${logMsg}. To change this, use 'showGradleLog' desired capability`);
170
+ this.log.debug(`${logMsg}. To change this, use 'showGradleLog' desired capability`);
172
171
  gradlebuild.on('stream-line', (line) => {
173
172
  if (this.showGradleLog) {
174
173
  if (line.startsWith('[STDERR]')) {
175
- gradleLog.warn(line);
174
+ this.log.warn(`[Gradle] ${line}`);
176
175
  } else {
177
- gradleLog.info(line);
176
+ this.log.info(`[Gradle] ${line}`);
178
177
  }
179
178
  }
180
179
  buildLastLines.push(`${EOL}${line}`);
@@ -189,7 +188,7 @@ class ServerBuilder {
189
188
  } catch (err) {
190
189
  let msg = `Unable to build Espresso server - ${err.message}\n` +
191
190
  `Gradle error message:${EOL}${buildLastLines}`;
192
- log.errorAndThrow(msg);
191
+ this.log.errorAndThrow(msg);
193
192
  }
194
193
  }
195
194
  }