@testomatio/reporter 2.0.0-beta.1-xml → 2.0.0-beta.2-gaxios
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/lib/adapter/nightwatch.js +5 -5
- package/lib/adapter/webdriver.d.ts +1 -1
- package/lib/bin/cli.js +6 -7
- package/lib/bin/reportXml.js +2 -4
- package/lib/bin/startTest.js +2 -3
- package/lib/bin/uploadArtifacts.js +4 -5
- package/lib/data-storage.d.ts +1 -1
- package/lib/junit-adapter/csharp.d.ts +0 -1
- package/lib/junit-adapter/csharp.js +1 -11
- package/lib/pipe/bitbucket.d.ts +2 -0
- package/lib/pipe/bitbucket.js +21 -19
- package/lib/pipe/gitlab.d.ts +2 -0
- package/lib/pipe/gitlab.js +27 -8
- package/lib/pipe/testomatio.d.ts +2 -1
- package/lib/pipe/testomatio.js +75 -65
- package/lib/reporter.d.ts +12 -12
- package/lib/services/artifacts.d.ts +1 -1
- package/lib/services/key-values.d.ts +1 -1
- package/lib/services/logger.d.ts +1 -1
- package/lib/utils/utils.d.ts +0 -2
- package/lib/utils/utils.js +4 -20
- package/lib/xmlReader.js +11 -38
- package/package.json +5 -6
- package/src/adapter/nightwatch.js +1 -1
- package/src/adapter/webdriver.js +1 -1
- package/src/bin/cli.js +1 -2
- package/src/bin/reportXml.js +1 -4
- package/src/bin/startTest.js +1 -2
- package/src/bin/uploadArtifacts.js +1 -2
- package/src/junit-adapter/csharp.js +1 -13
- package/src/pipe/bitbucket.js +22 -24
- package/src/pipe/gitlab.js +27 -8
- package/src/pipe/testomatio.js +95 -95
- package/src/utils/utils.js +1 -14
- package/src/xmlReader.js +11 -47
package/src/pipe/testomatio.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import createDebugMessages from 'debug';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
|
-
|
|
4
|
-
// Retry interceptor function
|
|
5
|
-
import axiosRetry from 'axios-retry';
|
|
6
|
-
|
|
7
|
-
// Default axios instance
|
|
8
|
-
import axios from 'axios';
|
|
9
|
-
|
|
3
|
+
import { Gaxios } from 'gaxios';
|
|
10
4
|
import JsonCycle from 'json-cycle';
|
|
11
5
|
import { APP_PREFIX, STATUS, AXIOS_TIMEOUT, REPORTER_REQUEST_RETRIES } from '../constants.js';
|
|
12
6
|
import { isValidUrl, foundedTestLog } from '../utils/utils.js';
|
|
@@ -57,43 +51,31 @@ class TestomatioPipe {
|
|
|
57
51
|
this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
|
|
58
52
|
this.env = process.env.TESTOMATIO_ENV;
|
|
59
53
|
this.label = process.env.TESTOMATIO_LABEL;
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
|
|
55
|
+
// Create a new instance of gaxios with a custom config
|
|
56
|
+
this.client = new Gaxios({
|
|
62
57
|
baseURL: `${this.url.trim()}`,
|
|
63
58
|
timeout: AXIOS_TIMEOUT,
|
|
64
|
-
proxy: proxy
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
proxy: proxy ? proxy.toString() : undefined,
|
|
60
|
+
retry: true,
|
|
61
|
+
agent: new (require('https').Agent)({ rejectUnauthorized: false, keepAlive: false }),
|
|
62
|
+
retryConfig: {
|
|
63
|
+
retry: REPORTER_REQUEST_RETRIES.retriesPerRequest,
|
|
64
|
+
retryDelay: REPORTER_REQUEST_RETRIES.retryTimeout,
|
|
65
|
+
shouldRetry: (error) => {
|
|
66
|
+
if (!error.response) return false;
|
|
67
|
+
switch (error.response?.status) {
|
|
68
|
+
case 400: // Bad request (probably wrong API key)
|
|
69
|
+
case 404: // Test not matched
|
|
70
|
+
case 429: // Rate limit exceeded
|
|
71
|
+
case 500: // Internal server error
|
|
72
|
+
return false;
|
|
73
|
+
default:
|
|
74
|
+
break;
|
|
69
75
|
}
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Pass the axios instance to the retry function
|
|
74
|
-
axiosRetry(this.axios, {
|
|
75
|
-
// do not use retries for unit tests
|
|
76
|
-
retries: REPORTER_REQUEST_RETRIES.retriesPerRequest, // Number of retries
|
|
77
|
-
shouldResetTimeout: true,
|
|
78
|
-
retryCondition: error => {
|
|
79
|
-
if (!error.response) return false;
|
|
80
|
-
switch (error.response?.status) {
|
|
81
|
-
case 400: // Bad request (probably wrong API key)
|
|
82
|
-
case 404: // Test not matched
|
|
83
|
-
case 429: // Rate limit exceeded
|
|
84
|
-
case 500: // Internal server error
|
|
85
|
-
return false;
|
|
86
|
-
default:
|
|
87
|
-
break;
|
|
76
|
+
return error.response?.status >= 401; // Retry on 401+ and 5xx
|
|
88
77
|
}
|
|
89
|
-
|
|
90
|
-
},
|
|
91
|
-
retryDelay: () => REPORTER_REQUEST_RETRIES.retryTimeout, // sum = 15sec
|
|
92
|
-
onRetry: async (retryCount, error) => {
|
|
93
|
-
this.retriesTimestamps.push(Date.now());
|
|
94
|
-
|
|
95
|
-
debug(`${error.message || `Request failed ${error.status}`}. Retry #${retryCount} ...`);
|
|
96
|
-
},
|
|
78
|
+
}
|
|
97
79
|
});
|
|
98
80
|
|
|
99
81
|
this.isEnabled = true;
|
|
@@ -134,12 +116,15 @@ class TestomatioPipe {
|
|
|
134
116
|
return;
|
|
135
117
|
}
|
|
136
118
|
|
|
137
|
-
const resp = await this.
|
|
138
|
-
|
|
119
|
+
const resp = await this.client.request({
|
|
120
|
+
method: 'GET',
|
|
121
|
+
url: '/api/test_grep',
|
|
122
|
+
params: q
|
|
123
|
+
});
|
|
139
124
|
|
|
140
|
-
if (Array.isArray(data?.tests) && data?.tests?.length > 0) {
|
|
141
|
-
foundedTestLog(APP_PREFIX, data.tests);
|
|
142
|
-
return data.tests;
|
|
125
|
+
if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
|
|
126
|
+
foundedTestLog(APP_PREFIX, resp.data.tests);
|
|
127
|
+
return resp.data.tests;
|
|
143
128
|
}
|
|
144
129
|
|
|
145
130
|
console.log(APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
|
|
@@ -163,7 +148,6 @@ class TestomatioPipe {
|
|
|
163
148
|
|
|
164
149
|
// GitHub Actions Url
|
|
165
150
|
if (!buildUrl && process.env.GITHUB_RUN_ID) {
|
|
166
|
-
// eslint-disable-next-line max-len
|
|
167
151
|
buildUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
|
|
168
152
|
}
|
|
169
153
|
|
|
@@ -199,16 +183,23 @@ class TestomatioPipe {
|
|
|
199
183
|
if (this.runId) {
|
|
200
184
|
this.store.runId = this.runId;
|
|
201
185
|
debug(`Run with id ${this.runId} already created, updating...`);
|
|
202
|
-
const resp = await this.
|
|
186
|
+
const resp = await this.client.request({
|
|
187
|
+
method: 'PUT',
|
|
188
|
+
url: `/api/reporter/${this.runId}`,
|
|
189
|
+
data: runParams
|
|
190
|
+
});
|
|
203
191
|
if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
|
|
204
192
|
return;
|
|
205
193
|
}
|
|
206
194
|
|
|
207
195
|
debug('Creating run...');
|
|
208
196
|
try {
|
|
209
|
-
const resp = await this.
|
|
197
|
+
const resp = await this.client.request({
|
|
198
|
+
method: 'POST',
|
|
199
|
+
url: '/api/reporter',
|
|
200
|
+
data: runParams,
|
|
210
201
|
maxContentLength: Infinity,
|
|
211
|
-
|
|
202
|
+
responseType: 'json'
|
|
212
203
|
});
|
|
213
204
|
|
|
214
205
|
this.runId = resp.data.uid;
|
|
@@ -225,6 +216,7 @@ class TestomatioPipe {
|
|
|
225
216
|
debug('Run created', this.runId);
|
|
226
217
|
} catch (err) {
|
|
227
218
|
const errorText = err.response?.data?.message || err.message;
|
|
219
|
+
debug('Error creating run', err);
|
|
228
220
|
console.log(errorText || err);
|
|
229
221
|
if (!this.apiKey) console.error('Testomat.io API key is not set');
|
|
230
222
|
if (!this.apiKey?.startsWith('tstmt')) console.error('Testomat.io API key is invalid');
|
|
@@ -271,7 +263,15 @@ class TestomatioPipe {
|
|
|
271
263
|
|
|
272
264
|
debug('Adding test', json);
|
|
273
265
|
|
|
274
|
-
return this.
|
|
266
|
+
return this.client.request({
|
|
267
|
+
method: 'POST',
|
|
268
|
+
url: `/api/reporter/${this.runId}/testrun`,
|
|
269
|
+
data: json,
|
|
270
|
+
headers: {
|
|
271
|
+
'Content-Type': 'application/json',
|
|
272
|
+
},
|
|
273
|
+
maxContentLength: Infinity
|
|
274
|
+
}).catch(err => {
|
|
275
275
|
this.requestFailures++;
|
|
276
276
|
this.notReportedTestsCount++;
|
|
277
277
|
if (err.response) {
|
|
@@ -323,38 +323,43 @@ class TestomatioPipe {
|
|
|
323
323
|
const testsToSend = this.batch.tests.splice(0);
|
|
324
324
|
debug('📨 Batch upload', testsToSend.length, 'tests');
|
|
325
325
|
|
|
326
|
-
return this.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
this.hasUnmatchedTests = true;
|
|
345
|
-
}
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
326
|
+
return this.client.request({
|
|
327
|
+
method: 'POST',
|
|
328
|
+
url: `/api/reporter/${this.runId}/testrun`,
|
|
329
|
+
data: {
|
|
330
|
+
api_key: this.apiKey,
|
|
331
|
+
tests: testsToSend,
|
|
332
|
+
batch_index: this.batch.batchIndex
|
|
333
|
+
},
|
|
334
|
+
headers: {
|
|
335
|
+
'Content-Type': 'application/json',
|
|
336
|
+
},
|
|
337
|
+
maxContentLength: Infinity
|
|
338
|
+
}).catch(err => {
|
|
339
|
+
this.requestFailures++;
|
|
340
|
+
this.notReportedTestsCount += testsToSend.length;
|
|
341
|
+
if (err.response) {
|
|
342
|
+
if (err.response.status >= 400) {
|
|
343
|
+
const responseData = err.response.data || { message: '' };
|
|
348
344
|
console.log(
|
|
349
345
|
APP_PREFIX,
|
|
350
|
-
pc.yellow(`Warning: (${err.response
|
|
351
|
-
`Report couldn't be processed: ${err?.response?.data?.message}`,
|
|
346
|
+
pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
|
|
352
347
|
);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
348
|
+
if (err.response?.data?.message?.includes('could not be matched')) {
|
|
349
|
+
this.hasUnmatchedTests = true;
|
|
350
|
+
}
|
|
351
|
+
return;
|
|
356
352
|
}
|
|
357
|
-
|
|
353
|
+
console.log(
|
|
354
|
+
APP_PREFIX,
|
|
355
|
+
pc.yellow(`Warning: (${err.response?.status})`),
|
|
356
|
+
`Report couldn't be processed: ${err?.response?.data?.message}`,
|
|
357
|
+
);
|
|
358
|
+
printCreateIssue(err);
|
|
359
|
+
} else {
|
|
360
|
+
console.log(APP_PREFIX, "Report couldn't be processed", err);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
358
363
|
};
|
|
359
364
|
|
|
360
365
|
/**
|
|
@@ -413,12 +418,16 @@ class TestomatioPipe {
|
|
|
413
418
|
|
|
414
419
|
try {
|
|
415
420
|
if (this.runId && !this.proceed) {
|
|
416
|
-
await this.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
421
|
+
await this.client.request({
|
|
422
|
+
method: 'PUT',
|
|
423
|
+
url: `/api/reporter/${this.runId}`,
|
|
424
|
+
data: {
|
|
425
|
+
api_key: this.apiKey,
|
|
426
|
+
duration: params.duration,
|
|
427
|
+
status_event,
|
|
428
|
+
detach: params.detach,
|
|
429
|
+
tests: params.tests,
|
|
430
|
+
}
|
|
422
431
|
});
|
|
423
432
|
if (this.runUrl) {
|
|
424
433
|
console.log(APP_PREFIX, '📊 Report Saved. Report URL:', pc.magenta(this.runUrl));
|
|
@@ -478,20 +487,11 @@ function printCreateIssue(err) {
|
|
|
478
487
|
if (!err.config) return;
|
|
479
488
|
|
|
480
489
|
const time = new Date().toUTCString();
|
|
481
|
-
const {
|
|
490
|
+
const { body, url, baseURL, method } = err?.config || {};
|
|
482
491
|
console.log('```js');
|
|
483
|
-
console.log({
|
|
492
|
+
console.log({ body: body?.replace(/"(tstmt_[^"]+)"/g, 'tstmt_*'), url, baseURL, method, time });
|
|
484
493
|
console.log('```');
|
|
485
494
|
});
|
|
486
495
|
}
|
|
487
496
|
|
|
488
|
-
const axiosAddTestrunRequestConfig = {
|
|
489
|
-
maxContentLength: Infinity,
|
|
490
|
-
maxBodyLength: Infinity,
|
|
491
|
-
headers: {
|
|
492
|
-
// Overwrite Axios's automatically set Content-Type
|
|
493
|
-
'Content-Type': 'application/json',
|
|
494
|
-
},
|
|
495
|
-
};
|
|
496
|
-
|
|
497
497
|
export default TestomatioPipe;
|
package/src/utils/utils.js
CHANGED
|
@@ -5,13 +5,9 @@ import fs from 'fs';
|
|
|
5
5
|
import isValid from 'is-valid-path';
|
|
6
6
|
import createDebugMessages from 'debug';
|
|
7
7
|
import os from 'os';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
8
|
|
|
10
9
|
const debug = createDebugMessages('@testomatio/reporter:util');
|
|
11
10
|
|
|
12
|
-
// Use __dirname directly since we're compiling to CommonJS
|
|
13
|
-
const __dirname = path.resolve();
|
|
14
|
-
|
|
15
11
|
/**
|
|
16
12
|
* @param {String} testTitle - Test title
|
|
17
13
|
*
|
|
@@ -111,7 +107,7 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
|
|
|
111
107
|
.join('\n');
|
|
112
108
|
};
|
|
113
109
|
|
|
114
|
-
|
|
110
|
+
const TEST_ID_REGEX = /@T([\w\d]{8})/;
|
|
115
111
|
|
|
116
112
|
const fetchIdFromCode = (code, opts = {}) => {
|
|
117
113
|
const comments = code
|
|
@@ -154,9 +150,6 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
154
150
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
|
|
155
151
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
|
|
156
152
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
157
|
-
} else if (opts.lang === 'csharp') {
|
|
158
|
-
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
|
|
159
|
-
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
160
153
|
} else {
|
|
161
154
|
lineIndex = lines.findIndex(l => l.includes(title));
|
|
162
155
|
}
|
|
@@ -360,12 +353,6 @@ function formatStep(step, shift = 0) {
|
|
|
360
353
|
return lines;
|
|
361
354
|
}
|
|
362
355
|
|
|
363
|
-
export function getPackageVersion() {
|
|
364
|
-
const packageJsonPath = path.resolve(__dirname, '../../package.json');
|
|
365
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
366
|
-
return packageJson.version;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
356
|
export {
|
|
370
357
|
ansiRegExp,
|
|
371
358
|
isSameTest,
|
package/src/xmlReader.js
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
fetchSourceCodeFromStackTrace,
|
|
14
14
|
fetchIdFromCode,
|
|
15
15
|
humanize,
|
|
16
|
-
TEST_ID_REGEX,
|
|
17
16
|
} from './utils/utils.js';
|
|
18
17
|
import { pipesFactory } from './pipe/index.js';
|
|
19
18
|
import adapterFactory from './junit-adapter/index.js';
|
|
@@ -27,9 +26,8 @@ const debug = createDebugMessages('@testomatio/reporter:xml');
|
|
|
27
26
|
const ridRunId = randomUUID();
|
|
28
27
|
|
|
29
28
|
const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
|
|
30
|
-
const { TESTOMATIO_RUNGROUP_TITLE,
|
|
31
|
-
|
|
32
|
-
TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED } = process.env;
|
|
29
|
+
const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED } =
|
|
30
|
+
process.env;
|
|
33
31
|
|
|
34
32
|
const options = {
|
|
35
33
|
ignoreDeclaration: true,
|
|
@@ -39,8 +37,6 @@ const options = {
|
|
|
39
37
|
parseTagValue: true,
|
|
40
38
|
};
|
|
41
39
|
|
|
42
|
-
const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
|
|
43
|
-
|
|
44
40
|
const reduceOptions = {};
|
|
45
41
|
|
|
46
42
|
class XmlReader {
|
|
@@ -95,7 +91,7 @@ class XmlReader {
|
|
|
95
91
|
];
|
|
96
92
|
|
|
97
93
|
for (const regex of cutRegexes) {
|
|
98
|
-
xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0,
|
|
94
|
+
xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, 5000)}${p3}`);
|
|
99
95
|
}
|
|
100
96
|
|
|
101
97
|
const jsonResult = this.parser.parse(xmlData);
|
|
@@ -345,7 +341,6 @@ class XmlReader {
|
|
|
345
341
|
if (file.endsWith('.rb')) this.stats.language = 'ruby';
|
|
346
342
|
if (file.endsWith('.js')) this.stats.language = 'js';
|
|
347
343
|
if (file.endsWith('.ts')) this.stats.language = 'ts';
|
|
348
|
-
if (file.endsWith('.cs')) this.stats.language = 'csharp';
|
|
349
344
|
}
|
|
350
345
|
|
|
351
346
|
if (!fs.existsSync(file)) {
|
|
@@ -399,14 +394,13 @@ class XmlReader {
|
|
|
399
394
|
async uploadArtifacts() {
|
|
400
395
|
for (const test of this.tests.filter(t => !!t.stack)) {
|
|
401
396
|
let files = [];
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
files = test.files.map(f => path.isAbsolute(f) ? f : path.join(process.cwd(), f));
|
|
397
|
+
if (test.files?.length) files = test.files.map(f => path.join(process.cwd(), f));
|
|
398
|
+
files = [...files, ...fetchFilesFromStackTrace(test.stack)];
|
|
405
399
|
|
|
406
400
|
if (!files.length) continue;
|
|
407
401
|
|
|
408
402
|
const runId = this.runId || this.store.runId || Date.now().toString();
|
|
409
|
-
test.artifacts = await Promise.all(files.map(f => this.uploader.uploadFileByPath(f, [runId
|
|
403
|
+
test.artifacts = await Promise.all(files.map(f => this.uploader.uploadFileByPath(f, [runId])));
|
|
410
404
|
console.log(APP_PREFIX, `🗄️ Uploaded ${pc.bold(`${files.length} artifacts`)} for test ${test.title}`);
|
|
411
405
|
}
|
|
412
406
|
}
|
|
@@ -477,7 +471,7 @@ function reduceTestCases(prev, item) {
|
|
|
477
471
|
testCases
|
|
478
472
|
.filter(t => !!t)
|
|
479
473
|
.forEach(testCaseItem => {
|
|
480
|
-
const file = testCaseItem.file || item.filepath ||
|
|
474
|
+
const file = testCaseItem.file || item.filepath || '';
|
|
481
475
|
|
|
482
476
|
let stack = '';
|
|
483
477
|
let message = '';
|
|
@@ -511,38 +505,15 @@ function reduceTestCases(prev, item) {
|
|
|
511
505
|
stack = `${
|
|
512
506
|
testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''
|
|
513
507
|
}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (tags?.length && !testId) {
|
|
517
|
-
testId = tags.filter(t => t.startsWith('T')).map(t => `@${t}`).find(t => t.match(TEST_ID_REGEX))?.slice(2);
|
|
518
|
-
}
|
|
508
|
+
const testId = fetchIdFromOutput(stack);
|
|
519
509
|
|
|
520
510
|
let status = STATUS.PASSED.toString();
|
|
521
511
|
if ('failure' in testCaseItem || 'error' in testCaseItem) status = STATUS.FAILED;
|
|
522
512
|
if ('skipped' in testCaseItem) status = STATUS.SKIPPED;
|
|
523
|
-
if (testCaseItem.result && Object.values(STATUS).includes(testCaseItem.result.toLowerCase())) {
|
|
524
|
-
status = testCaseItem.result.toLowerCase();
|
|
525
|
-
}
|
|
526
513
|
|
|
527
514
|
let rid = null;
|
|
528
515
|
if (testCaseItem.id) rid = `${ridRunId}-${testCaseItem.id}`;
|
|
529
516
|
|
|
530
|
-
// Extract attachments
|
|
531
|
-
let files = [];
|
|
532
|
-
if (testCaseItem.attachments) {
|
|
533
|
-
const attachments = Array.isArray(testCaseItem.attachments.attachment)
|
|
534
|
-
? testCaseItem.attachments.attachment
|
|
535
|
-
: [testCaseItem.attachments.attachment];
|
|
536
|
-
|
|
537
|
-
files = attachments
|
|
538
|
-
.filter(a => a && a.filePath)
|
|
539
|
-
.map(a => a.filePath);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// Extract files from stack trace using existing utility
|
|
543
|
-
const stackFiles = fetchFilesFromStackTrace(stack);
|
|
544
|
-
files = [...new Set([...files, ...stackFiles])]; // Remove duplicates
|
|
545
|
-
|
|
546
517
|
prev.push({
|
|
547
518
|
rid,
|
|
548
519
|
file,
|
|
@@ -557,9 +528,7 @@ function reduceTestCases(prev, item) {
|
|
|
557
528
|
run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
|
|
558
529
|
status,
|
|
559
530
|
title,
|
|
560
|
-
root_suite_id: TESTOMATIO_SUITE,
|
|
561
531
|
suite_title: suiteTitle,
|
|
562
|
-
files,
|
|
563
532
|
});
|
|
564
533
|
});
|
|
565
534
|
return prev;
|
|
@@ -586,15 +555,10 @@ function fetchProperties(item) {
|
|
|
586
555
|
|
|
587
556
|
if (!item.properties) return {};
|
|
588
557
|
|
|
589
|
-
|
|
590
|
-
const properties = Array.isArray(item.properties.property)
|
|
591
|
-
? item.properties.property
|
|
592
|
-
: [item.properties.property].filter(Boolean);
|
|
593
|
-
|
|
594
|
-
const prop = properties.find(p => p.name === 'Description');
|
|
558
|
+
const prop = [item.properties?.property].flat().find(p => p.name === 'Description');
|
|
595
559
|
if (prop) title = prop.value;
|
|
596
|
-
|
|
597
|
-
|
|
560
|
+
[item.properties?.property]
|
|
561
|
+
.flat()
|
|
598
562
|
.filter(p => p.name === 'Category')
|
|
599
563
|
.forEach(p => tags.push(p.value));
|
|
600
564
|
return { title, tags };
|