@testim/testim-cli 3.266.0 → 3.268.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.
- package/commons/socket/baseSocketServiceSocketIO.js +25 -2
- package/commons/socket/testResultService.js +0 -1
- package/commons/testimDesiredCapabilitiesBuilder.js +14 -7
- package/commons/testimServicesApi.js +31 -5
- package/npm-shrinkwrap.json +38 -38
- package/package.json +1 -1
- package/reports/consoleReporter.js +6 -2
- package/runOptions.d.ts +4 -3
- package/runOptions.js +3 -2
- package/runner.js +1 -1
- package/runners/ParallelWorkerManager.js +66 -12
- package/runners/TestPlanRunner.js +2 -4
- package/services/gridService.js +48 -36
- package/services/gridService.test.js +11 -18
- package/testRunHandler.js +216 -235
- package/testRunStatus.js +9 -1
- package/testimNpmDriver.js +15 -18
- package/workers/BaseWorker.js +98 -44
- package/workers/BaseWorker.test.js +2 -7
- package/workers/WorkerAppium.js +64 -24
- package/workers/WorkerExtension.js +11 -5
- package/workers/WorkerExtensionSingleBrowser.js +12 -2
- package/workers/WorkerSelenium.js +29 -20
|
@@ -4,6 +4,7 @@ const Promise = require('bluebird');
|
|
|
4
4
|
const pRetry = require('p-retry');
|
|
5
5
|
const io = require('socket.io-client');
|
|
6
6
|
const config = require('../config');
|
|
7
|
+
const utils = require('../../utils');
|
|
7
8
|
|
|
8
9
|
const MAX_SOCKET_RECONNECT_ATTEMPT = 50;
|
|
9
10
|
const MAX_RECONNECT_ATTEMPT_BEFORE_SWITCH = 10;
|
|
@@ -15,7 +16,9 @@ const logger = require('../logger').getLogger('base socket service');
|
|
|
15
16
|
class BaseSocketServiceSocketIO {
|
|
16
17
|
constructor() {
|
|
17
18
|
this.attempts = 0;
|
|
19
|
+
/** @type {{ [testResultId: string]: testId }} */
|
|
18
20
|
this.rooms = {};
|
|
21
|
+
/** @type {undefined | Promise<void>} */
|
|
19
22
|
this.emitPromiseQueue = undefined;
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -28,10 +31,18 @@ class BaseSocketServiceSocketIO {
|
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} resultId
|
|
36
|
+
* @param {string} testId
|
|
37
|
+
*/
|
|
31
38
|
joinRoom(resultId, testId) {
|
|
32
39
|
this.rooms[resultId] = testId;
|
|
33
40
|
}
|
|
34
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} resultId
|
|
44
|
+
* @param {string} testId
|
|
45
|
+
*/
|
|
35
46
|
leaveRoom(resultId) {
|
|
36
47
|
delete this.rooms[resultId];
|
|
37
48
|
}
|
|
@@ -97,6 +108,10 @@ class BaseSocketServiceSocketIO {
|
|
|
97
108
|
});
|
|
98
109
|
}
|
|
99
110
|
|
|
111
|
+
/**
|
|
112
|
+
* @param {string} projectId
|
|
113
|
+
* @param {string} ns
|
|
114
|
+
*/
|
|
100
115
|
initNewSocket(projectId, ns) {
|
|
101
116
|
const opts = {
|
|
102
117
|
query: { projectId },
|
|
@@ -124,6 +139,10 @@ class BaseSocketServiceSocketIO {
|
|
|
124
139
|
});
|
|
125
140
|
}
|
|
126
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @param {string} projectId
|
|
144
|
+
* @param {string} ns
|
|
145
|
+
*/
|
|
127
146
|
init(projectId, ns) {
|
|
128
147
|
const opts = {
|
|
129
148
|
query: { projectId },
|
|
@@ -146,6 +165,10 @@ class BaseSocketServiceSocketIO {
|
|
|
146
165
|
this.addSocketHandlers();
|
|
147
166
|
}
|
|
148
167
|
|
|
168
|
+
/**
|
|
169
|
+
* @param {string} eventName
|
|
170
|
+
* @param {*} eventData
|
|
171
|
+
*/
|
|
149
172
|
emitPromise(eventName, eventData) {
|
|
150
173
|
const errorneousEvents = {};
|
|
151
174
|
|
|
@@ -158,10 +181,10 @@ class BaseSocketServiceSocketIO {
|
|
|
158
181
|
|
|
159
182
|
return reject(new Error('bad ack'));
|
|
160
183
|
});
|
|
161
|
-
})
|
|
184
|
+
});
|
|
162
185
|
|
|
163
186
|
this.emitPromiseQueue = (this.emitPromiseQueue || Promise.resolve())
|
|
164
|
-
.then(() => pRetry(emitAndWait, { retries: 200, minTimeout: 3000 }))
|
|
187
|
+
.then(() => pRetry(() => utils.promiseTimeout(emitAndWait(), EMIT_PROMISE_TIMEOUT), { retries: 200, minTimeout: 3000, factor: 1 }))
|
|
165
188
|
.finally(() => {
|
|
166
189
|
if (Object.keys(errorneousEvents).length > 0) {
|
|
167
190
|
logger.error('Bad acknowledge from socket emit', { errorneousEvents });
|
|
@@ -561,11 +561,11 @@ 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 }) {
|
|
564
|
+
function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, options, appPath }) {
|
|
565
565
|
const { deviceModel, osVersion, deviceUdid } = options;
|
|
566
566
|
const headspinSelector = {};
|
|
567
567
|
|
|
568
|
-
if (!nativeApp) {
|
|
568
|
+
if (!nativeApp && !appPath) {
|
|
569
569
|
throw Error('missing mobile app!');
|
|
570
570
|
}
|
|
571
571
|
if (gridInfo.type !== gridTypes.TESTIM_HEADSPIN) {
|
|
@@ -578,21 +578,29 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
|
|
|
578
578
|
path: `/v0/${gridInfo.accessToken}/wd/hub`,
|
|
579
579
|
};
|
|
580
580
|
|
|
581
|
-
let appCaps = {
|
|
581
|
+
let appCaps = {
|
|
582
|
+
'headspin:capture': true,
|
|
583
|
+
};
|
|
582
584
|
switch (projectType) {
|
|
583
585
|
case 'ios':
|
|
584
586
|
appCaps = {
|
|
585
|
-
|
|
587
|
+
...appCaps,
|
|
586
588
|
platformName: 'iOS',
|
|
587
589
|
'appium:automationName': 'XCUITest',
|
|
590
|
+
...(nativeApp && { 'appium:bundleId': nativeApp.id }),
|
|
591
|
+
...(appPath && { 'appium:app': appPath }),
|
|
588
592
|
};
|
|
589
593
|
break;
|
|
590
594
|
case 'android':
|
|
591
595
|
appCaps = {
|
|
596
|
+
...appCaps,
|
|
592
597
|
platformName: 'Android',
|
|
593
598
|
'appium:automationName': 'UiAutomator2',
|
|
594
|
-
|
|
595
|
-
|
|
599
|
+
...(nativeApp && {
|
|
600
|
+
'appium:appPackage': nativeApp.packageName,
|
|
601
|
+
'appium:appActivity': nativeApp.activity,
|
|
602
|
+
}),
|
|
603
|
+
...(appPath && { 'appium:app': appPath }),
|
|
596
604
|
};
|
|
597
605
|
break;
|
|
598
606
|
default:
|
|
@@ -609,7 +617,6 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
|
|
|
609
617
|
delete headspinSelector.model;
|
|
610
618
|
delete headspinSelector.os_version;
|
|
611
619
|
}
|
|
612
|
-
|
|
613
620
|
if (!_.isEmpty(headspinSelector)) {
|
|
614
621
|
appCaps['headspin:selector'] = headspinSelector;
|
|
615
622
|
}
|
|
@@ -237,6 +237,15 @@ function getSuiteTestList({
|
|
|
237
237
|
}), { retries: DEFAULT_REQUEST_RETRY });
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
async function getAppDetails({ appId, projectId }) {
|
|
241
|
+
try {
|
|
242
|
+
return await pRetry(() => getWithAuth(`/mobile-app/app/${appId}?projectId=${projectId}`), { retries: DEFAULT_REQUEST_RETRY, factor: 1 });
|
|
243
|
+
} catch (error) {
|
|
244
|
+
logger.error('failed getting application details', { appId, error });
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
240
249
|
function getUsageForCurrentBillingPeriod(projectId) {
|
|
241
250
|
return pRetry(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`), { retries: DEFAULT_REQUEST_RETRY })
|
|
242
251
|
.catch((error) => {
|
|
@@ -395,10 +404,16 @@ function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
|
|
|
395
404
|
}), { retries: DEFAULT_REQUEST_RETRY });
|
|
396
405
|
}
|
|
397
406
|
|
|
407
|
+
/** @param {string} uri */
|
|
398
408
|
function relativize(uri) {
|
|
399
409
|
return uri.startsWith('/') ? uri : `/${uri}`;
|
|
400
410
|
}
|
|
401
411
|
|
|
412
|
+
/**
|
|
413
|
+
* @param {string} filePath
|
|
414
|
+
* @param {string} bucket
|
|
415
|
+
* @param {string} projectId
|
|
416
|
+
*/
|
|
402
417
|
function getStorageRelativePath(filePath, bucket, projectId) {
|
|
403
418
|
let fullPath = relativize(filePath);
|
|
404
419
|
if (projectId) {
|
|
@@ -411,7 +426,15 @@ function getStorageRelativePath(filePath, bucket, projectId) {
|
|
|
411
426
|
return fullPath;
|
|
412
427
|
}
|
|
413
428
|
|
|
414
|
-
|
|
429
|
+
/**
|
|
430
|
+
* @param {string} projectId
|
|
431
|
+
* @param {string} testId
|
|
432
|
+
* @param {string} testResultId
|
|
433
|
+
* @param {*} content
|
|
434
|
+
* @param {string} subType
|
|
435
|
+
* @param {string} mimeType
|
|
436
|
+
*/
|
|
437
|
+
async function uploadArtifact(projectId, testId, testResultId, content, subType, mimeType = 'application/octet-stream') {
|
|
415
438
|
let fileSuffix = null;
|
|
416
439
|
if (mimeType === 'application/json') {
|
|
417
440
|
fileSuffix = '.json';
|
|
@@ -431,9 +454,11 @@ function uploadArtifact(projectId, testId, testResultId, content, subType, mimeT
|
|
|
431
454
|
},
|
|
432
455
|
};
|
|
433
456
|
|
|
434
|
-
|
|
435
|
-
'X-Asset-Encoding': 'gzip',
|
|
436
|
-
|
|
457
|
+
await pRetry(
|
|
458
|
+
() => postAuthFormData(`/storage${storagePath}`, {}, files, { 'X-Asset-Encoding': 'gzip' }),
|
|
459
|
+
{ retries: DEFAULT_REQUEST_RETRY, factor: 1 }
|
|
460
|
+
);
|
|
461
|
+
return storagePath;
|
|
437
462
|
}
|
|
438
463
|
|
|
439
464
|
const uploadRunDataArtifact = _.memoize(async (projectId, testId, testResultId, runData) => {
|
|
@@ -530,6 +555,7 @@ function updateRemoteRunFailure(body) {
|
|
|
530
555
|
}
|
|
531
556
|
|
|
532
557
|
module.exports = {
|
|
558
|
+
getAppDetails,
|
|
533
559
|
getS3Artifact,
|
|
534
560
|
getTestPlan,
|
|
535
561
|
saveTestPlanResult,
|
|
@@ -553,7 +579,7 @@ module.exports = {
|
|
|
553
579
|
saveRemoteStep,
|
|
554
580
|
getEditorUrl,
|
|
555
581
|
getLabFeaturesByProjectId,
|
|
556
|
-
uploadRunDataArtifact
|
|
582
|
+
uploadRunDataArtifact,
|
|
557
583
|
updateTestDataArtifact: Promise.method(updateTestDataArtifact),
|
|
558
584
|
initializeUserWithAuth,
|
|
559
585
|
addTestRetry,
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.268.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@testim/testim-cli",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.268.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.
|
|
1464
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
1465
|
-
"integrity": "sha512-
|
|
1463
|
+
"version": "18.11.13",
|
|
1464
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
1465
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
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.
|
|
4420
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
4421
|
-
"integrity": "sha512-
|
|
4419
|
+
"version": "18.11.13",
|
|
4420
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
4421
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
4422
4422
|
},
|
|
4423
4423
|
"node_modules/devtools/node_modules/ua-parser-js": {
|
|
4424
4424
|
"version": "1.0.32",
|
|
@@ -6216,9 +6216,9 @@
|
|
|
6216
6216
|
}
|
|
6217
6217
|
},
|
|
6218
6218
|
"node_modules/got": {
|
|
6219
|
-
"version": "11.8.
|
|
6220
|
-
"resolved": "https://registry.npmjs.org/got/-/got-11.8.
|
|
6221
|
-
"integrity": "sha512-
|
|
6219
|
+
"version": "11.8.6",
|
|
6220
|
+
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
|
6221
|
+
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
|
6222
6222
|
"dependencies": {
|
|
6223
6223
|
"@sindresorhus/is": "^4.0.0",
|
|
6224
6224
|
"@szmarczak/http-timer": "^4.0.5",
|
|
@@ -15393,9 +15393,9 @@
|
|
|
15393
15393
|
}
|
|
15394
15394
|
},
|
|
15395
15395
|
"node_modules/vm2": {
|
|
15396
|
-
"version": "3.9.
|
|
15397
|
-
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.
|
|
15398
|
-
"integrity": "sha512-
|
|
15396
|
+
"version": "3.9.13",
|
|
15397
|
+
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz",
|
|
15398
|
+
"integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==",
|
|
15399
15399
|
"dependencies": {
|
|
15400
15400
|
"acorn": "^8.7.0",
|
|
15401
15401
|
"acorn-walk": "^8.2.0"
|
|
@@ -15468,9 +15468,9 @@
|
|
|
15468
15468
|
}
|
|
15469
15469
|
},
|
|
15470
15470
|
"node_modules/webdriver/node_modules/@types/node": {
|
|
15471
|
-
"version": "18.11.
|
|
15472
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
15473
|
-
"integrity": "sha512-
|
|
15471
|
+
"version": "18.11.13",
|
|
15472
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
15473
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
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.
|
|
15514
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
15515
|
-
"integrity": "sha512-
|
|
15513
|
+
"version": "18.11.13",
|
|
15514
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
15515
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
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.
|
|
17133
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
17134
|
-
"integrity": "sha512-
|
|
17132
|
+
"version": "18.11.13",
|
|
17133
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
17134
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
17135
17135
|
}
|
|
17136
17136
|
}
|
|
17137
17137
|
},
|
|
@@ -19496,9 +19496,9 @@
|
|
|
19496
19496
|
},
|
|
19497
19497
|
"dependencies": {
|
|
19498
19498
|
"@types/node": {
|
|
19499
|
-
"version": "18.11.
|
|
19500
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
19501
|
-
"integrity": "sha512-
|
|
19499
|
+
"version": "18.11.13",
|
|
19500
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
19501
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
19502
19502
|
},
|
|
19503
19503
|
"ua-parser-js": {
|
|
19504
19504
|
"version": "1.0.32",
|
|
@@ -20937,9 +20937,9 @@
|
|
|
20937
20937
|
}
|
|
20938
20938
|
},
|
|
20939
20939
|
"got": {
|
|
20940
|
-
"version": "11.8.
|
|
20941
|
-
"resolved": "https://registry.npmjs.org/got/-/got-11.8.
|
|
20942
|
-
"integrity": "sha512-
|
|
20940
|
+
"version": "11.8.6",
|
|
20941
|
+
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
|
20942
|
+
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
|
20943
20943
|
"requires": {
|
|
20944
20944
|
"@sindresorhus/is": "^4.0.0",
|
|
20945
20945
|
"@szmarczak/http-timer": "^4.0.5",
|
|
@@ -27933,9 +27933,9 @@
|
|
|
27933
27933
|
}
|
|
27934
27934
|
},
|
|
27935
27935
|
"vm2": {
|
|
27936
|
-
"version": "3.9.
|
|
27937
|
-
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.
|
|
27938
|
-
"integrity": "sha512-
|
|
27936
|
+
"version": "3.9.13",
|
|
27937
|
+
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz",
|
|
27938
|
+
"integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==",
|
|
27939
27939
|
"requires": {
|
|
27940
27940
|
"acorn": "^8.7.0",
|
|
27941
27941
|
"acorn-walk": "^8.2.0"
|
|
@@ -27994,9 +27994,9 @@
|
|
|
27994
27994
|
},
|
|
27995
27995
|
"dependencies": {
|
|
27996
27996
|
"@types/node": {
|
|
27997
|
-
"version": "18.11.
|
|
27998
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
27999
|
-
"integrity": "sha512-
|
|
27997
|
+
"version": "18.11.13",
|
|
27998
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
27999
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
28000
28000
|
}
|
|
28001
28001
|
}
|
|
28002
28002
|
},
|
|
@@ -28035,9 +28035,9 @@
|
|
|
28035
28035
|
},
|
|
28036
28036
|
"dependencies": {
|
|
28037
28037
|
"@types/node": {
|
|
28038
|
-
"version": "18.11.
|
|
28039
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.
|
|
28040
|
-
"integrity": "sha512-
|
|
28038
|
+
"version": "18.11.13",
|
|
28039
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
|
|
28040
|
+
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
|
|
28041
28041
|
},
|
|
28042
28042
|
"brace-expansion": {
|
|
28043
28043
|
"version": "2.0.1",
|
package/package.json
CHANGED
|
@@ -8,6 +8,8 @@ const featureAvailabilityService = require('../commons/featureAvailabilityServic
|
|
|
8
8
|
const { getAbortedTests, getFailedTests, getPassedTests, getFailureEvaluatingCount, getSkippedCount } = require('./reporterUtils');
|
|
9
9
|
|
|
10
10
|
const colorize = { success: chalk.green, warn: chalk.yellow, error: chalk.red };
|
|
11
|
+
const { CLI_MODE } = constants;
|
|
12
|
+
const DEVICE = 'device';
|
|
11
13
|
|
|
12
14
|
class ConsoleReporter {
|
|
13
15
|
constructor(options, branchToUse) {
|
|
@@ -143,13 +145,15 @@ class ConsoleReporter {
|
|
|
143
145
|
|
|
144
146
|
onGetSlot(workerId, browser) {
|
|
145
147
|
const gridNameOrId = this.options.grid || this.options.gridId;
|
|
148
|
+
const instanceType = this.options.mode === CLI_MODE.APPIUM ? DEVICE : browser;
|
|
146
149
|
if (gridNameOrId) {
|
|
147
|
-
console.log(this.toWorkerIdPrefix(workerId), `Get ${chalk.underline(
|
|
150
|
+
console.log(this.toWorkerIdPrefix(workerId), `Get ${chalk.underline(instanceType)} slot from ${chalk.underline(gridNameOrId)}`);
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
onGetSession(workerId, testName, mode) {
|
|
152
|
-
|
|
155
|
+
const instanceType = mode === CLI_MODE.APPIUM ? DEVICE : 'browser';
|
|
156
|
+
console.log(this.toWorkerIdPrefix(workerId), `Get ${instanceType} to run ${chalk.underline(testName)}`);
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
onWaitToTestStart(workerId) {
|
package/runOptions.d.ts
CHANGED
|
@@ -109,9 +109,10 @@ interface RunnerOptions extends Partial<Omit<TunnelOptions, 'tunnelOnlyMode' | '
|
|
|
109
109
|
retries?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20;
|
|
110
110
|
|
|
111
111
|
//# region mobile flags
|
|
112
|
-
deviceModel
|
|
113
|
-
deviceUdid
|
|
114
|
-
osVersion
|
|
112
|
+
deviceModel?: string;
|
|
113
|
+
deviceUdid?: string;
|
|
114
|
+
osVersion?: string;
|
|
115
|
+
appId?: string;
|
|
115
116
|
// #endregion
|
|
116
117
|
|
|
117
118
|
|
package/runOptions.js
CHANGED
|
@@ -220,6 +220,7 @@ program
|
|
|
220
220
|
.option('--device-model [device-model]', 'The device model to use, iPhone 12, Nexus 5X, SM-G900P etc....')
|
|
221
221
|
.option('--device-udid [device-udid]', 'the device unique id')
|
|
222
222
|
.option('--os-version [os-version]', 'The operating system version number')
|
|
223
|
+
.option('--app-id [app-id]', 'The application id from app library on Testim Editor App')
|
|
223
224
|
|
|
224
225
|
.option('-str --suppress-tms-reporting [suppress-tms-reporting]', 'disable test management reporting', false)
|
|
225
226
|
.option('-tsr --tms-suppress-reporting [tms-suppress-reporting]', 'disable test management reporting', false)
|
|
@@ -1037,7 +1038,6 @@ module.exports = {
|
|
|
1037
1038
|
if (program.deviceUdid && (program.deviceModel || program.osVersion)) {
|
|
1038
1039
|
throw new ArgError('It is not possible to use --osVersion or --deviceModel with --device-udid. device-udid is unique and cannot be combined with another flag');
|
|
1039
1040
|
}
|
|
1040
|
-
|
|
1041
1041
|
if (program.lightweightMode) {
|
|
1042
1042
|
try {
|
|
1043
1043
|
const DEFAULTS = {
|
|
@@ -1154,10 +1154,11 @@ module.exports = {
|
|
|
1154
1154
|
retentionDays: program.setRetention,
|
|
1155
1155
|
passZeroTests: Boolean(program.passZeroTests),
|
|
1156
1156
|
runQuarantinedTests: Boolean(program.runQuarantinedTests),
|
|
1157
|
-
|
|
1157
|
+
//Mobile-Flags
|
|
1158
1158
|
deviceModel: program.deviceModel,
|
|
1159
1159
|
deviceUdid: program.deviceUdid,
|
|
1160
1160
|
osVersion: program.osVersion,
|
|
1161
|
+
appId: program.appId,
|
|
1161
1162
|
|
|
1162
1163
|
// Extension
|
|
1163
1164
|
ext: program.ext,
|
package/runner.js
CHANGED
|
@@ -254,7 +254,7 @@ async function runRunner(options, customExtensionLocalLocation) {
|
|
|
254
254
|
options.source = (useLocalChromeDriver || useChromeLauncher) ? 'cli-local' : 'cli';
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
npmDriver.checkNpmVersion();
|
|
257
|
+
await npmDriver.checkNpmVersion();
|
|
258
258
|
perf.log('in runner.js after checkNpmVersion');
|
|
259
259
|
|
|
260
260
|
await validateCliAccount(options);
|
|
@@ -14,11 +14,18 @@ const { StopRunOnError } = require('../errors');
|
|
|
14
14
|
|
|
15
15
|
require('../player/webdriver'); // preload
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @template {unknown[]} T
|
|
19
|
+
* @typedef {T extends [infer H, ...infer R] ? R : T} RemoveFirst
|
|
20
|
+
*/
|
|
21
|
+
|
|
17
22
|
class ParallelWorkerManager {
|
|
23
|
+
/** @param {string=} customExtensionLocalLocation */
|
|
18
24
|
constructor(customExtensionLocalLocation) {
|
|
19
25
|
this.customExtensionLocalLocation = customExtensionLocalLocation;
|
|
20
26
|
}
|
|
21
27
|
|
|
28
|
+
/** @param {typeof CLI_MODE[keyof typeof CLI_MODE]} mode */
|
|
22
29
|
getWorkerType(mode) {
|
|
23
30
|
switch (mode) {
|
|
24
31
|
case CLI_MODE.SELENIUM:
|
|
@@ -33,6 +40,12 @@ class ParallelWorkerManager {
|
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @param {number} count
|
|
45
|
+
* @param {ExecutionQueue} queue
|
|
46
|
+
* @param {typeof CLI_MODE[keyof typeof CLI_MODE]} mode
|
|
47
|
+
* @param {...RemoveFirst<ConstructorParameters<typeof import('../workers/BaseWorker')>>} args
|
|
48
|
+
*/
|
|
36
49
|
createWorkers(count, queue, mode, ...args) {
|
|
37
50
|
const Worker = this.getWorkerType(mode);
|
|
38
51
|
const createWorker = () => {
|
|
@@ -47,6 +60,17 @@ class ParallelWorkerManager {
|
|
|
47
60
|
return Array.from(new Array(count), createWorker);
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* @param {import('./TestPlanRunner').ExecutionList} testList
|
|
65
|
+
* @param {import('../testRunStatus')} testStatus
|
|
66
|
+
* @param {string} executionId
|
|
67
|
+
* @param {string} executionName
|
|
68
|
+
* @param {import('../runOptions').RunnerOptions} options
|
|
69
|
+
* @param {string} branchToUse
|
|
70
|
+
* @param {ReturnType<typeof testimCustomToken['getTokenV3UserData']>} authData
|
|
71
|
+
* @param {number} workerCount
|
|
72
|
+
* @param {boolean} stopOnError
|
|
73
|
+
*/
|
|
50
74
|
async runTests(testList, testStatus, executionId, executionName, options, branchToUse, authData, workerCount, stopOnError) {
|
|
51
75
|
if (testList && testList.length === 0) {
|
|
52
76
|
return undefined;
|
|
@@ -72,6 +96,13 @@ class ParallelWorkerManager {
|
|
|
72
96
|
const lightweightMode = options.lightweightMode;
|
|
73
97
|
const sessionType = utils.getSessionType(options);
|
|
74
98
|
|
|
99
|
+
/**
|
|
100
|
+
* @param {number} wid
|
|
101
|
+
* @param {string} testId
|
|
102
|
+
* @param {string} resultId
|
|
103
|
+
* @param {boolean | undefined} isRerun
|
|
104
|
+
* @param {`${number}:${number}`} testRetryKey
|
|
105
|
+
*/
|
|
75
106
|
const onTestStarted = (wid, testId, resultId, isRerun, testRetryKey) => {
|
|
76
107
|
runningTests++;
|
|
77
108
|
analyticsService.analyticsTestStart({
|
|
@@ -93,6 +124,13 @@ class ParallelWorkerManager {
|
|
|
93
124
|
return testStatus.testStartAndReport(wid, executionId, resultId, isRerun, testRetryKey);
|
|
94
125
|
};
|
|
95
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @param {number} wid
|
|
129
|
+
* @param {string} testId
|
|
130
|
+
* @param {*} testResult
|
|
131
|
+
* @param {string} sessionId
|
|
132
|
+
* @param {boolean | undefined} isRerun
|
|
133
|
+
*/
|
|
96
134
|
const onTestCompleted = async (wid, testId, testResult, sessionId, isRerun) => {
|
|
97
135
|
runningTests--;
|
|
98
136
|
const update = {};
|
|
@@ -135,7 +173,7 @@ class ParallelWorkerManager {
|
|
|
135
173
|
.catch(err => logger.error('testEndAndReport threw an error', { err }));
|
|
136
174
|
|
|
137
175
|
if (isRerun) {
|
|
138
|
-
return
|
|
176
|
+
return;
|
|
139
177
|
}
|
|
140
178
|
combinedTestResults[testResult.resultId] = testResult;
|
|
141
179
|
analyticsService.analyticsTestEnd({
|
|
@@ -163,11 +201,13 @@ class ParallelWorkerManager {
|
|
|
163
201
|
const completedTests = Object.keys(combinedTestResults).length;
|
|
164
202
|
if (completedTests === testCount || (stoppedOnError && runningTests === 0)) {
|
|
165
203
|
resolve(combinedTestResults);
|
|
166
|
-
return undefined;
|
|
167
204
|
}
|
|
168
|
-
return undefined;
|
|
169
205
|
};
|
|
170
206
|
|
|
207
|
+
/**
|
|
208
|
+
* @param {number} wid
|
|
209
|
+
* @param {{ name: string; testId: string; resultId: string; runnerStatus: 'SKIPPED'; testStatus: 'quarantine' }} testResult
|
|
210
|
+
*/
|
|
171
211
|
const onTestIgnored = (wid, testResult) => {
|
|
172
212
|
combinedTestResults[testResult.resultId] = testResult;
|
|
173
213
|
testStatus.onTestIgnored(wid, testResult.resultId);
|
|
@@ -178,7 +218,7 @@ class ParallelWorkerManager {
|
|
|
178
218
|
}
|
|
179
219
|
};
|
|
180
220
|
|
|
181
|
-
const onGridSlot = (
|
|
221
|
+
const onGridSlot = (resultId, gridInfo) => testStatus.onGridSlot(resultId, gridInfo);
|
|
182
222
|
|
|
183
223
|
options.userData = {
|
|
184
224
|
loginData: Object.assign({}, testimCustomToken.getTokenV3UserData(), {
|
|
@@ -191,14 +231,24 @@ class ParallelWorkerManager {
|
|
|
191
231
|
servicesUrl: config.SERVICES_HOST,
|
|
192
232
|
};
|
|
193
233
|
perf.log('in localStrategy before createWorker');
|
|
194
|
-
this.createWorkers(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
234
|
+
this.createWorkers(
|
|
235
|
+
workerCount,
|
|
236
|
+
executionQueue,
|
|
237
|
+
options.mode,
|
|
238
|
+
options,
|
|
239
|
+
this.customExtensionLocalLocation,
|
|
240
|
+
executionId,
|
|
241
|
+
onTestStarted,
|
|
242
|
+
onTestCompleted,
|
|
243
|
+
onGridSlot,
|
|
244
|
+
onTestIgnored,
|
|
245
|
+
).forEach((worker, index) => {
|
|
246
|
+
perf.log('before schedule worker.run after createWorkers');
|
|
247
|
+
schedule(() => {
|
|
248
|
+
perf.log('right before worker.run');
|
|
249
|
+
worker.run();
|
|
250
|
+
}, index);
|
|
251
|
+
});
|
|
202
252
|
});
|
|
203
253
|
|
|
204
254
|
try {
|
|
@@ -215,6 +265,10 @@ class ParallelWorkerManager {
|
|
|
215
265
|
}
|
|
216
266
|
}
|
|
217
267
|
|
|
268
|
+
/**
|
|
269
|
+
* @param {Function} fn
|
|
270
|
+
* @param {number} index
|
|
271
|
+
*/
|
|
218
272
|
function schedule(fn, index) {
|
|
219
273
|
if (index === 0) {
|
|
220
274
|
fn();
|
|
@@ -26,9 +26,7 @@ const TDK_CHILD_RESULTS_TIMEOUT = 1000 * 60 * 5;
|
|
|
26
26
|
/** @typedef {Awaited<ReturnType<typeof getSuite>>['tests'][number]} ExecutionList */
|
|
27
27
|
|
|
28
28
|
class TestPlanRunner {
|
|
29
|
-
/**
|
|
30
|
-
* @param {string=} customExtensionLocalLocation
|
|
31
|
-
*/
|
|
29
|
+
/** @param {string=} customExtensionLocalLocation */
|
|
32
30
|
constructor(customExtensionLocalLocation) {
|
|
33
31
|
this.workerManager = new ParallelWorkerManager(customExtensionLocalLocation);
|
|
34
32
|
this.startTime = Date.now();
|
|
@@ -115,7 +113,7 @@ class TestPlanRunner {
|
|
|
115
113
|
}
|
|
116
114
|
const { runKey: apiKey, url: serverUrl } = applitoolsIntegrationData;
|
|
117
115
|
const tmpSDK = require('@applitools/eyes-sdk-core').makeSDK({ name: 'Testim.io', version: '4.0.0', spec: {} });
|
|
118
|
-
await tmpSDK.
|
|
116
|
+
await tmpSDK.closeBatches({ settings: { batchIds: [executionId], serverUrl, apiKey } });
|
|
119
117
|
} catch (err) {
|
|
120
118
|
// If a batch with this name did not exist, do not log an error.
|
|
121
119
|
if (err.message && (err.message.startsWith('Request failed with status code 404') || err.message.startsWith('no batchIds were set'))) {
|