@testim/testim-cli 3.261.0 → 3.263.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/cli.js +11 -5
- package/commons/featureFlags.js +1 -0
- package/commons/testimServicesApi.js +10 -7
- package/executionQueue.js +9 -1
- package/npm-shrinkwrap.json +52 -52
- package/package.json +1 -1
- package/player/stepActions/RefreshStepAction.js +7 -4
- package/player/stepActions/baseJsStepAction.js +45 -46
- package/player/stepActions/dropFileStepAction.js +11 -12
- package/player/stepActions/evaluateExpressionStepAction.js +32 -33
- package/player/stepActions/extensionOnlyStepAction.js +3 -4
- package/player/stepActions/extractTextStepAction.js +8 -10
- package/player/stepActions/hoverStepAction.js +3 -3
- package/player/stepActions/locateStepAction.js +39 -34
- package/player/stepActions/mouseStepAction.js +36 -34
- package/player/stepActions/navigationStepAction.js +7 -8
- package/player/stepActions/scrollStepAction.js +22 -22
- package/player/stepActions/stepAction.js +21 -21
- package/player/stepActions/stepActionRegistrar.js +63 -58
- package/player/stepActions/submitStepAction.js +2 -3
- package/player/stepActions/textStepAction.js +14 -14
- package/player/stepActions/textValidationStepAction.js +50 -38
- package/player/stepActions/wheelStepAction.js +5 -11
- package/polyfills/Array.prototype.at.js +13 -0
- package/polyfills/index.js +1 -0
- package/processHandler.js +2 -0
- package/reports/junitReporter.js +18 -1
- package/runOptions.d.ts +4 -0
- package/runOptions.js +8 -1
- package/runner.js +7 -0
- package/runners/TestPlanRunner.js +20 -19
- package/runners/runnerUtils.js +1 -2
- package/testRunHandler.js +18 -9
- package/testRunStatus.js +209 -157
- package/utils/index.js +9 -2
- package/workers/BaseWorker.js +11 -0
- package/workers/WorkerExtension.js +117 -91
- package/workers/WorkerSelenium.js +8 -3
- package/player/stepActions/scripts/polyfills.js +0 -393
package/testRunStatus.js
CHANGED
|
@@ -1,41 +1,50 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { TESTIM_CONCURRENT_WORKER_COUNT } = require('./commons/config');
|
|
3
|
+
const _ = require('lodash');
|
|
5
4
|
const utils = require('./utils');
|
|
6
|
-
const reporter = require('./reports/reporter
|
|
7
|
-
const
|
|
5
|
+
const reporter = require('./reports/reporter');
|
|
6
|
+
const constants = require('./commons/constants');
|
|
8
7
|
const gridService = require('./services/gridService');
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
const featureFlags = require('./commons/featureFlags');
|
|
9
|
+
const servicesApi = require('./commons/testimServicesApi');
|
|
11
10
|
const OverrideTestDataBuilder = require('./OverrideTestDataBuilder');
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
11
|
+
const featureAvailabilityService = require('./commons/featureAvailabilityService');
|
|
12
|
+
const { ArgError } = require('./errors');
|
|
13
|
+
const { getLogger } = require('./commons/logger');
|
|
15
14
|
const { registerExitHook } = require('./processHandler');
|
|
16
15
|
const { calculateCoverage } = require('./coverage/jsCoverage');
|
|
17
|
-
const
|
|
18
|
-
const featureFlags = require('./commons/featureFlags');
|
|
16
|
+
const { SeleniumPerfStats } = require('./commons/SeleniumPerfStats');
|
|
19
17
|
const { mapFilesToLocalDrive } = require('./services/localRCASaver');
|
|
20
|
-
const {
|
|
18
|
+
const { TESTIM_CONCURRENT_WORKER_COUNT } = require('./commons/config');
|
|
21
19
|
|
|
20
|
+
const logger = getLogger('test-run-status');
|
|
22
21
|
const gitBranch = utils.getEnvironmentGitBranch();
|
|
23
22
|
const gitCommit = process.env.GIT_COMMIT || process.env.CIRCLE_SHA1 || process.env.TRAVIS_COMMIT;
|
|
24
23
|
const gitRepoUrl = process.env.GIT_URL || process.env.CIRCLE_REPOSITORY_URL;
|
|
25
24
|
const runnerVersion = utils.getRunnerVersion();
|
|
26
25
|
|
|
27
26
|
|
|
28
|
-
function runHook(fn, ...args) {
|
|
27
|
+
async function runHook(fn, ...args) {
|
|
29
28
|
if (!fn || typeof fn !== 'function') {
|
|
30
|
-
return
|
|
29
|
+
return undefined;
|
|
31
30
|
}
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const res = await fn(...args);
|
|
34
|
+
return res || {};
|
|
35
|
+
} catch (err) {
|
|
33
36
|
logger.warn('failed to run hook', { err });
|
|
34
37
|
throw new ArgError(`failed to run hook promise ${err.message}`);
|
|
35
|
-
}
|
|
38
|
+
}
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
class RunStatus {
|
|
42
|
+
/**
|
|
43
|
+
* @param {any[]} testInfoList
|
|
44
|
+
* @param {import('./runOptions').RunnerOptions} options
|
|
45
|
+
* @param {string} testPlanId
|
|
46
|
+
* @param {string} branchToUse
|
|
47
|
+
*/
|
|
39
48
|
constructor(testInfoList, options, testPlanId, branchToUse) {
|
|
40
49
|
this.options = options;
|
|
41
50
|
this.options.runParams = this.options.runParams || {};
|
|
@@ -65,7 +74,7 @@ class RunStatus {
|
|
|
65
74
|
testPlanId,
|
|
66
75
|
testPlans: options.testPlan,
|
|
67
76
|
testLabels: options.label,
|
|
68
|
-
testSuites:
|
|
77
|
+
testSuites: [...new Set(testInfoList.flatMap(test => test.testSuites))],
|
|
69
78
|
testNames: options.name,
|
|
70
79
|
testIds: options.testId,
|
|
71
80
|
testConfigs: options.testConfigNames,
|
|
@@ -104,7 +113,18 @@ class RunStatus {
|
|
|
104
113
|
}) {
|
|
105
114
|
const orgTestResult = this.testRunStatus[originalTestResultId] || {};
|
|
106
115
|
const {
|
|
107
|
-
config,
|
|
116
|
+
config,
|
|
117
|
+
isTestsContainer,
|
|
118
|
+
testId,
|
|
119
|
+
name,
|
|
120
|
+
testStatus,
|
|
121
|
+
testCreatorName,
|
|
122
|
+
testCreatorEmail,
|
|
123
|
+
testOwnerName,
|
|
124
|
+
testOwnerEmail,
|
|
125
|
+
testLabels,
|
|
126
|
+
testSuites,
|
|
127
|
+
allLabels,
|
|
108
128
|
} = orgTestResult;
|
|
109
129
|
|
|
110
130
|
const newTestResult = {
|
|
@@ -120,7 +140,15 @@ class RunStatus {
|
|
|
120
140
|
testStatus,
|
|
121
141
|
};
|
|
122
142
|
|
|
123
|
-
this.testRunStatus[newResultId] = newTestResult
|
|
143
|
+
this.testRunStatus[newResultId] = Object.assign({}, newTestResult, {
|
|
144
|
+
testCreatorName,
|
|
145
|
+
testCreatorEmail,
|
|
146
|
+
testOwnerName,
|
|
147
|
+
testOwnerEmail,
|
|
148
|
+
testLabels,
|
|
149
|
+
testSuites,
|
|
150
|
+
allLabels,
|
|
151
|
+
});
|
|
124
152
|
|
|
125
153
|
return servicesApi.addTestRetry({
|
|
126
154
|
projectId,
|
|
@@ -146,55 +174,58 @@ class RunStatus {
|
|
|
146
174
|
return test;
|
|
147
175
|
}
|
|
148
176
|
|
|
149
|
-
updateTestStatusRunning(test, executionId, testRetryKey) {
|
|
177
|
+
async updateTestStatusRunning(test, executionId, testRetryKey) {
|
|
150
178
|
const { project: projectId, remoteRunId, projectData } = this.options;
|
|
151
179
|
if (this.options.lightweightMode?.onlyTestIdsNoSuite) {
|
|
152
180
|
return this.executionStartedPromise;
|
|
153
181
|
}
|
|
154
182
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
183
|
+
let testDataUrl = '';
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
testDataUrl = await servicesApi.updateTestDataArtifact(projectId, test.testId, test.resultId, test.config.testData, projectData.defaults);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
logger.error('failed to upload test data artifact (runner)', { err });
|
|
189
|
+
}
|
|
190
|
+
const testConfig = _.cloneDeep(test.config);
|
|
191
|
+
delete testConfig.testData;
|
|
192
|
+
testConfig.testDataUrl = testDataUrl;
|
|
193
|
+
await this.executionStartedPromise;
|
|
194
|
+
return servicesApi.updateTestStatus(projectId, executionId, test.testId, test.resultId, 'RUNNING', { startTime: test.startTime, config: testConfig, remoteRunId, testRetryKey });
|
|
167
195
|
}
|
|
168
196
|
|
|
169
|
-
testStartReport(test, executionId, testRetryKey) {
|
|
197
|
+
async testStartReport(test, executionId, testRetryKey) {
|
|
170
198
|
if (utils.isQuarantineAndNotRemoteRun(test, this.options)) {
|
|
171
|
-
return
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
const globalParameters = this.exportsGlobal;
|
|
202
|
+
try {
|
|
203
|
+
const params = await runHook(this.options.beforeTest, Object.assign({}, test, { exportsGlobal: globalParameters, globalParameters }), this.options.userData.loginData.token);
|
|
204
|
+
|
|
205
|
+
// Temporary Sapiens log (SUP-3192)
|
|
206
|
+
if (this.options.projectData && this.options.projectData.projectId === 'fZ63D61PRQQVvvtGY6Ue' && this.options.suites && this.options.suites.includes('Sanity')) {
|
|
207
|
+
logger.info('testRunStatus - testStartReport', {
|
|
208
|
+
'test.config.testData': test.config.testData,
|
|
209
|
+
'this.exportsGlobal': this.exportsGlobal,
|
|
210
|
+
'this.fileUserParamsData': this.fileUserParamsData,
|
|
211
|
+
'this.beforeSuiteParams': this.beforeSuiteParams,
|
|
212
|
+
params,
|
|
213
|
+
executionId,
|
|
214
|
+
'test.testId': test.testId,
|
|
215
|
+
'test.resultId': test.resultId,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
test.config.testData = Object.assign({}, test.config.testData, this.exportsGlobal, this.fileUserParamsData, this.beforeSuiteParams, params);
|
|
220
|
+
this.options.runParams[test.resultId] = test.config.testData;
|
|
221
|
+
test.startTime = Date.now();
|
|
222
|
+
await this.updateTestStatusRunning(test, executionId, testRetryKey);
|
|
223
|
+
|
|
224
|
+
return test;
|
|
225
|
+
} catch (err) {
|
|
226
|
+
logger.error('Failed to start test', { err });
|
|
227
|
+
throw err;
|
|
172
228
|
}
|
|
173
|
-
return runHook(this.options.beforeTest, Object.assign({}, test, { exportsGlobal: this.exportsGlobal }), this.options.userData.loginData.token)
|
|
174
|
-
.then(async (params) => {
|
|
175
|
-
// Temporary Sapiens log (SUP-3192)
|
|
176
|
-
if (this.options.projectData && this.options.projectData.projectId === 'fZ63D61PRQQVvvtGY6Ue' && this.options.suites && this.options.suites.includes('Sanity')) {
|
|
177
|
-
logger.info('testRunStatus - testStartReport', {
|
|
178
|
-
'test.config.testData': test.config.testData,
|
|
179
|
-
'this.exportsGlobal': this.exportsGlobal,
|
|
180
|
-
'this.fileUserParamsData': this.fileUserParamsData,
|
|
181
|
-
'this.beforeSuiteParams': this.beforeSuiteParams,
|
|
182
|
-
params,
|
|
183
|
-
executionId,
|
|
184
|
-
'test.testId': test.testId,
|
|
185
|
-
'test.resultId': test.resultId,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
test.config.testData = Object.assign({}, test.config.testData, this.exportsGlobal, this.fileUserParamsData, this.beforeSuiteParams, params);
|
|
189
|
-
this.options.runParams[test.resultId] = test.config.testData;
|
|
190
|
-
test.startTime = Date.now();
|
|
191
|
-
await this.updateTestStatusRunning(test, executionId, testRetryKey);
|
|
192
|
-
|
|
193
|
-
return test;
|
|
194
|
-
}).catch(err => {
|
|
195
|
-
logger.error('Failed to start test', { err });
|
|
196
|
-
throw err;
|
|
197
|
-
});
|
|
198
229
|
}
|
|
199
230
|
|
|
200
231
|
testStartAndReport(wid, executionId, resultId, isRerun, testRetryKey) {
|
|
@@ -219,16 +250,14 @@ class RunStatus {
|
|
|
219
250
|
reporter.onTestPassed(name);
|
|
220
251
|
return;
|
|
221
252
|
}
|
|
222
|
-
reporter.onTestFailed(
|
|
253
|
+
reporter.onTestFailed(
|
|
254
|
+
test,
|
|
223
255
|
test.failureReason,
|
|
224
|
-
utils.getTestUrl(this.options.editorUrl,
|
|
225
|
-
this.options.project,
|
|
226
|
-
testId,
|
|
227
|
-
resultId,
|
|
228
|
-
this.branchToUse),
|
|
256
|
+
utils.getTestUrl(this.options.editorUrl, this.options.project, testId, resultId, this.branchToUse),
|
|
229
257
|
testId,
|
|
230
258
|
isRerun,
|
|
231
|
-
resultId
|
|
259
|
+
resultId,
|
|
260
|
+
);
|
|
232
261
|
}
|
|
233
262
|
|
|
234
263
|
calcResultText(result) {
|
|
@@ -298,7 +327,7 @@ class RunStatus {
|
|
|
298
327
|
const globalParameters = result.exportsGlobal;
|
|
299
328
|
try {
|
|
300
329
|
try {
|
|
301
|
-
await runHook(this.options.afterTest, Object.assign({}, test, { globalParameters }), this.options.userData.loginData.token);
|
|
330
|
+
await runHook(this.options.afterTest, Object.assign({}, test, { exportsGlobal: globalParameters, globalParameters }), this.options.userData.loginData.token);
|
|
302
331
|
} catch (err) {
|
|
303
332
|
logger.error('HOOK threw an error', { test: test.testId, err });
|
|
304
333
|
// eslint-disable-next-line no-console
|
|
@@ -349,6 +378,10 @@ class RunStatus {
|
|
|
349
378
|
|
|
350
379
|
const runConfig = options.browser ? utils.getRunConfigByBrowserName(options.browser, options.saucelabs, options.browserstack) : testInfo.runConfig;
|
|
351
380
|
|
|
381
|
+
if (runConfig && featureFlags.flags.dec2022eolBrowsers.isEnabled() && utils.getBrowserInfo(runConfig.browserValue)?.eol) {
|
|
382
|
+
throw new ArgError(`Unsupported Browser: ${runConfig.browserName}`);
|
|
383
|
+
}
|
|
384
|
+
|
|
352
385
|
resultStatus[testInfo.resultId].config = Object.assign({}, this.execConfig, {
|
|
353
386
|
companyId,
|
|
354
387
|
testData: testInfo.testData?.value ? testInfo.testData.value : null,
|
|
@@ -364,7 +397,7 @@ class RunStatus {
|
|
|
364
397
|
}, {});
|
|
365
398
|
}
|
|
366
399
|
|
|
367
|
-
executionStart(executionId, projectId, startTime, testPlanName, testNames) {
|
|
400
|
+
async executionStart(executionId, projectId, startTime, testPlanName, testNames) {
|
|
368
401
|
logger.info('execution started', { executionId });
|
|
369
402
|
const { options } = this;
|
|
370
403
|
const { remoteRunId, projectData } = options;
|
|
@@ -383,66 +416,74 @@ class RunStatus {
|
|
|
383
416
|
]));
|
|
384
417
|
|
|
385
418
|
this.startTime = startTime || Date.now();
|
|
386
|
-
const runHooksProps = {
|
|
387
|
-
|
|
388
|
-
|
|
419
|
+
const runHooksProps = {
|
|
420
|
+
projectId,
|
|
421
|
+
executionId,
|
|
422
|
+
...(featureFlags.flags.testNamesToBeforeSuiteHook.isEnabled() && { testNames }),
|
|
423
|
+
};
|
|
424
|
+
const params = await runHook(options.beforeSuite, runHooksProps);
|
|
425
|
+
const overrideTestDataBuilder = new OverrideTestDataBuilder(params, _.cloneDeep(this.testInfoList), projectId);
|
|
426
|
+
this.testInfoList = overrideTestDataBuilder.overrideTestData();
|
|
427
|
+
this.calcTestRunStatus();
|
|
428
|
+
this.beforeSuiteParams = params;
|
|
429
|
+
|
|
430
|
+
const { testInfoList } = this;
|
|
431
|
+
const beforeTests = [];
|
|
432
|
+
const tests = [];
|
|
433
|
+
const afterTests = [];
|
|
434
|
+
for (const test of testInfoList) {
|
|
435
|
+
if (test.isBeforeTestPlan) {
|
|
436
|
+
beforeTests.push(test);
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (test.isAfterTestPlan) {
|
|
440
|
+
afterTests.push(test);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
tests.push(test);
|
|
389
444
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const testResults = _.cloneDeep(this.testRunStatus);
|
|
404
|
-
return promiseMap(Object.keys(testResults), testResultId => {
|
|
405
|
-
const test = testResults[testResultId];
|
|
406
|
-
const testData = test.config?.testData;
|
|
407
|
-
const testId = test.testId;
|
|
408
|
-
return servicesApi.updateTestDataArtifact(projectId, testId, testResultId, testData, projectData.defaults)
|
|
409
|
-
.then((testDataUrl) => {
|
|
410
|
-
if (!testDataUrl) {
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
delete test.config.testData;
|
|
414
|
-
test.config.testDataUrl = testDataUrl;
|
|
415
|
-
});
|
|
416
|
-
}).then(() => {
|
|
417
|
-
const isLocalRun = Boolean(options.useLocalChromeDriver || options.useChromeLauncher);
|
|
418
|
-
const data = {
|
|
419
|
-
executionId,
|
|
420
|
-
projectId,
|
|
421
|
-
labels: testPlanName || [],
|
|
422
|
-
startTime,
|
|
423
|
-
executions: testResults,
|
|
424
|
-
config: this.execConfig,
|
|
425
|
-
resultLabels: options.resultLabels,
|
|
426
|
-
remoteRunId: options.remoteRunId,
|
|
427
|
-
localRunUserId: options.user,
|
|
428
|
-
isLocalRun,
|
|
429
|
-
intersections: options.intersections,
|
|
430
|
-
};
|
|
431
|
-
const ret = servicesApi.reportExecutionStarted(data);
|
|
432
|
-
this.executionStartedPromise = ret;
|
|
433
|
-
ret.catch(e => logger.error(e));
|
|
434
|
-
return ret;
|
|
435
|
-
});
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
return reportExecutionStarted()
|
|
439
|
-
.catch(err => {
|
|
440
|
-
logger.error('Failed to start suite', { err });
|
|
441
|
-
// eslint-disable-next-line no-console
|
|
442
|
-
console.error('Failed to start test run. Please contact support@testim.io');
|
|
443
|
-
})
|
|
444
|
-
.then(() => ({ beforeTests, tests, afterTests }));
|
|
445
|
+
|
|
446
|
+
const reportExecutionStarted = async () => {
|
|
447
|
+
const testResults = _.cloneDeep(this.testRunStatus);
|
|
448
|
+
await utils.promiseMap(Object.keys(testResults), async testResultId => {
|
|
449
|
+
const test = testResults[testResultId];
|
|
450
|
+
const testData = test.config?.testData;
|
|
451
|
+
const testId = test.testId;
|
|
452
|
+
const testDataUrl = await servicesApi.updateTestDataArtifact(projectId, testId, testResultId, testData, projectData.defaults);
|
|
453
|
+
if (!testDataUrl) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
delete test.config.testData;
|
|
457
|
+
test.config.testDataUrl = testDataUrl;
|
|
445
458
|
});
|
|
459
|
+
const isLocalRun = Boolean(options.useLocalChromeDriver || options.useChromeLauncher);
|
|
460
|
+
const data = {
|
|
461
|
+
executionId,
|
|
462
|
+
projectId,
|
|
463
|
+
labels: testPlanName || [],
|
|
464
|
+
startTime,
|
|
465
|
+
executions: testResults,
|
|
466
|
+
config: this.execConfig,
|
|
467
|
+
resultLabels: options.resultLabels,
|
|
468
|
+
remoteRunId: options.remoteRunId,
|
|
469
|
+
localRunUserId: options.user,
|
|
470
|
+
isLocalRun,
|
|
471
|
+
intersections: options.intersections,
|
|
472
|
+
};
|
|
473
|
+
const ret = servicesApi.reportExecutionStarted(data);
|
|
474
|
+
this.executionStartedPromise = ret;
|
|
475
|
+
ret.catch(e => logger.error(e));
|
|
476
|
+
return ret;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
try {
|
|
480
|
+
await reportExecutionStarted();
|
|
481
|
+
} catch (err) {
|
|
482
|
+
logger.error('Failed to start suite', { err });
|
|
483
|
+
// eslint-disable-next-line no-console
|
|
484
|
+
console.error('Failed to start test run. Please contact support@testim.io');
|
|
485
|
+
}
|
|
486
|
+
return { beforeTests, tests, afterTests };
|
|
446
487
|
}
|
|
447
488
|
|
|
448
489
|
concatSeleniumPerfMarks(marks) {
|
|
@@ -456,47 +497,58 @@ class RunStatus {
|
|
|
456
497
|
.value();
|
|
457
498
|
}
|
|
458
499
|
|
|
459
|
-
executionEnd(executionId) {
|
|
500
|
+
async executionEnd(executionId) {
|
|
460
501
|
const tests = utils.groupTestsByRetries(this.testRunStatus);
|
|
461
502
|
const total = tests.length;
|
|
462
|
-
const passed = tests.filter(({ status }) => status === constants.runnerTestStatus.PASSED).length;
|
|
463
|
-
const skipped = tests.filter(({ status }) => status === constants.runnerTestStatus.SKIPPED).length;
|
|
464
|
-
const failedInEvaluatingStatus = tests.filter(({ status, testStatus }) => status === constants.runnerTestStatus.FAILED && testStatus === constants.testStatus.EVALUATING).length;
|
|
465
503
|
|
|
466
|
-
|
|
467
|
-
|
|
504
|
+
let passed = 0;
|
|
505
|
+
let skipped = 0;
|
|
506
|
+
let failedInEvaluatingStatus = 0;
|
|
507
|
+
for (const { status, testStatus } of tests) {
|
|
508
|
+
if (status === constants.runnerTestStatus.PASSED) {
|
|
509
|
+
passed++;
|
|
510
|
+
}
|
|
511
|
+
if (status === constants.runnerTestStatus.SKIPPED) {
|
|
512
|
+
skipped++;
|
|
513
|
+
}
|
|
514
|
+
if (status === constants.runnerTestStatus.FAILED && testStatus === constants.testStatus.EVALUATING) {
|
|
515
|
+
failedInEvaluatingStatus++;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const { seleniumPerfMarks, ...resultExtraData } = this.seleniumPerfStats.getStats();
|
|
468
520
|
|
|
469
|
-
|
|
521
|
+
await runHook(this.options.afterSuite, {
|
|
470
522
|
exportsGlobal: this.exportsGlobal,
|
|
471
523
|
tests,
|
|
472
524
|
total,
|
|
473
525
|
passed,
|
|
474
526
|
skipped,
|
|
475
|
-
})
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
resultExtraData.coverageSummary = coverageSummary;
|
|
527
|
+
});
|
|
528
|
+
const coverageSummary = await calculateCoverage(this.options, this.branchToUse, total, executionId);
|
|
529
|
+
resultExtraData.coverageSummary = coverageSummary;
|
|
479
530
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
531
|
+
if (this.options.lightweightMode?.onlyTestIdsNoSuite) {
|
|
532
|
+
return undefined;
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
return await servicesApi.reportExecutionFinished(
|
|
536
|
+
'FINISHED',
|
|
537
|
+
executionId,
|
|
538
|
+
this.options.project,
|
|
539
|
+
total === (passed + skipped + failedInEvaluatingStatus),
|
|
540
|
+
{
|
|
541
|
+
tmsSuppressReporting: this.options.tmsSuppressReporting,
|
|
542
|
+
tmsRunId: this.options.tmsRunId,
|
|
543
|
+
tmsCustomFields: this.options.tmsCustomFields,
|
|
544
|
+
},
|
|
545
|
+
this.options.remoteRunId,
|
|
546
|
+
resultExtraData
|
|
547
|
+
);
|
|
548
|
+
} catch (err) {
|
|
549
|
+
logger.error('Failed to update suite finished', { err });
|
|
550
|
+
throw err;
|
|
551
|
+
}
|
|
500
552
|
}
|
|
501
553
|
|
|
502
554
|
async markAllQueuedTests(executionId, status, failureReason, success) {
|
package/utils/index.js
CHANGED
|
@@ -43,16 +43,22 @@ const BROWSERS = [
|
|
|
43
43
|
{ browserName: 'Chrome', bs: { browser: 'Chrome', browser_version: '94' }, sl: { browserName: 'chrome', version: '94.0' }, browserValue: 'chrome' },
|
|
44
44
|
{ browserName: 'Firefox', bs: { browser: 'Firefox', browser_version: '89' }, sl: { browserName: 'firefox', version: '89.0' }, browserValue: 'firefox' },
|
|
45
45
|
{ browserName: 'Safari', bs: { browser: 'Safari' }, sl: { browserName: 'safari' }, browserValue: 'safari' },
|
|
46
|
-
{ browserName: 'Edge', bs: { browser: 'Edge', browser_version: '18' }, sl: { browserName: 'MicrosoftEdge', version: '18.17763' }, browserValue: 'edge' },
|
|
46
|
+
{ browserName: 'Edge', bs: { browser: 'Edge', browser_version: '18' }, sl: { browserName: 'MicrosoftEdge', version: '18.17763' }, browserValue: 'edge', eol: true },
|
|
47
47
|
// eslint-disable-next-line max-len
|
|
48
48
|
{ browserName: 'Edge Chromium', bs: { browser: 'Edge', browser_version: '94' }, sl: { browserName: 'MicrosoftEdge', version: '94' }, synonyms: ['edge-chromium'], browserValue: 'edge-chromium', seleniumName: 'MicrosoftEdge' },
|
|
49
|
-
|
|
49
|
+
// eslint-disable-next-line max-len
|
|
50
|
+
{ browserName: 'Internet Explorer 11', bs: { browser: 'IE', browser_version: '11' }, sl: { browserName: 'internet explorer', version: '11.0' }, synonyms: ['ie11'], browserValue: 'ie11', eol: true },
|
|
50
51
|
{ browserName: 'Browser', bs: {}, sl: { browserName: 'Browser' }, browserValue: 'browser' },
|
|
51
52
|
{ browserName: 'Android', bs: { browserName: 'android' }, sl: {}, browserValue: 'android' },
|
|
52
53
|
{ browserName: 'iPad', bs: { browserName: 'iPad' }, sl: {}, browserValue: 'ipad' },
|
|
53
54
|
{ browserName: 'iPhone', bs: { browserName: 'iPhone' }, sl: {}, browserValue: 'iphone' },
|
|
54
55
|
];
|
|
55
56
|
|
|
57
|
+
function getBrowserInfo(browserValue) {
|
|
58
|
+
browserValue = browserValue.toLowerCase();
|
|
59
|
+
return BROWSERS.find((b) => b.browserValue === browserValue);
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
function getRunConfigByBrowserName(browser, saucelabs, browserstack) {
|
|
57
63
|
browser = browser.toLowerCase();
|
|
58
64
|
const selectedBrowser = BROWSERS.find(b => b.browserName.toLowerCase() === browser || browser.includes(b.synonyms)) || BROWSERS[0];
|
|
@@ -182,6 +188,7 @@ module.exports = {
|
|
|
182
188
|
groupTestsByRetries,
|
|
183
189
|
getPlanType,
|
|
184
190
|
getCdpAddressForHost,
|
|
191
|
+
getBrowserInfo,
|
|
185
192
|
...fsUtils,
|
|
186
193
|
...argsUtils,
|
|
187
194
|
...timeUtils,
|
package/workers/BaseWorker.js
CHANGED
|
@@ -38,6 +38,17 @@ function buildFailureResult(testId, testName, resultId, reason) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
class BaseWorker {
|
|
41
|
+
/**
|
|
42
|
+
* @param {import('../executionQueue')} executionQueue
|
|
43
|
+
* @param {import('../runOptions').RunnerOptions} options
|
|
44
|
+
* @param {string=} customExtensionLocalLocation
|
|
45
|
+
* @param {string} executionId
|
|
46
|
+
* @param {Function} onTestStarted
|
|
47
|
+
* @param {Function} onTestCompleted
|
|
48
|
+
* @param {Function} onGridSlot
|
|
49
|
+
* @param {Function} onTestIgnored
|
|
50
|
+
* @param {boolean=} releaseSlotOnTestFinished
|
|
51
|
+
*/
|
|
41
52
|
constructor(executionQueue, options, customExtensionLocalLocation, executionId, onTestStarted, onTestCompleted, onGridSlot, onTestIgnored, releaseSlotOnTestFinished = true) {
|
|
42
53
|
this.lambdatestService = new LambdatestService();
|
|
43
54
|
|