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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1183 -0
  3. package/dist/colors.d.ts +54 -0
  4. package/dist/colors.js +57 -0
  5. package/dist/examples/ReporterWorkflow.d.ts +54 -0
  6. package/dist/examples/ReporterWorkflow.js +307 -0
  7. package/dist/providers/ProviderRegistry.d.ts +79 -0
  8. package/dist/providers/ProviderRegistry.js +195 -0
  9. package/dist/providers/ai/AIProviderFactory.d.ts +33 -0
  10. package/dist/providers/ai/AIProviderFactory.js +82 -0
  11. package/dist/providers/ai/AnthropicProvider.d.ts +15 -0
  12. package/dist/providers/ai/AnthropicProvider.js +128 -0
  13. package/dist/providers/ai/AzureOpenAIProvider.d.ts +20 -0
  14. package/dist/providers/ai/AzureOpenAIProvider.js +158 -0
  15. package/dist/providers/ai/GoogleAIProvider.d.ts +17 -0
  16. package/dist/providers/ai/GoogleAIProvider.js +154 -0
  17. package/dist/providers/ai/MistralProvider.d.ts +16 -0
  18. package/dist/providers/ai/MistralProvider.js +137 -0
  19. package/dist/providers/ai/OpenAIProvider.d.ts +16 -0
  20. package/dist/providers/ai/OpenAIProvider.js +141 -0
  21. package/dist/providers/bugTrackers/AzureDevOpsBugTracker.d.ts +32 -0
  22. package/dist/providers/bugTrackers/AzureDevOpsBugTracker.js +295 -0
  23. package/dist/providers/bugTrackers/GitHubBugTracker.d.ts +28 -0
  24. package/dist/providers/bugTrackers/GitHubBugTracker.js +241 -0
  25. package/dist/providers/bugTrackers/JiraBugTracker.d.ts +29 -0
  26. package/dist/providers/bugTrackers/JiraBugTracker.js +279 -0
  27. package/dist/providers/databases/MySQLProvider.d.ts +32 -0
  28. package/dist/providers/databases/MySQLProvider.js +274 -0
  29. package/dist/providers/databases/SQLiteProvider.d.ts +28 -0
  30. package/dist/providers/databases/SQLiteProvider.js +272 -0
  31. package/dist/providers/factories/BugTrackerFactory.d.ts +20 -0
  32. package/dist/providers/factories/BugTrackerFactory.js +50 -0
  33. package/dist/providers/factories/DatabaseFactory.d.ts +28 -0
  34. package/dist/providers/factories/DatabaseFactory.js +71 -0
  35. package/dist/providers/factories/NotificationFactory.d.ts +24 -0
  36. package/dist/providers/factories/NotificationFactory.js +64 -0
  37. package/dist/providers/factories/PRProviderFactory.d.ts +20 -0
  38. package/dist/providers/factories/PRProviderFactory.js +45 -0
  39. package/dist/providers/index.d.ts +28 -0
  40. package/dist/providers/index.js +55 -0
  41. package/dist/providers/interfaces/IAIProvider.d.ts +59 -0
  42. package/dist/providers/interfaces/IAIProvider.js +5 -0
  43. package/dist/providers/interfaces/IBugTrackerProvider.d.ts +70 -0
  44. package/dist/providers/interfaces/IBugTrackerProvider.js +20 -0
  45. package/dist/providers/interfaces/IDatabaseProvider.d.ts +90 -0
  46. package/dist/providers/interfaces/IDatabaseProvider.js +5 -0
  47. package/dist/providers/interfaces/INotificationProvider.d.ts +59 -0
  48. package/dist/providers/interfaces/INotificationProvider.js +13 -0
  49. package/dist/providers/interfaces/IPRProvider.d.ts +82 -0
  50. package/dist/providers/interfaces/IPRProvider.js +5 -0
  51. package/dist/providers/notifications/EmailNotificationProvider.d.ts +29 -0
  52. package/dist/providers/notifications/EmailNotificationProvider.js +290 -0
  53. package/dist/providers/pr/AzureDevOpsPRProvider.d.ts +30 -0
  54. package/dist/providers/pr/AzureDevOpsPRProvider.js +263 -0
  55. package/dist/providers/pr/GitHubPRProvider.d.ts +29 -0
  56. package/dist/providers/pr/GitHubPRProvider.js +320 -0
  57. package/dist/reporter.d.ts +138 -0
  58. package/dist/reporter.js +787 -0
  59. package/dist/types/index.d.ts +168 -0
  60. package/dist/types/index.js +2 -0
  61. package/dist/utils/buildInfoUtils.d.ts +26 -0
  62. package/dist/utils/buildInfoUtils.js +125 -0
  63. package/dist/utils/configValidator.d.ts +67 -0
  64. package/dist/utils/configValidator.js +454 -0
  65. package/dist/utils/fileHandlerUtils.d.ts +42 -0
  66. package/dist/utils/fileHandlerUtils.js +136 -0
  67. package/dist/utils/genaiUtils.d.ts +38 -0
  68. package/dist/utils/genaiUtils.js +178 -0
  69. package/dist/utils/historyUtils.d.ts +49 -0
  70. package/dist/utils/historyUtils.js +118 -0
  71. package/dist/utils/utils.d.ts +104 -0
  72. package/dist/utils/utils.js +371 -0
  73. package/docs/API.md +591 -0
  74. package/docs/ENV_CONFIG_GUIDE.md +444 -0
  75. package/docs/IMPLEMENTATION_SUMMARY.md +285 -0
  76. package/docs/PROVIDERS.md +261 -0
  77. package/docs/QUICKSTART.md +350 -0
  78. package/docs/README.md +253 -0
  79. package/docs/TROUBLESHOOTING.md +577 -0
  80. package/docs/design.md +384 -0
  81. package/docs/logo.png +0 -0
  82. package/examples/README.md +326 -0
  83. package/examples/VALIDATION.md +68 -0
  84. package/examples/env-configs/.env.anthropic-minimal +40 -0
  85. package/examples/env-configs/.env.azure-stack +71 -0
  86. package/examples/env-configs/.env.example +32 -0
  87. package/examples/env-configs/.env.github-stack +57 -0
  88. package/examples/env-configs/.env.google-mysql +61 -0
  89. package/examples/env-configs/.env.ms-auth-examples +56 -0
  90. package/examples/env-configs/.env.openai-jira +64 -0
  91. package/examples/package.json +22 -0
  92. package/package.json +70 -0
  93. package/playwright-ai-reporter-0.0.4.tgz +0 -0
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.GenAIUtils = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const dotenv = __importStar(require("dotenv"));
40
+ const ProviderRegistry_1 = require("../providers/ProviderRegistry");
41
+ // Load environment variables from .env file
42
+ dotenv.config({ path: path.resolve(process.cwd(), '.env') });
43
+ /**
44
+ * Utility for generating AI-powered suggestions for test failures
45
+ */
46
+ class GenAIUtils {
47
+ /**
48
+ * Calls the configured AI provider to get a suggestion for fixing a failed test
49
+ *
50
+ * @param prompt - The prompt to send to the AI
51
+ * @returns AI's suggested fix
52
+ */
53
+ static async callGenAISuggestion(prompt) {
54
+ try {
55
+ const provider = await ProviderRegistry_1.ProviderRegistry.getAIProvider();
56
+ console.log(`[GenAI] Using AI provider: ${provider.getName()}`);
57
+ const messages = [
58
+ {
59
+ role: 'system',
60
+ content: 'You are a test engineer helping debug flaky Playwright tests.',
61
+ },
62
+ {
63
+ role: 'user',
64
+ content: prompt,
65
+ },
66
+ ];
67
+ const response = await provider.generateCompletion(messages, {
68
+ maxTokens: 1000,
69
+ temperature: 0.7,
70
+ });
71
+ return response.content;
72
+ }
73
+ catch (error) {
74
+ console.error('[GenAI] Error calling AI provider:', error);
75
+ return `Error retrieving suggestion from AI provider: ${error instanceof Error ? error.message : 'Unknown error'}`;
76
+ }
77
+ }
78
+ /**
79
+ * Generates a fix suggestion for a failed test
80
+ *
81
+ * @param failure - The test failure information
82
+ * @param sourceCode - Map of source code files for context
83
+ * @returns The path to the saved suggestion file
84
+ */
85
+ static async generateFixSuggestion(failure, sourceCode) {
86
+ if (!failure.testFile) {
87
+ console.warn(`[GenAI] Cannot generate fix for test without file path: ${failure.testTitle}`);
88
+ return null;
89
+ }
90
+ try {
91
+ // Ensure the prompt and fixes directories exist
92
+ const promptDir = path.join(process.cwd(), 'test-results', 'prompts');
93
+ const fixesDir = path.join(process.cwd(), 'test-results', 'fixes');
94
+ fs.mkdirSync(promptDir, { recursive: true });
95
+ fs.mkdirSync(fixesDir, { recursive: true });
96
+ // Read the source file content if not already in cache
97
+ let source = sourceCode.get(failure.testFile);
98
+ if (!source) {
99
+ source = fs.readFileSync(failure.testFile, 'utf8');
100
+ sourceCode.set(failure.testFile, source);
101
+ }
102
+ // Create the prompt
103
+ const promptContent = [
104
+ `# Instructions`,
105
+ '',
106
+ `- The following Playwright test failed.`,
107
+ `- Explain why it failed and suggest a fix, respecting Playwright best practices.`,
108
+ `- Be concise and provide a code snippet with the fix.`,
109
+ '',
110
+ `# Test info`,
111
+ '',
112
+ `- Name: ${failure.testTitle}`,
113
+ `- File: ${failure.testFile}`,
114
+ `- Line: ${failure.location?.line || 'unknown'}`,
115
+ `- Column: ${failure.location?.column || 'unknown'}`,
116
+ '',
117
+ '# Error details',
118
+ '',
119
+ '```',
120
+ failure.errorMessage,
121
+ '```',
122
+ '',
123
+ '# Stack trace',
124
+ '',
125
+ '```',
126
+ this.truncateStackTrace(failure.errorStack),
127
+ '```',
128
+ '',
129
+ '# Test source',
130
+ '',
131
+ '```ts',
132
+ source,
133
+ '```',
134
+ ].join('\n');
135
+ // Generate a clean filename for the test
136
+ const safeFilename = this.sanitizeFilename(failure.testId ? `${failure.testId}` : `${path.basename(failure.testFile, '.ts')}-${failure.testTitle}`);
137
+ // Save the prompt
138
+ const promptPath = path.join(promptDir, `${safeFilename}.md`);
139
+ fs.writeFileSync(promptPath, promptContent, 'utf8');
140
+ // Call AI for the fix suggestion
141
+ const suggestion = await this.callGenAISuggestion(promptContent);
142
+ // Save the suggestion
143
+ const fixPath = path.join(fixesDir, `fix-${safeFilename}.md`);
144
+ fs.writeFileSync(fixPath, suggestion, 'utf8');
145
+ return { promptPath, fixPath };
146
+ }
147
+ catch (error) {
148
+ console.error('[GenAI] Error generating fix suggestion:', error);
149
+ return null;
150
+ }
151
+ }
152
+ /**
153
+ * Truncates a stack trace to a reasonable length
154
+ *
155
+ * @param stack - The full stack trace
156
+ * @returns Truncated stack trace
157
+ */
158
+ static truncateStackTrace(stack) {
159
+ if (!stack)
160
+ return '';
161
+ const lines = stack.split('\n');
162
+ // Return first 15 lines max to keep the context reasonable
163
+ return lines.slice(0, 15).join('\n') + (lines.length > 15 ? '\n... (truncated)' : '');
164
+ }
165
+ /**
166
+ * Sanitizes a filename to be used in a file path
167
+ *
168
+ * @param filename - The filename to sanitize
169
+ * @returns Sanitized filename
170
+ */
171
+ static sanitizeFilename(filename) {
172
+ return filename
173
+ .replace(/[\\/:*?"<>|]/g, '_')
174
+ .replace(/\s+/g, '-')
175
+ .substring(0, 100); // Limit length
176
+ }
177
+ }
178
+ exports.GenAIUtils = GenAIUtils;
@@ -0,0 +1,49 @@
1
+ import { TestFailure } from '../types';
2
+ /**
3
+ * Interface for the last run information
4
+ */
5
+ interface LastRunInfo {
6
+ status: string;
7
+ failedTests: string[];
8
+ }
9
+ /**
10
+ * Interface for test failure history item
11
+ */
12
+ interface TestFailureHistory extends TestFailure {
13
+ timestamp?: string;
14
+ }
15
+ /**
16
+ * Utility functions for working with test history
17
+ */
18
+ export declare class HistoryUtils {
19
+ /**
20
+ * Retrieves information about the last test run
21
+ * @param outputDir - Directory where test results are stored
22
+ * @returns Information about the last test run, or null if not available
23
+ */
24
+ static getLastRunInfo(outputDir?: string): LastRunInfo | null;
25
+ /**
26
+ * Checks if a particular test was failing in the previous run
27
+ * @param testId - ID of the test to check
28
+ * @param outputDir - Directory where test results are stored
29
+ * @returns True if the test was failing in the previous run, false otherwise
30
+ */
31
+ static wasTestFailingPreviously(testId: string, outputDir?: string): boolean;
32
+ /**
33
+ * Compares current test failures with previous run failures to identify new and fixed tests
34
+ * @param currentFailures - List of currently failed test IDs
35
+ * @param outputDir - Directory where test results are stored
36
+ * @returns Object with lists of newly failing and fixed tests
37
+ */
38
+ static compareWithPreviousRun(currentFailures: string[], outputDir?: string): {
39
+ newlyFailing: string[];
40
+ fixed: string[];
41
+ };
42
+ /**
43
+ * Gets the full test failure history
44
+ * @param outputDir - Directory where test results are stored
45
+ * @returns Array of test failures with timestamps
46
+ */
47
+ static getTestFailureHistory(outputDir?: string): TestFailureHistory[];
48
+ }
49
+ export {};
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HistoryUtils = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * Utility functions for working with test history
41
+ */
42
+ class HistoryUtils {
43
+ /**
44
+ * Retrieves information about the last test run
45
+ * @param outputDir - Directory where test results are stored
46
+ * @returns Information about the last test run, or null if not available
47
+ */
48
+ static getLastRunInfo(outputDir = './test-results') {
49
+ try {
50
+ const lastRunFilePath = path.join(outputDir, '.last-run.json');
51
+ if (!fs.existsSync(lastRunFilePath)) {
52
+ return null;
53
+ }
54
+ const content = fs.readFileSync(lastRunFilePath, 'utf8');
55
+ return JSON.parse(content);
56
+ }
57
+ catch (error) {
58
+ console.error('Error reading last run information:', error);
59
+ return null;
60
+ }
61
+ }
62
+ /**
63
+ * Checks if a particular test was failing in the previous run
64
+ * @param testId - ID of the test to check
65
+ * @param outputDir - Directory where test results are stored
66
+ * @returns True if the test was failing in the previous run, false otherwise
67
+ */
68
+ static wasTestFailingPreviously(testId, outputDir = './test-results') {
69
+ const lastRunInfo = this.getLastRunInfo(outputDir);
70
+ if (!lastRunInfo) {
71
+ return false;
72
+ }
73
+ return lastRunInfo.failedTests.includes(testId);
74
+ }
75
+ /**
76
+ * Compares current test failures with previous run failures to identify new and fixed tests
77
+ * @param currentFailures - List of currently failed test IDs
78
+ * @param outputDir - Directory where test results are stored
79
+ * @returns Object with lists of newly failing and fixed tests
80
+ */
81
+ static compareWithPreviousRun(currentFailures, outputDir = './test-results') {
82
+ const lastRunInfo = this.getLastRunInfo(outputDir);
83
+ if (!lastRunInfo) {
84
+ // No previous run data available, all current failures are new
85
+ return {
86
+ newlyFailing: currentFailures,
87
+ fixed: [],
88
+ };
89
+ }
90
+ const previousFailures = lastRunInfo.failedTests || [];
91
+ return {
92
+ // Tests failing now but not in previous run
93
+ newlyFailing: currentFailures.filter((id) => !previousFailures.includes(id)),
94
+ // Tests that were failing before but now passing
95
+ fixed: previousFailures.filter((id) => !currentFailures.includes(id)),
96
+ };
97
+ }
98
+ /**
99
+ * Gets the full test failure history
100
+ * @param outputDir - Directory where test results are stored
101
+ * @returns Array of test failures with timestamps
102
+ */
103
+ static getTestFailureHistory(outputDir = './test-results') {
104
+ try {
105
+ const failuresFilePath = path.join(outputDir, 'testFailures.json');
106
+ if (!fs.existsSync(failuresFilePath)) {
107
+ return [];
108
+ }
109
+ const content = fs.readFileSync(failuresFilePath, 'utf8');
110
+ return JSON.parse(content);
111
+ }
112
+ catch (error) {
113
+ console.error('Error reading test failure history:', error);
114
+ return [];
115
+ }
116
+ }
117
+ }
118
+ exports.HistoryUtils = HistoryUtils;
@@ -0,0 +1,104 @@
1
+ import { TestRecord, TestSummary, SlowTest, TestFailure, BuildInfo } from '../types';
2
+ import { TestCase } from '@playwright/test/reporter';
3
+ /**
4
+ * Utility class containing static methods for test result processing and calculations.
5
+ * Provides functionality for formatting time, calculating statistics, and processing test results.
6
+ */
7
+ export declare class TestUtils {
8
+ /**
9
+ * Formats a time duration from seconds into a human-readable string.
10
+ * Converts to minutes if the duration is longer than 60 seconds.
11
+ *
12
+ * @param timeInSeconds - The time duration to format in seconds
13
+ * @returns A formatted string with appropriate units (e.g., "1.23s" or "2.50min")
14
+ */
15
+ static formatTime(timeInSeconds: number): string;
16
+ /**
17
+ * Calculates the average duration from an array of time measurements.
18
+ *
19
+ * @param durations - Array of durations in seconds
20
+ * @returns The average duration in seconds, or 0 if the array is empty
21
+ */
22
+ static calculateAverageTime(durations: number[]): number;
23
+ /**
24
+ * Finds the slowest tests from all test records.
25
+ * Only considers passed tests when calculating the slowest ones.
26
+ *
27
+ * @param testRecords - Map of all test records
28
+ * @param limit - Maximum number of slow tests to return
29
+ * @returns Array of the slowest tests, sorted by duration
30
+ */
31
+ static findSlowestTests(testRecords: Map<string, TestRecord>, limit: number): SlowTest[];
32
+ /**
33
+ * Categorizes the error message into predefined types
34
+ * @param message - Error message
35
+ * @returns Error category
36
+ */
37
+ static categorizeError(message: string): string;
38
+ /**
39
+ * Convert test outcome to status
40
+ * @param outcome - Test outcome
41
+ * @returns Standardized status
42
+ */
43
+ static outcomeToStatus(outcome: string): string;
44
+ /**
45
+ * Determines the team that owns a test based on test name and annotations
46
+ * @param test - Test case to analyze
47
+ * @returns Name of the team that owns the test
48
+ */
49
+ static getOwningTeam(test: TestCase): string;
50
+ /**
51
+ * Helper method to wrap a string for team name matching
52
+ * @param text - Text to wrap
53
+ * @returns Wrapped text
54
+ */
55
+ private static wrap;
56
+ /**
57
+ * Processes all test records to generate comprehensive test results.
58
+ * Calculates passed, failed, and skipped test counts, and collects timing information.
59
+ *
60
+ * @param testRecords - Map of all test records
61
+ * @returns Object containing test counts, failures, and timing information
62
+ */
63
+ static processTestResults(testRecords: Map<string, TestRecord>): {
64
+ passedCount: number;
65
+ testCount: number;
66
+ skippedCount: number;
67
+ failedCount: number;
68
+ failures: TestFailure[];
69
+ passedDurations: number[];
70
+ };
71
+ }
72
+ /**
73
+ * Logger class responsible for formatting and outputting test results.
74
+ * Provides methods for logging test summaries, metrics, and failures with appropriate formatting.
75
+ */
76
+ export declare class Logger {
77
+ /**
78
+ * Logs the overall test run summary with appropriate coloring.
79
+ * Includes total tests, passed tests, skipped tests, and total time.
80
+ *
81
+ * @param summary - The test summary to log
82
+ */
83
+ static logSummary(summary: TestSummary): void;
84
+ /**
85
+ * Logs build information if available
86
+ *
87
+ * @param buildInfo - The build information to log
88
+ */
89
+ static logBuildInfo(buildInfo: BuildInfo): void;
90
+ /**
91
+ * Logs detailed metrics about the test run.
92
+ * Includes average test time and information about slow tests.
93
+ *
94
+ * @param summary - The test summary containing metrics to log
95
+ */
96
+ static logMetrics(summary: TestSummary): void;
97
+ /**
98
+ * Logs detailed information about test failures.
99
+ * Includes test title, stack trace, and timeout information.
100
+ *
101
+ * @param failures - Array of test failures to log
102
+ */
103
+ static logFailures(failures: TestFailure[]): void;
104
+ }