testbeats 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/package.json +65 -0
- package/src/beats/index.js +74 -0
- package/src/cli.js +23 -0
- package/src/commands/publish.js +54 -0
- package/src/extensions/ci-info.js +134 -0
- package/src/extensions/custom.js +29 -0
- package/src/extensions/hyperlinks.js +60 -0
- package/src/extensions/index.js +63 -0
- package/src/extensions/mentions.js +112 -0
- package/src/extensions/metadata.js +89 -0
- package/src/extensions/percy-analysis.js +203 -0
- package/src/extensions/quick-chart-test-summary.js +82 -0
- package/src/extensions/report-portal-analysis.js +95 -0
- package/src/extensions/report-portal-history.js +105 -0
- package/src/helpers/ci.js +62 -0
- package/src/helpers/constants.js +45 -0
- package/src/helpers/extension.helper.js +107 -0
- package/src/helpers/helper.js +102 -0
- package/src/helpers/metadata.helper.js +115 -0
- package/src/helpers/percy.js +60 -0
- package/src/helpers/performance.js +141 -0
- package/src/helpers/report-portal.js +47 -0
- package/src/index.d.ts +243 -0
- package/src/index.js +14 -0
- package/src/targets/chat.js +242 -0
- package/src/targets/custom.js +28 -0
- package/src/targets/delay.js +19 -0
- package/src/targets/index.js +39 -0
- package/src/targets/influx.js +208 -0
- package/src/targets/slack.js +266 -0
- package/src/targets/teams.js +304 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
const request = require('phin-retry');
|
|
2
|
+
const { getPercentage, truncate, getPrettyDuration } = require('../helpers/helper');
|
|
3
|
+
const { getValidMetrics, getMetricValuesText } = require('../helpers/performance');
|
|
4
|
+
const extension_manager = require('../extensions');
|
|
5
|
+
const { HOOK, STATUS } = require('../helpers/constants');
|
|
6
|
+
|
|
7
|
+
const TestResult = require('test-results-parser/src/models/TestResult');
|
|
8
|
+
const PerformanceTestResult = require('performance-results-parser/src/models/PerformanceTestResult');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {object} param0
|
|
12
|
+
* @param {PerformanceTestResult | TestResult} param0.result
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
async function run({ result, target }) {
|
|
16
|
+
setTargetInputs(target);
|
|
17
|
+
const root_payload = getRootPayload();
|
|
18
|
+
const payload = getMainPayload(target);
|
|
19
|
+
if (result instanceof PerformanceTestResult) {
|
|
20
|
+
await setPerformancePayload({ result, target, payload, root_payload });
|
|
21
|
+
} else {
|
|
22
|
+
await setFunctionalPayload({ result, target, payload, root_payload });
|
|
23
|
+
}
|
|
24
|
+
setRootPayload(root_payload, payload);
|
|
25
|
+
return request.post({
|
|
26
|
+
url: target.inputs.url,
|
|
27
|
+
body: root_payload
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function setPerformancePayload({ result, target, payload, root_payload }) {
|
|
32
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.START });
|
|
33
|
+
setTitleBlock({ result, target, payload });
|
|
34
|
+
await setMainBlockForPerformance({ result, target, payload });
|
|
35
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.AFTER_SUMMARY });
|
|
36
|
+
await setTransactionBlock({ result, target, payload });
|
|
37
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.END });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function setFunctionalPayload({ result, target, payload, root_payload }) {
|
|
41
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.START });
|
|
42
|
+
setTitleBlock({ result, target, payload });
|
|
43
|
+
setMainBlock({ result, target, payload });
|
|
44
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.AFTER_SUMMARY });
|
|
45
|
+
setSuiteBlock({ result, target, payload });
|
|
46
|
+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.END });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function setTargetInputs(target) {
|
|
50
|
+
target.inputs = Object.assign({}, default_inputs, target.inputs);
|
|
51
|
+
if (target.inputs.publish === 'test-summary-slim') {
|
|
52
|
+
target.inputs.include_suites = false;
|
|
53
|
+
}
|
|
54
|
+
if (target.inputs.publish === 'failure-details') {
|
|
55
|
+
target.inputs.include_failure_details = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getMainPayload(target) {
|
|
60
|
+
const main = {
|
|
61
|
+
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
62
|
+
"type": "AdaptiveCard",
|
|
63
|
+
"version": "1.0",
|
|
64
|
+
"body": [],
|
|
65
|
+
"actions": []
|
|
66
|
+
};
|
|
67
|
+
if (target.inputs.width) {
|
|
68
|
+
if (!main.msteams) {
|
|
69
|
+
main.msteams = {};
|
|
70
|
+
}
|
|
71
|
+
main.msteams.width = target.inputs.width;
|
|
72
|
+
}
|
|
73
|
+
return main;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getTitleText(result, target) {
|
|
77
|
+
const title = target.inputs.title ? target.inputs.title : result.name;
|
|
78
|
+
if (target.inputs.title_suffix) {
|
|
79
|
+
return `${title} ${target.inputs.title_suffix}`;
|
|
80
|
+
}
|
|
81
|
+
return `${title}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function setTitleBlock({ result, target, payload }) {
|
|
85
|
+
const title = getTitleText(result, target);
|
|
86
|
+
const emoji = result.status === 'PASS' ? '✅' : '❌';
|
|
87
|
+
let text = '';
|
|
88
|
+
if (target.inputs.include_suites === false) {
|
|
89
|
+
text = `${emoji} ${title}`;
|
|
90
|
+
} else if (result.suites && result.suites.length > 1 || result.transactions && result.transactions.length > 1) {
|
|
91
|
+
text = title;
|
|
92
|
+
} else {
|
|
93
|
+
text = `${emoji} ${title}`;
|
|
94
|
+
}
|
|
95
|
+
if (target.inputs.title_link) {
|
|
96
|
+
text = `[${text}](${target.inputs.title_link})`
|
|
97
|
+
}
|
|
98
|
+
payload.body.push({
|
|
99
|
+
"type": "TextBlock",
|
|
100
|
+
"text": text,
|
|
101
|
+
"size": "medium",
|
|
102
|
+
"weight": "bolder",
|
|
103
|
+
"wrap": true
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function setMainBlock({ result, target, payload }) {
|
|
108
|
+
const facts = [];
|
|
109
|
+
const percentage = getPercentage(result.passed, result.total);
|
|
110
|
+
facts.push({
|
|
111
|
+
"title": "Results:",
|
|
112
|
+
"value": `${result.passed} / ${result.total} Passed (${percentage}%)`
|
|
113
|
+
});
|
|
114
|
+
facts.push({
|
|
115
|
+
"title": "Duration:",
|
|
116
|
+
"value": `${getPrettyDuration(result.duration, target.inputs.duration)}`
|
|
117
|
+
});
|
|
118
|
+
payload.body.push({
|
|
119
|
+
"type": "FactSet",
|
|
120
|
+
"facts": facts
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function setSuiteBlock({ result, target, payload }) {
|
|
125
|
+
let suite_attachments_length = 0;
|
|
126
|
+
if (target.inputs.include_suites) {
|
|
127
|
+
for (let i = 0; i < result.suites.length && suite_attachments_length < target.inputs.max_suites; i++) {
|
|
128
|
+
const suite = result.suites[i];
|
|
129
|
+
if (target.inputs.only_failures && suite.status !== 'FAIL') {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// if suites length eq to 1 then main block will include suite summary
|
|
133
|
+
if (result.suites.length > 1) {
|
|
134
|
+
payload.body.push(...getSuiteSummary({ suite, target }));
|
|
135
|
+
suite_attachments_length += 1;
|
|
136
|
+
}
|
|
137
|
+
if (target.inputs.include_failure_details) {
|
|
138
|
+
payload.body.push(...getFailureDetailsFactSets(suite));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getSuiteSummary({ suite, target }) {
|
|
145
|
+
const percentage = getPercentage(suite.passed, suite.total);
|
|
146
|
+
const emoji = suite.status === 'PASS' ? '✅' : '❌';
|
|
147
|
+
return [
|
|
148
|
+
{
|
|
149
|
+
"type": "TextBlock",
|
|
150
|
+
"text": `${emoji} ${suite.name}`,
|
|
151
|
+
"isSubtle": true,
|
|
152
|
+
"weight": "bolder",
|
|
153
|
+
"wrap": true
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"type": "FactSet",
|
|
157
|
+
"facts": [
|
|
158
|
+
{
|
|
159
|
+
"title": "Results:",
|
|
160
|
+
"value": `${suite.passed} / ${suite.total} Passed (${percentage}%)`
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"title": "Duration:",
|
|
164
|
+
"value": `${getPrettyDuration(suite.duration, target.inputs.duration)}`
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getFailureDetailsFactSets(suite) {
|
|
172
|
+
const fact_sets = [];
|
|
173
|
+
const cases = suite.cases;
|
|
174
|
+
for (let i = 0; i < cases.length; i++) {
|
|
175
|
+
const test_case = cases[i];
|
|
176
|
+
if (test_case.status === 'FAIL') {
|
|
177
|
+
fact_sets.push({
|
|
178
|
+
"type": "FactSet",
|
|
179
|
+
"facts": [
|
|
180
|
+
{
|
|
181
|
+
"title": "Test:",
|
|
182
|
+
"value": test_case.name
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"title": "Error:",
|
|
186
|
+
"value": truncate(test_case.failure, 150)
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return fact_sets;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function getRootPayload() {
|
|
196
|
+
return {
|
|
197
|
+
"type": "message",
|
|
198
|
+
"attachments": [
|
|
199
|
+
{
|
|
200
|
+
"contentType": "application/vnd.microsoft.card.adaptive",
|
|
201
|
+
"content": ''
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function setRootPayload(root_payload, payload) {
|
|
208
|
+
root_payload.attachments[0].content = payload;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @param {object} param0
|
|
213
|
+
* @param {PerformanceTestResult} param0.result
|
|
214
|
+
*/
|
|
215
|
+
async function setMainBlockForPerformance({ result, target, payload }) {
|
|
216
|
+
const total = result.transactions.length;
|
|
217
|
+
const passed = result.transactions.filter(_transaction => _transaction.status === 'PASS').length;
|
|
218
|
+
const percentage = getPercentage(passed, total);
|
|
219
|
+
payload.body.push({
|
|
220
|
+
"type": "FactSet",
|
|
221
|
+
"facts": [
|
|
222
|
+
{
|
|
223
|
+
"title": "Results:",
|
|
224
|
+
"value": `${passed} / ${total} Passed (${percentage}%)`
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
});
|
|
228
|
+
payload.body.push({
|
|
229
|
+
"type": "FactSet",
|
|
230
|
+
"facts": await getFactMetrics({ metrics: result.metrics, result, target })
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function getFactMetrics({ metrics, target, result }) {
|
|
235
|
+
const facts = [];
|
|
236
|
+
const valid_metrics = await getValidMetrics({ metrics, target, result });
|
|
237
|
+
for (let i = 0; i < valid_metrics.length; i++) {
|
|
238
|
+
const metric = valid_metrics[i];
|
|
239
|
+
facts.push({
|
|
240
|
+
"title": `${metric.name}:`,
|
|
241
|
+
"value": getMetricValuesText({ metrics, metric, target, result })
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
return facts;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @param {object} param0
|
|
249
|
+
* @param {PerformanceTestResult} param0.result
|
|
250
|
+
*/
|
|
251
|
+
async function setTransactionBlock({ result, target, payload }) {
|
|
252
|
+
if (target.inputs.include_suites) {
|
|
253
|
+
for (let i = 0; i < result.transactions.length; i++) {
|
|
254
|
+
const transaction = result.transactions[i];
|
|
255
|
+
if (target.inputs.only_failures && transaction.status !== 'FAIL') {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
// if transactions length eq to 1 then main block will include transaction summary
|
|
259
|
+
if (result.transactions.length > 1) {
|
|
260
|
+
const emoji = transaction.status === 'PASS' ? '✅' : '❌';
|
|
261
|
+
payload.body.push({
|
|
262
|
+
"type": "TextBlock",
|
|
263
|
+
"text": `${emoji} ${transaction.name}`,
|
|
264
|
+
"isSubtle": true,
|
|
265
|
+
"weight": "bolder",
|
|
266
|
+
"wrap": true
|
|
267
|
+
});
|
|
268
|
+
payload.body.push({
|
|
269
|
+
"type": "FactSet",
|
|
270
|
+
"facts": await getFactMetrics({ metrics: transaction.metrics, result, target })
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const default_options = {
|
|
278
|
+
condition: STATUS.PASS_OR_FAIL
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const default_inputs = {
|
|
282
|
+
publish: 'test-summary',
|
|
283
|
+
include_suites: true,
|
|
284
|
+
max_suites: 10,
|
|
285
|
+
only_failures: false,
|
|
286
|
+
include_failure_details: false,
|
|
287
|
+
width: '',
|
|
288
|
+
duration: '',
|
|
289
|
+
metrics: [
|
|
290
|
+
{
|
|
291
|
+
"name": "Samples",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"name": "Duration",
|
|
295
|
+
"condition": "always",
|
|
296
|
+
"fields": ["avg", "p95"]
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
module.exports = {
|
|
302
|
+
run,
|
|
303
|
+
default_options
|
|
304
|
+
}
|