qase-javascript-commons 2.2.19 → 2.3.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/changelog.md +21 -15
- package/dist/client/clientV1.d.ts +31 -0
- package/dist/client/clientV1.js +177 -0
- package/dist/client/clientV2.d.ts +26 -0
- package/dist/client/clientV2.js +197 -0
- package/dist/client/dateUtils.d.ts +2 -0
- package/dist/client/dateUtils.js +21 -0
- package/dist/client/interface.d.ts +6 -0
- package/dist/client/interface.js +2 -0
- package/dist/config/config-validation-schema.js +0 -22
- package/dist/env/env-enum.d.ts +1 -2
- package/dist/env/env-enum.js +0 -1
- package/dist/env/env-to-config.js +0 -1
- package/dist/env/env-type.d.ts +2 -3
- package/dist/env/env-validation-schema.js +0 -4
- package/dist/formatter/json-formatter.d.ts +2 -2
- package/dist/formatter/jsonp-formatter.d.ts +2 -2
- package/dist/models/attachment.d.ts +2 -2
- package/dist/models/config/TestOpsOptionsType.d.ts +25 -0
- package/dist/models/config/TestOpsOptionsType.js +2 -0
- package/dist/models/execution-sum.d.ts +2 -2
- package/dist/models/host-data.d.ts +2 -1
- package/dist/models/report.d.ts +3 -3
- package/dist/models/short-result.d.ts +2 -2
- package/dist/models/stats.d.ts +2 -2
- package/dist/models/test-result.d.ts +6 -6
- package/dist/options/options-type.d.ts +2 -6
- package/dist/qase.d.ts +1 -0
- package/dist/qase.js +16 -53
- package/dist/reporters/index.d.ts +1 -1
- package/dist/reporters/testops-reporter.d.ts +8 -161
- package/dist/reporters/testops-reporter.js +24 -537
- package/dist/state/state.js +1 -0
- package/dist/steps/step.d.ts +1 -1
- package/dist/steps/step.js +2 -2
- package/dist/utils/hostData.js +4 -2
- package/dist/utils/logger.js +17 -23
- package/dist/writer/fs-writer.d.ts +3 -3
- package/package.json +3 -2
- package/dist/utils/custom-boundary.d.ts +0 -26
- package/dist/utils/custom-boundary.js +0 -30
|
@@ -4,13 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TestOpsReporter = void 0;
|
|
7
|
-
const fs_1 = require("fs");
|
|
8
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const qaseio_1 = require("qaseio");
|
|
10
8
|
const abstract_reporter_1 = require("./abstract-reporter");
|
|
11
9
|
const models_1 = require("../models");
|
|
12
|
-
const qase_error_1 = require("../utils/qase-error");
|
|
13
|
-
const axios_1 = require("axios");
|
|
14
10
|
const state_1 = require("../state/state");
|
|
15
11
|
const async_mutex_1 = require("async-mutex");
|
|
16
12
|
const defaultChunkSize = 200;
|
|
@@ -21,120 +17,29 @@ const defaultChunkSize = 200;
|
|
|
21
17
|
class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
22
18
|
api;
|
|
23
19
|
withState;
|
|
24
|
-
/**
|
|
25
|
-
* @type {Record<TestStatusEnum, string>}
|
|
26
|
-
*/
|
|
27
|
-
static statusMap = {
|
|
28
|
-
[models_1.TestStatusEnum.passed]: 'passed',
|
|
29
|
-
[models_1.TestStatusEnum.failed]: 'failed',
|
|
30
|
-
[models_1.TestStatusEnum.skipped]: 'skipped',
|
|
31
|
-
[models_1.TestStatusEnum.disabled]: 'disabled',
|
|
32
|
-
[models_1.TestStatusEnum.blocked]: 'blocked',
|
|
33
|
-
[models_1.TestStatusEnum.invalid]: 'invalid',
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* @type {Record<StepStatusEnum, ResultStepStatus>}
|
|
37
|
-
*/
|
|
38
|
-
static stepStatusMap = {
|
|
39
|
-
[models_1.StepStatusEnum.passed]: qaseio_1.ResultStepStatus.PASSED,
|
|
40
|
-
[models_1.StepStatusEnum.failed]: qaseio_1.ResultStepStatus.FAILED,
|
|
41
|
-
[models_1.StepStatusEnum.blocked]: qaseio_1.ResultStepStatus.BLOCKED,
|
|
42
|
-
[models_1.StepStatusEnum.skipped]: qaseio_1.ResultStepStatus.SKIPPED,
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* @type {Record<StepStatusEnum, ResultStepStatus>}
|
|
46
|
-
*/
|
|
47
|
-
static stepStatusMapV1 = {
|
|
48
|
-
[models_1.StepStatusEnum.passed]: qaseio_1.TestStepResultCreateStatusEnum.PASSED,
|
|
49
|
-
[models_1.StepStatusEnum.failed]: qaseio_1.TestStepResultCreateStatusEnum.FAILED,
|
|
50
|
-
[models_1.StepStatusEnum.blocked]: qaseio_1.TestStepResultCreateStatusEnum.BLOCKED,
|
|
51
|
-
[models_1.StepStatusEnum.skipped]: qaseio_1.TestStepResultCreateStatusEnum.BLOCKED,
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* @type {string}
|
|
55
|
-
* @private
|
|
56
|
-
*/
|
|
57
|
-
baseUrl;
|
|
58
|
-
/**
|
|
59
|
-
* @type {string}
|
|
60
|
-
* @private
|
|
61
|
-
*/
|
|
62
20
|
projectCode;
|
|
63
|
-
|
|
64
|
-
* @type {boolean | undefined}
|
|
65
|
-
* @private
|
|
66
|
-
*/
|
|
67
|
-
isUploadAttachments;
|
|
68
|
-
/**
|
|
69
|
-
* @type {TestOpsRunType}
|
|
70
|
-
* @private
|
|
71
|
-
*/
|
|
72
|
-
run;
|
|
73
|
-
/**
|
|
74
|
-
* @type { string | undefined}
|
|
75
|
-
* @private
|
|
76
|
-
*/
|
|
77
|
-
environment;
|
|
78
|
-
/**
|
|
79
|
-
* @type { number | undefined}
|
|
80
|
-
* @private
|
|
81
|
-
*/
|
|
82
|
-
planId;
|
|
83
|
-
/**
|
|
84
|
-
* @type {TestResultType[]}
|
|
85
|
-
* @private
|
|
86
|
-
*/
|
|
21
|
+
baseUrl;
|
|
87
22
|
batchSize;
|
|
88
|
-
|
|
89
|
-
* @type {boolean | undefined}
|
|
90
|
-
* @private
|
|
91
|
-
*/
|
|
92
|
-
useV2;
|
|
93
|
-
/**
|
|
94
|
-
* @type {boolean | undefined}
|
|
95
|
-
* @private
|
|
96
|
-
*/
|
|
97
|
-
defect;
|
|
98
|
-
/**
|
|
99
|
-
* @type {string | undefined}
|
|
100
|
-
* @private
|
|
101
|
-
*/
|
|
102
|
-
rootSuite;
|
|
103
|
-
/**
|
|
104
|
-
* @type {number}
|
|
105
|
-
* @private
|
|
106
|
-
*/
|
|
23
|
+
runId;
|
|
107
24
|
firstIndex = 0;
|
|
108
|
-
/**
|
|
109
|
-
* @type {boolean}
|
|
110
|
-
* @private
|
|
111
|
-
*/
|
|
112
25
|
isTestRunReady = false;
|
|
113
26
|
mutex = new async_mutex_1.Mutex();
|
|
114
27
|
/**
|
|
115
28
|
* @param {LoggerInterface} logger
|
|
116
|
-
* @param {
|
|
117
|
-
* @param {QaseApiInterface} api
|
|
29
|
+
* @param {IClient} api
|
|
118
30
|
* @param {boolean} withState
|
|
119
|
-
* @param {string
|
|
120
|
-
* @param {string | undefined} rootSuite
|
|
31
|
+
* @param {string} projectCode
|
|
121
32
|
* @param {string | undefined} baseUrl
|
|
33
|
+
* @param {number | undefined} batchSize
|
|
122
34
|
*/
|
|
123
|
-
constructor(logger,
|
|
124
|
-
const { project, uploadAttachments, run, plan, } = options;
|
|
35
|
+
constructor(logger, api, withState, projectCode, baseUrl, batchSize, runId) {
|
|
125
36
|
super(logger);
|
|
126
37
|
this.api = api;
|
|
127
38
|
this.withState = withState;
|
|
39
|
+
this.projectCode = projectCode;
|
|
128
40
|
this.baseUrl = this.getBaseUrl(baseUrl);
|
|
129
|
-
this.
|
|
130
|
-
this.
|
|
131
|
-
this.run = { complete: true, ...run };
|
|
132
|
-
this.environment = environment;
|
|
133
|
-
this.planId = plan.id;
|
|
134
|
-
this.batchSize = options.batch?.size ?? defaultChunkSize;
|
|
135
|
-
this.useV2 = options.useV2 ?? true;
|
|
136
|
-
this.defect = options.defect ?? false;
|
|
137
|
-
this.rootSuite = rootSuite;
|
|
41
|
+
this.batchSize = batchSize ?? defaultChunkSize;
|
|
42
|
+
this.runId = runId;
|
|
138
43
|
}
|
|
139
44
|
/**
|
|
140
45
|
* @returns {Promise<void>}
|
|
@@ -174,33 +79,11 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
174
79
|
* @returns {Promise<void>}
|
|
175
80
|
*/
|
|
176
81
|
async checkOrCreateTestRun() {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
this.logger.logDebug('Creating test run');
|
|
182
|
-
let environmentId;
|
|
183
|
-
if (this.environment != undefined) {
|
|
184
|
-
try {
|
|
185
|
-
const { data } = await this.api.environment.getEnvironments(this.projectCode, undefined, this.environment, 100);
|
|
186
|
-
const env = data.result?.entities?.find((env) => env.slug === this.environment);
|
|
187
|
-
if (env) {
|
|
188
|
-
environmentId = env.id;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
throw this.processError(error, 'Error on getting environments');
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
const { result } = await this.createRun(this.run.title, this.run.description, environmentId);
|
|
196
|
-
if (!result?.id) {
|
|
197
|
-
throw new Error('Cannot create run.');
|
|
198
|
-
}
|
|
199
|
-
this.logger.logDebug(`Test run created: ${result.id}`);
|
|
200
|
-
this.run.id = result.id;
|
|
201
|
-
process.env['QASE_TESTOPS_RUN_ID'] = String(result.id);
|
|
82
|
+
const runId = await this.api.createRun();
|
|
83
|
+
this.runId = runId;
|
|
84
|
+
process.env['QASE_TESTOPS_RUN_ID'] = String(runId);
|
|
202
85
|
if (this.withState) {
|
|
203
|
-
state_1.StateManager.setRunId(
|
|
86
|
+
state_1.StateManager.setRunId(runId);
|
|
204
87
|
}
|
|
205
88
|
this.isTestRunReady = true;
|
|
206
89
|
}
|
|
@@ -210,36 +93,10 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
210
93
|
* @private
|
|
211
94
|
*/
|
|
212
95
|
async publishResults(testResults) {
|
|
213
|
-
if (this.
|
|
214
|
-
|
|
215
|
-
for (const result of testResults) {
|
|
216
|
-
const resultCreateV2 = await this.transformTestResult(result);
|
|
217
|
-
results.push(resultCreateV2);
|
|
218
|
-
}
|
|
219
|
-
try {
|
|
220
|
-
await this.api.result.createResultsV2(this.projectCode, this.run.id, {
|
|
221
|
-
results: results,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
throw this.processError(error, 'Error on uploading results', results);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
const results = [];
|
|
230
|
-
for (const result of testResults) {
|
|
231
|
-
const resultCreate = await this.transformTestResultV1(result);
|
|
232
|
-
results.push(resultCreate);
|
|
233
|
-
}
|
|
234
|
-
try {
|
|
235
|
-
await this.api.results.createResultBulk(this.projectCode, this.run.id, {
|
|
236
|
-
results: results,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
catch (error) {
|
|
240
|
-
throw this.processError(error, 'Error on uploading results', results);
|
|
241
|
-
}
|
|
96
|
+
if (!this.runId) {
|
|
97
|
+
throw new Error('Run ID is not set');
|
|
242
98
|
}
|
|
99
|
+
await this.api.uploadResults(this.runId, testResults);
|
|
243
100
|
this.logger.logDebug(`Results sent to Qase: ${testResults.length}`);
|
|
244
101
|
}
|
|
245
102
|
/**
|
|
@@ -280,384 +137,11 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
280
137
|
* @returns {Promise<void>}
|
|
281
138
|
*/
|
|
282
139
|
async complete() {
|
|
283
|
-
if (!this.
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
try {
|
|
287
|
-
await this.api.runs.completeRun(this.projectCode, this.run.id);
|
|
288
|
-
this.logger.log((0, chalk_1.default) `{green Run ${this.run.id} completed}`);
|
|
289
|
-
}
|
|
290
|
-
catch (error) {
|
|
291
|
-
throw this.processError(error, 'Error on completing run');
|
|
292
|
-
}
|
|
293
|
-
const runUrl = `${this.baseUrl}/run/${this.projectCode}/dashboard/${this.run.id}`;
|
|
294
|
-
this.logger.log((0, chalk_1.default) `{blue Test run link: ${runUrl}}`);
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* @param {TestResultType} result
|
|
298
|
-
* @returns Promise<ResultCreateV2>
|
|
299
|
-
* @private
|
|
300
|
-
*/
|
|
301
|
-
async transformTestResult(result) {
|
|
302
|
-
const attachments = await this.uploadAttachments(result.attachments);
|
|
303
|
-
const steps = await this.transformSteps(result.steps, result.title);
|
|
304
|
-
const param = {};
|
|
305
|
-
for (const key in result.params) {
|
|
306
|
-
const value = result.params[key];
|
|
307
|
-
if (!value) {
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
param[key] = value;
|
|
311
|
-
}
|
|
312
|
-
const group_params = [];
|
|
313
|
-
const keys = Object.keys(result.group_params);
|
|
314
|
-
if (keys.length > 0) {
|
|
315
|
-
group_params.push(keys);
|
|
316
|
-
}
|
|
317
|
-
for (const key in result.group_params) {
|
|
318
|
-
const value = result.group_params[key];
|
|
319
|
-
if (!value) {
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
param[key] = value;
|
|
323
|
-
}
|
|
324
|
-
const model = {
|
|
325
|
-
title: result.title,
|
|
326
|
-
execution: this.getExecution(result.execution),
|
|
327
|
-
testops_id: Array.isArray(result.testops_id) ? null : result.testops_id,
|
|
328
|
-
attachments: attachments,
|
|
329
|
-
steps: steps,
|
|
330
|
-
params: param,
|
|
331
|
-
param_groups: group_params,
|
|
332
|
-
relations: this.getRelation(result.relations),
|
|
333
|
-
message: result.message,
|
|
334
|
-
fields: result.fields,
|
|
335
|
-
defect: this.defect,
|
|
336
|
-
};
|
|
337
|
-
this.logger.logDebug(`Transformed result: ${JSON.stringify(model)}`);
|
|
338
|
-
return model;
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* @param {TestResultType} result
|
|
342
|
-
* @returns Promise<ResultCreate>
|
|
343
|
-
* @private
|
|
344
|
-
*/
|
|
345
|
-
async transformTestResultV1(result) {
|
|
346
|
-
const attachments = await this.uploadAttachments(result.attachments);
|
|
347
|
-
const steps = await this.transformStepsV1(result.steps, result.title);
|
|
348
|
-
const param = {};
|
|
349
|
-
for (const key in result.params) {
|
|
350
|
-
const value = result.params[key];
|
|
351
|
-
if (!value) {
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
param[key] = value;
|
|
355
|
-
}
|
|
356
|
-
const group_params = [];
|
|
357
|
-
const keys = Object.keys(result.group_params);
|
|
358
|
-
if (keys.length > 0) {
|
|
359
|
-
group_params.push(keys);
|
|
360
|
-
}
|
|
361
|
-
for (const key in result.group_params) {
|
|
362
|
-
const value = result.group_params[key];
|
|
363
|
-
if (!value) {
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
param[key] = value;
|
|
367
|
-
}
|
|
368
|
-
const resultCreate = {
|
|
369
|
-
attachments: attachments,
|
|
370
|
-
comment: result.message,
|
|
371
|
-
defect: this.defect,
|
|
372
|
-
param: param,
|
|
373
|
-
param_groups: group_params,
|
|
374
|
-
stacktrace: result.execution.stacktrace,
|
|
375
|
-
start_time: result.execution.start_time ? result.execution.start_time | 0 : null,
|
|
376
|
-
status: result.execution.status,
|
|
377
|
-
steps: steps,
|
|
378
|
-
time: result.execution.end_time,
|
|
379
|
-
time_ms: result.execution.duration,
|
|
380
|
-
};
|
|
381
|
-
const id = Array.isArray(result.testops_id) ? null : result.testops_id;
|
|
382
|
-
if (id) {
|
|
383
|
-
resultCreate.case_id = id;
|
|
384
|
-
}
|
|
385
|
-
const rootSuite = this.rootSuite ? `${this.rootSuite}\t` : '';
|
|
386
|
-
resultCreate.case = {
|
|
387
|
-
title: result.title,
|
|
388
|
-
suite_title: result.relations?.suite ? `${rootSuite}${result.relations.suite.data.map((suite) => suite.title).join('\t')}` : rootSuite,
|
|
389
|
-
description: result.fields['description'] ?? null,
|
|
390
|
-
postconditions: result.fields['postconditions'] ?? null,
|
|
391
|
-
preconditions: result.fields['preconditions'] ?? null,
|
|
392
|
-
};
|
|
393
|
-
if (result.fields['severity']) {
|
|
394
|
-
resultCreate.case.severity = result.fields['severity'];
|
|
395
|
-
}
|
|
396
|
-
if (result.fields['priority']) {
|
|
397
|
-
resultCreate.case.priority = result.fields['priority'];
|
|
398
|
-
}
|
|
399
|
-
if (result.fields['layer']) {
|
|
400
|
-
resultCreate.case.layer = result.fields['layer'];
|
|
401
|
-
}
|
|
402
|
-
if (result.fields['author']) {
|
|
403
|
-
const resp = await this.api.authors.getAuthors(result.fields['author']);
|
|
404
|
-
if (resp.data.result?.entities && resp.data.result.entities.length > 0) {
|
|
405
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
406
|
-
resultCreate.author_id = resp.data.result.entities[0]?.author_id ?? null;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
this.logger.logDebug(`Transformed result: ${JSON.stringify(resultCreate)}`);
|
|
410
|
-
return resultCreate;
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* @returns {ResultExecution}
|
|
414
|
-
* @private
|
|
415
|
-
* @param {TestExecution} exec
|
|
416
|
-
*/
|
|
417
|
-
getExecution(exec) {
|
|
418
|
-
return {
|
|
419
|
-
status: TestOpsReporter.statusMap[exec.status],
|
|
420
|
-
start_time: exec.start_time,
|
|
421
|
-
end_time: exec.end_time,
|
|
422
|
-
duration: exec.duration,
|
|
423
|
-
stacktrace: exec.stacktrace,
|
|
424
|
-
thread: exec.thread,
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* @param {Relation | null} relation
|
|
429
|
-
* @returns {ResultRelations}
|
|
430
|
-
* @private
|
|
431
|
-
*/
|
|
432
|
-
getRelation(relation) {
|
|
433
|
-
if (!relation?.suite) {
|
|
434
|
-
if (this.rootSuite == undefined) {
|
|
435
|
-
return {};
|
|
436
|
-
}
|
|
437
|
-
return {
|
|
438
|
-
suite: {
|
|
439
|
-
data: [
|
|
440
|
-
{
|
|
441
|
-
public_id: null,
|
|
442
|
-
title: this.rootSuite,
|
|
443
|
-
},
|
|
444
|
-
],
|
|
445
|
-
},
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
const suiteData = [];
|
|
449
|
-
if (this.rootSuite != undefined) {
|
|
450
|
-
suiteData.push({
|
|
451
|
-
public_id: null,
|
|
452
|
-
title: this.rootSuite,
|
|
453
|
-
});
|
|
140
|
+
if (!this.runId) {
|
|
141
|
+
throw new Error('Run ID is not set');
|
|
454
142
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
public_id: null,
|
|
458
|
-
title: data.title,
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
return {
|
|
462
|
-
suite: {
|
|
463
|
-
data: suiteData,
|
|
464
|
-
},
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* @param {TestStepType[]} steps
|
|
469
|
-
* @param testTitle
|
|
470
|
-
* @returns Promise<ResultStep[]>
|
|
471
|
-
* @private
|
|
472
|
-
*/
|
|
473
|
-
async transformSteps(steps, testTitle) {
|
|
474
|
-
const resultsSteps = [];
|
|
475
|
-
for (const step of steps) {
|
|
476
|
-
const attachmentHashes = await this.uploadAttachments(step.attachments);
|
|
477
|
-
const resultStep = {
|
|
478
|
-
data: {
|
|
479
|
-
action: '',
|
|
480
|
-
},
|
|
481
|
-
execution: {
|
|
482
|
-
status: TestOpsReporter.stepStatusMap[step.execution.status],
|
|
483
|
-
attachments: attachmentHashes,
|
|
484
|
-
},
|
|
485
|
-
};
|
|
486
|
-
if (step.step_type === models_1.StepType.TEXT) {
|
|
487
|
-
if ('action' in step.data && resultStep.data != undefined) {
|
|
488
|
-
if (step.data.action === '') {
|
|
489
|
-
this.logEmptyStep(testTitle);
|
|
490
|
-
resultStep.data.action = 'Unnamed step';
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
resultStep.data.action = step.data.action;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if ('expected_result' in step.data && resultStep.data != undefined && step.data.expected_result != null) {
|
|
497
|
-
resultStep.data.expected_result = step.data.expected_result;
|
|
498
|
-
}
|
|
499
|
-
if ('data' in step.data && resultStep.data != undefined && step.data.data != null) {
|
|
500
|
-
resultStep.data.input_data = step.data.data;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
if (step.step_type === models_1.StepType.GHERKIN) {
|
|
504
|
-
if ('keyword' in step.data && resultStep.data != undefined) {
|
|
505
|
-
resultStep.data.action = step.data.keyword;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
if (step.steps.length > 0) {
|
|
509
|
-
resultStep.steps = await this.transformSteps(step.steps, testTitle);
|
|
510
|
-
}
|
|
511
|
-
resultsSteps.push(resultStep);
|
|
512
|
-
}
|
|
513
|
-
return resultsSteps;
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* @param {TestStepType[]} steps
|
|
517
|
-
* @param testTitle
|
|
518
|
-
* @returns Promise<TestStepResultCreate[]>
|
|
519
|
-
* @private
|
|
520
|
-
*/
|
|
521
|
-
async transformStepsV1(steps, testTitle) {
|
|
522
|
-
const resultsSteps = [];
|
|
523
|
-
for (const step of steps) {
|
|
524
|
-
const attachmentHashes = await this.uploadAttachments(step.attachments);
|
|
525
|
-
const resultStep = {
|
|
526
|
-
status: TestOpsReporter.stepStatusMapV1[step.execution.status],
|
|
527
|
-
attachments: attachmentHashes,
|
|
528
|
-
};
|
|
529
|
-
if (step.step_type === models_1.StepType.TEXT) {
|
|
530
|
-
if ('action' in step.data) {
|
|
531
|
-
if (step.data.action === '') {
|
|
532
|
-
this.logEmptyStep(testTitle);
|
|
533
|
-
resultStep.action = 'Unnamed step';
|
|
534
|
-
}
|
|
535
|
-
else {
|
|
536
|
-
resultStep.action = step.data.action;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
if (step.step_type === models_1.StepType.GHERKIN) {
|
|
541
|
-
if ('keyword' in step.data) {
|
|
542
|
-
resultStep.action = step.data.keyword;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
if (step.steps.length > 0) {
|
|
546
|
-
resultStep.steps = await this.transformStepsV1(step.steps, testTitle);
|
|
547
|
-
}
|
|
548
|
-
resultsSteps.push(resultStep);
|
|
549
|
-
}
|
|
550
|
-
return resultsSteps;
|
|
551
|
-
}
|
|
552
|
-
logEmptyStep(testTitle) {
|
|
553
|
-
this.logger.log((0, chalk_1.default) `{magenta Test '${testTitle}' has empty action in step. The reporter will mark this step as unnamed step.}`);
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* @param {string} title
|
|
557
|
-
* @param {string} description
|
|
558
|
-
* @param {number | undefined} environment
|
|
559
|
-
* @returns {Promise<IdResponse>}
|
|
560
|
-
* @private
|
|
561
|
-
*/
|
|
562
|
-
async createRun(title, description, environment) {
|
|
563
|
-
try {
|
|
564
|
-
const runObject = {
|
|
565
|
-
title,
|
|
566
|
-
description,
|
|
567
|
-
is_autotest: true,
|
|
568
|
-
cases: [],
|
|
569
|
-
start_time: this.getDate(),
|
|
570
|
-
};
|
|
571
|
-
if (environment !== undefined) {
|
|
572
|
-
runObject.environment_id = environment;
|
|
573
|
-
}
|
|
574
|
-
if (this.planId) {
|
|
575
|
-
runObject.plan_id = this.planId;
|
|
576
|
-
}
|
|
577
|
-
const { data } = await this.api.runs.createRun(this.projectCode, runObject);
|
|
578
|
-
return data;
|
|
579
|
-
}
|
|
580
|
-
catch (error) {
|
|
581
|
-
throw this.processError(error, 'Error on creating run');
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* @returns {string}
|
|
586
|
-
* @private
|
|
587
|
-
*/
|
|
588
|
-
getDate() {
|
|
589
|
-
const date = new Date();
|
|
590
|
-
date.setSeconds(-10);
|
|
591
|
-
const year = date.getUTCFullYear();
|
|
592
|
-
const month = ('0' + (date.getUTCMonth() + 1).toString()).slice(-2); // Months are zero indexed, so we add 1
|
|
593
|
-
const day = ('0' + date.getUTCDate().toString()).slice(-2);
|
|
594
|
-
const hours = ('0' + date.getUTCHours().toString()).slice(-2);
|
|
595
|
-
const minutes = ('0' + date.getUTCMinutes().toString()).slice(-2);
|
|
596
|
-
const seconds = ('0' + date.getUTCSeconds().toString()).slice(-2);
|
|
597
|
-
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* @returns {Promise<void>}
|
|
601
|
-
* @private
|
|
602
|
-
*/
|
|
603
|
-
async uploadAttachments(attachments) {
|
|
604
|
-
if (!this.isUploadAttachments) {
|
|
605
|
-
return [];
|
|
606
|
-
}
|
|
607
|
-
const acc = [];
|
|
608
|
-
for (const attachment of attachments) {
|
|
609
|
-
this.logger.logDebug(`Uploading attachment: ${attachment.file_path ?? attachment.file_name}`);
|
|
610
|
-
try {
|
|
611
|
-
let data;
|
|
612
|
-
if (attachment.file_path) {
|
|
613
|
-
data = { name: attachment.file_name, value: (0, fs_1.createReadStream)(attachment.file_path) };
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
if (typeof attachment.content === 'string') {
|
|
617
|
-
data = { name: attachment.file_name, value: Buffer.from(attachment.content) };
|
|
618
|
-
}
|
|
619
|
-
else {
|
|
620
|
-
data = { name: attachment.file_name, value: attachment.content };
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
const response = await this.api.attachments.uploadAttachment(this.projectCode, [data]);
|
|
624
|
-
if (response.data.result?.[0]?.hash != undefined) {
|
|
625
|
-
acc.push(response.data.result[0].hash);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
catch (error) {
|
|
629
|
-
this.logger.logError('Cannot upload attachment:', error);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return acc;
|
|
633
|
-
}
|
|
634
|
-
/**
|
|
635
|
-
* Process error and throw QaseError
|
|
636
|
-
* @param {Error | AxiosError} error
|
|
637
|
-
* @param {string} message
|
|
638
|
-
* @param {object} model
|
|
639
|
-
* @private
|
|
640
|
-
*/
|
|
641
|
-
processError(error, message, model) {
|
|
642
|
-
if (!(0, axios_1.isAxiosError)(error)) {
|
|
643
|
-
return new qase_error_1.QaseError(message, { cause: error });
|
|
644
|
-
}
|
|
645
|
-
const err = error;
|
|
646
|
-
if (err.response?.status === 401) {
|
|
647
|
-
return new qase_error_1.QaseError(message + ': \n Unauthorized. Please check your API token. Maybe it is expired or invalid.');
|
|
648
|
-
}
|
|
649
|
-
if (err.response?.status === 404) {
|
|
650
|
-
return new qase_error_1.QaseError(message + ': Not found.');
|
|
651
|
-
}
|
|
652
|
-
if (err.response?.status === 403) {
|
|
653
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions
|
|
654
|
-
return new qase_error_1.QaseError(`${message}: ${error.response?.data?.errorMessage}`);
|
|
655
|
-
}
|
|
656
|
-
if (err.response?.status === 400 || err.response?.status === 422) {
|
|
657
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions
|
|
658
|
-
return new qase_error_1.QaseError(message + ': \n Bad request: \n' + `${JSON.stringify(err.response?.data)}` + '. \n Body: \n ' + JSON.stringify(model));
|
|
659
|
-
}
|
|
660
|
-
return new qase_error_1.QaseError(message, { cause: err });
|
|
143
|
+
await this.api.completeRun(this.runId);
|
|
144
|
+
this.logger.log((0, chalk_1.default) `{green Run ${this.runId} completed}`);
|
|
661
145
|
}
|
|
662
146
|
/**
|
|
663
147
|
* @param {string | undefined} url
|
|
@@ -677,7 +161,10 @@ class TestOpsReporter extends abstract_reporter_1.AbstractReporter {
|
|
|
677
161
|
* @private
|
|
678
162
|
*/
|
|
679
163
|
prepareFailedTestLink(id, title) {
|
|
680
|
-
|
|
164
|
+
if (!this.runId) {
|
|
165
|
+
throw new Error('Run ID is not set');
|
|
166
|
+
}
|
|
167
|
+
const baseLink = `${this.baseUrl}/run/${this.projectCode}/dashboard/${this.runId}?source=logs&status=%5B2%5D&search=`;
|
|
681
168
|
if (id) {
|
|
682
169
|
return `${baseLink}${id}`;
|
|
683
170
|
}
|
package/dist/state/state.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.StateManager = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
9
10
|
class StateManager {
|
|
10
11
|
static statePath = path_1.default.resolve(__dirname, 'reporterState.json');
|
|
11
12
|
static getState() {
|
package/dist/steps/step.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Attachment, TestStepType } from '../models';
|
|
2
|
-
export type StepFunction<T =
|
|
2
|
+
export type StepFunction<T = unknown> = (this: QaseStep, step: QaseStep) => T | Promise<T>;
|
|
3
3
|
export declare class QaseStep {
|
|
4
4
|
name: string;
|
|
5
5
|
attachments: Attachment[];
|
package/dist/steps/step.js
CHANGED
|
@@ -71,7 +71,7 @@ class QaseStep {
|
|
|
71
71
|
step.steps = this.steps;
|
|
72
72
|
await messageEmitter(step);
|
|
73
73
|
}
|
|
74
|
-
catch (
|
|
74
|
+
catch (error) {
|
|
75
75
|
step.execution = {
|
|
76
76
|
start_time: startDate,
|
|
77
77
|
end_time: new Date().getTime(),
|
|
@@ -81,7 +81,7 @@ class QaseStep {
|
|
|
81
81
|
step.attachments = this.attachments;
|
|
82
82
|
step.steps = this.steps;
|
|
83
83
|
await messageEmitter(step);
|
|
84
|
-
throw
|
|
84
|
+
throw error;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
package/dist/utils/hostData.js
CHANGED
|
@@ -167,7 +167,8 @@ function getHostInfo(framework, reporterName) {
|
|
|
167
167
|
framework: getPackageVersion(framework) ?? '',
|
|
168
168
|
reporter: getPackageVersion(reporterName) ?? '',
|
|
169
169
|
commons: getPackageVersion('qase-javascript-commons') ?? '',
|
|
170
|
-
|
|
170
|
+
apiClientV1: getPackageVersion('qase-api-client') ?? '',
|
|
171
|
+
apiClientV2: getPackageVersion('qase-api-v2-client') ?? '',
|
|
171
172
|
};
|
|
172
173
|
}
|
|
173
174
|
catch (error) {
|
|
@@ -182,7 +183,8 @@ function getHostInfo(framework, reporterName) {
|
|
|
182
183
|
framework: '',
|
|
183
184
|
reporter: '',
|
|
184
185
|
commons: '',
|
|
185
|
-
|
|
186
|
+
apiClientV1: '',
|
|
187
|
+
apiClientV2: '',
|
|
186
188
|
};
|
|
187
189
|
}
|
|
188
190
|
}
|