@testim/testim-cli 3.268.0 → 3.270.0

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,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  'use strict';
2
4
 
3
5
  const path = require('path');
@@ -5,7 +7,8 @@ const os = require('os');
5
7
  const dataUriToBuffer = require('data-uri-to-buffer');
6
8
  const { spawn: threadSpawn, config } = require('threads');
7
9
  const Promise = require('bluebird');
8
- const fs = require('fs-extra');
10
+ const fse = require('fs-extra');
11
+ const fs = require('fs');
9
12
  const utils = require('../../../utils');
10
13
  const logger = require('../../../commons/logger').getLogger('cli-service');
11
14
  const { getS3Artifact } = require('../../../commons/testimServicesApi');
@@ -13,6 +16,7 @@ const npmWrapper = require('../../../commons/npmWrapper');
13
16
  const featureFlags = require('../../../commons/featureFlags');
14
17
  const { TimeoutError } = require('../../../errors');
15
18
 
19
+ /** @type {import('worker_threads') | false} */
16
20
  let workerThreads;
17
21
 
18
22
  config.set({
@@ -32,6 +36,15 @@ function convertWindowsBackslash(input) {
32
36
  return input.replace(/\\/g, '/');
33
37
  }
34
38
 
39
+ /**
40
+ * @param {string} transactionId
41
+ * @param {any} incomingParams
42
+ * @param {any} context
43
+ * @param {any} code
44
+ * @param {Record<string, any>} packageLocalLocations
45
+ * @param {number=} timeout
46
+ * @param {string=} fileDataUrl
47
+ */
35
48
  function runCode(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
36
49
  const requireCode = Object.keys(packageLocalLocations).reduce((all, pMember) => {
37
50
  all += `
@@ -204,7 +217,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
204
217
 
205
218
  const testimConsoleLogDataAggregates = [];
206
219
  const thread = threadSpawn(constructWithArguments(Function, ['input', 'done', 'progress', runFn]));
207
- return new Promise((resolve) => {
220
+ return utils.promiseTimeout(new Promise((resolve) => {
208
221
  thread
209
222
  .send({ incomingParams, context, code })
210
223
  .on('message', message => {
@@ -226,7 +239,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
226
239
  tstConsoleLogs: testimConsoleLogDataAggregates,
227
240
  status: 'failed',
228
241
  result: {
229
- resultValue: err && err.toString(),
242
+ resultValue: err?.toString(),
230
243
  exports: {},
231
244
  exportsTest: {},
232
245
  exportsGlobal: {},
@@ -237,22 +250,25 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
237
250
  .on('exit', () => {
238
251
  logger.debug('Run code worker has been terminated', { transactionId });
239
252
  });
240
- }).timeout(timeout)
241
- .catch(Promise.TimeoutError, err => {
253
+ }), timeout)
254
+ .catch(err => {
255
+ if (!(err instanceof utils.TimeoutError)) {
256
+ throw err;
257
+ }
242
258
  logger.warn('timeout to run code', { transactionId, err });
243
- return Promise.resolve({
259
+ return {
244
260
  tstConsoleLogs: testimConsoleLogDataAggregates,
245
261
  status: 'failed',
246
262
  result: {
247
- resultValue: err && err.toString(),
263
+ resultValue: err?.toString(),
248
264
  exports: {},
249
265
  exportsTest: {},
250
266
  exportsGlobal: {},
251
267
  },
252
268
  success: false,
253
- });
269
+ };
254
270
  })
255
- .finally(() => thread && thread.kill());
271
+ .finally(() => thread?.kill());
256
272
  }
257
273
 
258
274
  function requireOrImportMethod(path) {
@@ -260,7 +276,6 @@ function requireOrImportMethod(path) {
260
276
  return { sync: true, lib: require(path) };
261
277
  } catch (err) {
262
278
  if (err.code === 'ERR_REQUIRE_ESM') {
263
- const fs = require('fs');
264
279
  const pathModule = require('path');
265
280
 
266
281
  const lib = fs.promises.readFile(`${path}${pathModule.sep}package.json`).then(file => {
@@ -275,7 +290,22 @@ function requireOrImportMethod(path) {
275
290
  }
276
291
  }
277
292
 
278
- function runCodeWithWorkerThread(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
293
+ /**
294
+ * @param {string} transactionId
295
+ * @param {any} incomingParams
296
+ * @param {any} context
297
+ * @param {any} code
298
+ * @param {number=} timeout
299
+ */
300
+ function runCodeWithWorkerThread(
301
+ transactionId,
302
+ incomingParams,
303
+ context,
304
+ code,
305
+ packageLocalLocations = {},
306
+ timeout = undefined,
307
+ fileDataUrl = undefined,
308
+ ) {
279
309
  // technically shouldn't happen, but better safe than sorry.
280
310
  if (!workerThreads) {
281
311
  workerThreads = require('worker_threads');
@@ -477,7 +507,7 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
477
507
  const thread = new Worker(runFn, {
478
508
  eval: true,
479
509
  });
480
- return new Promise((resolve) => {
510
+ return utils.promiseTimeout(new Promise((resolve) => {
481
511
  thread
482
512
  .on('message', message => {
483
513
  if (message.action === 'finish') {
@@ -500,7 +530,7 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
500
530
  tstConsoleLogs: testimConsoleLogDataAggregates,
501
531
  status: 'failed',
502
532
  result: {
503
- resultValue: err && err.toString(),
533
+ resultValue: err?.toString(),
504
534
  exports: {},
505
535
  exportsTest: {},
506
536
  exportsGlobal: {},
@@ -513,26 +543,29 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
513
543
  });
514
544
  // context can contain methods and proxies which cannot pass.
515
545
  thread.postMessage({ incomingParams, context: JSON.parse(JSON.stringify(context)), code });
516
- }).timeout(timeout)
517
- .catch(Promise.TimeoutError, err => {
546
+ }), timeout)
547
+ .catch(err => {
548
+ if (!(err instanceof utils.TimeoutError)) {
549
+ throw err;
550
+ }
518
551
  logger.warn('timeout to run code', { transactionId, err });
519
- return Promise.resolve({
552
+ return {
520
553
  tstConsoleLogs: testimConsoleLogDataAggregates,
521
554
  status: 'failed',
522
555
  result: {
523
- resultValue: err && err.toString(),
556
+ resultValue: err?.toString(),
524
557
  exports: {},
525
558
  exportsTest: {},
526
559
  exportsGlobal: {},
527
560
  },
528
561
  success: false,
529
- });
562
+ };
530
563
  })
531
- .finally(() => thread && thread.terminate());
564
+ .finally(() => thread?.terminate());
532
565
  }
533
566
 
534
567
  function removeFolder(installFolder) {
535
- return new Promise(resolve => fs.remove(installFolder)
568
+ return new Promise(resolve => fse.remove(installFolder)
536
569
  .then(resolve)
537
570
  .catch(err => {
538
571
  logger.warn('failed to remove install npm packages folder', { err });
package/bluebirdConfig.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  /**
4
4
  * Configure bluebird promises
@@ -6,18 +6,19 @@
6
6
  const Promise = require('bluebird');
7
7
  const { isDebuggerConnected } = require('./commons/detectDebugger');
8
8
  const { OVERRIDE_TIMEOUTS } = require('./commons/config');
9
+
9
10
  Promise.config({
10
11
  // Disable warnings.
11
12
  warnings: false,
12
13
  // Enable long stack traces.
13
14
  longStackTraces: Boolean(isDebuggerConnected()),
14
15
  // Disable cancellation.
15
- cancellation: false
16
+ cancellation: false,
16
17
  });
17
18
 
18
19
  let warnedAboutDebugger = false;
19
20
  if (OVERRIDE_TIMEOUTS) {
20
- let old = Promise.prototype.timeout;
21
+ const old = Promise.prototype.timeout;
21
22
  const timeoutOverride = Number(OVERRIDE_TIMEOUTS || 6e5);
22
23
  if (!OVERRIDE_TIMEOUTS && !warnedAboutDebugger) {
23
24
  warnedAboutDebugger = true;
@@ -31,7 +32,7 @@ if (OVERRIDE_TIMEOUTS) {
31
32
  if (process.env.IS_BLUEBIRD_NATIVE_PROMISE_SCHEDULER) {
32
33
  // If the debugger is connected we skip the trampoline in order to schedule with native promise scheduling
33
34
  // which makes the V8 debugger aware of promise scheduling and makes async stack traces work without a lot of unnecessary bluebird-specific frames.
34
- const NativePromise = (async function () {})().constructor;
35
+ const NativePromise = (async function () {}()).constructor;
35
36
  const ResolvedNativePromise = NativePromise.resolve();
36
37
  Promise.setScheduler(fn => ResolvedNativePromise.then(fn));
37
38
  }
package/cliAgentMode.js CHANGED
@@ -90,15 +90,6 @@ async function runAgentMode(options) {
90
90
  );
91
91
  }
92
92
 
93
- async function hackForCoralogixAndXhr() {
94
- Promise.resolve().then(() => {
95
- // @ts-ignore
96
- global.xhr2 = require('./commons/xhr2'); // this is inside a `then` to not block and let network requests start
97
- });
98
-
99
- // this gets picked up later in sessionPlayerInit
100
- }
101
-
102
93
  let startedWithStart = false;
103
94
 
104
95
  function getStartedWithStart() {
@@ -179,7 +170,6 @@ async function startTestimStandaloneBrowser(options) {
179
170
 
180
171
  let shouldDownloadExtension = !(options.ext || options.extensionPath);
181
172
 
182
- await hackForCoralogixAndXhr();
183
173
  if (shouldDownloadExtension && await fs.pathExists(downloadedExtensionPath)) {
184
174
  const stat = await fs.stat(downloadedExtensionPath);
185
175
  shouldDownloadExtension = (Date.now() - EXTENSION_CACHE_TIME > stat.mtimeMs);
@@ -2,8 +2,8 @@
2
2
 
3
3
  const logger = require('./logger').getLogger('http-request');
4
4
  const superagent = require('superagent');
5
- const Promise = require('bluebird');
6
5
  const { makeCounters } = require('./httpRequestCounters');
6
+ const { promiseFromCallback } = require('../utils/promiseUtils');
7
7
 
8
8
  const wrapWithMonitoring = makeCounters();
9
9
 
@@ -63,7 +63,7 @@ function deleteFullRes(url, body = {}, headers = {}, timeout = DEFAULT_REQUEST_T
63
63
  request.proxy(getProxy());
64
64
  }
65
65
 
66
- return Promise.fromCallback((callback) => request.end(callback));
66
+ return promiseFromCallback((callback) => request.end(callback));
67
67
  }
68
68
 
69
69
  function post({
@@ -98,7 +98,7 @@ function postFullRes(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT,
98
98
  request.retry(retry);
99
99
  }
100
100
 
101
- return Promise.fromCallback((callback) => request.end(callback)).catch(e => e, e => {
101
+ return promiseFromCallback((callback) => request.end(callback)).catch(e => e, e => {
102
102
  e.url = url;
103
103
  e.originalRequestTimeout = timeout;
104
104
  e.additionalSetHeaders = headers;
@@ -127,7 +127,7 @@ function postForm(url, fields, files, headers = {}, timeout = DEFAULT_REQUEST_TI
127
127
  request.proxy(getProxy());
128
128
  }
129
129
 
130
- return Promise.fromCallback((callback) => request.end(callback))
130
+ return promiseFromCallback((callback) => request.end(callback))
131
131
  .then((res) => {
132
132
  if (res.type === 'text/plain') {
133
133
  return res.text;
@@ -156,7 +156,7 @@ function _get(url, query, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT, { isB
156
156
  request.proxy(getProxy());
157
157
  }
158
158
 
159
- return Promise.fromCallback((callback) => request.end(callback));
159
+ return promiseFromCallback((callback) => request.end(callback));
160
160
  }
161
161
 
162
162
  function getText(url, query, headers) {
@@ -191,7 +191,7 @@ function head(url) {
191
191
  request.proxy(getProxy());
192
192
  }
193
193
 
194
- return Promise.fromCallback((callback) => request.end(callback))
194
+ return promiseFromCallback((callback) => request.end(callback))
195
195
  .catch(logErrorAndRethrow('failed to head request', { url }));
196
196
  }
197
197
 
@@ -210,7 +210,7 @@ function put(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
210
210
  request.proxy(getProxy());
211
211
  }
212
212
 
213
- return Promise.fromCallback((callback) => request.end(callback))
213
+ return promiseFromCallback((callback) => request.end(callback))
214
214
  .then((res) => res.body)
215
215
  .catch(logErrorAndRethrow('failed to put request', { url }));
216
216
  }
@@ -236,7 +236,7 @@ function download(url) {
236
236
  request.proxy(getProxy());
237
237
  }
238
238
 
239
- return Promise.fromCallback((callback) => request.end(callback))
239
+ return promiseFromCallback((callback) => request.end(callback))
240
240
  .then(response => {
241
241
  logger.info('finished to download', { url });
242
242
  return response;
@@ -17,11 +17,6 @@ const PREPARE_MOCK_NETWORK_ERROR_PREFIX = 'JSON file supplied to --mock-network-
17
17
 
18
18
  const logger = require('./logger').getLogger('prepare runner');
19
19
 
20
- Promise.resolve().then(() => {
21
- // @ts-ignore
22
- global.xhr2 = require('./xhr2'); // this is inside a `then` to not block and let network requests start
23
- });
24
-
25
20
  /** @param {import('../runOptions').RunnerOptions} options */
26
21
  async function prepare(options) {
27
22
  /**
@@ -1,13 +1,16 @@
1
+ // @ts-check
2
+
1
3
  'use strict';
2
4
 
3
5
  const path = require('path');
4
6
  const Promise = require('bluebird');
5
7
  const debounce = require('lodash/debounce');
6
- const fs = Promise.promisifyAll(require('fs'));
8
+ const fs = require('fs');
7
9
  const { getCliLocation } = require('../utils');
8
10
 
9
11
  const logger = require('./logger').getLogger('local cache');
10
12
  const crypto = require('crypto');
13
+ const utils = require('../utils');
11
14
 
12
15
  let cacheLocation = path.resolve(getCliLocation(), 'testim-cache');
13
16
 
@@ -25,10 +28,19 @@ const THREE_HOURS = 1000 * 60 * 60 * 3;
25
28
 
26
29
  const getCacheFileLocation = () => path.resolve(path.resolve(cacheLocation, 'testim.cache'));
27
30
 
28
- const getLocalRunnerCache = () => fs.readFileAsync(getCacheFileLocation()).then(async buffer => {
29
- const key = await _encryptKeyPromise;
30
- return decrypt(key, buffer);
31
- }).timeout(30000).catch(() => ({}));
31
+ async function getLocalRunnerCache() {
32
+ try {
33
+ return await utils.promiseTimeout(
34
+ fs.promises.readFile(getCacheFileLocation()).then(async buffer => {
35
+ const key = await _encryptKeyPromise;
36
+ return decrypt(key, buffer);
37
+ }),
38
+ 30_000,
39
+ );
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
32
44
 
33
45
  let localRunnerCache = getLocalRunnerCache();
34
46
 
@@ -59,7 +71,7 @@ const encryptAndSave = debounce(async (object) => {
59
71
  if (!pathExists) {
60
72
  await fs.promises.mkdir(cacheLocation, { recursive: true });
61
73
  }
62
- await fs.writeFileAsync(getCacheFileLocation(), result);
74
+ await fs.promises.writeFile(getCacheFileLocation(), result);
63
75
  } catch (err) {
64
76
  logger.error('failed saving cache', { err });
65
77
  error = err;
@@ -77,6 +89,7 @@ function decrypt(key, buffer) {
77
89
  const keyBuffer = Buffer.from(key);
78
90
  const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.concat([keyBuffer, Buffer.alloc(32)], 32), iv);
79
91
  const decrypted = decipher.update(encryptedText);
92
+ // @ts-ignore
80
93
  return JSON.parse(Buffer.concat([decrypted, decipher.final()]));
81
94
  }
82
95
  /**
@@ -561,7 +561,7 @@ function buildSeleniumOptions(browserOptions, testName, testRunConfig, gridInfo,
561
561
  }
562
562
 
563
563
  //testRunConfig not in used for now
564
- function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, options, appPath }) {
564
+ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, options, appPath, androidActivityWait }) {
565
565
  const { deviceModel, osVersion, deviceUdid } = options;
566
566
  const headspinSelector = {};
567
567
 
@@ -576,10 +576,13 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
576
576
  hostname: gridInfo.host,
577
577
  port: gridInfo.port,
578
578
  path: `/v0/${gridInfo.accessToken}/wd/hub`,
579
+ // connectionRetryTimeout: 900000, -- not used for now
579
580
  };
580
-
581
+ //TODO: check if more caps should be defined as default
581
582
  let appCaps = {
582
583
  'headspin:capture': true,
584
+ 'appium:autoAcceptAlerts': true,
585
+ 'appium:noReset': true,
583
586
  };
584
587
  switch (projectType) {
585
588
  case 'ios':
@@ -588,7 +591,9 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
588
591
  platformName: 'iOS',
589
592
  'appium:automationName': 'XCUITest',
590
593
  ...(nativeApp && { 'appium:bundleId': nativeApp.id }),
591
- ...(appPath && { 'appium:app': appPath }),
594
+ ...(appPath && {
595
+ 'appium:app': appPath,
596
+ }),
592
597
  };
593
598
  break;
594
599
  case 'android':
@@ -596,11 +601,14 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
596
601
  ...appCaps,
597
602
  platformName: 'Android',
598
603
  'appium:automationName': 'UiAutomator2',
604
+ 'appium:appWaitActivity': androidActivityWait,
599
605
  ...(nativeApp && {
600
- 'appium:appPackage': nativeApp.packageName,
606
+ 'appium:appPackage': nativeApp.id || nativeApp.packageName,
601
607
  'appium:appActivity': nativeApp.activity,
602
608
  }),
603
- ...(appPath && { 'appium:app': appPath }),
609
+ ...(appPath && {
610
+ 'appium:app': appPath,
611
+ }),
604
612
  };
605
613
  break;
606
614
  default:
@@ -214,7 +214,7 @@ async function getTestPlanTestList(projectId, names, planIds, branch, intersecti
214
214
  * testConfigIds?: string[];
215
215
  * intersections: import('../runOptions').RunnerOptions['intersections'];
216
216
  * }} param0
217
- * @returns {import('services/src/suite/service').RunListResult}
217
+ * @returns {Promise<import('services/src/suite/service').RunListResult>}
218
218
  */
219
219
  function getSuiteTestList({
220
220
  projectId, labels, testIds, testNames, testConfigNames, suiteNames, suiteIds, branch, rerunFailedByRunId, testConfigIds, intersections,
@@ -234,7 +234,7 @@ function getSuiteTestList({
234
234
  testConfigIds,
235
235
  intersections,
236
236
  },
237
- }), { retries: DEFAULT_REQUEST_RETRY });
237
+ }), { retries: DEFAULT_REQUEST_RETRY, factor: 1 });
238
238
  }
239
239
 
240
240
  async function getAppDetails({ appId, projectId }) {
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const Promise = require('bluebird');
6
6
  const YAML = require('yaml');
7
7
  const os = require('os');
8
+ const utils = require('./utils');
8
9
  const { launchChrome } = require('./commons/chrome-launcher');
9
10
 
10
11
  async function getProjectId() {
@@ -17,7 +18,7 @@ async function getToken() {
17
18
 
18
19
  function timeout(promise, ms) {
19
20
  // we need this to time out even if we disabled timeouts system wide
20
- return Promise.race([promise, Promise.delay(ms).then(() => { throw new Promise.TimeoutError('timeout'); })]);
21
+ return Promise.race([promise, utils.delay(ms).then(() => { throw new utils.TimeoutError('timeout'); })]);
21
22
  }
22
23
 
23
24
  async function getCredentialsFromChrome() {
@@ -73,14 +74,14 @@ async function doLogin({ overwriteExisting = true, projects = null } = {}) {
73
74
  projects = await timeout(Promise.resolve(getCredentialsFromChrome()), 62000).catch(e => null);
74
75
  }
75
76
 
76
- if (projects && projects.token) { // V1(legacy) of the login extension API
77
+ if (projects?.token) { // V1(legacy) of the login extension API
77
78
  credentials.token = projects.token;
78
79
  credentials.projectId = projects.projectId;
79
80
  spinner.succeed();
80
81
 
81
82
  await writeCredentials(testimCredentialsFile, credentials);
82
83
  return;
83
- } if (projects && projects.length) { // V2(current) of the login extension API
84
+ } if (projects?.length) { // V2(current) of the login extension API
84
85
  spinner.succeed();
85
86
 
86
87
  const response = projects.length === 1 ?
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@testim/testim-cli",
3
- "version": "3.268.0",
3
+ "version": "3.270.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@testim/testim-cli",
9
- "version": "3.268.0",
9
+ "version": "3.270.0",
10
10
  "license": "Proprietary",
11
11
  "dependencies": {
12
12
  "@applitools/eyes-sdk-core": "13.11.21",
@@ -1460,9 +1460,9 @@
1460
1460
  }
1461
1461
  },
1462
1462
  "node_modules/@wdio/types/node_modules/@types/node": {
1463
- "version": "18.11.13",
1464
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
1465
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
1463
+ "version": "18.11.17",
1464
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
1465
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
1466
1466
  },
1467
1467
  "node_modules/@wdio/utils": {
1468
1468
  "version": "7.24.0",
@@ -4416,9 +4416,9 @@
4416
4416
  "integrity": "sha512-+iipnm2hvmlWs4MVNx7HwSTxhDxsXnQyK5F1OalZVXeUhdPgP/23T42NCyg0TK3wL/Yg92SVrSuGKqdg12o54w=="
4417
4417
  },
4418
4418
  "node_modules/devtools/node_modules/@types/node": {
4419
- "version": "18.11.13",
4420
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
4421
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
4419
+ "version": "18.11.17",
4420
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
4421
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
4422
4422
  },
4423
4423
  "node_modules/devtools/node_modules/ua-parser-js": {
4424
4424
  "version": "1.0.32",
@@ -15468,9 +15468,9 @@
15468
15468
  }
15469
15469
  },
15470
15470
  "node_modules/webdriver/node_modules/@types/node": {
15471
- "version": "18.11.13",
15472
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
15473
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
15471
+ "version": "18.11.17",
15472
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
15473
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
15474
15474
  },
15475
15475
  "node_modules/webdriverio": {
15476
15476
  "version": "7.24.0",
@@ -15510,9 +15510,9 @@
15510
15510
  }
15511
15511
  },
15512
15512
  "node_modules/webdriverio/node_modules/@types/node": {
15513
- "version": "18.11.13",
15514
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
15515
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
15513
+ "version": "18.11.17",
15514
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
15515
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
15516
15516
  },
15517
15517
  "node_modules/webdriverio/node_modules/brace-expansion": {
15518
15518
  "version": "2.0.1",
@@ -17129,9 +17129,9 @@
17129
17129
  },
17130
17130
  "dependencies": {
17131
17131
  "@types/node": {
17132
- "version": "18.11.13",
17133
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
17134
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
17132
+ "version": "18.11.17",
17133
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
17134
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
17135
17135
  }
17136
17136
  }
17137
17137
  },
@@ -19496,9 +19496,9 @@
19496
19496
  },
19497
19497
  "dependencies": {
19498
19498
  "@types/node": {
19499
- "version": "18.11.13",
19500
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
19501
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
19499
+ "version": "18.11.17",
19500
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
19501
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
19502
19502
  },
19503
19503
  "ua-parser-js": {
19504
19504
  "version": "1.0.32",
@@ -27994,9 +27994,9 @@
27994
27994
  },
27995
27995
  "dependencies": {
27996
27996
  "@types/node": {
27997
- "version": "18.11.13",
27998
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
27999
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
27997
+ "version": "18.11.17",
27998
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
27999
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
28000
28000
  }
28001
28001
  }
28002
28002
  },
@@ -28035,9 +28035,9 @@
28035
28035
  },
28036
28036
  "dependencies": {
28037
28037
  "@types/node": {
28038
- "version": "18.11.13",
28039
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
28040
- "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
28038
+ "version": "18.11.17",
28039
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
28040
+ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
28041
28041
  },
28042
28042
  "brace-expansion": {
28043
28043
  "version": "2.0.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testim/testim-cli",
3
- "version": "3.268.0",
3
+ "version": "3.270.0",
4
4
  "description": "Command line interface for running Testing on your CI",
5
5
  "author": "Oren Rubin",
6
6
  "contributors": [{
@@ -1,6 +1,6 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
- const Promise = require('bluebird');
3
+ const utils = require('../utils');
4
4
  const WebDriver = require('./webdriver');
5
5
 
6
6
  class ExtensionTestPlayer {
@@ -11,10 +11,12 @@ class ExtensionTestPlayer {
11
11
 
12
12
  onDone() {
13
13
  const END_DRIVER_TIMEOUT = 1000 * 60 * 2;
14
- return this.driver.end()
15
- .timeout(END_DRIVER_TIMEOUT)
16
- .catch(Promise.TimeoutError, () => {
17
- return this.driver.forceEnd();
14
+ return utils.promiseTimeout(this.driver.end(), END_DRIVER_TIMEOUT)
15
+ .catch((error) => {
16
+ if (error instanceof utils.TimeoutError) {
17
+ return this.driver.forceEnd();
18
+ }
19
+ throw error;
18
20
  })
19
21
  .catch(() => {})
20
22
  .then(() => {
@@ -22,6 +22,7 @@ const WebDriver = require('./webdriver');
22
22
  // delete after https://github.com/testimio/clickim/pull/3430 release to the store
23
23
  const CryptoJS = require('crypto-js');
24
24
  const StepActionUtils = require('./utils/stepActionUtils');
25
+ const utils = require('../utils');
25
26
 
26
27
  class SeleniumTestPlayer {
27
28
  //eslint-disable-next-line default-param-last
@@ -83,7 +84,7 @@ class SeleniumTestPlayer {
83
84
  }
84
85
 
85
86
  onStepCompleted(result, testId, resultId, step) {
86
- if (step && step.isTabOpener) {
87
+ if (step?.isTabOpener) {
87
88
  this.tabService.addNewPopup(this.id, step.id)
88
89
  .catch(() => { });
89
90
  }
@@ -91,10 +92,13 @@ class SeleniumTestPlayer {
91
92
 
92
93
  onDone() {
93
94
  const END_DRIVER_TIMEOUT = 1000 * 60 * 2;
94
- return this.driver.end()
95
- .timeout(END_DRIVER_TIMEOUT)
96
- .catch(Promise.TimeoutError, () => this.driver.forceEnd())
97
- .catch(() => { })
95
+ return utils.promiseTimeout(this.driver.end(), END_DRIVER_TIMEOUT)
96
+ .catch(error => {
97
+ if (error instanceof utils.TimeoutError) {
98
+ return this.driver.forceEnd().catch(() => null);
99
+ }
100
+ return undefined;
101
+ })
98
102
  .then(() => {
99
103
  this.sessionPlayer.playbackManager.off(commonConstants.playback.RESULT, this.onStepCompleted);
100
104
  this.sessionPlayer = null;
@@ -108,10 +112,11 @@ class SeleniumTestPlayer {
108
112
  this.tabService.clearAllTabs(this.id);
109
113
  }
110
114
 
111
- addTab(openerStepId, options = { loadInfo: true }) {
112
- return this.driver.getTabIds()
113
- .tap(ids => this.tabService.addNewTab(this.id, ids[ids.length - 1], openerStepId, options))
114
- .then(ids => this.sessionPlayer.addPlaybackFrameHandler(ids[ids.length - 1], undefined, { emptyPage: true }));
115
+ async addTab(openerStepId, options = { loadInfo: true }) {
116
+ const ids = await this.driver.getTabIds();
117
+ const lastId = ids.at(-1);
118
+ await this.tabService.addNewTab(this.id, lastId, openerStepId, options);
119
+ return this.sessionPlayer.addPlaybackFrameHandler(lastId, undefined, { emptyPage: true });
115
120
  }
116
121
 
117
122
  async addAllTabs(openerStepId, options = { loadInfo: true, checkForMainTab: true, takeScreenshots: true }, blackList = []) {
@@ -132,8 +137,8 @@ class SeleniumTestPlayer {
132
137
  // if we only have one tab because we removed the editor tab - we have to switchTab to one of the other tabs, otherwise
133
138
  // tabService will assume it's on a good context but it's not.
134
139
  const tabInfo = this.tabService.getMainTabInfo(this.id);
135
- const utils = this.tabService.getTabUtils(this.id, tabInfo);
136
- await this.tabService.switchTab(utils.tabId, this.id, { forceSwitch: true });
140
+ const tabUtils = this.tabService.getTabUtils(this.id, tabInfo);
141
+ await this.tabService.switchTab(tabUtils.tabId, this.id, { forceSwitch: true });
137
142
  }
138
143
  // deal with checkForMainTab failing due to the page refreshing or JavaScript not responding or a similar issue
139
144
  this.tabService.fixMissingMainTab(this.id);
@@ -12,6 +12,7 @@ const guid = require('../../utils').guid;
12
12
 
13
13
  const UrlUtils = sessionPlayer.urlUtils;
14
14
  const semver = require('semver');
15
+ const utils = require('../../utils');
15
16
 
16
17
  const constants = sessionPlayer.commonConstants.stepResult;
17
18
  const tabMatcher = sessionPlayer.tabMatcher;
@@ -156,55 +157,49 @@ class TabService {
156
157
  Object.values(this.getAllTabInfos(sessionId))[0].isMain = true;
157
158
  }
158
159
 
159
- buildTabInfo(sessionId, tabId, order, openerStepId, options = {}) {
160
- return this.getTabDetails(tabId, sessionId, options)
161
- .then(tab => {
162
- const infoId = guid();
163
-
164
- function isMainTab(tabService) {
165
- if (options.checkForMainTab) {
166
- return tab.isMainTab;
167
- }
168
-
169
- if (!tab.isMainTab || tab.isMainTab === 'unknown') {
170
- const missingMainTab = !tabService.getMainTabInfo(sessionId);
171
- return missingMainTab;
172
- }
173
- return tab.isMainTab;
174
- }
175
- this.sessionTabs[sessionId].tabInfos[tabId] = {
176
- infoId,
177
- url: tab.url,
178
- title: tab.title,
179
- favIconUrl: tab.favIconUrl,
180
- order,
181
- from: this.getTabInfo(sessionId, tab.openerTabId),
182
- isMain: isMainTab(this),
183
- openerStepId,
184
- };
185
-
186
- return infoId;
187
- });
188
- }
160
+ async buildTabInfo(sessionId, tabId, order, openerStepId, options = {}) {
161
+ const tab = await this.getTabDetails(tabId, sessionId, options);
162
+ const infoId = guid();
163
+ function isMainTab(tabService) {
164
+ if (options.checkForMainTab) {
165
+ return tab.isMainTab;
166
+ }
189
167
 
190
- addTab(sessionId, id, order, openerStepId, options = {}) {
191
- return this.buildTabInfo(sessionId, id, order, openerStepId, options)
192
- .then(infoId => {
193
- const _windowUtils = new WindowUtils(id, this.driver);
194
- this._utils[infoId] = {
195
- attachDebugger: () => Promise.resolve(),
196
- detachDebugger: () => Promise.resolve(),
197
- onDebuggerDetached: () => {},
198
- tabId: id,
199
- domUtils: { getDOM: () => Promise.resolve() },
200
- windowUtils: _windowUtils,
201
- imageCaptureUtils: new ImageCaptureUtils(
202
- id,
203
- _windowUtils,
204
- new ScreenshotUtils(id, this.driver, { takeScreenshots: options.takeScreenshots })
205
- ),
206
- };
207
- });
168
+ if (!tab.isMainTab || tab.isMainTab === 'unknown') {
169
+ const missingMainTab = !tabService.getMainTabInfo(sessionId);
170
+ return missingMainTab;
171
+ }
172
+ return tab.isMainTab;
173
+ }
174
+ this.sessionTabs[sessionId].tabInfos[tabId] = {
175
+ infoId,
176
+ url: tab.url,
177
+ title: tab.title,
178
+ favIconUrl: tab.favIconUrl,
179
+ order,
180
+ from: this.getTabInfo(sessionId, tab.openerTabId),
181
+ isMain: isMainTab(this),
182
+ openerStepId,
183
+ };
184
+ return infoId;
185
+ }
186
+
187
+ async addTab(sessionId, id, order, openerStepId, options = {}) {
188
+ const infoId = await this.buildTabInfo(sessionId, id, order, openerStepId, options);
189
+ const _windowUtils = new WindowUtils(id, this.driver);
190
+ this._utils[infoId] = {
191
+ attachDebugger: () => Promise.resolve(),
192
+ detachDebugger: () => Promise.resolve(),
193
+ onDebuggerDetached: () => {},
194
+ tabId: id,
195
+ domUtils: { getDOM: () => Promise.resolve() },
196
+ windowUtils: _windowUtils,
197
+ imageCaptureUtils: new ImageCaptureUtils(
198
+ id,
199
+ _windowUtils,
200
+ new ScreenshotUtils(id, this.driver, { takeScreenshots: options.takeScreenshots })
201
+ ),
202
+ };
208
203
  }
209
204
 
210
205
  getTabUtilsByTabIdAndSessionId(sessionId, tabId) {
@@ -295,20 +290,20 @@ class TabService {
295
290
  }
296
291
 
297
292
  const infos = this.getAllTabInfos(sessionId);
298
- const alltopFrameUrls = Object.keys(infos)
293
+ const allTopFrameUrls = Object.keys(infos)
299
294
  .map(tabId => infos[tabId].url);
300
295
 
301
- if (this.exactUrlMatch(first, second, alltopFrameUrls)) {
296
+ if (this.exactUrlMatch(first, second, allTopFrameUrls)) {
302
297
  return true;
303
298
  }
304
299
 
305
300
  const combineDomainAndPath = urlParts => (`${urlParts.domain}/${urlParts.path.join('/')}`);
306
- if (this.singleExactMatchForParts(first, second, alltopFrameUrls, combineDomainAndPath)) {
301
+ if (this.singleExactMatchForParts(first, second, allTopFrameUrls, combineDomainAndPath)) {
307
302
  return true;
308
303
  }
309
304
 
310
305
  const combineDomainPathAndHash = urlParts => (`${urlParts.domain}/${urlParts.path.join('/')}#${urlParts.hash}`);
311
- if (this.singleExactMatchForParts(first, second, alltopFrameUrls, combineDomainPathAndHash)) {
306
+ if (this.singleExactMatchForParts(first, second, allTopFrameUrls, combineDomainPathAndHash)) {
312
307
  return true;
313
308
  }
314
309
 
@@ -409,32 +404,32 @@ class TabService {
409
404
  });
410
405
  }
411
406
 
412
- getUnregisteredTabId(sessionId) {
413
- return this.driver.getTabIds()
414
- .then(ids => ids.find(tabId => !this.getAllTabIds(sessionId).includes(tabId)));
407
+ async getUnregisteredTabId(sessionId) {
408
+ const ids = await this.driver.getTabIds();
409
+ return ids.find(tabId => !this.getAllTabIds(sessionId).includes(tabId));
415
410
  }
416
411
 
417
- waitForTabToOpen(sessionId) {
418
- return this.getUnregisteredTabId(sessionId)
419
- .then(newId => (newId ?
420
- Promise.resolve(newId) :
421
- Promise.delay(500).then(() => this.waitForTabToOpen(sessionId))));
412
+ async waitForTabToOpen(sessionId) {
413
+ const newId = await this.getUnregisteredTabId(sessionId);
414
+ if (newId) {
415
+ return newId;
416
+ }
417
+ await utils.delay(500);
418
+ return await this.waitForTabToOpen(sessionId);
422
419
  }
423
420
 
424
- tryToAddTab(sessionId, openerStepId) {
421
+ async tryToAddTab(sessionId, openerStepId) {
425
422
  if (this.pendingTabs[sessionId]) {
426
423
  // don't mess with the main flow
427
- return Promise.resolve();
424
+ return;
428
425
  }
429
- return this.getUnregisteredTabId(sessionId)
430
- .then(newId => {
431
- if (!newId) {
432
- return Promise.resolve();
433
- }
434
- return this.addNewTab(sessionId, newId)
435
- .then(() => this.addFrameHandler(newId))
436
- .then(() => (this.sessionTabs[sessionId].currentTab = null));
437
- });
426
+ const newId = await this.getUnregisteredTabId(sessionId);
427
+ if (!newId) {
428
+ return;
429
+ }
430
+ await this.addNewTab(sessionId, newId);
431
+ await this.addFrameHandler(newId);
432
+ this.sessionTabs[sessionId].currentTab = null;
438
433
  }
439
434
 
440
435
  addNewPopup(id, openerStepId) {
@@ -507,7 +502,7 @@ class TabService {
507
502
  errorType: constants.INVALID_TEST_VERSION,
508
503
  });
509
504
  }
510
- const openerStepId = (step.tabInfo || {}).openerStepId;
505
+ const openerStepId = step.tabInfo?.openerStepId;
511
506
  return this.waitToPendingTabs(sessionId, openerStepId)
512
507
  .then(() => {
513
508
  let tabId;
@@ -529,10 +524,10 @@ class TabService {
529
524
 
530
525
  if (!tabId) {
531
526
  return this.tryToAddTab(sessionId, openerStepId)
532
- .then(() => Promise.reject(new Error('No tab ID found')));
527
+ .then(() => { throw new Error('No tab ID found'); });
533
528
  }
534
529
  if (this.sessionTabs[sessionId].currentTab === tabId) {
535
- return Promise.resolve(tabId);
530
+ return tabId;
536
531
  }
537
532
  return this.switchTab(tabId, sessionId)
538
533
  .then(() => {
@@ -541,7 +536,7 @@ class TabService {
541
536
  })
542
537
  .catch(err => {
543
538
  const windowClosedErrors = ['no such window', 'no window found', 'the window could not be found'];
544
- if (err.message && windowClosedErrors.find(errorString => err.message.toLowerCase().includes(errorString))) {
539
+ if (err.message && windowClosedErrors.some(errorString => err.message.toLowerCase().includes(errorString))) {
545
540
  this.sessionTabs[sessionId].tabCount--;
546
541
  this.sessionTabs[sessionId].tabInfos[tabId].isClosed = true;
547
542
  return this.getTabIdByTabInfo(sessionId, step);
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ const _ = require('lodash');
3
4
  const BaseJsStepAction = require('./baseJsStepAction');
4
- const Bluebird = require('bluebird');
5
5
  const service = require('../../agent/routers/cliJsCode/service');
6
6
  const sessionPlayer = require('../../commons/getSessionPlayerRequire');
7
- const _ = require('lodash');
7
+ const utils = require('../../utils');
8
8
 
9
9
  const constants = sessionPlayer.commonConstants.stepResult;
10
10
 
@@ -36,7 +36,7 @@ class BaseCliJsStepAction extends BaseJsStepAction {
36
36
  try {
37
37
  return await this.executeCliCode();
38
38
  } catch (err) {
39
- if (err instanceof Bluebird.TimeoutError) {
39
+ if (err instanceof utils.TimeoutError) {
40
40
  return {
41
41
  success: false,
42
42
  errorType: constants.ACTION_TIMEOUT,
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const StepAction = require('./stepAction');
4
- const Bluebird = require('bluebird');
5
4
  const { NpmPackageError } = require('../../errors');
6
5
 
7
6
  const service = require('../../agent/routers/cliJsCode/service');
7
+ const utils = require('../../utils');
8
8
 
9
9
  class NodePackageStepAction extends StepAction {
10
10
  async performAction() {
@@ -29,7 +29,7 @@ class NodePackageStepAction extends StepAction {
29
29
  message: err.message,
30
30
  };
31
31
  }
32
- if (err instanceof Bluebird.TimeoutError) {
32
+ if (err instanceof utils.TimeoutError) {
33
33
  return {
34
34
  success: false,
35
35
  code: 'timeout',
@@ -6,6 +6,7 @@ const Promise = require('bluebird');
6
6
  const pRetry = require('p-retry');
7
7
  const { delay } = require('../../utils');
8
8
  const { PageNotAvailableError } = require('../../errors');
9
+ const utils = require('../../utils');
9
10
  const logger = require('../../commons/logger').getLogger('window-utils');
10
11
 
11
12
  class WindowUtils {
@@ -18,6 +19,7 @@ class WindowUtils {
18
19
  this.driver = driver;
19
20
  }
20
21
 
22
+ // Seems unused and not working since bad args to executeJS
21
23
  getElementFromPoint(x, y) {
22
24
  /* eslint-disable */
23
25
  function elementFromPoint(x, y) {
@@ -47,7 +49,7 @@ class WindowUtils {
47
49
 
48
50
  scrollToPositionWithoutAnimation(pos) {
49
51
  /* eslint-disable */
50
- // if scroll behaviour is not supported, then the scrolling is not animated anyway
52
+ // if scroll behavior is not supported, then the scrolling is not animated anyway
51
53
  function scrollWithoutAnimation(position) {
52
54
  var scrollBehaviorSupported = 'scrollBehavior' in document.documentElement.style;
53
55
  if (scrollBehaviorSupported) {
@@ -126,15 +128,13 @@ class WindowUtils {
126
128
  return Promise.resolve();
127
129
  }
128
130
 
129
- checkSize(size) {
130
- return Promise.delay(1000)
131
- .then(() => this.getViewportSize())
132
- .then(actualSize => {
133
- if (actualSize.width !== size.width || actualSize.height !== size.height) {
134
- return Promise.reject({ actualSize, expectedSize: size });
135
- }
136
- return { actualSize, expectedSize: size };
137
- });
131
+ async checkSize(size) {
132
+ await utils.delay(1000);
133
+ const actualSize = await this.getViewportSize();
134
+ if (actualSize.width !== size.width || actualSize.height !== size.height) {
135
+ return Promise.reject({ actualSize, expectedSize: size });
136
+ }
137
+ return { actualSize, expectedSize: size };
138
138
  }
139
139
 
140
140
  async setViewportSize(size) {
@@ -155,12 +155,19 @@ class WindowUtils {
155
155
  return false;
156
156
  }
157
157
 
158
- return locationObj.href !== 'chrome-error://chromewebdata/' && locationObj.href !== 'safari-resource:/ErrorPage.html' && locationObj.href.indexOf('res://ieframe.dll/http_404.htm') !== 0 && locationObj.href.indexOf('ms-appx-web://microsoft.microsoftedge/assets/errorpages/') !== 0;
158
+ return (
159
+ locationObj.href !== 'chrome-error://chromewebdata/' &&
160
+ locationObj.href !== 'safari-resource:/ErrorPage.html' &&
161
+ locationObj.href.indexOf('res://ieframe.dll/http_404.htm') !== 0 &&
162
+ locationObj.href.indexOf('ms-appx-web://microsoft.microsoftedge/assets/errorpages/') !== 0
163
+ );
159
164
  }
160
165
  /* eslint-enable */
161
166
 
162
167
  const result = await this.driver.executeJS(pageIsAvailable);
163
- return await (result.value ? Promise.resolve() : Promise.reject(new PageNotAvailableError()));
168
+ if (!result.value) {
169
+ throw new PageNotAvailableError('validatePageIsAvailable:PageNotAvailableError');
170
+ }
164
171
  }
165
172
 
166
173
  focusTab() {
@@ -1 +1,5 @@
1
1
  require('./Array.prototype.at');
2
+ const xhr2 = require('../commons/xhr2');
3
+
4
+ global.xhr2 = xhr2;
5
+ global.XMLHttpRequest = xhr2;
@@ -358,7 +358,7 @@ class TestPlanRunner {
358
358
  const suiteResult = await getSuite(options, branchToUse);
359
359
  perf.log('after getSuite');
360
360
 
361
- if (!suiteResult.tests[0]?.length) {
361
+ if (!suiteResult?.tests[0]?.length) {
362
362
  if (options.rerunFailedByRunId) {
363
363
  throw new ArgError('No failed tests found in the provided run');
364
364
  }
@@ -10,7 +10,6 @@ const { ArgError } = require('../errors');
10
10
  /**
11
11
  * @param {import('../runOptions').RunnerOptions} options
12
12
  * @param {string} branchToUse
13
- * @returns
14
13
  */
15
14
  async function getSuite(options, branchToUse) {
16
15
  if (options.lightweightMode?.onlyTestIdsNoSuite && options.testId) {
@@ -1,24 +1,28 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  const service = require('../agent/routers/cliJsCode/service');
4
- const Promise = require('bluebird');
5
- const {NpmPackageError} = require('../errors');
4
+ const { NpmPackageError } = require('../errors');
5
+ const utils = require('../utils');
6
6
 
7
- module.exports.run = (browser, step) => {
8
- const {stepId, testResultId, retryIndex, stepResultId, packageData, timeout} = step.data;
9
- return service.installPackage(stepId, testResultId, retryIndex, packageData, stepResultId, timeout)
10
- .then(data => ({data, success: true}))
11
- .catch(NpmPackageError, err => {
7
+ module.exports.run = async (browser, step) => {
8
+ const { stepId, testResultId, retryIndex, stepResultId, packageData, timeout } = step.data;
9
+ try {
10
+ const data = await service.installPackage(stepId, testResultId, retryIndex, packageData, stepResultId, timeout);
11
+ return { data, success: true };
12
+ } catch (err) {
13
+ if (err instanceof NpmPackageError) {
12
14
  return {
13
15
  success: false,
14
- code: "invalid-node-package",
15
- message: err.message
16
+ code: 'invalid-node-package',
17
+ message: err.message,
16
18
  };
17
- })
18
- .catch(Promise.TimeoutError, () => {
19
+ }
20
+ if (err instanceof utils.TimeoutError) {
19
21
  return {
20
22
  success: false,
21
- code: "timeout"
23
+ code: 'timeout',
22
24
  };
23
- });
25
+ }
26
+ throw err;
27
+ }
24
28
  };
package/testRunHandler.js CHANGED
@@ -98,6 +98,20 @@ class TestRun {
98
98
  return this._executionName;
99
99
  }
100
100
 
101
+ get androidActivityWait() {
102
+ const activity = 'appMetadata' in this._nativeApp ? this._nativeApp.appMetadata.activity : this._nativeApp.activity;
103
+ const lastValue = activity.split('.').pop();
104
+ return activity.replace(lastValue, '*');
105
+ }
106
+
107
+ get nativeAppLink() {
108
+ let link = null;
109
+ if ('filePath' in this._nativeApp) {
110
+ link = `${config.SERVICES_HOST}/storage${this._nativeApp.filePath}?access_token=${this._options.authData.token}`;
111
+ }
112
+ return link;
113
+ }
114
+
101
115
  async getNativeAppData() {
102
116
  const { appId, baseUrl } = this._options;
103
117
  if (baseUrl && !this._nativeApp && !appId) {
@@ -112,6 +126,9 @@ class TestRun {
112
126
  };
113
127
  }
114
128
  if (this._nativeApp && !appId) {
129
+ if ('appMetadata' in this._nativeApp) {
130
+ return this._nativeApp.appMetadata;
131
+ }
115
132
  return this._nativeApp;
116
133
  }
117
134
  return null;
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  /* eslint-disable no-console */
2
4
  const semver = require('semver');
3
5
  const config = require('./commons/config');
@@ -32,7 +34,7 @@ async function checkNpmVersion() {
32
34
  return;
33
35
  }
34
36
  try {
35
- const latestVersion = await utils.promiseTimeout(getNpmVersion('@testim/testim-cli'), 5000, 'The API call to NPM timed out');
37
+ const latestVersion = await utils.promiseTimeout(getNpmVersion(), 5000, 'The API call to NPM timed out');
36
38
  const packVersion = getPackageVersion();
37
39
  if (packVersion && semver.lt(packVersion, latestVersion)) {
38
40
  console.log(chalk.yellow(
@@ -87,4 +87,5 @@ module.exports = {
87
87
  promiseTimeout,
88
88
  promiseMap,
89
89
  promiseFromCallback,
90
+ TimeoutError,
90
91
  };
@@ -31,7 +31,10 @@ class WorkerAppium extends BaseWorker {
31
31
  async getBrowserOnce(testRunHandler, customExtensionLocalLocation, appiumTestPlayer, gridInfo) {
32
32
  reporter.onGetSession(this.id, this.testName, testRunHandler.runMode);
33
33
  const { driver } = appiumTestPlayer;
34
- let appPath = null;
34
+ const projectType = this.options.projectData.type;
35
+ const nativeApp = await testRunHandler.getNativeAppData();
36
+ const androidActivityWait = projectType === 'android' ? testRunHandler.androidActivityWait : null;
37
+ let appPath = testRunHandler.nativeAppLink;
35
38
  if (this.options.appId) {
36
39
  const { project: projectId, appId } = this.options;
37
40
  const mobileApp = await testimServicesApi.getAppDetails({ appId, projectId });
@@ -41,10 +44,17 @@ class WorkerAppium extends BaseWorker {
41
44
  }
42
45
  appPath = `${config.SERVICES_HOST}/storage${mobileApp.filePath}?access_token=${this.options.authData.token}`;
43
46
  }
44
- const nativeApp = await testRunHandler.getNativeAppData();
45
- const projectType = this.options.projectData.type;
46
47
  try {
47
- const capabilities = desiredCapabilitiesBuilder.buildAppiumOptions({ projectType, gridInfo, testRunConfig: this.testRunConfig, nativeApp, options: this.options, appPath });
48
+ const capabilities = desiredCapabilitiesBuilder.buildAppiumOptions({
49
+ projectType,
50
+ gridInfo,
51
+ testRunConfig: this.testRunConfig,
52
+ nativeApp,
53
+ options: this.options,
54
+ appPath,
55
+ androidActivityWait,
56
+ });
57
+
48
58
  const activeSession = await driver.remote(capabilities);
49
59
  driver.activeSession = activeSession;
50
60
  await this.updateDeviceInfo(testRunHandler, activeSession);
@@ -1,9 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const Promise = require('bluebird');
4
-
5
- const { timeoutMessages } = require('../commons/constants');
6
- const { PageNotAvailableError } = require('../errors');
7
4
  const BaseWorker = require('./BaseWorker');
8
5
  const logger = require('../commons/logger').getLogger('worker-selenium');
9
6
  const reporter = require('../reports/reporter');
@@ -11,6 +8,9 @@ const SeleniumTestPlayer = require('../player/seleniumTestPlayer');
11
8
  const WindowUtils = require('../player/utils/windowUtils');
12
9
  const sessionPlayerInit = require('../commons/getSessionPlayerRequire');
13
10
  const perf = require('../commons/performance-logger');
11
+ const utils = require('../utils');
12
+ const { timeoutMessages } = require('../commons/constants');
13
+ const { PageNotAvailableError } = require('../errors');
14
14
  const { preloadTests } = require('../commons/preloadTests');
15
15
 
16
16
  // this navigation timeout is handled from outside the worker, so don't pass a small timeout to navigate
@@ -147,9 +147,9 @@ class WorkerSelenium extends BaseWorker {
147
147
  ).catch(reject))
148
148
  .log('right after playTestByCode')
149
149
  .timeout(this.testRunTimeout, timeoutMessages.TEST_COMPLETE_TIMEOUT_MSG)
150
- .catch(Promise.TimeoutError, err => {
151
- if (sessionPlayer.stopPlayingOnTestTimeout) {
152
- sessionPlayer.stopPlayingOnTestTimeout();
150
+ .catch(err => {
151
+ if (err instanceof utils.TimeoutError) {
152
+ sessionPlayer.stopPlayingOnTestTimeout?.();
153
153
  }
154
154
  throw err;
155
155
  })
@@ -179,9 +179,9 @@ class WorkerSelenium extends BaseWorker {
179
179
  preloadedTest
180
180
  ).catch(reject))
181
181
  .timeout(this.testRunTimeout, timeoutMessages.TEST_COMPLETE_TIMEOUT_MSG)
182
- .catch(Promise.TimeoutError, err => {
183
- if (sessionPlayer.stopPlayingOnTestTimeout) {
184
- sessionPlayer.stopPlayingOnTestTimeout();
182
+ .catch(err => {
183
+ if (err instanceof utils.TimeoutError) {
184
+ sessionPlayer.stopPlayingOnTestTimeout?.();
185
185
  }
186
186
  throw err;
187
187
  })