@testomatio/reporter 2.0.0-beta-esm → 2.0.0-beta.1-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/codecept.d.ts +2 -0
- package/lib/adapter/codecept.js +31 -26
- package/lib/adapter/cucumber/current.d.ts +14 -0
- package/lib/adapter/cucumber/legacy.d.ts +0 -0
- package/lib/adapter/cucumber.d.ts +2 -0
- package/lib/adapter/cypress-plugin/index.d.ts +2 -0
- package/lib/adapter/cypress-plugin/index.js +10 -10
- package/lib/adapter/jasmine.d.ts +11 -0
- package/lib/adapter/jest.d.ts +13 -0
- package/lib/adapter/mocha.d.ts +2 -0
- package/lib/adapter/mocha.js +4 -4
- package/lib/adapter/nightwatch.d.ts +4 -0
- package/lib/adapter/nightwatch.js +80 -0
- package/lib/adapter/playwright.d.ts +14 -0
- package/lib/adapter/playwright.js +58 -33
- package/lib/adapter/vitest.d.ts +35 -0
- package/lib/adapter/vitest.js +6 -6
- package/lib/adapter/webdriver.d.ts +24 -0
- package/lib/adapter/webdriver.js +51 -14
- package/lib/bin/cli.d.ts +2 -0
- package/lib/bin/cli.js +250 -0
- package/lib/bin/reportXml.d.ts +2 -0
- package/lib/bin/reportXml.js +15 -11
- package/lib/bin/startTest.d.ts +2 -0
- package/lib/bin/startTest.js +12 -7
- package/lib/bin/uploadArtifacts.d.ts +2 -0
- package/lib/bin/uploadArtifacts.js +82 -0
- package/lib/client.d.ts +76 -0
- package/lib/client.js +128 -53
- package/lib/config.d.ts +1 -0
- package/lib/config.js +2 -2
- package/lib/constants.d.ts +25 -0
- package/lib/constants.js +5 -1
- package/lib/data-storage.d.ts +34 -0
- package/lib/data-storage.js +19 -9
- package/lib/junit-adapter/adapter.d.ts +9 -0
- package/lib/junit-adapter/csharp.d.ts +5 -0
- package/lib/junit-adapter/csharp.js +11 -1
- package/lib/junit-adapter/index.d.ts +3 -0
- package/lib/junit-adapter/java.d.ts +5 -0
- package/lib/junit-adapter/javascript.d.ts +4 -0
- package/lib/junit-adapter/python.d.ts +5 -0
- package/lib/junit-adapter/ruby.d.ts +4 -0
- package/lib/output.d.ts +11 -0
- package/lib/package.json +3 -1
- package/lib/pipe/bitbucket.d.ts +23 -0
- package/lib/pipe/bitbucket.js +19 -9
- package/lib/pipe/csv.d.ts +47 -0
- package/lib/pipe/csv.js +2 -2
- package/lib/pipe/debug.d.ts +29 -0
- package/lib/pipe/debug.js +108 -0
- package/lib/pipe/github.d.ts +30 -0
- package/lib/pipe/github.js +37 -5
- package/lib/pipe/gitlab.d.ts +23 -0
- package/lib/pipe/gitlab.js +2 -3
- package/lib/pipe/html.d.ts +35 -0
- package/lib/pipe/html.js +9 -4
- package/lib/pipe/index.d.ts +1 -0
- package/lib/pipe/index.js +20 -10
- package/lib/pipe/testomatio.d.ts +70 -0
- package/lib/pipe/testomatio.js +54 -39
- package/lib/reporter-functions.d.ts +34 -0
- package/lib/reporter-functions.js +17 -7
- package/lib/reporter.d.ts +232 -0
- package/lib/reporter.js +19 -33
- package/lib/services/artifacts.d.ts +33 -0
- package/lib/services/index.d.ts +9 -0
- package/lib/services/key-values.d.ts +27 -0
- package/lib/services/key-values.js +1 -1
- package/lib/services/logger.d.ts +64 -0
- package/lib/services/logger.js +1 -2
- package/lib/template/testomatio.hbs +651 -1366
- package/lib/uploader.d.ts +60 -0
- package/lib/uploader.js +312 -0
- package/lib/utils/pipe_utils.d.ts +41 -0
- package/lib/utils/pipe_utils.js +3 -5
- package/lib/utils/utils.d.ts +47 -0
- package/lib/utils/utils.js +99 -12
- package/lib/xmlReader.d.ts +92 -0
- package/lib/xmlReader.js +64 -25
- package/package.json +19 -13
- package/src/adapter/codecept.js +30 -26
- package/src/adapter/cypress-plugin/index.js +5 -5
- package/src/adapter/mocha.cjs +1 -1
- package/src/adapter/mocha.js +4 -4
- package/src/adapter/nightwatch.js +88 -0
- package/src/adapter/playwright.js +59 -31
- package/src/adapter/vitest.js +6 -6
- package/src/adapter/webdriver.js +42 -12
- package/src/bin/cli.js +303 -0
- package/src/bin/reportXml.js +19 -9
- package/src/bin/startTest.js +9 -4
- package/src/bin/uploadArtifacts.js +91 -0
- package/src/client.js +137 -57
- package/src/config.js +2 -2
- package/src/constants.js +5 -1
- package/src/data-storage.js +2 -2
- package/src/junit-adapter/csharp.js +13 -1
- package/src/pipe/bitbucket.js +2 -2
- package/src/pipe/csv.js +3 -3
- package/src/pipe/debug.js +104 -0
- package/src/pipe/github.js +3 -5
- package/src/pipe/gitlab.js +6 -7
- package/src/pipe/html.js +14 -7
- package/src/pipe/index.js +5 -7
- package/src/pipe/testomatio.js +75 -76
- package/src/reporter-functions.js +18 -7
- package/src/reporter.cjs_decprecated +21 -0
- package/src/reporter.js +20 -11
- package/src/services/key-values.js +1 -1
- package/src/services/logger.js +5 -4
- package/src/template/testomatio.hbs +651 -1366
- package/src/uploader.js +371 -0
- package/src/utils/pipe_utils.js +4 -12
- package/src/utils/utils.js +64 -15
- package/src/xmlReader.js +76 -26
- package/lib/adapter/jasmine/jasmine.js +0 -63
- package/lib/adapter/mocha/mocha.js +0 -125
- package/lib/fileUploader.js +0 -245
- package/lib/utils/chalk.js +0 -10
- package/src/fileUploader.js +0 -307
- package/src/reporter.cjs +0 -22
- package/src/utils/chalk.js +0 -13
package/lib/client.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
@@ -33,32 +43,33 @@ const minimatch_1 = require("minimatch");
|
|
|
33
43
|
const fs_1 = __importDefault(require("fs"));
|
|
34
44
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
35
45
|
const crypto_1 = require("crypto");
|
|
36
|
-
const fileUploader_js_1 = require("./fileUploader.js");
|
|
37
46
|
const constants_js_1 = require("./constants.js");
|
|
38
47
|
const index_js_1 = require("./pipe/index.js");
|
|
39
48
|
const glob_1 = require("glob");
|
|
40
49
|
const path_1 = __importStar(require("path"));
|
|
41
50
|
const node_url_1 = require("node:url");
|
|
51
|
+
const uploader_js_1 = require("./uploader.js");
|
|
52
|
+
const utils_js_1 = require("./utils/utils.js");
|
|
53
|
+
const filesize_1 = require("filesize");
|
|
42
54
|
const debug = (0, debug_1.default)('@testomatio/reporter:client');
|
|
43
55
|
// removed __dirname usage, because:
|
|
44
56
|
// 1. replaced with ESM syntax (import.meta.url), but it throws an error on tsc compilation;
|
|
45
|
-
// 2. got error "__dirname already defined" in compiles js code (cjs dir)
|
|
57
|
+
// 2. got error "__dirname already defined" in compiles js code (cjs dir)
|
|
46
58
|
let listOfTestFilesToExcludeFromReport = null;
|
|
47
59
|
/**
|
|
48
|
-
* @typedef {import('../types').TestData} TestData
|
|
49
|
-
* @typedef {import('../types').PipeResult} PipeResult
|
|
60
|
+
* @typedef {import('../types/types.js').TestData} TestData
|
|
61
|
+
* @typedef {import('../types/types.js').PipeResult} PipeResult
|
|
50
62
|
*/
|
|
51
63
|
class Client {
|
|
52
64
|
/**
|
|
53
65
|
* Create a Testomat client instance
|
|
54
66
|
* @returns
|
|
55
67
|
*/
|
|
56
|
-
// eslint-disable-next-line
|
|
57
68
|
constructor(params = {}) {
|
|
58
|
-
this.
|
|
69
|
+
this.paramsForPipesFactory = params;
|
|
70
|
+
this.pipeStore = {};
|
|
71
|
+
this.runId = (0, crypto_1.randomUUID)(); // will be replaced by real run id
|
|
59
72
|
this.queue = Promise.resolve();
|
|
60
|
-
this.totalUploaded = 0;
|
|
61
|
-
this.failedToUpload = 0;
|
|
62
73
|
// @ts-ignore this line will be removed in compiled code, because __dirname is defined in commonjs
|
|
63
74
|
const pathToPackageJSON = path_1.default.join(__dirname, '../package.json');
|
|
64
75
|
try {
|
|
@@ -69,6 +80,7 @@ class Client {
|
|
|
69
80
|
// do nothing
|
|
70
81
|
}
|
|
71
82
|
this.executionList = Promise.resolve();
|
|
83
|
+
this.uploader = new uploader_js_1.S3Uploader();
|
|
72
84
|
}
|
|
73
85
|
/**
|
|
74
86
|
* Asynchronously prepares the execution list for running tests through various pipes.
|
|
@@ -87,8 +99,7 @@ class Client {
|
|
|
87
99
|
* or resolves to undefined if no valid results are found or if all pipes are disabled.
|
|
88
100
|
*/
|
|
89
101
|
async prepareRun(params) {
|
|
90
|
-
|
|
91
|
-
this.pipes = await (0, index_js_1.pipesFactory)(params, store);
|
|
102
|
+
this.pipes = await (0, index_js_1.pipesFactory)(params || this.paramsForPipesFactory || {}, this.pipeStore);
|
|
92
103
|
const { pipe, pipeOptions } = params;
|
|
93
104
|
// all pipes disabled, skipping
|
|
94
105
|
if (!this.pipes.some(p => p.isEnabled)) {
|
|
@@ -96,7 +107,7 @@ class Client {
|
|
|
96
107
|
}
|
|
97
108
|
try {
|
|
98
109
|
const filterPipe = this.pipes.find(p => p.constructor.name.toLowerCase() === `${pipe.toLowerCase()}pipe`);
|
|
99
|
-
if (!filterPipe
|
|
110
|
+
if (!filterPipe?.isEnabled) {
|
|
100
111
|
// TODO:for the future for the another pipes
|
|
101
112
|
console.warn(constants_js_1.APP_PREFIX, `At the moment processing is available only for the "testomatio" key. Example: "testomatio:tag-name=xxx"`);
|
|
102
113
|
return;
|
|
@@ -120,7 +131,7 @@ class Client {
|
|
|
120
131
|
*/
|
|
121
132
|
async createRun(params) {
|
|
122
133
|
if (!this.pipes || !this.pipes.length)
|
|
123
|
-
this.pipes = await (0, index_js_1.pipesFactory)(params || {},
|
|
134
|
+
this.pipes = await (0, index_js_1.pipesFactory)(params || this.paramsForPipesFactory || {}, this.pipeStore);
|
|
124
135
|
debug('Creating run...');
|
|
125
136
|
// all pipes disabled, skipping
|
|
126
137
|
if (!this.pipes?.filter(p => p.isEnabled).length)
|
|
@@ -128,6 +139,13 @@ class Client {
|
|
|
128
139
|
this.queue = this.queue
|
|
129
140
|
.then(() => Promise.all(this.pipes.map(p => p.createRun())))
|
|
130
141
|
.catch(err => console.log(constants_js_1.APP_PREFIX, err))
|
|
142
|
+
.then(() => {
|
|
143
|
+
const runId = this.pipeStore?.runId;
|
|
144
|
+
if (runId)
|
|
145
|
+
this.runId = runId;
|
|
146
|
+
(0, utils_js_1.storeRunId)(this.runId);
|
|
147
|
+
})
|
|
148
|
+
.then(() => this.uploader.checkEnabled())
|
|
131
149
|
.then(() => undefined); // fixes return type
|
|
132
150
|
// debug('Run', this.queue);
|
|
133
151
|
return this.queue;
|
|
@@ -157,8 +175,45 @@ class Client {
|
|
|
157
175
|
/**
|
|
158
176
|
* @type {TestData}
|
|
159
177
|
*/
|
|
160
|
-
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, manuallyAttachedArtifacts,
|
|
161
|
-
let { message = '' } = testData;
|
|
178
|
+
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, manuallyAttachedArtifacts, } = testData;
|
|
179
|
+
let { message = '', meta = {} } = testData;
|
|
180
|
+
// stringify meta values and limit keys and values length to 255
|
|
181
|
+
meta = Object.entries(meta)
|
|
182
|
+
.filter(([, value]) => value !== null && value !== undefined)
|
|
183
|
+
.map(([key, value]) => {
|
|
184
|
+
try {
|
|
185
|
+
if (typeof value === 'object') {
|
|
186
|
+
value = JSON.stringify(value);
|
|
187
|
+
}
|
|
188
|
+
else if (typeof value !== 'string') {
|
|
189
|
+
try {
|
|
190
|
+
value = value.toString();
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.warn(constants_js_1.APP_PREFIX, `Can't convert meta value to string`, err);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (value?.length > 255) {
|
|
197
|
+
value = value.substring(0, 255);
|
|
198
|
+
debug(constants_js_1.APP_PREFIX, `Meta info value "${value}" is too long, trimmed to 255 characters`);
|
|
199
|
+
}
|
|
200
|
+
if (key?.length > 255) {
|
|
201
|
+
const newKey = key.substring(0, 255);
|
|
202
|
+
debug(constants_js_1.APP_PREFIX, `Meta info key "${key}" is too long, trimmed to 255 characters`);
|
|
203
|
+
return [newKey, value];
|
|
204
|
+
}
|
|
205
|
+
return [key, value];
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
debug(constants_js_1.APP_PREFIX, `Error while processing meta info key ${key}`, err);
|
|
209
|
+
return [null, null];
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
.reduce((acc, [key, value]) => {
|
|
213
|
+
if (key)
|
|
214
|
+
acc[key] = value;
|
|
215
|
+
return acc;
|
|
216
|
+
}, {});
|
|
162
217
|
let errorFormatted = '';
|
|
163
218
|
if (error) {
|
|
164
219
|
errorFormatted += this.formatError(error) || '';
|
|
@@ -170,19 +225,21 @@ class Client {
|
|
|
170
225
|
if (manuallyAttachedArtifacts?.length)
|
|
171
226
|
files.push(...manuallyAttachedArtifacts);
|
|
172
227
|
const uploadedFiles = [];
|
|
173
|
-
for (
|
|
174
|
-
|
|
228
|
+
for (let f of files) {
|
|
229
|
+
if (!f)
|
|
230
|
+
continue; // f === null
|
|
231
|
+
if (typeof f === 'object') {
|
|
232
|
+
if (!f.path)
|
|
233
|
+
continue;
|
|
234
|
+
f = f.path;
|
|
235
|
+
}
|
|
236
|
+
uploadedFiles.push(this.uploader.uploadFileByPath(f, [this.runId, rid, path_1.default.basename(f)]));
|
|
175
237
|
}
|
|
176
238
|
for (const [idx, buffer] of filesBuffers.entries()) {
|
|
177
239
|
const fileName = `${idx + 1}-${title.replace(/\s+/g, '-')}`;
|
|
178
|
-
uploadedFiles.push(
|
|
240
|
+
uploadedFiles.push(this.uploader.uploadFileAsBuffer(buffer, [this.runId, rid, fileName]));
|
|
179
241
|
}
|
|
180
242
|
const artifacts = (await Promise.all(uploadedFiles)).filter(n => !!n);
|
|
181
|
-
if (artifacts.length < uploadedFiles.length) {
|
|
182
|
-
const failedUploading = uploadedFiles.length - artifacts.length;
|
|
183
|
-
this.failedToUpload += failedUploading;
|
|
184
|
-
}
|
|
185
|
-
this.totalUploaded += artifacts.length;
|
|
186
243
|
const data = {
|
|
187
244
|
rid,
|
|
188
245
|
files,
|
|
@@ -232,15 +289,47 @@ class Client {
|
|
|
232
289
|
this.queue = this.queue
|
|
233
290
|
.then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
|
|
234
291
|
.then(() => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (this.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
292
|
+
if (!this.uploader.isEnabled)
|
|
293
|
+
return;
|
|
294
|
+
const filesizeStrMaxLength = 7;
|
|
295
|
+
if (this.uploader.successfulUploads.length) {
|
|
296
|
+
debug('\n', constants_js_1.APP_PREFIX, `🗄️ ${this.uploader.successfulUploads.length} artifacts uploaded to S3 bucket`);
|
|
297
|
+
const uploadedArtifacts = this.uploader.successfulUploads.map(file => ({
|
|
298
|
+
relativePath: file.path.replace(process.cwd(), ''),
|
|
299
|
+
link: file.link,
|
|
300
|
+
sizePretty: (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
301
|
+
}));
|
|
302
|
+
uploadedArtifacts.forEach(upload => {
|
|
303
|
+
debug(`🟢Uploaded artifact`, `${upload.relativePath},`, 'size:', `${upload.sizePretty},`, 'link:', `${upload.link}`);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (this.uploader.failedUploads.length) {
|
|
307
|
+
console.log(constants_js_1.APP_PREFIX, `🗄️ ${this.uploader.failedUploads.length} artifacts 🔴${picocolors_1.default.bold('failed')} to upload`);
|
|
308
|
+
const failedUploads = this.uploader.failedUploads.map(file => ({
|
|
309
|
+
relativePath: file.path.replace(process.cwd(), ''),
|
|
310
|
+
sizePretty: (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
311
|
+
}));
|
|
312
|
+
const pathPadding = Math.max(...failedUploads.map(upload => upload.relativePath.length)) + 1;
|
|
313
|
+
failedUploads.forEach(upload => {
|
|
314
|
+
console.log(` ${picocolors_1.default.gray('|')} 🔴 ${upload.relativePath.padEnd(pathPadding)} ${picocolors_1.default.gray(`| ${upload.sizePretty.padStart(filesizeStrMaxLength)} |`)}`);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (this.uploader.skippedUploads.length) {
|
|
318
|
+
console.log('\n', constants_js_1.APP_PREFIX, `🗄️ ${picocolors_1.default.bold(this.uploader.skippedUploads.length)} artifacts uploading 🟡${picocolors_1.default.bold('skipped')}`);
|
|
319
|
+
const skippedUploads = this.uploader.skippedUploads.map(file => ({
|
|
320
|
+
relativePath: file.path.replace(process.cwd(), ''),
|
|
321
|
+
sizePretty: file.size === null ? 'unknown' : (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
322
|
+
}));
|
|
323
|
+
const pathPadding = Math.max(...skippedUploads.map(upload => upload.relativePath.length)) + 1;
|
|
324
|
+
skippedUploads.forEach(upload => {
|
|
325
|
+
console.log(` ${picocolors_1.default.gray('|')} 🟡 ${upload.relativePath.padEnd(pathPadding)} ${picocolors_1.default.gray(`| ${upload.sizePretty.padStart(filesizeStrMaxLength)} |`)}`);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
if (this.uploader.skippedUploads.length || this.uploader.failedUploads.length) {
|
|
329
|
+
const command = `TESTOMATIO=<your_api_key> TESTOMATIO_RUN=${this.runId} npx @testomatio/reporter upload-artifacts`;
|
|
330
|
+
const numberOfNotUploadedArtifacts = this.uploader.skippedUploads.length + this.uploader.failedUploads.length;
|
|
331
|
+
console.log(constants_js_1.APP_PREFIX, `${numberOfNotUploadedArtifacts} artifacts were not uploaded.
|
|
332
|
+
Run "${picocolors_1.default.magenta(command)}" with valid S3 credentials to upload skipped & failed artifacts`);
|
|
244
333
|
}
|
|
245
334
|
})
|
|
246
335
|
.catch(err => console.log(constants_js_1.APP_PREFIX, err));
|
|
@@ -255,7 +344,7 @@ class Client {
|
|
|
255
344
|
logs = logs?.trim();
|
|
256
345
|
if (Array.isArray(steps)) {
|
|
257
346
|
steps = steps
|
|
258
|
-
.map(step => formatStep(step))
|
|
347
|
+
.map(step => (0, utils_js_1.formatStep)(step))
|
|
259
348
|
.flat()
|
|
260
349
|
.join('\n');
|
|
261
350
|
}
|
|
@@ -327,20 +416,6 @@ function isNotInternalFrame(frame) {
|
|
|
327
416
|
!frame.getFileName().includes('node_modules') &&
|
|
328
417
|
!frame.getFileName().includes('internal'));
|
|
329
418
|
}
|
|
330
|
-
function formatStep(step, shift = 0) {
|
|
331
|
-
const prefix = ' '.repeat(shift);
|
|
332
|
-
const lines = [];
|
|
333
|
-
if (step.error) {
|
|
334
|
-
lines.push(`${prefix}${picocolors_1.default.red(step.title)} ${picocolors_1.default.gray(`${step.duration}ms`)}`);
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
lines.push(`${prefix}${step.title} ${picocolors_1.default.gray(`${step.duration}ms`)}`);
|
|
338
|
-
}
|
|
339
|
-
for (const child of step.steps || []) {
|
|
340
|
-
lines.push(...formatStep(child, shift + 2));
|
|
341
|
-
}
|
|
342
|
-
return lines;
|
|
343
|
-
}
|
|
344
419
|
/**
|
|
345
420
|
*
|
|
346
421
|
* @param {TestData} testData
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const config: NodeJS.ProcessEnv;
|
package/lib/config.js
CHANGED
|
@@ -9,10 +9,10 @@ const debug_1 = __importDefault(require("debug"));
|
|
|
9
9
|
const debug = (0, debug_1.default)('@testomatio/reporter:config');
|
|
10
10
|
/* for possibility to use multiple env files (reading different paths)
|
|
11
11
|
const envFileVars = dotenv.config({ path: '.env' }).parsed; */
|
|
12
|
-
if (process.env.TESTOMATIO_API_KEY) {
|
|
12
|
+
if (process.env.TESTOMATIO_API_KEY && !process.env.TESTOMATIO) {
|
|
13
13
|
process.env.TESTOMATIO = process.env.TESTOMATIO_API_KEY;
|
|
14
14
|
}
|
|
15
|
-
if (process.env.TESTOMATIO_TOKEN) {
|
|
15
|
+
if (process.env.TESTOMATIO_TOKEN && !process.env.TESTOMATIO) {
|
|
16
16
|
process.env.TESTOMATIO = process.env.TESTOMATIO_TOKEN;
|
|
17
17
|
}
|
|
18
18
|
if (process.env.TESTOMATIO === 'undefined')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const APP_PREFIX: string;
|
|
2
|
+
export const TESTOMAT_TMP_STORAGE_DIR: string;
|
|
3
|
+
export const CSV_HEADERS: {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
}[];
|
|
7
|
+
export namespace STATUS {
|
|
8
|
+
let PASSED: string;
|
|
9
|
+
let FAILED: string;
|
|
10
|
+
let SKIPPED: string;
|
|
11
|
+
let FINISHED: string;
|
|
12
|
+
}
|
|
13
|
+
export namespace HTML_REPORT {
|
|
14
|
+
let FOLDER: string;
|
|
15
|
+
let REPORT_DEFAULT_NAME: string;
|
|
16
|
+
let TEMPLATE_NAME: string;
|
|
17
|
+
}
|
|
18
|
+
export const AXIOS_TIMEOUT: number;
|
|
19
|
+
export const testomatLogoURL: "https://avatars.githubusercontent.com/u/59105116?s=36&v=4";
|
|
20
|
+
export namespace REPORTER_REQUEST_RETRIES {
|
|
21
|
+
let retryTimeout: number;
|
|
22
|
+
let retriesPerRequest: number;
|
|
23
|
+
let maxTotalRetries: number;
|
|
24
|
+
let withinTimeSeconds: number;
|
|
25
|
+
}
|
package/lib/constants.js
CHANGED
|
@@ -9,7 +9,11 @@ const os_1 = __importDefault(require("os"));
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const APP_PREFIX = picocolors_1.default.gray('[TESTOMATIO]');
|
|
11
11
|
exports.APP_PREFIX = APP_PREFIX;
|
|
12
|
-
const
|
|
12
|
+
const TESTOMATIO_REQUEST_TIMEOUT = parseInt(process.env.TESTOMATIO_REQUEST_TIMEOUT, 10);
|
|
13
|
+
if (TESTOMATIO_REQUEST_TIMEOUT) {
|
|
14
|
+
console.log(`${APP_PREFIX} Request timeout is set to ${TESTOMATIO_REQUEST_TIMEOUT / 1000}s`);
|
|
15
|
+
}
|
|
16
|
+
const AXIOS_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
|
|
13
17
|
exports.AXIOS_TIMEOUT = AXIOS_TIMEOUT;
|
|
14
18
|
const TESTOMAT_TMP_STORAGE_DIR = path_1.default.join(os_1.default.tmpdir(), 'testomatio_tmp');
|
|
15
19
|
exports.TESTOMAT_TMP_STORAGE_DIR = TESTOMAT_TMP_STORAGE_DIR;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const dataStorage: DataStorage;
|
|
2
|
+
declare class DataStorage {
|
|
3
|
+
static "__#11@#instance": any;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @returns {DataStorage}
|
|
7
|
+
*/
|
|
8
|
+
static getInstance(): DataStorage;
|
|
9
|
+
context: any;
|
|
10
|
+
setContext(context: any): void;
|
|
11
|
+
isFileStorage: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Puts any data to storage (file or global variable).
|
|
14
|
+
* If file: stores data as text, if global variable – stores as array of data.
|
|
15
|
+
* @param {'log' | 'artifact' | 'keyvalue'} dataType
|
|
16
|
+
* @param {*} data anything you want to store (string, object, array, etc)
|
|
17
|
+
* @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
|
|
18
|
+
* suite name + test name is used by default
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
putData(dataType: "log" | "artifact" | "keyvalue", data: any, context?: any): void;
|
|
22
|
+
/**
|
|
23
|
+
* Returns data, stored for specific test/context (or data which was stored without test id specified).
|
|
24
|
+
* This method will get data from global variable and/or from from file (previosly saved with put method).
|
|
25
|
+
*
|
|
26
|
+
* @param {'log' | 'artifact' | 'keyvalue'} dataType
|
|
27
|
+
* @param {string} context
|
|
28
|
+
* @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
|
|
29
|
+
*/
|
|
30
|
+
getData(dataType: "log" | "artifact" | "keyvalue", context: string): any[];
|
|
31
|
+
#private;
|
|
32
|
+
}
|
|
33
|
+
export function stringToMD5Hash(str: any): string;
|
|
34
|
+
export {};
|
package/lib/data-storage.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
@@ -76,7 +86,7 @@ class DataStorage {
|
|
|
76
86
|
return;
|
|
77
87
|
context = context || this.context || utils_js_1.testRunnerHelper.getNameOfCurrentlyRunningTest();
|
|
78
88
|
if (!context) {
|
|
79
|
-
debug(`No context provided for "${dataType}" data:`, data);
|
|
89
|
+
// debug(`No context provided for "${dataType}" data:`, data);
|
|
80
90
|
return;
|
|
81
91
|
}
|
|
82
92
|
const contextHash = stringToMD5Hash(context);
|
|
@@ -119,7 +129,7 @@ class DataStorage {
|
|
|
119
129
|
if (testDataFromFile.length) {
|
|
120
130
|
return testDataFromFile;
|
|
121
131
|
}
|
|
122
|
-
debug(`No "${dataType}" data for context "${contextHash}" in both file and global variable`);
|
|
132
|
+
// debug(`No "${dataType}" data for context "${contextHash}" in both file and global variable`);
|
|
123
133
|
// in case no data found for context
|
|
124
134
|
return null;
|
|
125
135
|
}
|
|
@@ -3,6 +3,7 @@ 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"));
|
|
6
7
|
const adapter_js_1 = __importDefault(require("./adapter.js"));
|
|
7
8
|
class CSharpAdapter extends adapter_js_1.default {
|
|
8
9
|
formatTest(t) {
|
|
@@ -12,9 +13,18 @@ class CSharpAdapter extends adapter_js_1.default {
|
|
|
12
13
|
t.example = { ...example[1].split(',') };
|
|
13
14
|
const suite = t.suite_title.split('.');
|
|
14
15
|
t.suite_title = suite.pop();
|
|
15
|
-
t.file =
|
|
16
|
+
t.file = namespaceToFileName(t.file);
|
|
16
17
|
t.title = title.trim();
|
|
17
18
|
return t;
|
|
18
19
|
}
|
|
20
|
+
getFilePath(t) {
|
|
21
|
+
const fileName = namespaceToFileName(t.file);
|
|
22
|
+
return fileName;
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
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/output.d.ts
ADDED
package/lib/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class BitbucketPipe
|
|
3
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
4
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
5
|
+
*/
|
|
6
|
+
export class BitbucketPipe {
|
|
7
|
+
constructor(params: any, store?: {});
|
|
8
|
+
isEnabled: boolean;
|
|
9
|
+
ENV: NodeJS.ProcessEnv;
|
|
10
|
+
store: {};
|
|
11
|
+
tests: any[];
|
|
12
|
+
token: any;
|
|
13
|
+
hiddenCommentData: string;
|
|
14
|
+
cleanLog(log: any): Promise<string>;
|
|
15
|
+
prepareRun(): Promise<void>;
|
|
16
|
+
createRun(): Promise<void>;
|
|
17
|
+
addTest(test: any): void;
|
|
18
|
+
finishRun(runParams: any): Promise<void>;
|
|
19
|
+
toString(): string;
|
|
20
|
+
updateRun(): void;
|
|
21
|
+
}
|
|
22
|
+
export type Pipe = import("../../types/types.js").Pipe;
|
|
23
|
+
export type TestData = import("../../types/types.js").TestData;
|
package/lib/pipe/bitbucket.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
@@ -41,8 +51,8 @@ const debug = (0, debug_1.default)('@testomatio/reporter:pipe:bitbucket');
|
|
|
41
51
|
//! and your pipeline trigger should be a pull request
|
|
42
52
|
/**
|
|
43
53
|
* @class BitbucketPipe
|
|
44
|
-
* @typedef {import('../../types').Pipe} Pipe
|
|
45
|
-
* @typedef {import('../../types').TestData} TestData
|
|
54
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
55
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
46
56
|
*/
|
|
47
57
|
class BitbucketPipe {
|
|
48
58
|
constructor(params, store = {}) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export default CsvPipe;
|
|
2
|
+
export type Pipe = import("../../types/types.js").Pipe;
|
|
3
|
+
export type TestData = import("../../types/types.js").TestData;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
6
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
7
|
+
* @class CsvPipe
|
|
8
|
+
* @implements {Pipe}
|
|
9
|
+
*/
|
|
10
|
+
declare class CsvPipe implements Pipe {
|
|
11
|
+
constructor(params: any, store: any);
|
|
12
|
+
store: any;
|
|
13
|
+
title: any;
|
|
14
|
+
results: any[];
|
|
15
|
+
outputDir: string;
|
|
16
|
+
defaultReportName: string;
|
|
17
|
+
csvFilename: string;
|
|
18
|
+
isEnabled: boolean;
|
|
19
|
+
outputFile: string;
|
|
20
|
+
prepareRun(): Promise<void>;
|
|
21
|
+
createRun(): Promise<void>;
|
|
22
|
+
updateRun(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Create a folder that will contain the exported files
|
|
25
|
+
*/
|
|
26
|
+
checkExportDir(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Save data to the csv file.
|
|
29
|
+
* @param {Object} data - data that will be added to the CSV file.
|
|
30
|
+
* Example: [{suite_title: "Suite #1", test: "Test-case-1", message: "Test msg"}]
|
|
31
|
+
* @param {Object} headers - csv file headers. Example: [{ id: 'suite_title', title: 'Suite_title' }]
|
|
32
|
+
*/
|
|
33
|
+
saveToCsv(data: any, headers: any): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Add test data to the result array for saving. As a result of this function, we get a result object to save.
|
|
36
|
+
* @param {Object} test - object which includes each test entry.
|
|
37
|
+
*/
|
|
38
|
+
addTest(test: any): void;
|
|
39
|
+
/**
|
|
40
|
+
* @param {{ tests?: TestData[] }} runParams
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
finishRun(runParams: {
|
|
44
|
+
tests?: TestData[];
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
toString(): string;
|
|
47
|
+
}
|
package/lib/pipe/csv.js
CHANGED
|
@@ -13,8 +13,8 @@ const utils_js_1 = require("../utils/utils.js");
|
|
|
13
13
|
const constants_js_1 = require("../constants.js");
|
|
14
14
|
const debug = (0, debug_1.default)('@testomatio/reporter:pipe:csv');
|
|
15
15
|
/**
|
|
16
|
-
* @typedef {import('../../types').Pipe} Pipe
|
|
17
|
-
* @typedef {import('../../types').TestData} TestData
|
|
16
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
17
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
18
18
|
* @class CsvPipe
|
|
19
19
|
* @implements {Pipe}
|
|
20
20
|
*/
|