@testomatio/reporter 1.2.0 → 1.2.1-beta.codecept-id
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/README.md +45 -51
- package/lib/adapter/codecept.js +1 -14
- package/lib/adapter/cucumber/legacy.js +1 -1
- package/lib/adapter/cucumber.js +2 -2
- package/lib/adapter/jest.js +1 -1
- package/lib/adapter/mocha.js +4 -6
- package/lib/adapter/playwright.js +1 -1
- package/lib/bin/reportXml.js +13 -13
- package/lib/bin/startTest.js +10 -11
- package/lib/constants.js +8 -5
- package/lib/fileUploader.js +29 -33
- package/lib/junit-adapter/adapter.js +0 -2
- package/lib/junit-adapter/csharp.js +3 -4
- package/lib/junit-adapter/index.js +2 -3
- package/lib/junit-adapter/java.js +11 -11
- package/lib/junit-adapter/javascript.js +1 -2
- package/lib/junit-adapter/python.js +12 -14
- package/lib/junit-adapter/ruby.js +1 -2
- package/lib/pipe/csv.js +2 -3
- package/lib/pipe/github.js +4 -3
- package/lib/pipe/gitlab.js +14 -7
- package/lib/pipe/html.js +0 -1
- package/lib/pipe/index.js +1 -1
- package/lib/template/testomatio.hbs +362 -724
- package/lib/utils/pipe_utils.js +70 -77
- package/lib/utils/utils.js +33 -32
- package/package.json +4 -2
package/lib/utils/pipe_utils.js
CHANGED
|
@@ -6,17 +6,17 @@ const { APP_PREFIX } = require('../constants');
|
|
|
6
6
|
* @param {Object} artifacts - The artifacts object containing S3 credentials.
|
|
7
7
|
*/
|
|
8
8
|
function setS3Credentials(artifacts) {
|
|
9
|
-
|
|
9
|
+
if (!Object.keys(artifacts).length) return;
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
console.log(APP_PREFIX, 'S3 were credentials obtained from Testomat.io...');
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
if (artifacts.ACCESS_KEY_ID) process.env.S3_ACCESS_KEY_ID = artifacts.ACCESS_KEY_ID;
|
|
14
|
+
if (artifacts.SECRET_ACCESS_KEY) process.env.S3_SECRET_ACCESS_KEY = artifacts.SECRET_ACCESS_KEY;
|
|
15
|
+
if (artifacts.REGION) process.env.S3_REGION = artifacts.REGION;
|
|
16
|
+
if (artifacts.BUCKET) process.env.S3_BUCKET = artifacts.BUCKET;
|
|
17
|
+
if (artifacts.ENDPOINT) process.env.S3_ENDPOINT = artifacts.ENDPOINT;
|
|
18
|
+
if (artifacts.presign) process.env.TESTOMATIO_PRIVATE_ARTIFACTS = '1';
|
|
19
|
+
resetConfig();
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Generates mode request parameters based on the input params.
|
|
@@ -27,25 +27,25 @@ function setS3Credentials(artifacts) {
|
|
|
27
27
|
* @returns {Object|null} - An object containing the generated request parameters, or null if the type is invalid.
|
|
28
28
|
*/
|
|
29
29
|
function generateFilterRequestParams(params) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
30
|
+
const { type, id, apiKey } = params;
|
|
31
|
+
|
|
32
|
+
if (!type) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!id) {
|
|
37
|
+
console.error(APP_PREFIX, `Please make sure your settings "${type.toUpperCase()}"= "${id}" is correct!`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
params: {
|
|
43
|
+
type,
|
|
44
|
+
id: encodeURIComponent(id),
|
|
45
|
+
api_key: apiKey,
|
|
46
|
+
},
|
|
47
|
+
responseType: 'json',
|
|
48
|
+
};
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -55,13 +55,13 @@ function generateFilterRequestParams(params) {
|
|
|
55
55
|
* The object has properties "type" and "id".
|
|
56
56
|
*/
|
|
57
57
|
function parseFilterParams(opts) {
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
const [type, id] = opts.split('=');
|
|
59
|
+
const validType = updateFilterType(type);
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
return {
|
|
62
|
+
type: validType,
|
|
63
|
+
id,
|
|
64
|
+
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -71,33 +71,26 @@ function parseFilterParams(opts) {
|
|
|
71
71
|
* Returns undefined if the type is not valid.
|
|
72
72
|
*/
|
|
73
73
|
function updateFilterType(type) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const index = filterTypes.indexOf(typeLowerCase);
|
|
97
|
-
|
|
98
|
-
return (index !== -1)
|
|
99
|
-
? filterApi[index]
|
|
100
|
-
: undefined
|
|
74
|
+
const typeLowerCase = type.toLowerCase();
|
|
75
|
+
|
|
76
|
+
const filterTypes = ['tag-name', 'plan-id', 'label', 'jira-ticket'];
|
|
77
|
+
|
|
78
|
+
const filterApi = [
|
|
79
|
+
'tag',
|
|
80
|
+
'plan',
|
|
81
|
+
'label',
|
|
82
|
+
'jira',
|
|
83
|
+
// "ims-issue", //TODO: WIP
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
if (!filterTypes.includes(typeLowerCase)) {
|
|
87
|
+
console.log(APP_PREFIX, `❗❗❗ Invalid "filter=${type}" start settings! Available option list: ${filterTypes}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const index = filterTypes.indexOf(typeLowerCase);
|
|
92
|
+
|
|
93
|
+
return index !== -1 ? filterApi[index] : undefined;
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
/**
|
|
@@ -106,10 +99,10 @@ function updateFilterType(type) {
|
|
|
106
99
|
* @returns {string} - An emoji corresponding to the provided status.
|
|
107
100
|
*/
|
|
108
101
|
function statusEmoji(status) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
if (status === 'passed') return '🟢';
|
|
103
|
+
if (status === 'failed') return '🔴';
|
|
104
|
+
if (status === 'skipped') return '🟡';
|
|
105
|
+
return '';
|
|
113
106
|
}
|
|
114
107
|
|
|
115
108
|
/**
|
|
@@ -118,18 +111,18 @@ function statusEmoji(status) {
|
|
|
118
111
|
* @returns {string} - A formatted full name string for the test object.
|
|
119
112
|
*/
|
|
120
113
|
function fullName(t) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
let line = '';
|
|
115
|
+
if (t.suite_title) line = `${t.suite_title}: `;
|
|
116
|
+
line += `**${t.title}**`;
|
|
117
|
+
if (t.example) line += ` \`[${Object.values(t.example)}]\``;
|
|
118
|
+
return line;
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
module.exports = {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
};
|
|
122
|
+
updateFilterType,
|
|
123
|
+
parseFilterParams,
|
|
124
|
+
generateFilterRequestParams,
|
|
125
|
+
setS3Credentials,
|
|
126
|
+
statusEmoji,
|
|
127
|
+
fullName,
|
|
128
|
+
};
|
package/lib/utils/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ const debug = require('debug')('@testomatio/reporter:util');
|
|
|
13
13
|
const parseTest = testTitle => {
|
|
14
14
|
if (!testTitle) return null;
|
|
15
15
|
|
|
16
|
-
const captures = testTitle.match(
|
|
16
|
+
const captures = testTitle.match(/\@T[\w\d]{8}/);
|
|
17
17
|
|
|
18
18
|
if (captures) {
|
|
19
19
|
return captures[1];
|
|
@@ -28,7 +28,7 @@ const parseTest = testTitle => {
|
|
|
28
28
|
* @returns {String|null} suiteId
|
|
29
29
|
*/
|
|
30
30
|
const parseSuite = suiteTitle => {
|
|
31
|
-
const captures = suiteTitle.match(
|
|
31
|
+
const captures = suiteTitle.match(/\@S[\w\d]{8}/);
|
|
32
32
|
if (captures) {
|
|
33
33
|
return captures[1];
|
|
34
34
|
}
|
|
@@ -55,21 +55,20 @@ const isValidUrl = s => {
|
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
const fileMatchRegex = /file:(\/\/?[^:\s]+?\.(png|avi|webm|jpg|html|txt))/
|
|
58
|
+
const fileMatchRegex = /file:(\/\/?[^:\s]+?\.(png|avi|webm|jpg|html|txt))/gi;
|
|
59
59
|
|
|
60
60
|
const fetchFilesFromStackTrace = (stack = '') => {
|
|
61
|
-
|
|
62
61
|
const files = Array.from(stack.matchAll(fileMatchRegex))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
.map(f => f[1].trim())
|
|
63
|
+
.map(f => (f.startsWith('//') ? f.substring(1) : f));
|
|
64
|
+
|
|
66
65
|
debug('Found files in stack trace: ', files);
|
|
67
66
|
|
|
68
67
|
return files.filter(f => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
const isFile = fs.existsSync(f);
|
|
69
|
+
if (!isFile) debug('File %s could not be found and uploaded as artifact', f);
|
|
70
|
+
return isFile;
|
|
71
|
+
});
|
|
73
72
|
};
|
|
74
73
|
|
|
75
74
|
const fetchSourceCodeFromStackTrace = (stack = '') => {
|
|
@@ -109,25 +108,30 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
|
|
|
109
108
|
const TEST_ID_REGEX = /@T([\w\d]{8})/;
|
|
110
109
|
|
|
111
110
|
const fetchIdFromCode = (code, opts = {}) => {
|
|
112
|
-
const comments = code
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
const comments = code
|
|
112
|
+
.split('\n')
|
|
113
|
+
.map(l => l.trim())
|
|
114
|
+
.filter(l => {
|
|
115
|
+
switch (opts.lang) {
|
|
116
|
+
case 'ruby':
|
|
117
|
+
case 'python':
|
|
118
|
+
return l.startsWith('# ');
|
|
119
|
+
default:
|
|
120
|
+
return l.startsWith('// ');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
121
123
|
|
|
122
124
|
return comments.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
+
};
|
|
125
126
|
|
|
126
|
-
const fetchIdFromOutput =
|
|
127
|
-
const lines = output
|
|
127
|
+
const fetchIdFromOutput = output => {
|
|
128
|
+
const lines = output
|
|
129
|
+
.split('\n')
|
|
130
|
+
.map(l => l.trim())
|
|
131
|
+
.filter(l => l.startsWith('tid://'));
|
|
128
132
|
|
|
129
133
|
return lines.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
|
|
130
|
-
}
|
|
134
|
+
};
|
|
131
135
|
|
|
132
136
|
const fetchSourceCode = (contents, opts = {}) => {
|
|
133
137
|
if (!opts.title && !opts.line) return '';
|
|
@@ -141,7 +145,7 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
141
145
|
// remove special chars from title
|
|
142
146
|
if (!lineIndex && opts.title) {
|
|
143
147
|
const title = opts.title.replace(/[([@].*/g, '');
|
|
144
|
-
|
|
148
|
+
|
|
145
149
|
if (opts.lang === 'java') {
|
|
146
150
|
lineIndex = lines.findIndex(l => l.includes(`test${title}`));
|
|
147
151
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
|
|
@@ -235,14 +239,11 @@ const fileSystem = {
|
|
|
235
239
|
},
|
|
236
240
|
};
|
|
237
241
|
|
|
238
|
-
|
|
239
242
|
const foundedTestLog = (app, tests) => {
|
|
240
243
|
const n = tests.length;
|
|
241
244
|
|
|
242
|
-
return
|
|
243
|
-
|
|
244
|
-
: console.log(app, `✅ We found ${n} tests!`);
|
|
245
|
-
}
|
|
245
|
+
return n === 1 ? console.log(app, `✅ We found one test!`) : console.log(app, `✅ We found ${n} tests!`);
|
|
246
|
+
};
|
|
246
247
|
|
|
247
248
|
const humanize = text => {
|
|
248
249
|
text = decamelize(text);
|
|
@@ -333,4 +334,4 @@ module.exports = {
|
|
|
333
334
|
removeColorCodes,
|
|
334
335
|
foundedTestLog,
|
|
335
336
|
testRunnerHelper,
|
|
336
|
-
};
|
|
337
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1-beta.codecept-id",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"main": "./lib/reporter.js",
|
|
6
6
|
"typings": "typings/index.d.ts",
|
|
@@ -41,9 +41,11 @@
|
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
43
43
|
"clear-exportdir": "rm -rf export/",
|
|
44
|
-
"pretty": "prettier --
|
|
44
|
+
"pretty": "prettier --check .",
|
|
45
|
+
"pretty:fix": "prettier --write .",
|
|
45
46
|
"lint": "eslint lib",
|
|
46
47
|
"lint:fix": "eslint lib --fix",
|
|
48
|
+
"format": "npm run lint:fix && npm run pretty:fix",
|
|
47
49
|
"test": "mocha tests/**",
|
|
48
50
|
"init": "cd ./tests/adapter/examples/cucumber && npm i",
|
|
49
51
|
"test:adapter": "mocha './tests/adapter/index.test.js'",
|