@testomatio/reporter 2.0.0-beta.1-xml → 2.0.0-beta.2-xml
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 +1 -1
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const client_js_1 = __importDefault(require("../client.js"));
|
|
7
7
|
const config_js_1 = require("../config.js");
|
|
8
|
-
const
|
|
8
|
+
const constants_1 = require("../constants");
|
|
9
9
|
const utils_js_1 = require("../utils/utils.js");
|
|
10
10
|
const apiKey = config_js_1.config.TESTOMATIO;
|
|
11
11
|
const client = new client_js_1.default({ apiKey });
|
|
@@ -29,14 +29,14 @@ module.exports = {
|
|
|
29
29
|
let status;
|
|
30
30
|
switch (test.status) {
|
|
31
31
|
case 'pass':
|
|
32
|
-
status =
|
|
32
|
+
status = constants_1.STATUS.PASSED;
|
|
33
33
|
break;
|
|
34
34
|
case 'fail':
|
|
35
|
-
status =
|
|
35
|
+
status = constants_1.STATUS.FAILED;
|
|
36
36
|
break;
|
|
37
37
|
// probably not required (because skipped tests are in separate array), but just in case
|
|
38
38
|
case 'skip':
|
|
39
|
-
status =
|
|
39
|
+
status = constants_1.STATUS.SKIPPED;
|
|
40
40
|
console.info('Skipped test is in completed tests array:', test, 'Not expected behavior.');
|
|
41
41
|
break;
|
|
42
42
|
default:
|
|
@@ -58,7 +58,7 @@ module.exports = {
|
|
|
58
58
|
}
|
|
59
59
|
// just array with skipped tests titles, no any other info
|
|
60
60
|
for (const testTitle of skippedTests) {
|
|
61
|
-
client.addTestRun(
|
|
61
|
+
client.addTestRun(constants_1.STATUS.SKIPPED, {
|
|
62
62
|
suite_title: suiteTitle,
|
|
63
63
|
tags,
|
|
64
64
|
rid: `${testModule.uuid || ''}_${testTitle || ''}`,
|
|
@@ -19,6 +19,6 @@ declare class WebdriverReporter extends WDIOReporter {
|
|
|
19
19
|
*/
|
|
20
20
|
addBddScenario(scenario: import("../../types/types.js").WebdriverIOScenario): Promise<import("../../types/types.js").PipeResult[]>;
|
|
21
21
|
}
|
|
22
|
-
import
|
|
22
|
+
import WDIOReporter from '@wdio/reporter';
|
|
23
23
|
import TestomatClient from '../client.js';
|
|
24
24
|
import { RunnerStats } from '@wdio/reporter';
|
package/lib/bin/cli.js
CHANGED
|
@@ -11,18 +11,17 @@ const debug_1 = __importDefault(require("debug"));
|
|
|
11
11
|
const client_js_1 = __importDefault(require("../client.js"));
|
|
12
12
|
const xmlReader_js_1 = __importDefault(require("../xmlReader.js"));
|
|
13
13
|
const constants_js_1 = require("../constants.js");
|
|
14
|
-
const
|
|
14
|
+
const package_json_1 = require("../../package.json");
|
|
15
15
|
const config_js_1 = require("../config.js");
|
|
16
|
-
const
|
|
16
|
+
const utils_js_1 = require("../utils/utils.js");
|
|
17
17
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
18
18
|
const filesize_1 = require("filesize");
|
|
19
19
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
20
20
|
const debug = (0, debug_1.default)('@testomatio/reporter:xml-cli');
|
|
21
|
-
|
|
22
|
-
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
21
|
+
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${package_json_1.version}`)));
|
|
23
22
|
const program = new commander_1.Command();
|
|
24
23
|
program
|
|
25
|
-
.version(version)
|
|
24
|
+
.version(package_json_1.version)
|
|
26
25
|
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
27
26
|
.hook('preAction', thisCommand => {
|
|
28
27
|
const opts = thisCommand.opts();
|
|
@@ -49,7 +48,7 @@ program
|
|
|
49
48
|
.command('finish')
|
|
50
49
|
.description('Finish Run by its ID')
|
|
51
50
|
.action(async () => {
|
|
52
|
-
process.env.TESTOMATIO_RUN ||= (0,
|
|
51
|
+
process.env.TESTOMATIO_RUN ||= (0, utils_js_1.readLatestRunId)();
|
|
53
52
|
if (!process.env.TESTOMATIO_RUN) {
|
|
54
53
|
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
55
54
|
return process.exit(1);
|
|
@@ -181,7 +180,7 @@ program
|
|
|
181
180
|
.action(async (opts) => {
|
|
182
181
|
const apiKey = config_js_1.config.TESTOMATIO;
|
|
183
182
|
process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
|
|
184
|
-
const runId = process.env.TESTOMATIO_RUN || process.env.runId || (0,
|
|
183
|
+
const runId = process.env.TESTOMATIO_RUN || process.env.runId || (0, utils_js_1.readLatestRunId)();
|
|
185
184
|
if (!runId) {
|
|
186
185
|
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
187
186
|
return process.exit(1);
|
package/lib/bin/reportXml.js
CHANGED
|
@@ -10,12 +10,10 @@ const glob_1 = require("glob");
|
|
|
10
10
|
const debug_1 = __importDefault(require("debug"));
|
|
11
11
|
const constants_js_1 = require("../constants.js");
|
|
12
12
|
const xmlReader_js_1 = __importDefault(require("../xmlReader.js"));
|
|
13
|
-
const
|
|
13
|
+
const package_json_1 = require("../../package.json");
|
|
14
14
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
15
|
-
const path_1 = __importDefault(require("path"));
|
|
16
|
-
const version = (0, utils_js_1.getPackageVersion)();
|
|
17
15
|
const debug = (0, debug_1.default)('@testomatio/reporter:xml-cli');
|
|
18
|
-
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io XML Reporter v${version}`)));
|
|
16
|
+
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io XML Reporter v${package_json_1.version}`)));
|
|
19
17
|
const program = new commander_1.Command();
|
|
20
18
|
program
|
|
21
19
|
.arguments('<pattern>')
|
package/lib/bin/startTest.js
CHANGED
|
@@ -9,11 +9,10 @@ const commander_1 = require("commander");
|
|
|
9
9
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
10
|
const client_js_1 = __importDefault(require("../client.js"));
|
|
11
11
|
const constants_js_1 = require("../constants.js");
|
|
12
|
-
const
|
|
12
|
+
const package_json_1 = require("../../package.json");
|
|
13
13
|
const config_js_1 = require("../config.js");
|
|
14
14
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
15
|
-
|
|
16
|
-
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
15
|
+
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${package_json_1.version}`)));
|
|
17
16
|
const program = new commander_1.Command();
|
|
18
17
|
program
|
|
19
18
|
.option('-c, --command <cmd>', 'Test runner command')
|
|
@@ -9,13 +9,12 @@ const picocolors_1 = __importDefault(require("picocolors"));
|
|
|
9
9
|
const debug_1 = __importDefault(require("debug"));
|
|
10
10
|
const client_js_1 = __importDefault(require("../client.js"));
|
|
11
11
|
const constants_js_1 = require("../constants.js");
|
|
12
|
-
const
|
|
12
|
+
const package_json_1 = require("../../package.json");
|
|
13
13
|
const config_js_1 = require("../config.js");
|
|
14
|
-
const
|
|
14
|
+
const utils_js_1 = require("../utils/utils.js");
|
|
15
15
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
16
16
|
const debug = (0, debug_1.default)('@testomatio/reporter:upload-cli');
|
|
17
|
-
|
|
18
|
-
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
17
|
+
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${package_json_1.version}`)));
|
|
19
18
|
const program = new commander_1.Command();
|
|
20
19
|
program
|
|
21
20
|
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
@@ -29,7 +28,7 @@ program
|
|
|
29
28
|
}
|
|
30
29
|
const apiKey = config_js_1.config.TESTOMATIO;
|
|
31
30
|
process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
|
|
32
|
-
const runId = process.env.TESTOMATIO_RUN || process.env.runId || (0,
|
|
31
|
+
const runId = process.env.TESTOMATIO_RUN || process.env.runId || (0, utils_js_1.readLatestRunId)();
|
|
33
32
|
if (!runId) {
|
|
34
33
|
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
35
34
|
return process.exit(1);
|
package/lib/data-storage.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const path_1 = __importDefault(require("path"));
|
|
7
6
|
const adapter_js_1 = __importDefault(require("./adapter.js"));
|
|
8
7
|
class CSharpAdapter extends adapter_js_1.default {
|
|
9
8
|
formatTest(t) {
|
|
@@ -13,18 +12,9 @@ class CSharpAdapter extends adapter_js_1.default {
|
|
|
13
12
|
t.example = { ...example[1].split(',') };
|
|
14
13
|
const suite = t.suite_title.split('.');
|
|
15
14
|
t.suite_title = suite.pop();
|
|
16
|
-
t.file =
|
|
15
|
+
t.file = suite.join('/');
|
|
17
16
|
t.title = title.trim();
|
|
18
17
|
return t;
|
|
19
18
|
}
|
|
20
|
-
getFilePath(t) {
|
|
21
|
-
const fileName = namespaceToFileName(t.file);
|
|
22
|
-
return fileName;
|
|
23
|
-
}
|
|
24
19
|
}
|
|
25
20
|
module.exports = CSharpAdapter;
|
|
26
|
-
function namespaceToFileName(fileName) {
|
|
27
|
-
const fileParts = fileName.split('.');
|
|
28
|
-
fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1]?.replace(/\$.*/, '');
|
|
29
|
-
return `${fileParts.join(path_1.default.sep)}.cs`;
|
|
30
|
-
}
|
package/lib/pipe/bitbucket.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export class BitbucketPipe {
|
|
|
11
11
|
tests: any[];
|
|
12
12
|
token: any;
|
|
13
13
|
hiddenCommentData: string;
|
|
14
|
+
client: Gaxios;
|
|
14
15
|
cleanLog(log: any): Promise<string>;
|
|
15
16
|
prepareRun(): Promise<void>;
|
|
16
17
|
createRun(): Promise<void>;
|
|
@@ -21,3 +22,4 @@ export class BitbucketPipe {
|
|
|
21
22
|
}
|
|
22
23
|
export type Pipe = import("../../types/types.js").Pipe;
|
|
23
24
|
export type TestData = import("../../types/types.js").TestData;
|
|
25
|
+
import { Gaxios } from 'gaxios';
|
package/lib/pipe/bitbucket.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.BitbucketPipe = void 0;
|
|
|
40
40
|
const constants_js_1 = require("../constants.js");
|
|
41
41
|
const utils_js_1 = require("../utils/utils.js");
|
|
42
42
|
const pipe_utils_js_1 = require("../utils/pipe_utils.js");
|
|
43
|
-
const
|
|
43
|
+
const gaxios_1 = require("gaxios");
|
|
44
44
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
45
45
|
const humanize_duration_1 = __importDefault(require("humanize-duration"));
|
|
46
46
|
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
@@ -69,6 +69,13 @@ class BitbucketPipe {
|
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
this.isEnabled = true;
|
|
72
|
+
this.client = new gaxios_1.Gaxios({
|
|
73
|
+
baseURL: 'https://api.bitbucket.org/2.0',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
'Authorization': `Bearer ${this.token}`
|
|
77
|
+
}
|
|
78
|
+
});
|
|
72
79
|
debug('Bitbucket Pipe: Enabled');
|
|
73
80
|
}
|
|
74
81
|
async cleanLog(log) {
|
|
@@ -168,18 +175,17 @@ class BitbucketPipe {
|
|
|
168
175
|
}
|
|
169
176
|
// Construct Bitbucket API URL for comments
|
|
170
177
|
// eslint-disable-next-line max-len
|
|
171
|
-
const commentsRequestURL =
|
|
178
|
+
const commentsRequestURL = `/repositories/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pullrequests/${this.ENV.BITBUCKET_PR_ID}/comments`;
|
|
172
179
|
// Delete previous report
|
|
173
|
-
await deletePreviousReport(
|
|
180
|
+
await deletePreviousReport(this.client, commentsRequestURL, this.hiddenCommentData);
|
|
174
181
|
// Add current report
|
|
175
182
|
debug(`Adding comment via URL: ${commentsRequestURL}`);
|
|
176
183
|
debug(`Final Bitbucket API call body: ${body}`);
|
|
177
184
|
try {
|
|
178
|
-
const addCommentResponse = await
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
185
|
+
const addCommentResponse = await this.client.request({
|
|
186
|
+
method: 'POST',
|
|
187
|
+
url: commentsRequestURL,
|
|
188
|
+
data: { content: { raw: body } }
|
|
183
189
|
});
|
|
184
190
|
const commentID = addCommentResponse.data.id;
|
|
185
191
|
// eslint-disable-next-line max-len
|
|
@@ -198,17 +204,15 @@ class BitbucketPipe {
|
|
|
198
204
|
updateRun() { }
|
|
199
205
|
}
|
|
200
206
|
exports.BitbucketPipe = BitbucketPipe;
|
|
201
|
-
async function deletePreviousReport(
|
|
207
|
+
async function deletePreviousReport(client, commentsRequestURL, hiddenCommentData) {
|
|
202
208
|
if (process.env.BITBUCKET_KEEP_OUTDATED_REPORTS)
|
|
203
209
|
return;
|
|
204
210
|
// Get comments
|
|
205
211
|
let comments = [];
|
|
206
212
|
try {
|
|
207
|
-
const response = await
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
'Content-Type': 'application/json',
|
|
211
|
-
},
|
|
213
|
+
const response = await client.request({
|
|
214
|
+
method: 'GET',
|
|
215
|
+
url: commentsRequestURL
|
|
212
216
|
});
|
|
213
217
|
comments = response.data.values;
|
|
214
218
|
}
|
|
@@ -223,11 +227,9 @@ async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCom
|
|
|
223
227
|
try {
|
|
224
228
|
// Delete previous comment
|
|
225
229
|
const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
|
|
226
|
-
await
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
'Content-Type': 'application/json',
|
|
230
|
-
},
|
|
230
|
+
await client.request({
|
|
231
|
+
method: 'DELETE',
|
|
232
|
+
url: deleteCommentURL
|
|
231
233
|
});
|
|
232
234
|
}
|
|
233
235
|
catch (e) {
|
package/lib/pipe/gitlab.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare class GitLabPipe {
|
|
|
14
14
|
tests: any[];
|
|
15
15
|
token: any;
|
|
16
16
|
hiddenCommentData: string;
|
|
17
|
+
client: Gaxios;
|
|
17
18
|
prepareRun(): Promise<void>;
|
|
18
19
|
createRun(): Promise<void>;
|
|
19
20
|
addTest(test: any): void;
|
|
@@ -21,3 +22,4 @@ declare class GitLabPipe {
|
|
|
21
22
|
toString(): string;
|
|
22
23
|
updateRun(): void;
|
|
23
24
|
}
|
|
25
|
+
import { Gaxios } from 'gaxios';
|
package/lib/pipe/gitlab.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const debug_1 = __importDefault(require("debug"));
|
|
7
|
-
const
|
|
7
|
+
const gaxios_1 = require("gaxios");
|
|
8
8
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
9
9
|
const humanize_duration_1 = __importDefault(require("humanize-duration"));
|
|
10
10
|
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
@@ -39,6 +39,12 @@ class GitLabPipe {
|
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
this.isEnabled = true;
|
|
42
|
+
this.client = new gaxios_1.Gaxios({
|
|
43
|
+
baseURL: 'https://gitlab.com/api/v4',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
}
|
|
47
|
+
});
|
|
42
48
|
debug('GitLab Pipe: Enabled');
|
|
43
49
|
}
|
|
44
50
|
// TODO: to using SET opts as argument => prepareRun(opts)
|
|
@@ -126,13 +132,18 @@ class GitLabPipe {
|
|
|
126
132
|
body += '\n</details>';
|
|
127
133
|
}
|
|
128
134
|
// eslint-disable-next-line max-len
|
|
129
|
-
const commentsRequestURL =
|
|
135
|
+
const commentsRequestURL = `/projects/${this.ENV.CI_PROJECT_ID}/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}/notes`;
|
|
130
136
|
// delete previous report
|
|
131
|
-
await deletePreviousReport(
|
|
137
|
+
await deletePreviousReport(this.client, commentsRequestURL, this.hiddenCommentData, this.token);
|
|
132
138
|
// add current report
|
|
133
139
|
debug(`Adding comment via url: ${commentsRequestURL}`);
|
|
134
140
|
try {
|
|
135
|
-
const addCommentResponse = await
|
|
141
|
+
const addCommentResponse = await this.client.request({
|
|
142
|
+
method: 'POST',
|
|
143
|
+
url: commentsRequestURL,
|
|
144
|
+
params: { access_token: this.token },
|
|
145
|
+
data: { body }
|
|
146
|
+
});
|
|
136
147
|
const commentID = addCommentResponse.data.id;
|
|
137
148
|
// eslint-disable-next-line max-len
|
|
138
149
|
const commentURL = `${this.ENV.CI_PROJECT_URL}/-/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}#note_${commentID}`;
|
|
@@ -149,13 +160,17 @@ class GitLabPipe {
|
|
|
149
160
|
}
|
|
150
161
|
updateRun() { }
|
|
151
162
|
}
|
|
152
|
-
async function deletePreviousReport(
|
|
163
|
+
async function deletePreviousReport(client, commentsRequestURL, hiddenCommentData, token) {
|
|
153
164
|
if (process.env.GITLAB_KEEP_OUTDATED_REPORTS)
|
|
154
165
|
return;
|
|
155
166
|
// get comments
|
|
156
167
|
let comments = [];
|
|
157
168
|
try {
|
|
158
|
-
const response = await
|
|
169
|
+
const response = await client.request({
|
|
170
|
+
method: 'GET',
|
|
171
|
+
url: commentsRequestURL,
|
|
172
|
+
params: { access_token: token }
|
|
173
|
+
});
|
|
159
174
|
comments = response.data;
|
|
160
175
|
}
|
|
161
176
|
catch (e) {
|
|
@@ -168,8 +183,12 @@ async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCom
|
|
|
168
183
|
if (comment.body.includes(hiddenCommentData)) {
|
|
169
184
|
try {
|
|
170
185
|
// delete previous comment
|
|
171
|
-
const deleteCommentURL = `${commentsRequestURL}/${comment.id}
|
|
172
|
-
await
|
|
186
|
+
const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
|
|
187
|
+
await client.request({
|
|
188
|
+
method: 'DELETE',
|
|
189
|
+
url: deleteCommentURL,
|
|
190
|
+
params: { access_token: token }
|
|
191
|
+
});
|
|
173
192
|
}
|
|
174
193
|
catch (e) {
|
|
175
194
|
console.warn(`Can't delete previously added comment with testomat.io report. Ignore.`);
|
package/lib/pipe/testomatio.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ declare class TestomatioPipe implements Pipe {
|
|
|
31
31
|
groupTitle: any;
|
|
32
32
|
env: string;
|
|
33
33
|
label: string;
|
|
34
|
-
|
|
34
|
+
client: Gaxios;
|
|
35
35
|
proceed: string;
|
|
36
36
|
jiraId: string;
|
|
37
37
|
runId: any;
|
|
@@ -68,3 +68,4 @@ declare class TestomatioPipe implements Pipe {
|
|
|
68
68
|
toString(): string;
|
|
69
69
|
#private;
|
|
70
70
|
}
|
|
71
|
+
import { Gaxios } from 'gaxios';
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -5,10 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const debug_1 = __importDefault(require("debug"));
|
|
7
7
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
8
|
-
|
|
9
|
-
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
10
|
-
// Default axios instance
|
|
11
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const gaxios_1 = require("gaxios");
|
|
12
9
|
const json_cycle_1 = __importDefault(require("json-cycle"));
|
|
13
10
|
const constants_js_1 = require("../constants.js");
|
|
14
11
|
const utils_js_1 = require("../utils/utils.js");
|
|
@@ -54,42 +51,31 @@ class TestomatioPipe {
|
|
|
54
51
|
this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
|
|
55
52
|
this.env = process.env.TESTOMATIO_ENV;
|
|
56
53
|
this.label = process.env.TESTOMATIO_LABEL;
|
|
57
|
-
// Create a new instance of
|
|
58
|
-
this.
|
|
54
|
+
// Create a new instance of gaxios with a custom config
|
|
55
|
+
this.client = new gaxios_1.Gaxios({
|
|
59
56
|
baseURL: `${this.url.trim()}`,
|
|
60
57
|
timeout: constants_js_1.AXIOS_TIMEOUT,
|
|
61
|
-
proxy: proxy
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
:
|
|
68
|
-
|
|
69
|
-
// Pass the axios instance to the retry function
|
|
70
|
-
(0, axios_retry_1.default)(this.axios, {
|
|
71
|
-
// do not use retries for unit tests
|
|
72
|
-
retries: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest, // Number of retries
|
|
73
|
-
shouldResetTimeout: true,
|
|
74
|
-
retryCondition: error => {
|
|
75
|
-
if (!error.response)
|
|
76
|
-
return false;
|
|
77
|
-
switch (error.response?.status) {
|
|
78
|
-
case 400: // Bad request (probably wrong API key)
|
|
79
|
-
case 404: // Test not matched
|
|
80
|
-
case 429: // Rate limit exceeded
|
|
81
|
-
case 500: // Internal server error
|
|
58
|
+
proxy: proxy ? proxy.toString() : undefined,
|
|
59
|
+
retry: true,
|
|
60
|
+
agent: new (require('https').Agent)({ rejectUnauthorized: false, keepAlive: false }),
|
|
61
|
+
retryConfig: {
|
|
62
|
+
retry: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest,
|
|
63
|
+
retryDelay: constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout,
|
|
64
|
+
shouldRetry: (error) => {
|
|
65
|
+
if (!error.response)
|
|
82
66
|
return false;
|
|
83
|
-
|
|
84
|
-
|
|
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;
|
|
75
|
+
}
|
|
76
|
+
return error.response?.status >= 401; // Retry on 401+ and 5xx
|
|
85
77
|
}
|
|
86
|
-
|
|
87
|
-
},
|
|
88
|
-
retryDelay: () => constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout, // sum = 15sec
|
|
89
|
-
onRetry: async (retryCount, error) => {
|
|
90
|
-
this.retriesTimestamps.push(Date.now());
|
|
91
|
-
debug(`${error.message || `Request failed ${error.status}`}. Retry #${retryCount} ...`);
|
|
92
|
-
},
|
|
78
|
+
}
|
|
93
79
|
});
|
|
94
80
|
this.isEnabled = true;
|
|
95
81
|
// do not finish this run (for parallel testing)
|
|
@@ -124,11 +110,14 @@ class TestomatioPipe {
|
|
|
124
110
|
if (!q) {
|
|
125
111
|
return;
|
|
126
112
|
}
|
|
127
|
-
const resp = await this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
113
|
+
const resp = await this.client.request({
|
|
114
|
+
method: 'GET',
|
|
115
|
+
url: '/api/test_grep',
|
|
116
|
+
params: q
|
|
117
|
+
});
|
|
118
|
+
if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
|
|
119
|
+
(0, utils_js_1.foundedTestLog)(constants_js_1.APP_PREFIX, resp.data.tests);
|
|
120
|
+
return resp.data.tests;
|
|
132
121
|
}
|
|
133
122
|
console.log(constants_js_1.APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
|
|
134
123
|
}
|
|
@@ -150,7 +139,6 @@ class TestomatioPipe {
|
|
|
150
139
|
let buildUrl = process.env.BUILD_URL || process.env.CI_JOB_URL || process.env.CIRCLE_BUILD_URL;
|
|
151
140
|
// GitHub Actions Url
|
|
152
141
|
if (!buildUrl && process.env.GITHUB_RUN_ID) {
|
|
153
|
-
// eslint-disable-next-line max-len
|
|
154
142
|
buildUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
|
|
155
143
|
}
|
|
156
144
|
// Azure DevOps Url
|
|
@@ -180,16 +168,23 @@ class TestomatioPipe {
|
|
|
180
168
|
if (this.runId) {
|
|
181
169
|
this.store.runId = this.runId;
|
|
182
170
|
debug(`Run with id ${this.runId} already created, updating...`);
|
|
183
|
-
const resp = await this.
|
|
171
|
+
const resp = await this.client.request({
|
|
172
|
+
method: 'PUT',
|
|
173
|
+
url: `/api/reporter/${this.runId}`,
|
|
174
|
+
data: runParams
|
|
175
|
+
});
|
|
184
176
|
if (resp.data.artifacts)
|
|
185
177
|
(0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
|
|
186
178
|
return;
|
|
187
179
|
}
|
|
188
180
|
debug('Creating run...');
|
|
189
181
|
try {
|
|
190
|
-
const resp = await this.
|
|
182
|
+
const resp = await this.client.request({
|
|
183
|
+
method: 'POST',
|
|
184
|
+
url: '/api/reporter',
|
|
185
|
+
data: runParams,
|
|
191
186
|
maxContentLength: Infinity,
|
|
192
|
-
|
|
187
|
+
responseType: 'json'
|
|
193
188
|
});
|
|
194
189
|
this.runId = resp.data.uid;
|
|
195
190
|
this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
|
|
@@ -205,6 +200,7 @@ class TestomatioPipe {
|
|
|
205
200
|
}
|
|
206
201
|
catch (err) {
|
|
207
202
|
const errorText = err.response?.data?.message || err.message;
|
|
203
|
+
debug('Error creating run', err);
|
|
208
204
|
console.log(errorText || err);
|
|
209
205
|
if (!this.apiKey)
|
|
210
206
|
console.error('Testomat.io API key is not set');
|
|
@@ -245,7 +241,15 @@ class TestomatioPipe {
|
|
|
245
241
|
}
|
|
246
242
|
const json = json_cycle_1.default.stringify(data);
|
|
247
243
|
debug('Adding test', json);
|
|
248
|
-
return this.
|
|
244
|
+
return this.client.request({
|
|
245
|
+
method: 'POST',
|
|
246
|
+
url: `/api/reporter/${this.runId}/testrun`,
|
|
247
|
+
data: json,
|
|
248
|
+
headers: {
|
|
249
|
+
'Content-Type': 'application/json',
|
|
250
|
+
},
|
|
251
|
+
maxContentLength: Infinity
|
|
252
|
+
}).catch(err => {
|
|
249
253
|
this.requestFailures++;
|
|
250
254
|
this.notReportedTestsCount++;
|
|
251
255
|
if (err.response) {
|
|
@@ -290,9 +294,19 @@ class TestomatioPipe {
|
|
|
290
294
|
// get tests from batch and clear batch
|
|
291
295
|
const testsToSend = this.batch.tests.splice(0);
|
|
292
296
|
debug('📨 Batch upload', testsToSend.length, 'tests');
|
|
293
|
-
return this.
|
|
294
|
-
|
|
295
|
-
|
|
297
|
+
return this.client.request({
|
|
298
|
+
method: 'POST',
|
|
299
|
+
url: `/api/reporter/${this.runId}/testrun`,
|
|
300
|
+
data: {
|
|
301
|
+
api_key: this.apiKey,
|
|
302
|
+
tests: testsToSend,
|
|
303
|
+
batch_index: this.batch.batchIndex
|
|
304
|
+
},
|
|
305
|
+
headers: {
|
|
306
|
+
'Content-Type': 'application/json',
|
|
307
|
+
},
|
|
308
|
+
maxContentLength: Infinity
|
|
309
|
+
}).catch(err => {
|
|
296
310
|
this.requestFailures++;
|
|
297
311
|
this.notReportedTestsCount += testsToSend.length;
|
|
298
312
|
if (err.response) {
|
|
@@ -366,12 +380,16 @@ class TestomatioPipe {
|
|
|
366
380
|
status_event += '_parallel';
|
|
367
381
|
try {
|
|
368
382
|
if (this.runId && !this.proceed) {
|
|
369
|
-
await this.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
383
|
+
await this.client.request({
|
|
384
|
+
method: 'PUT',
|
|
385
|
+
url: `/api/reporter/${this.runId}`,
|
|
386
|
+
data: {
|
|
387
|
+
api_key: this.apiKey,
|
|
388
|
+
duration: params.duration,
|
|
389
|
+
status_event,
|
|
390
|
+
detach: params.detach,
|
|
391
|
+
tests: params.tests,
|
|
392
|
+
}
|
|
375
393
|
});
|
|
376
394
|
if (this.runUrl) {
|
|
377
395
|
console.log(constants_js_1.APP_PREFIX, '📊 Report Saved. Report URL:', picocolors_1.default.magenta(this.runUrl));
|
|
@@ -421,18 +439,10 @@ function printCreateIssue(err) {
|
|
|
421
439
|
if (!err.config)
|
|
422
440
|
return;
|
|
423
441
|
const time = new Date().toUTCString();
|
|
424
|
-
const {
|
|
442
|
+
const { body, url, baseURL, method } = err?.config || {};
|
|
425
443
|
console.log('```js');
|
|
426
|
-
console.log({
|
|
444
|
+
console.log({ body: body?.replace(/"(tstmt_[^"]+)"/g, 'tstmt_*'), url, baseURL, method, time });
|
|
427
445
|
console.log('```');
|
|
428
446
|
});
|
|
429
447
|
}
|
|
430
|
-
const axiosAddTestrunRequestConfig = {
|
|
431
|
-
maxContentLength: Infinity,
|
|
432
|
-
maxBodyLength: Infinity,
|
|
433
|
-
headers: {
|
|
434
|
-
// Overwrite Axios's automatically set Content-Type
|
|
435
|
-
'Content-Type': 'application/json',
|
|
436
|
-
},
|
|
437
|
-
};
|
|
438
448
|
module.exports = TestomatioPipe;
|
package/lib/reporter.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type log = typeof import("./reporter-functions.js");
|
|
|
8
8
|
export const log: (...args: any[]) => void;
|
|
9
9
|
export type logger = typeof import("./services/index.js");
|
|
10
10
|
export const logger: {
|
|
11
|
-
"__#
|
|
11
|
+
"__#13@#originalUserLogger": {
|
|
12
12
|
assert(condition?: boolean, ...data: any[]): void;
|
|
13
13
|
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
|
14
14
|
clear(): void;
|
|
@@ -53,13 +53,13 @@ export const logger: {
|
|
|
53
53
|
profile(label?: string): void;
|
|
54
54
|
profileEnd(label?: string): void;
|
|
55
55
|
};
|
|
56
|
-
"__#
|
|
56
|
+
"__#13@#userLoggerWithOverridenMethods": any;
|
|
57
57
|
logLevel: string;
|
|
58
58
|
step(strings: any, ...values: any[]): void;
|
|
59
59
|
getLogs(context: string): string[];
|
|
60
|
-
"__#
|
|
60
|
+
"__#13@#stringifyLogs"(...args: any[]): string;
|
|
61
61
|
_templateLiteralLog(strings: any, ...args: any[]): void;
|
|
62
|
-
"__#
|
|
62
|
+
"__#13@#logWrapper"(argsArray: any, level: any): void;
|
|
63
63
|
assert(...args: any[]): void;
|
|
64
64
|
debug(...args: any[]): void;
|
|
65
65
|
error(...args: any[]): void;
|
|
@@ -83,7 +83,7 @@ export type step = typeof import("./reporter-functions.js");
|
|
|
83
83
|
export const step: (message: string) => void;
|
|
84
84
|
declare namespace _default {
|
|
85
85
|
let testomatioLogger: {
|
|
86
|
-
"__#
|
|
86
|
+
"__#13@#originalUserLogger": {
|
|
87
87
|
assert(condition?: boolean, ...data: any[]): void;
|
|
88
88
|
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
|
89
89
|
clear(): void;
|
|
@@ -128,13 +128,13 @@ declare namespace _default {
|
|
|
128
128
|
profile(label?: string): void;
|
|
129
129
|
profileEnd(label?: string): void;
|
|
130
130
|
};
|
|
131
|
-
"__#
|
|
131
|
+
"__#13@#userLoggerWithOverridenMethods": any;
|
|
132
132
|
logLevel: string;
|
|
133
133
|
step(strings: any, ...values: any[]): void;
|
|
134
134
|
getLogs(context: string): string[];
|
|
135
|
-
"__#
|
|
135
|
+
"__#13@#stringifyLogs"(...args: any[]): string;
|
|
136
136
|
_templateLiteralLog(strings: any, ...args: any[]): void;
|
|
137
|
-
"__#
|
|
137
|
+
"__#13@#logWrapper"(argsArray: any, level: any): void;
|
|
138
138
|
assert(...args: any[]): void;
|
|
139
139
|
debug(...args: any[]): void;
|
|
140
140
|
error(...args: any[]): void;
|
|
@@ -157,7 +157,7 @@ declare namespace _default {
|
|
|
157
157
|
}, context?: any) => void;
|
|
158
158
|
let log: (...args: any[]) => void;
|
|
159
159
|
let logger: {
|
|
160
|
-
"__#
|
|
160
|
+
"__#13@#originalUserLogger": {
|
|
161
161
|
assert(condition?: boolean, ...data: any[]): void;
|
|
162
162
|
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
|
163
163
|
clear(): void;
|
|
@@ -202,13 +202,13 @@ declare namespace _default {
|
|
|
202
202
|
profile(label?: string): void;
|
|
203
203
|
profileEnd(label?: string): void;
|
|
204
204
|
};
|
|
205
|
-
"__#
|
|
205
|
+
"__#13@#userLoggerWithOverridenMethods": any;
|
|
206
206
|
logLevel: string;
|
|
207
207
|
step(strings: any, ...values: any[]): void;
|
|
208
208
|
getLogs(context: string): string[];
|
|
209
|
-
"__#
|
|
209
|
+
"__#13@#stringifyLogs"(...args: any[]): string;
|
|
210
210
|
_templateLiteralLog(strings: any, ...args: any[]): void;
|
|
211
|
-
"__#
|
|
211
|
+
"__#13@#logWrapper"(argsArray: any, level: any): void;
|
|
212
212
|
assert(...args: any[]): void;
|
|
213
213
|
debug(...args: any[]): void;
|
|
214
214
|
error(...args: any[]): void;
|
package/lib/services/logger.d.ts
CHANGED
package/lib/utils/utils.d.ts
CHANGED
package/lib/utils/utils.js
CHANGED
|
@@ -36,8 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp =
|
|
40
|
-
exports.getPackageVersion = getPackageVersion;
|
|
39
|
+
exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = void 0;
|
|
41
40
|
exports.formatStep = formatStep;
|
|
42
41
|
exports.readLatestRunId = readLatestRunId;
|
|
43
42
|
exports.removeColorCodes = removeColorCodes;
|
|
@@ -49,9 +48,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
49
48
|
const is_valid_path_1 = __importDefault(require("is-valid-path"));
|
|
50
49
|
const debug_1 = __importDefault(require("debug"));
|
|
51
50
|
const os_1 = __importDefault(require("os"));
|
|
52
|
-
const url_2 = require("url");
|
|
53
51
|
const debug = (0, debug_1.default)('@testomatio/reporter:util');
|
|
54
|
-
// Use __dirname directly since we're compiling to CommonJS
|
|
55
52
|
/**
|
|
56
53
|
* @param {String} testTitle - Test title
|
|
57
54
|
*
|
|
@@ -143,7 +140,7 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
|
|
|
143
140
|
.join('\n');
|
|
144
141
|
};
|
|
145
142
|
exports.fetchSourceCodeFromStackTrace = fetchSourceCodeFromStackTrace;
|
|
146
|
-
|
|
143
|
+
const TEST_ID_REGEX = /@T([\w\d]{8})/;
|
|
147
144
|
const fetchIdFromCode = (code, opts = {}) => {
|
|
148
145
|
const comments = code
|
|
149
146
|
.split('\n')
|
|
@@ -157,11 +154,11 @@ const fetchIdFromCode = (code, opts = {}) => {
|
|
|
157
154
|
return l.startsWith('// ');
|
|
158
155
|
}
|
|
159
156
|
});
|
|
160
|
-
return comments.find(c => c.match(
|
|
157
|
+
return comments.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
|
|
161
158
|
};
|
|
162
159
|
exports.fetchIdFromCode = fetchIdFromCode;
|
|
163
160
|
const fetchIdFromOutput = output => {
|
|
164
|
-
const TID_FULL_PATTERN = new RegExp(`tid:\\/\\/.*?(${
|
|
161
|
+
const TID_FULL_PATTERN = new RegExp(`tid:\\/\\/.*?(${TEST_ID_REGEX.source})`);
|
|
165
162
|
return output.match(TID_FULL_PATTERN)?.[2];
|
|
166
163
|
};
|
|
167
164
|
exports.fetchIdFromOutput = fetchIdFromOutput;
|
|
@@ -186,12 +183,6 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
186
183
|
if (lineIndex === -1)
|
|
187
184
|
lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
188
185
|
}
|
|
189
|
-
else if (opts.lang === 'csharp') {
|
|
190
|
-
if (lineIndex === -1)
|
|
191
|
-
lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
|
|
192
|
-
if (lineIndex === -1)
|
|
193
|
-
lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
194
|
-
}
|
|
195
186
|
else {
|
|
196
187
|
lineIndex = lines.findIndex(l => l.includes(title));
|
|
197
188
|
}
|
|
@@ -393,13 +384,6 @@ function formatStep(step, shift = 0) {
|
|
|
393
384
|
}
|
|
394
385
|
return lines;
|
|
395
386
|
}
|
|
396
|
-
function getPackageVersion() {
|
|
397
|
-
const packageJsonPath = path_1.default.resolve(__dirname, '../../package.json');
|
|
398
|
-
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
|
|
399
|
-
return packageJson.version;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
module.exports.getPackageVersion = getPackageVersion;
|
|
403
387
|
|
|
404
388
|
module.exports.formatStep = formatStep;
|
|
405
389
|
|
package/lib/xmlReader.js
CHANGED
|
@@ -20,7 +20,7 @@ const uploader_js_1 = require("./uploader.js");
|
|
|
20
20
|
const debug = (0, debug_1.default)('@testomatio/reporter:xml');
|
|
21
21
|
const ridRunId = (0, crypto_1.randomUUID)();
|
|
22
22
|
const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
|
|
23
|
-
const { TESTOMATIO_RUNGROUP_TITLE,
|
|
23
|
+
const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED } = process.env;
|
|
24
24
|
const options = {
|
|
25
25
|
ignoreDeclaration: true,
|
|
26
26
|
ignoreAttributes: false,
|
|
@@ -28,7 +28,6 @@ const options = {
|
|
|
28
28
|
attributeNamePrefix: '',
|
|
29
29
|
parseTagValue: true,
|
|
30
30
|
};
|
|
31
|
-
const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
|
|
32
31
|
const reduceOptions = {};
|
|
33
32
|
class XmlReader {
|
|
34
33
|
constructor(opts = {}) {
|
|
@@ -76,7 +75,7 @@ class XmlReader {
|
|
|
76
75
|
/(<system-out><!\[CDATA\[)([\s\S]*?)(\]\]><\/system-out>)/g,
|
|
77
76
|
];
|
|
78
77
|
for (const regex of cutRegexes) {
|
|
79
|
-
xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0,
|
|
78
|
+
xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, 5000)}${p3}`);
|
|
80
79
|
}
|
|
81
80
|
const jsonResult = this.parser.parse(xmlData);
|
|
82
81
|
let jsonSuite;
|
|
@@ -314,8 +313,6 @@ class XmlReader {
|
|
|
314
313
|
this.stats.language = 'js';
|
|
315
314
|
if (file.endsWith('.ts'))
|
|
316
315
|
this.stats.language = 'ts';
|
|
317
|
-
if (file.endsWith('.cs'))
|
|
318
|
-
this.stats.language = 'csharp';
|
|
319
316
|
}
|
|
320
317
|
if (!fs_1.default.existsSync(file)) {
|
|
321
318
|
debug('Failed to open file with the source code', file);
|
|
@@ -362,13 +359,13 @@ class XmlReader {
|
|
|
362
359
|
async uploadArtifacts() {
|
|
363
360
|
for (const test of this.tests.filter(t => !!t.stack)) {
|
|
364
361
|
let files = [];
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
files =
|
|
362
|
+
if (test.files?.length)
|
|
363
|
+
files = test.files.map(f => path_1.default.join(process.cwd(), f));
|
|
364
|
+
files = [...files, ...(0, utils_js_1.fetchFilesFromStackTrace)(test.stack)];
|
|
368
365
|
if (!files.length)
|
|
369
366
|
continue;
|
|
370
367
|
const runId = this.runId || this.store.runId || Date.now().toString();
|
|
371
|
-
test.artifacts = await Promise.all(files.map(f => this.uploader.uploadFileByPath(f, [runId
|
|
368
|
+
test.artifacts = await Promise.all(files.map(f => this.uploader.uploadFileByPath(f, [runId])));
|
|
372
369
|
console.log(constants_js_1.APP_PREFIX, `🗄️ Uploaded ${picocolors_1.default.bold(`${files.length} artifacts`)} for test ${test.title}`);
|
|
373
370
|
}
|
|
374
371
|
}
|
|
@@ -428,7 +425,7 @@ function reduceTestCases(prev, item) {
|
|
|
428
425
|
testCases
|
|
429
426
|
.filter(t => !!t)
|
|
430
427
|
.forEach(testCaseItem => {
|
|
431
|
-
const file = testCaseItem.file || item.filepath ||
|
|
428
|
+
const file = testCaseItem.file || item.filepath || '';
|
|
432
429
|
let stack = '';
|
|
433
430
|
let message = '';
|
|
434
431
|
if (testCaseItem.error)
|
|
@@ -461,34 +458,15 @@ function reduceTestCases(prev, item) {
|
|
|
461
458
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
462
459
|
}
|
|
463
460
|
stack = `${testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
|
|
464
|
-
|
|
465
|
-
if (tags?.length && !testId) {
|
|
466
|
-
testId = tags.filter(t => t.startsWith('T')).map(t => `@${t}`).find(t => t.match(utils_js_1.TEST_ID_REGEX))?.slice(2);
|
|
467
|
-
}
|
|
461
|
+
const testId = (0, utils_js_1.fetchIdFromOutput)(stack);
|
|
468
462
|
let status = constants_js_1.STATUS.PASSED.toString();
|
|
469
463
|
if ('failure' in testCaseItem || 'error' in testCaseItem)
|
|
470
464
|
status = constants_js_1.STATUS.FAILED;
|
|
471
465
|
if ('skipped' in testCaseItem)
|
|
472
466
|
status = constants_js_1.STATUS.SKIPPED;
|
|
473
|
-
if (testCaseItem.result && Object.values(constants_js_1.STATUS).includes(testCaseItem.result.toLowerCase())) {
|
|
474
|
-
status = testCaseItem.result.toLowerCase();
|
|
475
|
-
}
|
|
476
467
|
let rid = null;
|
|
477
468
|
if (testCaseItem.id)
|
|
478
469
|
rid = `${ridRunId}-${testCaseItem.id}`;
|
|
479
|
-
// Extract attachments
|
|
480
|
-
let files = [];
|
|
481
|
-
if (testCaseItem.attachments) {
|
|
482
|
-
const attachments = Array.isArray(testCaseItem.attachments.attachment)
|
|
483
|
-
? testCaseItem.attachments.attachment
|
|
484
|
-
: [testCaseItem.attachments.attachment];
|
|
485
|
-
files = attachments
|
|
486
|
-
.filter(a => a && a.filePath)
|
|
487
|
-
.map(a => a.filePath);
|
|
488
|
-
}
|
|
489
|
-
// Extract files from stack trace using existing utility
|
|
490
|
-
const stackFiles = (0, utils_js_1.fetchFilesFromStackTrace)(stack);
|
|
491
|
-
files = [...new Set([...files, ...stackFiles])]; // Remove duplicates
|
|
492
470
|
prev.push({
|
|
493
471
|
rid,
|
|
494
472
|
file,
|
|
@@ -503,9 +481,7 @@ function reduceTestCases(prev, item) {
|
|
|
503
481
|
run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
|
|
504
482
|
status,
|
|
505
483
|
title,
|
|
506
|
-
root_suite_id: TESTOMATIO_SUITE,
|
|
507
484
|
suite_title: suiteTitle,
|
|
508
|
-
files,
|
|
509
485
|
});
|
|
510
486
|
});
|
|
511
487
|
return prev;
|
|
@@ -529,14 +505,11 @@ function fetchProperties(item) {
|
|
|
529
505
|
let title = '';
|
|
530
506
|
if (!item.properties)
|
|
531
507
|
return {};
|
|
532
|
-
|
|
533
|
-
const properties = Array.isArray(item.properties.property)
|
|
534
|
-
? item.properties.property
|
|
535
|
-
: [item.properties.property].filter(Boolean);
|
|
536
|
-
const prop = properties.find(p => p.name === 'Description');
|
|
508
|
+
const prop = [item.properties?.property].flat().find(p => p.name === 'Description');
|
|
537
509
|
if (prop)
|
|
538
510
|
title = prop.value;
|
|
539
|
-
properties
|
|
511
|
+
[item.properties?.property]
|
|
512
|
+
.flat()
|
|
540
513
|
.filter(p => p.name === 'Category')
|
|
541
514
|
.forEach(p => tags.push(p.value));
|
|
542
515
|
return { title, tags };
|