testbeats 2.6.0 → 2.7.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/package.json +1 -1
- package/src/beats/beats.api.js +14 -0
- package/src/beats/beats.js +30 -4
- package/src/beats/beats.types.d.ts +8 -0
- package/src/commands/generate-config.command.js +2 -1
- package/src/extensions/failure-signatures.extension.js +43 -0
- package/src/extensions/index.js +3 -0
- package/src/helpers/constants.js +1 -0
- package/src/index.d.ts +21 -2
package/package.json
CHANGED
package/src/beats/beats.api.js
CHANGED
|
@@ -71,6 +71,20 @@ class BeatsApi {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {string} run_id
|
|
77
|
+
* @returns {import('./beats.types').IFailureSignature[]}
|
|
78
|
+
*/
|
|
79
|
+
getFailureSignatures(run_id) {
|
|
80
|
+
return request.get({
|
|
81
|
+
url: `${this.getBaseUrl()}/api/core/v1/automation/test-run-executions/${run_id}/failure-signatures`,
|
|
82
|
+
headers: {
|
|
83
|
+
'x-api-key': this.config.api_key
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
/**
|
|
75
89
|
*
|
|
76
90
|
* @param {string} run_id
|
package/src/beats/beats.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { getCIInformation } = require('../helpers/ci');
|
|
2
2
|
const logger = require('../utils/logger');
|
|
3
3
|
const { BeatsApi } = require('./beats.api');
|
|
4
|
-
const { HOOK, PROCESS_STATUS } = require('../helpers/constants');
|
|
4
|
+
const { HOOK, PROCESS_STATUS, EXTENSION } = require('../helpers/constants');
|
|
5
5
|
const TestResult = require('test-results-parser/src/models/TestResult');
|
|
6
6
|
const { BeatsAttachments } = require('./beats.attachments');
|
|
7
7
|
|
|
@@ -99,6 +99,7 @@ class Beats {
|
|
|
99
99
|
await this.#attachFailureSummary();
|
|
100
100
|
await this.#attachFailureAnalysis();
|
|
101
101
|
await this.#attachSmartAnalysis();
|
|
102
|
+
await this.#attachFailureSignatures();
|
|
102
103
|
await this.#attachErrorClusters();
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -169,6 +170,30 @@ class Beats {
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
async #attachFailureSignatures() {
|
|
174
|
+
if (this.result.status !== 'FAIL') {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (this.config.show_failure_signatures === false) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
logger.info('🔍 Fetching Failure Signatures...');
|
|
182
|
+
const signatures = await this.api.getFailureSignatures(this.test_run_id);
|
|
183
|
+
this.config.extensions.push({
|
|
184
|
+
name: EXTENSION.FAILURE_SIGNATURES,
|
|
185
|
+
hook: HOOK.AFTER_SUMMARY,
|
|
186
|
+
order: 400,
|
|
187
|
+
inputs: {
|
|
188
|
+
data: signatures
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
logger.error(`❌ Unable to attach failure signatures: ${error.message}`, error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
172
197
|
#getDelay() {
|
|
173
198
|
if (process.env.TEST_BEATS_DELAY) {
|
|
174
199
|
return parseInt(process.env.TEST_BEATS_DELAY);
|
|
@@ -203,10 +228,11 @@ class Beats {
|
|
|
203
228
|
}
|
|
204
229
|
|
|
205
230
|
async #attachErrorClusters() {
|
|
206
|
-
|
|
231
|
+
// Legacy feature: only attach if explicitly enabled
|
|
232
|
+
if (this.config.show_error_clusters !== true) {
|
|
207
233
|
return;
|
|
208
234
|
}
|
|
209
|
-
if (this.
|
|
235
|
+
if (this.result.status !== 'FAIL') {
|
|
210
236
|
return;
|
|
211
237
|
}
|
|
212
238
|
try {
|
|
@@ -215,7 +241,7 @@ class Beats {
|
|
|
215
241
|
this.config.extensions.push({
|
|
216
242
|
name: 'error-clusters',
|
|
217
243
|
hook: HOOK.AFTER_SUMMARY,
|
|
218
|
-
order:
|
|
244
|
+
order: 401,
|
|
219
245
|
inputs: {
|
|
220
246
|
data: res.values
|
|
221
247
|
}
|
|
@@ -432,7 +432,8 @@ class GenerateConfigCommand {
|
|
|
432
432
|
{ title: 'Metadata', value: 'metadata' },
|
|
433
433
|
{ title: 'AI Failure Summary', value: 'ai-failure-summary' },
|
|
434
434
|
{ title: 'Smart Analysis', value: 'smart-analysis' },
|
|
435
|
-
{ title: '
|
|
435
|
+
{ title: 'Failure Signatures', value: 'failure-signatures' },
|
|
436
|
+
{ title: 'Error Clusters (Legacy)', value: 'error-clusters' }
|
|
436
437
|
];
|
|
437
438
|
}
|
|
438
439
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const { BaseExtension } = require('./base.extension');
|
|
2
|
+
const { STATUS, HOOK } = require("../helpers/constants");
|
|
3
|
+
const { truncate } = require('../helpers/helper');
|
|
4
|
+
|
|
5
|
+
class FailureSignaturesExtension extends BaseExtension {
|
|
6
|
+
|
|
7
|
+
constructor(target, extension, result, payload, root_payload) {
|
|
8
|
+
super(target, extension, result, payload, root_payload);
|
|
9
|
+
this.#setDefaultOptions();
|
|
10
|
+
this.#setDefaultInputs();
|
|
11
|
+
this.updateExtensionInputs();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
run() {
|
|
15
|
+
this.#setText();
|
|
16
|
+
this.attach();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#setDefaultOptions() {
|
|
20
|
+
this.default_options.hook = HOOK.AFTER_SUMMARY,
|
|
21
|
+
this.default_options.condition = STATUS.PASS_OR_FAIL;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#setDefaultInputs() {
|
|
25
|
+
this.default_inputs.title = 'Top Failures';
|
|
26
|
+
this.default_inputs.title_link = '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#setText() {
|
|
30
|
+
const signatures = this.extension.inputs.data;
|
|
31
|
+
if (!signatures || !signatures.length) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const texts = [];
|
|
36
|
+
for (const signature of signatures) {
|
|
37
|
+
texts.push(`${truncate(signature.signature, 150)} - ${this.bold(`(x${signature.count})`)}`);
|
|
38
|
+
}
|
|
39
|
+
this.text = this.platform.bullets(texts);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { FailureSignaturesExtension }
|
package/src/extensions/index.js
CHANGED
|
@@ -13,6 +13,7 @@ const { EXTENSION } = require('../helpers/constants');
|
|
|
13
13
|
const { checkCondition } = require('../helpers/helper');
|
|
14
14
|
const logger = require('../utils/logger');
|
|
15
15
|
const { ErrorClustersExtension } = require('./error-clusters.extension');
|
|
16
|
+
const { FailureSignaturesExtension } = require('./failure-signatures.extension');
|
|
16
17
|
const { FailureAnalysisExtension } = require('./failure-analysis.extension');
|
|
17
18
|
const { BrowserstackExtension } = require('./browserstack.extension');
|
|
18
19
|
|
|
@@ -75,6 +76,8 @@ function getExtensionRunner(extension, options) {
|
|
|
75
76
|
return new ErrorClustersExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
76
77
|
case EXTENSION.BROWSERSTACK:
|
|
77
78
|
return new BrowserstackExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
79
|
+
case EXTENSION.FAILURE_SIGNATURES:
|
|
80
|
+
return new FailureSignaturesExtension(options.target, extension, options.result, options.payload, options.root_payload);
|
|
78
81
|
default:
|
|
79
82
|
return require(extension.name);
|
|
80
83
|
}
|
package/src/helpers/constants.js
CHANGED
|
@@ -27,6 +27,7 @@ const EXTENSION = Object.freeze({
|
|
|
27
27
|
FAILURE_ANALYSIS: 'failure-analysis',
|
|
28
28
|
SMART_ANALYSIS: 'smart-analysis',
|
|
29
29
|
ERROR_CLUSTERS: 'error-clusters',
|
|
30
|
+
FAILURE_SIGNATURES: 'failure-signatures',
|
|
30
31
|
BROWSERSTACK: 'browserstack',
|
|
31
32
|
HYPERLINKS: 'hyperlinks',
|
|
32
33
|
MENTIONS: 'mentions',
|
package/src/index.d.ts
CHANGED
|
@@ -20,10 +20,10 @@ export interface IExtension {
|
|
|
20
20
|
condition?: Condition;
|
|
21
21
|
hook?: Hook;
|
|
22
22
|
order?: number;
|
|
23
|
-
inputs?: ReportPortalAnalysisInputs | ReportPortalHistoryInputs | HyperlinkInputs | MentionInputs | QuickChartTestSummaryInputs | PercyAnalysisInputs | CustomExtensionInputs | MetadataInputs | CIInfoInputs | AIFailureSummaryInputs | BrowserstackInputs;
|
|
23
|
+
inputs?: ReportPortalAnalysisInputs | ReportPortalHistoryInputs | HyperlinkInputs | MentionInputs | QuickChartTestSummaryInputs | PercyAnalysisInputs | CustomExtensionInputs | MetadataInputs | CIInfoInputs | AIFailureSummaryInputs | BrowserstackInputs | FailureSignaturesInputs | ErrorClustersInputs;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export type ExtensionName = 'report-portal-analysis' | 'hyperlinks' | 'mentions' | 'report-portal-history' | 'quick-chart-test-summary' | 'metadata' | 'ci-info' | 'custom' | 'ai-failure-summary';
|
|
26
|
+
export type ExtensionName = 'report-portal-analysis' | 'hyperlinks' | 'mentions' | 'report-portal-history' | 'quick-chart-test-summary' | 'metadata' | 'ci-info' | 'custom' | 'ai-failure-summary' | 'failure-signatures' | 'error-clusters';
|
|
27
27
|
export type Hook = 'start' | 'end' | 'after-summary';
|
|
28
28
|
export type TargetName = 'slack' | 'teams' | 'chat' | 'github' | 'github-output' | 'custom' | 'delay';
|
|
29
29
|
export type PublishReportType = 'test-summary' | 'test-summary-slim' | 'failure-details';
|
|
@@ -86,6 +86,23 @@ export interface AIFailureSummaryInputs extends ExtensionInputs {
|
|
|
86
86
|
failure_summary: string;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
export interface FailureSignaturesInputs extends ExtensionInputs {
|
|
90
|
+
data?: Array<{
|
|
91
|
+
id: string;
|
|
92
|
+
signature: string;
|
|
93
|
+
failure_type: string;
|
|
94
|
+
count: number;
|
|
95
|
+
}>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ErrorClustersInputs extends ExtensionInputs {
|
|
99
|
+
data?: Array<{
|
|
100
|
+
test_failure_id: string;
|
|
101
|
+
failure: string;
|
|
102
|
+
count: number;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
105
|
+
|
|
89
106
|
export interface BrowserStackAutomationBuild {
|
|
90
107
|
name: string;
|
|
91
108
|
hashed_id: string;
|
|
@@ -309,7 +326,9 @@ export interface PublishReport {
|
|
|
309
326
|
show_failure_summary?: boolean;
|
|
310
327
|
show_failure_analysis?: boolean;
|
|
311
328
|
show_smart_analysis?: boolean;
|
|
329
|
+
/** @deprecated Use show_failure_signatures instead. Legacy feature - only enabled when explicitly set to true. */
|
|
312
330
|
show_error_clusters?: boolean;
|
|
331
|
+
show_failure_signatures?: boolean;
|
|
313
332
|
targets?: ITarget[];
|
|
314
333
|
extensions?: IExtension[];
|
|
315
334
|
results?: ParseOptions[] | PerformanceParseOptions[] | CustomResultOptions[];
|