testbeats 2.0.8 → 2.1.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/README.md +12 -8
- package/package.json +2 -2
- package/src/beats/beats.api.js +16 -1
- package/src/beats/beats.js +29 -0
- package/src/beats/beats.types.d.ts +15 -0
- package/src/commands/publish.command.js +31 -2
- package/src/extensions/base.extension.js +16 -0
- package/src/extensions/error-clusters.extension.js +44 -0
- package/src/extensions/index.js +3 -0
- package/src/extensions/smart-analysis.extension.js +22 -2
- package/src/helpers/constants.js +1 -0
- package/src/index.d.ts +1 -0
- package/src/targets/chat.js +25 -1
- package/src/targets/index.js +9 -1
- package/src/targets/slack.js +39 -1
- package/src/targets/teams.js +34 -1
package/README.md
CHANGED
|
@@ -9,11 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
<br />
|
|
11
11
|
|
|
12
|
-

|
|
16
|
-

|
|
12
|
+
[](https://github.com/test-results-reporter/testbeats/actions/workflows/build.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/test-results-parser)
|
|
14
|
+
[](https://bundlephobia.com/result?p=testbeats)
|
|
17
15
|
|
|
18
16
|
|
|
19
17
|
[](https://github.com/test-results-reporter/testbeats/stargazers)
|
|
@@ -23,9 +21,11 @@
|
|
|
23
21
|
|
|
24
22
|
</span>
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
<br />
|
|
25
|
+
|
|
26
|
+
**TestBeats** is a tool designed to streamline the process of publishing test results from various automation testing frameworks to communication platforms like **slack**, **teams** and more for easy access and collaboration. It unifies your test reporting to build quality insights and make faster decisions.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
It supports all major automation testing frameworks and tools.
|
|
29
29
|
|
|
30
30
|
Read more about the project at [https://testbeats.com](https://testbeats.com)
|
|
31
31
|
|
|
@@ -47,4 +47,8 @@ We use [Github Discussions](https://github.com/test-results-reporter/testbeats/d
|
|
|
47
47
|
|
|
48
48
|
## Support Us
|
|
49
49
|
|
|
50
|
-
Like this project! Star it on [Github](https://github.com/test-results-reporter/testbeats) ⭐. Your support means a lot to us.
|
|
50
|
+
Like this project! Star it on [Github](https://github.com/test-results-reporter/testbeats) ⭐. Your support means a lot to us.
|
|
51
|
+
|
|
52
|
+
<br />
|
|
53
|
+
|
|
54
|
+
> Read more about the project at [https://testbeats.com](https://testbeats.com)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testbeats",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Publish test results to Microsoft Teams, Google Chat, Slack and InfluxDB",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"pretty-ms": "^7.0.1",
|
|
56
56
|
"rosters": "0.0.1",
|
|
57
57
|
"sade": "^1.8.1",
|
|
58
|
-
"test-results-parser": "
|
|
58
|
+
"test-results-parser": "0.2.3"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"c8": "^7.12.0",
|
package/src/beats/beats.api.js
CHANGED
|
@@ -25,7 +25,7 @@ class BeatsApi {
|
|
|
25
25
|
*/
|
|
26
26
|
getTestRun(run_id) {
|
|
27
27
|
return request.get({
|
|
28
|
-
url: `${this.getBaseUrl()}/api/core/v1/test-runs
|
|
28
|
+
url: `${this.getBaseUrl()}/api/core/v1/test-runs/${run_id}`,
|
|
29
29
|
headers: {
|
|
30
30
|
'x-api-key': this.config.api_key
|
|
31
31
|
}
|
|
@@ -46,6 +46,21 @@ class BeatsApi {
|
|
|
46
46
|
getBaseUrl() {
|
|
47
47
|
return process.env.TEST_BEATS_URL || "https://app.testbeats.com";
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* @param {string} run_id
|
|
53
|
+
* @param {number} limit
|
|
54
|
+
* @returns {import('./beats.types').IErrorClustersResponse}
|
|
55
|
+
*/
|
|
56
|
+
getErrorClusters(run_id, limit = 3) {
|
|
57
|
+
return request.get({
|
|
58
|
+
url: `${this.getBaseUrl()}/api/core/v1/test-runs/${run_id}/error-clusters?limit=${limit}`,
|
|
59
|
+
headers: {
|
|
60
|
+
'x-api-key': this.config.api_key
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
49
64
|
}
|
|
50
65
|
|
|
51
66
|
module.exports = { BeatsApi }
|
package/src/beats/beats.js
CHANGED
|
@@ -33,6 +33,7 @@ class Beats {
|
|
|
33
33
|
this.#updateTitleLink();
|
|
34
34
|
await this.#attachFailureSummary();
|
|
35
35
|
await this.#attachSmartAnalysis();
|
|
36
|
+
await this.#attachErrorClusters();
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
#setCIInfo() {
|
|
@@ -189,6 +190,34 @@ class Beats {
|
|
|
189
190
|
logger.warn(`🙈 ${text} not generated in given time`);
|
|
190
191
|
}
|
|
191
192
|
|
|
193
|
+
async #attachErrorClusters() {
|
|
194
|
+
if (!this.test_run_id) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (!this.config.targets) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (this.result.status !== 'FAIL') {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (this.config.show_error_clusters === false) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
logger.info('🧮 Fetching Error Clusters...');
|
|
208
|
+
const res = await this.api.getErrorClusters(this.test_run_id, 3);
|
|
209
|
+
this.config.extensions.push({
|
|
210
|
+
name: 'error-clusters',
|
|
211
|
+
hook: HOOK.AFTER_SUMMARY,
|
|
212
|
+
inputs: {
|
|
213
|
+
data: res.values
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
logger.error(`❌ Unable to attach error clusters: ${error.message}`, error);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
192
221
|
}
|
|
193
222
|
|
|
194
223
|
module.exports = { Beats }
|
|
@@ -17,3 +17,18 @@ export type IBeatExecutionMetric = {
|
|
|
17
17
|
test_run_id: string
|
|
18
18
|
org_id: string
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
export type IPaginatedAPIResponse<T> = {
|
|
22
|
+
page: number
|
|
23
|
+
limit: number
|
|
24
|
+
total: number
|
|
25
|
+
values: T[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type IErrorClustersResponse = {} & IPaginatedAPIResponse<IErrorCluster>;
|
|
29
|
+
|
|
30
|
+
export type IErrorCluster = {
|
|
31
|
+
test_failure_id: string
|
|
32
|
+
failure: string
|
|
33
|
+
count: number
|
|
34
|
+
}
|
|
@@ -18,6 +18,7 @@ class PublishCommand {
|
|
|
18
18
|
*/
|
|
19
19
|
constructor(opts) {
|
|
20
20
|
this.opts = opts;
|
|
21
|
+
this.errors = [];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
async publish() {
|
|
@@ -31,7 +32,7 @@ class PublishCommand {
|
|
|
31
32
|
this.#validateConfig();
|
|
32
33
|
this.#processResults();
|
|
33
34
|
await this.#publishResults();
|
|
34
|
-
|
|
35
|
+
await this.#publishErrors();
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
#validateEnvDetails() {
|
|
@@ -184,13 +185,24 @@ class PublishCommand {
|
|
|
184
185
|
} else if (result_options.type === 'jmeter') {
|
|
185
186
|
this.results.push(prp.parse(result_options));
|
|
186
187
|
} else {
|
|
187
|
-
|
|
188
|
+
const { result, errors } = trp.parseV2(result_options);
|
|
189
|
+
if (result) {
|
|
190
|
+
this.results.push(result);
|
|
191
|
+
}
|
|
192
|
+
if (errors) {
|
|
193
|
+
this.errors = this.errors.concat(errors);
|
|
194
|
+
}
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
197
|
}
|
|
191
198
|
}
|
|
192
199
|
|
|
193
200
|
async #publishResults() {
|
|
201
|
+
if (!this.results.length) {
|
|
202
|
+
logger.warn('⚠️ No results to publish');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
194
206
|
for (const config of this.configs) {
|
|
195
207
|
for (let i = 0; i < this.results.length; i++) {
|
|
196
208
|
const result = this.results[i];
|
|
@@ -207,6 +219,23 @@ class PublishCommand {
|
|
|
207
219
|
}
|
|
208
220
|
}
|
|
209
221
|
}
|
|
222
|
+
logger.info('✅ Results published successfully!');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async #publishErrors() {
|
|
226
|
+
if (!this.errors.length) {
|
|
227
|
+
logger.debug('⚠️ No errors to publish');
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
logger.info('🛑 Publishing errors...');
|
|
231
|
+
for (const config of this.configs) {
|
|
232
|
+
if (config.targets) {
|
|
233
|
+
for (const target of config.targets) {
|
|
234
|
+
await target_manager.handleErrors({ target, errors: this.errors });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
throw new Error(this.errors.join('\n'));
|
|
210
239
|
}
|
|
211
240
|
|
|
212
241
|
}
|
|
@@ -86,6 +86,22 @@ class BaseExtension {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* @param {string|number} text
|
|
91
|
+
*/
|
|
92
|
+
bold(text) {
|
|
93
|
+
switch (this.target.name) {
|
|
94
|
+
case 'teams':
|
|
95
|
+
return `**${text}**`;
|
|
96
|
+
case 'slack':
|
|
97
|
+
return `*${text}*`;
|
|
98
|
+
case 'chat':
|
|
99
|
+
return `<b>${text}</b>`;
|
|
100
|
+
default:
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
}
|
|
90
106
|
|
|
91
107
|
module.exports = { BaseExtension }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { BaseExtension } = require('./base.extension');
|
|
2
|
+
const { STATUS, HOOK } = require("../helpers/constants");
|
|
3
|
+
|
|
4
|
+
class ErrorClustersExtension extends BaseExtension {
|
|
5
|
+
|
|
6
|
+
constructor(target, extension, result, payload, root_payload) {
|
|
7
|
+
super(target, extension, result, payload, root_payload);
|
|
8
|
+
this.#setDefaultOptions();
|
|
9
|
+
this.#setDefaultInputs();
|
|
10
|
+
this.updateExtensionInputs();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run() {
|
|
14
|
+
this.#setText();
|
|
15
|
+
this.attach();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#setDefaultOptions() {
|
|
19
|
+
this.default_options.hook = HOOK.AFTER_SUMMARY,
|
|
20
|
+
this.default_options.condition = STATUS.PASS_OR_FAIL;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#setDefaultInputs() {
|
|
24
|
+
this.default_inputs.title = 'Top Errors';
|
|
25
|
+
this.default_inputs.title_link = '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#setText() {
|
|
29
|
+
const data = this.extension.inputs.data;
|
|
30
|
+
if (!data || !data.length) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const clusters = data;
|
|
35
|
+
|
|
36
|
+
const texts = [];
|
|
37
|
+
for (const cluster of clusters) {
|
|
38
|
+
texts.push(`${cluster.failure} - ${this.bold(`(x${cluster.count})`)}`);
|
|
39
|
+
}
|
|
40
|
+
this.text = this.mergeTexts(texts);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { ErrorClustersExtension }
|
package/src/extensions/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const { CustomExtension } = require('./custom.extension');
|
|
|
12
12
|
const { EXTENSION } = require('../helpers/constants');
|
|
13
13
|
const { checkCondition } = require('../helpers/helper');
|
|
14
14
|
const logger = require('../utils/logger');
|
|
15
|
+
const { ErrorClustersExtension } = require('./error-clusters.extension');
|
|
15
16
|
|
|
16
17
|
async function run(options) {
|
|
17
18
|
const { target, result, hook } = options;
|
|
@@ -60,6 +61,8 @@ function getExtensionRunner(extension, options) {
|
|
|
60
61
|
return new AIFailureSummaryExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
61
62
|
case EXTENSION.SMART_ANALYSIS:
|
|
62
63
|
return new SmartAnalysisExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
64
|
+
case EXTENSION.ERROR_CLUSTERS:
|
|
65
|
+
return new ErrorClustersExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
63
66
|
default:
|
|
64
67
|
return require(extension.name);
|
|
65
68
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { BaseExtension } = require('./base.extension');
|
|
2
2
|
const { STATUS, HOOK } = require("../helpers/constants");
|
|
3
|
+
const logger = require('../utils/logger');
|
|
3
4
|
|
|
4
5
|
class SmartAnalysisExtension extends BaseExtension {
|
|
5
6
|
|
|
@@ -21,7 +22,7 @@ class SmartAnalysisExtension extends BaseExtension {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
#setDefaultInputs() {
|
|
24
|
-
this.default_inputs.title = '
|
|
25
|
+
this.default_inputs.title = '';
|
|
25
26
|
this.default_inputs.title_link = '';
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -37,6 +38,11 @@ class SmartAnalysisExtension extends BaseExtension {
|
|
|
37
38
|
*/
|
|
38
39
|
const execution_metrics = data.execution_metrics[0];
|
|
39
40
|
|
|
41
|
+
if (!execution_metrics) {
|
|
42
|
+
logger.warn('⚠️ No execution metrics found. Skipping.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
const smart_analysis = [];
|
|
41
47
|
if (execution_metrics.newly_failed) {
|
|
42
48
|
smart_analysis.push(`⭕ Newly Failed: ${execution_metrics.newly_failed}`);
|
|
@@ -54,7 +60,21 @@ class SmartAnalysisExtension extends BaseExtension {
|
|
|
54
60
|
smart_analysis.push(`🟢 Recovered: ${execution_metrics.recovered}`);
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
const texts = [];
|
|
64
|
+
const rows = [];
|
|
65
|
+
for (const item of smart_analysis) {
|
|
66
|
+
rows.push(item);
|
|
67
|
+
if (rows.length === 3) {
|
|
68
|
+
texts.push(rows.join(' | '));
|
|
69
|
+
rows.length = 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (rows.length > 0) {
|
|
74
|
+
texts.push(rows.join(' | '));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.text = this.mergeTexts(texts);
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
}
|
package/src/helpers/constants.js
CHANGED
|
@@ -22,6 +22,7 @@ const TARGET = Object.freeze({
|
|
|
22
22
|
const EXTENSION = Object.freeze({
|
|
23
23
|
AI_FAILURE_SUMMARY: 'ai-failure-summary',
|
|
24
24
|
SMART_ANALYSIS: 'smart-analysis',
|
|
25
|
+
ERROR_CLUSTERS: 'error-clusters',
|
|
25
26
|
HYPERLINKS: 'hyperlinks',
|
|
26
27
|
MENTIONS: 'mentions',
|
|
27
28
|
REPORT_PORTAL_ANALYSIS: 'report-portal-analysis',
|
package/src/index.d.ts
CHANGED
|
@@ -230,6 +230,7 @@ export interface PublishReport {
|
|
|
230
230
|
run?: string;
|
|
231
231
|
show_failure_summary?: boolean;
|
|
232
232
|
show_smart_analysis?: boolean;
|
|
233
|
+
show_error_clusters?: boolean;
|
|
233
234
|
targets?: Target[];
|
|
234
235
|
extensions?: Extension[];
|
|
235
236
|
results?: ParseOptions[] | PerformanceParseOptions[] | CustomResultOptions[];
|
package/src/targets/chat.js
CHANGED
|
@@ -223,7 +223,7 @@ const default_inputs = {
|
|
|
223
223
|
publish: 'test-summary',
|
|
224
224
|
include_suites: true,
|
|
225
225
|
max_suites: 10,
|
|
226
|
-
only_failures:
|
|
226
|
+
only_failures: true,
|
|
227
227
|
include_failure_details: false,
|
|
228
228
|
duration: '',
|
|
229
229
|
metrics: [
|
|
@@ -238,7 +238,31 @@ const default_inputs = {
|
|
|
238
238
|
]
|
|
239
239
|
};
|
|
240
240
|
|
|
241
|
+
async function handleErrors({ target, errors }) {
|
|
242
|
+
let title = 'Error: Reporting Test Results';
|
|
243
|
+
title = target.inputs.title ? title + ' - ' + target.inputs.title : title;
|
|
244
|
+
|
|
245
|
+
const root_payload = getRootPayload();
|
|
246
|
+
const payload = root_payload.cards[0];
|
|
247
|
+
|
|
248
|
+
payload.sections.push({
|
|
249
|
+
"widgets": [
|
|
250
|
+
{
|
|
251
|
+
"textParagraph": {
|
|
252
|
+
text: `<b>${title}</b><br><br><b>Errors</b>: <br>${errors.join('<br>')}`
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return request.post({
|
|
259
|
+
url: target.inputs.url,
|
|
260
|
+
body: root_payload
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
241
264
|
module.exports = {
|
|
242
265
|
run,
|
|
266
|
+
handleErrors,
|
|
243
267
|
default_options
|
|
244
268
|
}
|
package/src/targets/index.js
CHANGED
|
@@ -34,6 +34,14 @@ async function run(target, result) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
async function handleErrors({ target, errors }) {
|
|
38
|
+
const target_runner = getTargetRunner(target);
|
|
39
|
+
if (target_runner.handleErrors) {
|
|
40
|
+
await target_runner.handleErrors({ target, errors });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
module.exports = {
|
|
38
|
-
run
|
|
45
|
+
run,
|
|
46
|
+
handleErrors
|
|
39
47
|
}
|
package/src/targets/slack.js
CHANGED
|
@@ -249,7 +249,7 @@ const default_inputs = {
|
|
|
249
249
|
publish: 'test-summary',
|
|
250
250
|
include_suites: true,
|
|
251
251
|
max_suites: 10,
|
|
252
|
-
only_failures:
|
|
252
|
+
only_failures: true,
|
|
253
253
|
include_failure_details: false,
|
|
254
254
|
duration: '',
|
|
255
255
|
metrics: [
|
|
@@ -264,7 +264,45 @@ const default_inputs = {
|
|
|
264
264
|
]
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
async function handleErrors({ target, errors }) {
|
|
268
|
+
let title = 'Error: Reporting Test Results';
|
|
269
|
+
title = target.inputs.title ? title + ' - ' + target.inputs.title : title;
|
|
270
|
+
|
|
271
|
+
const blocks = [];
|
|
272
|
+
|
|
273
|
+
blocks.push({
|
|
274
|
+
"type": "section",
|
|
275
|
+
"text": {
|
|
276
|
+
"type": "mrkdwn",
|
|
277
|
+
"text": title
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
blocks.push({
|
|
281
|
+
"type": "section",
|
|
282
|
+
"text": {
|
|
283
|
+
"type": "mrkdwn",
|
|
284
|
+
"text": errors.join('\n\n')
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const payload = {
|
|
289
|
+
"attachments": [
|
|
290
|
+
{
|
|
291
|
+
"color": COLORS.DANGER,
|
|
292
|
+
"blocks": blocks,
|
|
293
|
+
"fallback": title,
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
return request.post({
|
|
299
|
+
url: target.inputs.url,
|
|
300
|
+
body: payload
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
267
304
|
module.exports = {
|
|
268
305
|
run,
|
|
306
|
+
handleErrors,
|
|
269
307
|
default_options
|
|
270
308
|
}
|
package/src/targets/teams.js
CHANGED
|
@@ -284,7 +284,7 @@ const default_inputs = {
|
|
|
284
284
|
publish: 'test-summary',
|
|
285
285
|
include_suites: true,
|
|
286
286
|
max_suites: 10,
|
|
287
|
-
only_failures:
|
|
287
|
+
only_failures: true,
|
|
288
288
|
include_failure_details: false,
|
|
289
289
|
width: '',
|
|
290
290
|
duration: '',
|
|
@@ -300,7 +300,40 @@ const default_inputs = {
|
|
|
300
300
|
]
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
async function handleErrors({ target, errors }) {
|
|
304
|
+
let title = 'Error: Reporting Test Results';
|
|
305
|
+
title = target.inputs.title ? title + ' - ' + target.inputs.title : title;
|
|
306
|
+
|
|
307
|
+
const root_payload = getRootPayload();
|
|
308
|
+
const payload = getMainPayload(target);
|
|
309
|
+
|
|
310
|
+
payload.body.push({
|
|
311
|
+
"type": "TextBlock",
|
|
312
|
+
"text": title,
|
|
313
|
+
"size": "medium",
|
|
314
|
+
"weight": "bolder",
|
|
315
|
+
"wrap": true
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
payload.body.push({
|
|
319
|
+
"type": "TextBlock",
|
|
320
|
+
"text": errors.join('\n'),
|
|
321
|
+
"size": "medium",
|
|
322
|
+
"weight": "bolder",
|
|
323
|
+
"wrap": true
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
setRootPayload(root_payload, payload);
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
return request.post({
|
|
330
|
+
url: target.inputs.url,
|
|
331
|
+
body: root_payload
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
303
335
|
module.exports = {
|
|
304
336
|
run,
|
|
337
|
+
handleErrors,
|
|
305
338
|
default_options
|
|
306
339
|
}
|