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,320 @@
1
+ "use strict";
2
+ /**
3
+ * GitHub Pull Request Provider
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.GitHubPRProvider = void 0;
40
+ class GitHubPRProvider {
41
+ constructor(config) {
42
+ this.config = config;
43
+ this.initialized = this.initialize();
44
+ }
45
+ async initialize() {
46
+ const { Octokit } = await Promise.resolve().then(() => __importStar(require('@octokit/rest')));
47
+ this.octokit = new Octokit({ auth: this.config.token });
48
+ }
49
+ async createBranch(branchName, baseBranch) {
50
+ await this.initialized;
51
+ try {
52
+ // Get the reference of the base branch
53
+ const baseRef = await this.octokit.git.getRef({
54
+ owner: this.config.owner,
55
+ repo: this.config.repo,
56
+ ref: `heads/${baseBranch}`,
57
+ });
58
+ // Create new branch from base
59
+ await this.octokit.git.createRef({
60
+ owner: this.config.owner,
61
+ repo: this.config.repo,
62
+ ref: `refs/heads/${branchName}`,
63
+ sha: baseRef.data.object.sha,
64
+ });
65
+ console.log(`Created branch: ${branchName} from ${baseBranch}`);
66
+ return true;
67
+ }
68
+ catch (error) {
69
+ console.error('Error creating branch:', error.message);
70
+ return false;
71
+ }
72
+ }
73
+ async commitChanges(branchName, changes, commitMessage) {
74
+ await this.initialized;
75
+ try {
76
+ // Get the current commit SHA of the branch
77
+ const branchRef = await this.octokit.git.getRef({
78
+ owner: this.config.owner,
79
+ repo: this.config.repo,
80
+ ref: `heads/${branchName}`,
81
+ });
82
+ const currentCommitSha = branchRef.data.object.sha;
83
+ // Get the tree of the current commit
84
+ const currentCommit = await this.octokit.git.getCommit({
85
+ owner: this.config.owner,
86
+ repo: this.config.repo,
87
+ commit_sha: currentCommitSha,
88
+ });
89
+ const baseTreeSha = currentCommit.data.tree.sha;
90
+ // Create blobs for each file change
91
+ const tree = [];
92
+ for (const change of changes) {
93
+ if (change.action === 'delete') {
94
+ tree.push({
95
+ path: change.path,
96
+ mode: '100644',
97
+ type: 'blob',
98
+ sha: null,
99
+ });
100
+ }
101
+ else {
102
+ const blob = await this.octokit.git.createBlob({
103
+ owner: this.config.owner,
104
+ repo: this.config.repo,
105
+ content: Buffer.from(change.content).toString('base64'),
106
+ encoding: 'base64',
107
+ });
108
+ tree.push({
109
+ path: change.path,
110
+ mode: '100644',
111
+ type: 'blob',
112
+ sha: blob.data.sha,
113
+ });
114
+ }
115
+ }
116
+ // Create a new tree
117
+ const newTree = await this.octokit.git.createTree({
118
+ owner: this.config.owner,
119
+ repo: this.config.repo,
120
+ base_tree: baseTreeSha,
121
+ tree,
122
+ });
123
+ // Create a new commit
124
+ const newCommit = await this.octokit.git.createCommit({
125
+ owner: this.config.owner,
126
+ repo: this.config.repo,
127
+ message: commitMessage,
128
+ tree: newTree.data.sha,
129
+ parents: [currentCommitSha],
130
+ });
131
+ // Update the branch reference
132
+ await this.octokit.git.updateRef({
133
+ owner: this.config.owner,
134
+ repo: this.config.repo,
135
+ ref: `heads/${branchName}`,
136
+ sha: newCommit.data.sha,
137
+ });
138
+ console.log(`Committed changes to ${branchName}: ${newCommit.data.sha}`);
139
+ return newCommit.data.sha;
140
+ }
141
+ catch (error) {
142
+ console.error('Error committing changes:', error.message);
143
+ return null;
144
+ }
145
+ }
146
+ async createPullRequest(options) {
147
+ await this.initialized;
148
+ try {
149
+ const pr = await this.octokit.pulls.create({
150
+ owner: this.config.owner,
151
+ repo: this.config.repo,
152
+ title: options.title,
153
+ body: options.description,
154
+ head: options.sourceBranch,
155
+ base: options.targetBranch,
156
+ draft: options.draft,
157
+ });
158
+ // Add reviewers if specified
159
+ if (options.reviewers && options.reviewers.length > 0) {
160
+ await this.octokit.pulls.requestReviewers({
161
+ owner: this.config.owner,
162
+ repo: this.config.repo,
163
+ pull_number: pr.data.number,
164
+ reviewers: options.reviewers,
165
+ });
166
+ }
167
+ // Add labels if specified
168
+ if (options.labels && options.labels.length > 0) {
169
+ await this.octokit.issues.addLabels({
170
+ owner: this.config.owner,
171
+ repo: this.config.repo,
172
+ issue_number: pr.data.number,
173
+ labels: options.labels,
174
+ });
175
+ }
176
+ console.log(`Created pull request: #${pr.data.number}`);
177
+ return {
178
+ id: pr.data.id.toString(),
179
+ number: pr.data.number,
180
+ url: pr.data.html_url,
181
+ status: 'open',
182
+ sourceBranch: options.sourceBranch,
183
+ targetBranch: options.targetBranch,
184
+ };
185
+ }
186
+ catch (error) {
187
+ console.error('Error creating pull request:', error.message);
188
+ return null;
189
+ }
190
+ }
191
+ async updatePullRequest(prId, updates) {
192
+ await this.initialized;
193
+ try {
194
+ const prNumber = parseInt(prId);
195
+ const updateData = {};
196
+ if (updates.title)
197
+ updateData.title = updates.title;
198
+ if (updates.description)
199
+ updateData.body = updates.description;
200
+ const pr = await this.octokit.pulls.update({
201
+ owner: this.config.owner,
202
+ repo: this.config.repo,
203
+ pull_number: prNumber,
204
+ ...updateData,
205
+ });
206
+ return {
207
+ id: pr.data.id.toString(),
208
+ number: pr.data.number,
209
+ url: pr.data.html_url,
210
+ status: pr.data.state === 'closed' ? (pr.data.merged ? 'merged' : 'closed') : 'open',
211
+ sourceBranch: pr.data.head.ref,
212
+ targetBranch: pr.data.base.ref,
213
+ };
214
+ }
215
+ catch (error) {
216
+ console.error('Error updating pull request:', error.message);
217
+ return null;
218
+ }
219
+ }
220
+ async addComment(prId, comment) {
221
+ await this.initialized;
222
+ try {
223
+ const prNumber = parseInt(prId);
224
+ await this.octokit.issues.createComment({
225
+ owner: this.config.owner,
226
+ repo: this.config.repo,
227
+ issue_number: prNumber,
228
+ body: comment,
229
+ });
230
+ console.log(`Added comment to PR #${prNumber}`);
231
+ return true;
232
+ }
233
+ catch (error) {
234
+ console.error('Error adding comment to pull request:', error.message);
235
+ return false;
236
+ }
237
+ }
238
+ async closePullRequest(prId, comment) {
239
+ await this.initialized;
240
+ try {
241
+ const prNumber = parseInt(prId);
242
+ if (comment) {
243
+ await this.addComment(prId, comment);
244
+ }
245
+ await this.octokit.pulls.update({
246
+ owner: this.config.owner,
247
+ repo: this.config.repo,
248
+ pull_number: prNumber,
249
+ state: 'closed',
250
+ });
251
+ console.log(`Closed PR #${prNumber}`);
252
+ return true;
253
+ }
254
+ catch (error) {
255
+ console.error('Error closing pull request:', error.message);
256
+ return false;
257
+ }
258
+ }
259
+ async createAutoFixPR(failures, baseBranch) {
260
+ await this.initialized;
261
+ try {
262
+ const branchName = `autofix/test-failures-${Date.now()}`;
263
+ // Create branch
264
+ const branchCreated = await this.createBranch(branchName, baseBranch);
265
+ if (!branchCreated) {
266
+ throw new Error('Failed to create branch');
267
+ }
268
+ // Prepare file changes
269
+ const changes = failures.map(({ filePath, fixContent }) => ({
270
+ path: filePath,
271
+ content: fixContent,
272
+ action: 'modify',
273
+ }));
274
+ // Commit changes
275
+ const commitSha = await this.commitChanges(branchName, changes, `fix: Auto-fix for ${failures.length} failing test(s)`);
276
+ if (!commitSha) {
277
+ throw new Error('Failed to commit changes');
278
+ }
279
+ // Create PR description
280
+ const description = this.generateAutoFixPRDescription(failures);
281
+ // Create pull request
282
+ const pr = await this.createPullRequest({
283
+ sourceBranch: branchName,
284
+ targetBranch: baseBranch,
285
+ title: `🤖 Auto-fix: ${failures.length} failing test(s)`,
286
+ description,
287
+ labels: ['auto-fix', 'test-failure'],
288
+ draft: true, // Create as draft by default for review
289
+ });
290
+ return pr;
291
+ }
292
+ catch (error) {
293
+ console.error('Error creating auto-fix PR:', error.message);
294
+ return null;
295
+ }
296
+ }
297
+ generateAutoFixPRDescription(failures) {
298
+ let description = `## 🤖 Auto-generated Fix for Test Failures\n\n`;
299
+ description += `This PR contains AI-generated fixes for ${failures.length} failing test(s).\n\n`;
300
+ description += `⚠️ **Please review carefully before merging!**\n\n`;
301
+ description += `### Failed Tests\n\n`;
302
+ failures.forEach(({ failure }, index) => {
303
+ description += `${index + 1}. **${failure.testTitle}**\n`;
304
+ description += ` - Suite: ${failure.suiteTitle}\n`;
305
+ if (failure.testFile) {
306
+ description += ` - File: \`${failure.testFile}\`\n`;
307
+ }
308
+ description += ` - Error: ${failure.errorCategory}\n\n`;
309
+ });
310
+ description += `### Modified Files\n\n`;
311
+ const uniqueFiles = [...new Set(failures.map((f) => f.filePath))];
312
+ uniqueFiles.forEach((file) => {
313
+ description += `- \`${file}\`\n`;
314
+ });
315
+ description += `\n---\n`;
316
+ description += `_This PR was automatically created by the Playwright AI Test Reporter_`;
317
+ return description;
318
+ }
319
+ }
320
+ exports.GitHubPRProvider = GitHubPRProvider;
@@ -0,0 +1,138 @@
1
+ import { Reporter, TestCase, TestResult, FullConfig, Suite } from '@playwright/test/reporter';
2
+ import { ReporterConfig } from './types';
3
+ /**
4
+ * PlaywrightTestReporter is a modern, maintainable reporter for Playwright tests.
5
+ * It provides detailed, colorized output of test results with comprehensive metrics
6
+ * and configurable options for better visibility into test execution.
7
+ *
8
+ * Features:
9
+ * - Colorized output for different test states (passed, failed, skipped, retried)
10
+ * - Detailed metrics including test duration and slow test identification
11
+ * - Configurable thresholds for slow tests and timeouts
12
+ * - Comprehensive error reporting with stack traces
13
+ * - Support for test retries with clear status indication
14
+ * - Complete monitoring of all error types including setup/teardown errors
15
+ * - JSON output files for CI integration and historical tracking
16
+ */
17
+ export default class PlaywrightTestReporter implements Reporter {
18
+ private suite;
19
+ private outputDir;
20
+ private readonly _testRecords;
21
+ private _startTime;
22
+ private readonly _config;
23
+ private _nonTestErrors;
24
+ private _hasInterruptedTests;
25
+ private _fileHandler;
26
+ /**
27
+ * Creates a new instance of the PlaywrightTestReporter.
28
+ *
29
+ * @param config - Optional configuration object to customize reporter behavior
30
+ */
31
+ constructor(config?: ReporterConfig);
32
+ /**
33
+ * Called when the test run begins.
34
+ * Initializes the start time and displays a start message.
35
+ *
36
+ * @param config - The full Playwright configuration
37
+ * @param suite - The root test suite
38
+ */
39
+ onBegin(config: FullConfig, suite: Suite): void;
40
+ /**
41
+ * Recursively counts the total number of tests in a suite and its children
42
+ *
43
+ * @param suite - The test suite to count tests from
44
+ * @returns The total number of tests
45
+ * @private
46
+ */
47
+ private _countTests;
48
+ /**
49
+ * Called when an error occurs during test setup or teardown.
50
+ * Logs the error with optional stack trace based on configuration.
51
+ * Now tracks errors to ensure they affect final exit code.
52
+ *
53
+ * @param error - The error that occurred
54
+ */
55
+ onError(error: Error): void;
56
+ /**
57
+ * Called when a test completes (whether passed, failed, or skipped).
58
+ * Records the test result and logs appropriate output based on the test status.
59
+ * Now tracks all test statuses including interrupted ones.
60
+ *
61
+ * @param test - The test case that completed
62
+ * @param result - The result of the test execution
63
+ */
64
+ onTestEnd(test: TestCase, result: TestResult): void;
65
+ /**
66
+ * Called when all tests have completed.
67
+ * Processes results, displays summary statistics, and sets appropriate exit code.
68
+ * Now properly handles all error conditions including non-test errors.
69
+ */
70
+ onEnd(): Promise<void>;
71
+ /**
72
+ * Exits the process with a success code.
73
+ * Extracted to a method to make the flow clearer and more maintainable.
74
+ * @private
75
+ */
76
+ private _exitWithSuccess;
77
+ /**
78
+ * Exits the process with an error code.
79
+ * Extracted to a method to make the flow clearer and more maintainable.
80
+ * @private
81
+ */
82
+ private _exitWithError;
83
+ /**
84
+ * Formats and logs the outcome of a single test with appropriate coloring.
85
+ * Handles different test states (passed, failed, skipped) and retry attempts.
86
+ * Now includes handling for interrupted tests and other unexpected statuses.
87
+ *
88
+ * @param title - The title of the test
89
+ * @param result - The result of the test execution
90
+ * @param timeTakenSec - The time taken by the test in seconds
91
+ * @private
92
+ */
93
+ private _logTestOutcome;
94
+ /**
95
+ * Records the status of the last test run in a JSON file
96
+ * @param hasFailed - Whether any tests failed
97
+ */
98
+ private saveLastRunStatus;
99
+ /**
100
+ * Generates AI-powered fix suggestions for test failures
101
+ *
102
+ * @param failures - Array of test failures
103
+ * @private
104
+ */
105
+ private _generateFixSuggestions;
106
+ /**
107
+ * Generates a pull request with the AI-generated fix
108
+ *
109
+ * @param failure - The test failure information
110
+ * @param fixResult - The result from GenAIUtils containing prompt and fix paths
111
+ * @private
112
+ */
113
+ private _generatePullRequest;
114
+ /**
115
+ * Creates bugs in the configured bug tracker for test failures
116
+ *
117
+ * @param failures - Array of test failures
118
+ * @private
119
+ */
120
+ private _createBugsForFailures;
121
+ /**
122
+ * Publishes test results to database
123
+ *
124
+ * @param summary - Test run summary
125
+ * @param allTestCases - All test cases details
126
+ * @param failures - Test failures
127
+ * @private
128
+ */
129
+ private _publishToDatabase;
130
+ /**
131
+ * Sends email notification with test results
132
+ *
133
+ * @param summary - Test run summary
134
+ * @param failures - Test failures
135
+ * @private
136
+ */
137
+ private _sendEmailNotification;
138
+ }