playwright-ai-reporter 0.0.4
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 +1183 -0
- package/dist/colors.d.ts +54 -0
- package/dist/colors.js +57 -0
- package/dist/examples/ReporterWorkflow.d.ts +54 -0
- package/dist/examples/ReporterWorkflow.js +307 -0
- package/dist/providers/ProviderRegistry.d.ts +79 -0
- package/dist/providers/ProviderRegistry.js +195 -0
- package/dist/providers/ai/AIProviderFactory.d.ts +33 -0
- package/dist/providers/ai/AIProviderFactory.js +82 -0
- package/dist/providers/ai/AnthropicProvider.d.ts +15 -0
- package/dist/providers/ai/AnthropicProvider.js +128 -0
- package/dist/providers/ai/AzureOpenAIProvider.d.ts +20 -0
- package/dist/providers/ai/AzureOpenAIProvider.js +158 -0
- package/dist/providers/ai/GoogleAIProvider.d.ts +17 -0
- package/dist/providers/ai/GoogleAIProvider.js +154 -0
- package/dist/providers/ai/MistralProvider.d.ts +16 -0
- package/dist/providers/ai/MistralProvider.js +137 -0
- package/dist/providers/ai/OpenAIProvider.d.ts +16 -0
- package/dist/providers/ai/OpenAIProvider.js +141 -0
- package/dist/providers/bugTrackers/AzureDevOpsBugTracker.d.ts +32 -0
- package/dist/providers/bugTrackers/AzureDevOpsBugTracker.js +295 -0
- package/dist/providers/bugTrackers/GitHubBugTracker.d.ts +28 -0
- package/dist/providers/bugTrackers/GitHubBugTracker.js +241 -0
- package/dist/providers/bugTrackers/JiraBugTracker.d.ts +29 -0
- package/dist/providers/bugTrackers/JiraBugTracker.js +279 -0
- package/dist/providers/databases/MySQLProvider.d.ts +32 -0
- package/dist/providers/databases/MySQLProvider.js +274 -0
- package/dist/providers/databases/SQLiteProvider.d.ts +28 -0
- package/dist/providers/databases/SQLiteProvider.js +272 -0
- package/dist/providers/factories/BugTrackerFactory.d.ts +20 -0
- package/dist/providers/factories/BugTrackerFactory.js +50 -0
- package/dist/providers/factories/DatabaseFactory.d.ts +28 -0
- package/dist/providers/factories/DatabaseFactory.js +71 -0
- package/dist/providers/factories/NotificationFactory.d.ts +24 -0
- package/dist/providers/factories/NotificationFactory.js +64 -0
- package/dist/providers/factories/PRProviderFactory.d.ts +20 -0
- package/dist/providers/factories/PRProviderFactory.js +45 -0
- package/dist/providers/index.d.ts +28 -0
- package/dist/providers/index.js +55 -0
- package/dist/providers/interfaces/IAIProvider.d.ts +59 -0
- package/dist/providers/interfaces/IAIProvider.js +5 -0
- package/dist/providers/interfaces/IBugTrackerProvider.d.ts +70 -0
- package/dist/providers/interfaces/IBugTrackerProvider.js +20 -0
- package/dist/providers/interfaces/IDatabaseProvider.d.ts +90 -0
- package/dist/providers/interfaces/IDatabaseProvider.js +5 -0
- package/dist/providers/interfaces/INotificationProvider.d.ts +59 -0
- package/dist/providers/interfaces/INotificationProvider.js +13 -0
- package/dist/providers/interfaces/IPRProvider.d.ts +82 -0
- package/dist/providers/interfaces/IPRProvider.js +5 -0
- package/dist/providers/notifications/EmailNotificationProvider.d.ts +29 -0
- package/dist/providers/notifications/EmailNotificationProvider.js +290 -0
- package/dist/providers/pr/AzureDevOpsPRProvider.d.ts +30 -0
- package/dist/providers/pr/AzureDevOpsPRProvider.js +263 -0
- package/dist/providers/pr/GitHubPRProvider.d.ts +29 -0
- package/dist/providers/pr/GitHubPRProvider.js +320 -0
- package/dist/reporter.d.ts +138 -0
- package/dist/reporter.js +787 -0
- package/dist/types/index.d.ts +168 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/buildInfoUtils.d.ts +26 -0
- package/dist/utils/buildInfoUtils.js +125 -0
- package/dist/utils/configValidator.d.ts +67 -0
- package/dist/utils/configValidator.js +454 -0
- package/dist/utils/fileHandlerUtils.d.ts +42 -0
- package/dist/utils/fileHandlerUtils.js +136 -0
- package/dist/utils/genaiUtils.d.ts +38 -0
- package/dist/utils/genaiUtils.js +178 -0
- package/dist/utils/historyUtils.d.ts +49 -0
- package/dist/utils/historyUtils.js +118 -0
- package/dist/utils/utils.d.ts +104 -0
- package/dist/utils/utils.js +371 -0
- package/docs/API.md +591 -0
- package/docs/ENV_CONFIG_GUIDE.md +444 -0
- package/docs/IMPLEMENTATION_SUMMARY.md +285 -0
- package/docs/PROVIDERS.md +261 -0
- package/docs/QUICKSTART.md +350 -0
- package/docs/README.md +253 -0
- package/docs/TROUBLESHOOTING.md +577 -0
- package/docs/design.md +384 -0
- package/docs/logo.png +0 -0
- package/examples/README.md +326 -0
- package/examples/VALIDATION.md +68 -0
- package/examples/env-configs/.env.anthropic-minimal +40 -0
- package/examples/env-configs/.env.azure-stack +71 -0
- package/examples/env-configs/.env.example +32 -0
- package/examples/env-configs/.env.github-stack +57 -0
- package/examples/env-configs/.env.google-mysql +61 -0
- package/examples/env-configs/.env.ms-auth-examples +56 -0
- package/examples/env-configs/.env.openai-jira +64 -0
- package/examples/package.json +22 -0
- package/package.json +70 -0
- package/playwright-ai-reporter-0.0.4.tgz +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Logger = exports.TestUtils = void 0;
|
|
4
|
+
const colors_1 = require("../colors");
|
|
5
|
+
// Adding required enum or interface definitions for Team
|
|
6
|
+
var Team;
|
|
7
|
+
(function (Team) {
|
|
8
|
+
Team["Frontend"] = "Frontend";
|
|
9
|
+
Team["Backend"] = "Backend";
|
|
10
|
+
Team["QA"] = "QA";
|
|
11
|
+
Team["DevOps"] = "DevOps";
|
|
12
|
+
Team["Performance"] = "Performance";
|
|
13
|
+
Team["Security"] = "Security";
|
|
14
|
+
Team["Accessibility"] = "Accessibility";
|
|
15
|
+
Team["Mobile"] = "Mobile";
|
|
16
|
+
Team["API"] = "API";
|
|
17
|
+
Team["Database"] = "Database";
|
|
18
|
+
Team["Analytics"] = "Analytics";
|
|
19
|
+
Team["Infrastructure"] = "Infrastructure";
|
|
20
|
+
Team["Monitoring"] = "Monitoring";
|
|
21
|
+
Team["Documentation"] = "Documentation";
|
|
22
|
+
Team["Support"] = "Support";
|
|
23
|
+
Team["Marketing"] = "Marketing";
|
|
24
|
+
Team["Sales"] = "Sales";
|
|
25
|
+
Team["Training"] = "Training";
|
|
26
|
+
Team["Research"] = "Research";
|
|
27
|
+
Team["Compliance"] = "Compliance";
|
|
28
|
+
Team["Legal"] = "Legal";
|
|
29
|
+
Team["Product"] = "Product";
|
|
30
|
+
Team["Design"] = "Design";
|
|
31
|
+
Team["UserExperience"] = "User Experience";
|
|
32
|
+
Team["UserInterface"] = "User Interface";
|
|
33
|
+
Team["BusinessIntelligence"] = "Business Intelligence";
|
|
34
|
+
Team["DataScience"] = "Data Science";
|
|
35
|
+
Team["DataEngineering"] = "Data Engineering";
|
|
36
|
+
Team["DataAnalytics"] = "Data Analytics";
|
|
37
|
+
Team["DataVisualization"] = "Data Visualization";
|
|
38
|
+
Team["DataGovernance"] = "Data Governance";
|
|
39
|
+
Team["DataQuality"] = "Data Quality";
|
|
40
|
+
// Add other teams as needed
|
|
41
|
+
})(Team || (Team = {}));
|
|
42
|
+
const FallbackTeam = 'Unknown'; // Default fallback when no team is identified
|
|
43
|
+
/**
|
|
44
|
+
* Utility class containing static methods for test result processing and calculations.
|
|
45
|
+
* Provides functionality for formatting time, calculating statistics, and processing test results.
|
|
46
|
+
*/
|
|
47
|
+
class TestUtils {
|
|
48
|
+
/**
|
|
49
|
+
* Formats a time duration from seconds into a human-readable string.
|
|
50
|
+
* Converts to minutes if the duration is longer than 60 seconds.
|
|
51
|
+
*
|
|
52
|
+
* @param timeInSeconds - The time duration to format in seconds
|
|
53
|
+
* @returns A formatted string with appropriate units (e.g., "1.23s" or "2.50min")
|
|
54
|
+
*/
|
|
55
|
+
static formatTime(timeInSeconds) {
|
|
56
|
+
return timeInSeconds < 60 ? `${timeInSeconds.toFixed(2)}s` : `${(timeInSeconds / 60).toFixed(2)}min`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculates the average duration from an array of time measurements.
|
|
60
|
+
*
|
|
61
|
+
* @param durations - Array of durations in seconds
|
|
62
|
+
* @returns The average duration in seconds, or 0 if the array is empty
|
|
63
|
+
*/
|
|
64
|
+
static calculateAverageTime(durations) {
|
|
65
|
+
return durations.length === 0 ? 0 : durations.reduce((sum, duration) => sum + duration, 0) / durations.length;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Finds the slowest tests from all test records.
|
|
69
|
+
* Only considers passed tests when calculating the slowest ones.
|
|
70
|
+
*
|
|
71
|
+
* @param testRecords - Map of all test records
|
|
72
|
+
* @param limit - Maximum number of slow tests to return
|
|
73
|
+
* @returns Array of the slowest tests, sorted by duration
|
|
74
|
+
*/
|
|
75
|
+
static findSlowestTests(testRecords, limit) {
|
|
76
|
+
return Array.from(testRecords.values())
|
|
77
|
+
.flatMap(({ test, attempts }) => attempts
|
|
78
|
+
.filter((a) => a.status === 'passed')
|
|
79
|
+
.map((a) => ({
|
|
80
|
+
testTitle: test.testTitle,
|
|
81
|
+
duration: a.duration,
|
|
82
|
+
})))
|
|
83
|
+
.sort((a, b) => b.duration - a.duration)
|
|
84
|
+
.slice(0, limit);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Categorizes the error message into predefined types
|
|
88
|
+
* @param message - Error message
|
|
89
|
+
* @returns Error category
|
|
90
|
+
*/
|
|
91
|
+
static categorizeError(message) {
|
|
92
|
+
if (message.includes('No node found') || message.includes('not visible')) {
|
|
93
|
+
return 'ElementNotFound';
|
|
94
|
+
}
|
|
95
|
+
else if (message.includes('Timeout') || message.includes('timed out')) {
|
|
96
|
+
return 'Timeout/DelayedElement';
|
|
97
|
+
}
|
|
98
|
+
else if (message.includes('selector') || message.includes('locator')) {
|
|
99
|
+
return 'SelectorChanged';
|
|
100
|
+
}
|
|
101
|
+
else if (message.includes('expect(') || message.includes('assertion failed')) {
|
|
102
|
+
return 'AssertionFailure';
|
|
103
|
+
}
|
|
104
|
+
else if (message.includes('Network') || message.includes('fetch failed') || message.includes('status=')) {
|
|
105
|
+
return 'NetworkError';
|
|
106
|
+
}
|
|
107
|
+
else if (message.includes('javascript error') ||
|
|
108
|
+
message.includes('undefined is not') ||
|
|
109
|
+
message.includes('null')) {
|
|
110
|
+
return 'JavaScriptError';
|
|
111
|
+
}
|
|
112
|
+
else if (message.includes('navigation') || message.includes('page.goto')) {
|
|
113
|
+
return 'NavigationError';
|
|
114
|
+
}
|
|
115
|
+
else if (message.includes('element is not clickable') || message.includes('intercepted')) {
|
|
116
|
+
return 'ElementInteractionError';
|
|
117
|
+
}
|
|
118
|
+
else if (message.includes('permission') || message.includes('access denied')) {
|
|
119
|
+
return 'PermissionError';
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
return 'Unknown';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Convert test outcome to status
|
|
127
|
+
* @param outcome - Test outcome
|
|
128
|
+
* @returns Standardized status
|
|
129
|
+
*/
|
|
130
|
+
static outcomeToStatus(outcome) {
|
|
131
|
+
switch (outcome) {
|
|
132
|
+
case 'skipped':
|
|
133
|
+
return 'skipped';
|
|
134
|
+
case 'expected':
|
|
135
|
+
return 'passed';
|
|
136
|
+
case 'unexpected':
|
|
137
|
+
return 'failed';
|
|
138
|
+
case 'flaky':
|
|
139
|
+
return 'failed';
|
|
140
|
+
default:
|
|
141
|
+
return outcome;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Determines the team that owns a test based on test name and annotations
|
|
146
|
+
* @param test - Test case to analyze
|
|
147
|
+
* @returns Name of the team that owns the test
|
|
148
|
+
*/
|
|
149
|
+
static getOwningTeam(test) {
|
|
150
|
+
const testName = test.title || '';
|
|
151
|
+
for (const team in Team) {
|
|
152
|
+
if (testName.includes(this.wrap(team))) {
|
|
153
|
+
return team;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const teamName = test.annotations.find((a) => a.type === 'team')?.description;
|
|
157
|
+
if (teamName && teamName in Team) {
|
|
158
|
+
return teamName;
|
|
159
|
+
}
|
|
160
|
+
const ownerName = test.annotations.find((a) => a.type === 'owner')?.description;
|
|
161
|
+
if (ownerName && ownerName in Team) {
|
|
162
|
+
return ownerName;
|
|
163
|
+
}
|
|
164
|
+
if (process.env.FALLBACK_TEAM && process.env.FALLBACK_TEAM !== '' && process.env.FALLBACK_TEAM in Team) {
|
|
165
|
+
return process.env.FALLBACK_TEAM;
|
|
166
|
+
}
|
|
167
|
+
return FallbackTeam;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Helper method to wrap a string for team name matching
|
|
171
|
+
* @param text - Text to wrap
|
|
172
|
+
* @returns Wrapped text
|
|
173
|
+
*/
|
|
174
|
+
static wrap(text) {
|
|
175
|
+
return `[${text}]`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Processes all test records to generate comprehensive test results.
|
|
179
|
+
* Calculates passed, failed, and skipped test counts, and collects timing information.
|
|
180
|
+
*
|
|
181
|
+
* @param testRecords - Map of all test records
|
|
182
|
+
* @returns Object containing test counts, failures, and timing information
|
|
183
|
+
*/
|
|
184
|
+
static processTestResults(testRecords) {
|
|
185
|
+
let passedCount = 0;
|
|
186
|
+
let testCount = 0;
|
|
187
|
+
let skippedCount = 0;
|
|
188
|
+
let failedCount = 0;
|
|
189
|
+
const failures = [];
|
|
190
|
+
const passedDurations = [];
|
|
191
|
+
for (const { test, attempts } of testRecords.values()) {
|
|
192
|
+
testCount++;
|
|
193
|
+
const finalOutcome = test.outcome;
|
|
194
|
+
const finalAttempt = attempts[attempts.length - 1];
|
|
195
|
+
if (finalOutcome === 'expected' || finalOutcome === 'flaky') {
|
|
196
|
+
passedCount++;
|
|
197
|
+
passedDurations.push(...attempts.filter((a) => a.status === 'passed').map((a) => a.duration));
|
|
198
|
+
}
|
|
199
|
+
else if (finalOutcome === 'unexpected') {
|
|
200
|
+
const isTimeout = finalAttempt.errors.some((e) => e.message.includes('timeout'));
|
|
201
|
+
const combinedStack = finalAttempt.errors.map((e) => e.stack || '').join('\n');
|
|
202
|
+
const errorMessage = finalAttempt.errors[0]?.message || '';
|
|
203
|
+
const errorCategory = this.categorizeError(errorMessage);
|
|
204
|
+
failures.push({
|
|
205
|
+
testId: test.testId,
|
|
206
|
+
testTitle: test.testTitle,
|
|
207
|
+
suiteTitle: test.suiteTitle || 'Unknown Suite',
|
|
208
|
+
errorMessage: errorMessage,
|
|
209
|
+
errorStack: combinedStack,
|
|
210
|
+
duration: finalAttempt.duration,
|
|
211
|
+
owningTeam: test.owningTeam || 'Unknown Team',
|
|
212
|
+
isTimeout,
|
|
213
|
+
errorCategory,
|
|
214
|
+
testFile: test.testFile,
|
|
215
|
+
location: test.location,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else if (finalOutcome === 'skipped') {
|
|
219
|
+
skippedCount++;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
const errorMessage = finalAttempt.status === 'interrupted' ? 'Test was interrupted' : `Unknown outcome: ${finalOutcome}`;
|
|
223
|
+
const errorCategory = this.categorizeError(errorMessage);
|
|
224
|
+
failures.push({
|
|
225
|
+
testId: test.testId,
|
|
226
|
+
testTitle: test.testTitle,
|
|
227
|
+
suiteTitle: test.suiteTitle || 'Unknown Suite',
|
|
228
|
+
errorMessage: errorMessage,
|
|
229
|
+
errorStack: '',
|
|
230
|
+
duration: finalAttempt.duration,
|
|
231
|
+
owningTeam: test.owningTeam || 'Unknown Team',
|
|
232
|
+
isTimeout: false,
|
|
233
|
+
errorCategory,
|
|
234
|
+
testFile: test.testFile,
|
|
235
|
+
location: test.location,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
failedCount = failures.length;
|
|
240
|
+
return {
|
|
241
|
+
passedCount,
|
|
242
|
+
testCount,
|
|
243
|
+
skippedCount,
|
|
244
|
+
failedCount,
|
|
245
|
+
failures,
|
|
246
|
+
passedDurations,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
exports.TestUtils = TestUtils;
|
|
251
|
+
/**
|
|
252
|
+
* Logger class responsible for formatting and outputting test results.
|
|
253
|
+
* Provides methods for logging test summaries, metrics, and failures with appropriate formatting.
|
|
254
|
+
*/
|
|
255
|
+
class Logger {
|
|
256
|
+
/**
|
|
257
|
+
* Logs the overall test run summary with appropriate coloring.
|
|
258
|
+
* Includes total tests, passed tests, skipped tests, and total time.
|
|
259
|
+
*
|
|
260
|
+
* @param summary - The test summary to log
|
|
261
|
+
*/
|
|
262
|
+
static logSummary(summary) {
|
|
263
|
+
console.log('\n');
|
|
264
|
+
console.log(`${colors_1.colors.fgBlue}===============================================${colors_1.colors.reset}`);
|
|
265
|
+
console.log(`${colors_1.colors.fgCyan}Test Summary:${colors_1.colors.reset}`);
|
|
266
|
+
console.log(`${colors_1.colors.fgBlue}===============================================${colors_1.colors.reset}`);
|
|
267
|
+
if (summary.failures.length > 0) {
|
|
268
|
+
console.log(`${colors_1.colors.fgRed}❌ ${summary.failures.length} of ${summary.testCount} tests failed | ` +
|
|
269
|
+
`${summary.passedCount} passed | ${summary.skippedCount} skipped | ⏱ Total: ${summary.totalTimeDisplay}${colors_1.colors.reset}`);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
console.log(`${colors_1.colors.fgGreen}✅ All ${summary.testCount} tests passed | ` +
|
|
273
|
+
`${summary.skippedCount} skipped | ⏱ Total: ${summary.totalTimeDisplay}${colors_1.colors.reset}`);
|
|
274
|
+
}
|
|
275
|
+
// Display build information if available
|
|
276
|
+
if (summary.buildInfo) {
|
|
277
|
+
this.logBuildInfo(summary.buildInfo);
|
|
278
|
+
}
|
|
279
|
+
this.logMetrics(summary);
|
|
280
|
+
// Add warning for skipped tests
|
|
281
|
+
if (summary.skippedCount > 0) {
|
|
282
|
+
console.log(`\n${colors_1.colors.fgYellow}⚠️ Warning: ${summary.skippedCount} test${summary.skippedCount === 1 ? ' was' : 's were'} skipped.${colors_1.colors.reset}`);
|
|
283
|
+
console.log(`${colors_1.colors.fgYellow} Please ensure to test the skipped scenarios manually before deployment.${colors_1.colors.reset}`);
|
|
284
|
+
}
|
|
285
|
+
console.log(`${colors_1.colors.fgBlue}===============================================${colors_1.colors.reset}`);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Logs build information if available
|
|
289
|
+
*
|
|
290
|
+
* @param buildInfo - The build information to log
|
|
291
|
+
*/
|
|
292
|
+
static logBuildInfo(buildInfo) {
|
|
293
|
+
if (!buildInfo.isPipeline) {
|
|
294
|
+
console.log(`${colors_1.colors.fgMagenta}🖥️ Running locally${colors_1.colors.reset}`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
console.log(`${colors_1.colors.fgMagenta}\nBuild Information:${colors_1.colors.reset}`);
|
|
298
|
+
console.log(`${colors_1.colors.fgMagenta}- CI System: ${buildInfo.executionSystem || 'Unknown CI'}${colors_1.colors.reset}`);
|
|
299
|
+
if (buildInfo.buildNumber) {
|
|
300
|
+
console.log(`${colors_1.colors.fgMagenta}- Build: ${buildInfo.buildNumber}${colors_1.colors.reset}`);
|
|
301
|
+
}
|
|
302
|
+
if (buildInfo.buildBranch) {
|
|
303
|
+
console.log(`${colors_1.colors.fgMagenta}- Branch: ${buildInfo.buildBranch}${colors_1.colors.reset}`);
|
|
304
|
+
}
|
|
305
|
+
if (buildInfo.commitId) {
|
|
306
|
+
console.log(`${colors_1.colors.fgMagenta}- Commit: ${buildInfo.commitId.substring(0, 8)}${colors_1.colors.reset}`);
|
|
307
|
+
}
|
|
308
|
+
if (buildInfo.commitId) {
|
|
309
|
+
console.log(`${colors_1.colors.fgMagenta}- Commit: ${buildInfo.commitId.substring(0, 8)}${colors_1.colors.reset}`);
|
|
310
|
+
}
|
|
311
|
+
if (buildInfo.buildLink) {
|
|
312
|
+
console.log(`${colors_1.colors.fgMagenta}- Build link: ${buildInfo.buildLink}${colors_1.colors.reset}`);
|
|
313
|
+
}
|
|
314
|
+
if (buildInfo.artifactsLink) {
|
|
315
|
+
console.log(`${colors_1.colors.fgMagenta}- Artifacts: ${buildInfo.artifactsLink}${colors_1.colors.reset}`);
|
|
316
|
+
}
|
|
317
|
+
// Only show test link for Azure Pipelines, as this is specific to that system
|
|
318
|
+
if (buildInfo.testLink && buildInfo.executionSystem === 'Azure Pipelines') {
|
|
319
|
+
console.log(`${colors_1.colors.fgMagenta}- Test Results: ${buildInfo.testLink}${colors_1.colors.reset}`);
|
|
320
|
+
}
|
|
321
|
+
if (buildInfo.commitLink && buildInfo.executionSystem === 'GitHub Actions') {
|
|
322
|
+
console.log(`${colors_1.colors.fgMagenta}- Commit: ${buildInfo.commitLink}${colors_1.colors.reset}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Logs detailed metrics about the test run.
|
|
327
|
+
* Includes average test time and information about slow tests.
|
|
328
|
+
*
|
|
329
|
+
* @param summary - The test summary containing metrics to log
|
|
330
|
+
*/
|
|
331
|
+
static logMetrics(summary) {
|
|
332
|
+
console.log(`${colors_1.colors.fgMagenta}\nAdditional Metrics:${colors_1.colors.reset}`);
|
|
333
|
+
console.log(`${colors_1.colors.fgMagenta}- Average passed test time: ${summary.averageTime.toFixed(2)}s${colors_1.colors.reset}`);
|
|
334
|
+
if (summary.slowestTest > 0) {
|
|
335
|
+
console.log(`${colors_1.colors.fgMagenta}- Slowest test took: ${summary.slowestTest.toFixed(2)}s${colors_1.colors.reset}`);
|
|
336
|
+
console.log(`${colors_1.colors.fgMagenta}- Top 3 slowest tests:${colors_1.colors.reset}`);
|
|
337
|
+
summary.slowestTests.forEach((test, index) => {
|
|
338
|
+
console.log(` ${index + 1}. ${test.testTitle}: ` +
|
|
339
|
+
`${colors_1.colors.fgYellow}${test.duration.toFixed(2)}s${colors_1.colors.reset}`);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Logs detailed information about test failures.
|
|
345
|
+
* Includes test title, stack trace, and timeout information.
|
|
346
|
+
*
|
|
347
|
+
* @param failures - Array of test failures to log
|
|
348
|
+
*/
|
|
349
|
+
static logFailures(failures) {
|
|
350
|
+
console.log('\n');
|
|
351
|
+
console.log(`${colors_1.colors.fgRed}===============================================${colors_1.colors.reset}`);
|
|
352
|
+
console.log(`${colors_1.colors.fgRed}Test Failures:${colors_1.colors.reset}`);
|
|
353
|
+
console.log(`${colors_1.colors.fgRed}===============================================${colors_1.colors.reset}`);
|
|
354
|
+
failures.forEach((failure, index) => {
|
|
355
|
+
console.log('\n');
|
|
356
|
+
console.group(`--- Failure #${index + 1} ---`);
|
|
357
|
+
console.log(` Test: ${failure.testTitle}`);
|
|
358
|
+
console.log(` ${colors_1.colors.fgGreen}Category: ${failure.errorCategory}${colors_1.colors.reset}`);
|
|
359
|
+
if (failure.errorStack) {
|
|
360
|
+
console.log(` Stack Trace:\n${failure.errorStack}`);
|
|
361
|
+
}
|
|
362
|
+
if (failure.isTimeout) {
|
|
363
|
+
console.log(`${colors_1.colors.fgYellow} (This failure involved a timeout.)${colors_1.colors.reset}`);
|
|
364
|
+
}
|
|
365
|
+
console.groupEnd();
|
|
366
|
+
});
|
|
367
|
+
console.log(`${colors_1.colors.fgRed}\n❌ Tests failed with exit code 1${colors_1.colors.reset}`);
|
|
368
|
+
console.log(`${colors_1.colors.fgRed}===============================================${colors_1.colors.reset}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
exports.Logger = Logger;
|