playwright-ai-insights 1.0.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.
@@ -0,0 +1,39 @@
1
+ name: Publish NPM Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v3
12
+
13
+ - uses: actions/setup-node@v3
14
+ with:
15
+ node-version: '18'
16
+ registry-url: 'https://registry.npmjs.org'
17
+
18
+ - name: Install dependencies
19
+ run: |
20
+ cd playwright-ai-insights
21
+ npm install
22
+
23
+ - name: Build
24
+ run: |
25
+ cd playwright-ai-insights
26
+ npm run build
27
+
28
+ - name: Publish to NPM
29
+ run: |
30
+ cd playwright-ai-insights
31
+ npm publish --access public
32
+ env:
33
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
34
+
35
+ - name: Create GitHub Release Assets
36
+ uses: actions/upload-artifact@v3
37
+ with:
38
+ name: build-artifacts
39
+ path: playwright-ai-insights/dist/
@@ -0,0 +1,41 @@
1
+ name: Test NPM Package
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ paths:
7
+ - 'playwright-ai-insights/**'
8
+ pull_request:
9
+ branches: [main]
10
+ paths:
11
+ - 'playwright-ai-insights/**'
12
+
13
+ jobs:
14
+ test:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v3
18
+
19
+ - uses: actions/setup-node@v3
20
+ with:
21
+ node-version: '18'
22
+
23
+ - name: Install dependencies
24
+ run: |
25
+ cd playwright-ai-insights
26
+ npm install
27
+
28
+ - name: Typecheck
29
+ run: |
30
+ cd playwright-ai-insights
31
+ npm run typecheck
32
+
33
+ - name: Build
34
+ run: |
35
+ cd playwright-ai-insights
36
+ npm run build
37
+
38
+ - name: Lint
39
+ run: |
40
+ cd playwright-ai-insights
41
+ npm run lint || true
package/EXAMPLES.md ADDED
@@ -0,0 +1,324 @@
1
+ # Usage Examples
2
+
3
+ ## Integration with Existing Playwright Projects
4
+
5
+ ### Example 1: Add AI Analysis to Test Hooks
6
+
7
+ ```javascript
8
+ // tests/fixtures/withAI.js
9
+ import { test as base } from '@playwright/test';
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import PlaywrightAI, { analyzeTestFailures } from '@playwright-ai/insights';
13
+
14
+ // Initialize once
15
+ PlaywrightAI.initialize({
16
+ openaiApiKey: process.env.OPENAI_API_KEY,
17
+ debug: process.env.DEBUG === 'true',
18
+ });
19
+
20
+ const failuresDir = './test-results/failures';
21
+
22
+ export const test = base.extend({
23
+ analyzeFail: async ({ page }, use) => {
24
+ const failures = [];
25
+
26
+ await use(async (testName, errorMessage, captureDOM = true) => {
27
+ let domSnapshot = '';
28
+ if (captureDOM) {
29
+ try {
30
+ domSnapshot = await page.content();
31
+ } catch (e) {
32
+ console.warn('Failed to capture DOM');
33
+ }
34
+ }
35
+
36
+ failures.push({
37
+ testName,
38
+ error: errorMessage,
39
+ domSnapshot,
40
+ });
41
+ });
42
+
43
+ // Analyze failures after test
44
+ if (failures.length > 0) {
45
+ const report = await analyzeTestFailures(failures);
46
+
47
+ // Save report
48
+ fs.mkdirSync(failuresDir, { recursive: true });
49
+ fs.writeFileSync(
50
+ path.join(failuresDir, `${failures[0].testName}.json`),
51
+ JSON.stringify(report, null, 2)
52
+ );
53
+ }
54
+ },
55
+ });
56
+
57
+ export { expect } from '@playwright/test';
58
+ ```
59
+
60
+ Usage in test:
61
+
62
+ ```javascript
63
+ import { test, expect } from './fixtures/withAI';
64
+
65
+ test('login with valid credentials', async ({ page, analyzeFail }) => {
66
+ await page.goto('https://example.com/login');
67
+
68
+ try {
69
+ await expect(page.locator('#login-btn')).toBeVisible({ timeout: 5000 });
70
+ } catch (error) {
71
+ await analyzeFail('Login button should be visible', error.message);
72
+ throw error;
73
+ }
74
+ });
75
+ ```
76
+
77
+ ### Example 2: Standalone Analysis Script
78
+
79
+ ```javascript
80
+ // scripts/analyze-failures.js
81
+ import fs from 'fs';
82
+ import PlaywrightAI, { analyzeTestFailures } from '@playwright-ai/insights';
83
+
84
+ async function main() {
85
+ PlaywrightAI.initialize({
86
+ openaiApiKey: process.env.OPENAI_API_KEY,
87
+ });
88
+
89
+ // Read failures from playwright-report
90
+ const failures = [];
91
+ const reportDir = './playwright-report/data';
92
+
93
+ for (const file of fs.readdirSync(reportDir)) {
94
+ if (file.endsWith('.md')) {
95
+ const content = fs.readFileSync(`${reportDir}/${file}`, 'utf-8');
96
+
97
+ failures.push({
98
+ testName: file.replace('.md', ''),
99
+ error: content.split('\n')[0],
100
+ domSnapshot: content,
101
+ });
102
+ }
103
+ }
104
+
105
+ console.log(`Analyzing ${failures.length} failures...`);
106
+ const report = await analyzeTestFailures(failures);
107
+
108
+ // Save HTML report
109
+ const html = generateHTML(report);
110
+ fs.writeFileSync('./ai-insights-report.html', html);
111
+ console.log('✅ Report saved to ./ai-insights-report.html');
112
+ }
113
+
114
+ function generateHTML(report) {
115
+ return `
116
+ <html>
117
+ <head>
118
+ <title>AI Insights Report</title>
119
+ <style>
120
+ body { font-family: sans-serif; margin: 20px; }
121
+ h1 { color: #333; }
122
+ .summary { background: #f5f5f5; padding: 15px; border-radius: 5px; }
123
+ .failure { margin: 20px 0; border-left: 4px solid #007bff; padding: 10px; }
124
+ .suggestion { background: #e7f3ff; padding: 10px; margin: 10px 0; border-radius: 3px; }
125
+ </style>
126
+ </head>
127
+ <body>
128
+ <h1>AI Insights Report</h1>
129
+ <div class="summary">
130
+ <p><strong>Total Failures:</strong> ${report.summary.totalFailures}</p>
131
+ <p><strong>Locator Issues:</strong> ${report.summary.locatorIssues}</p>
132
+ <p><strong>Average Confidence:</strong> ${report.summary.averageConfidence}%</p>
133
+ </div>
134
+ <div>
135
+ ${report.failures.map(f => `
136
+ <div class="failure">
137
+ <h3>${f.testName}</h3>
138
+ <p>${f.rootCause}</p>
139
+ ${report.suggestions
140
+ .filter(s => s.testName === f.testName)
141
+ .map(s => `
142
+ <div class="suggestion">
143
+ <strong>Suggested Locator:</strong> <code>${s.suggestedLocator}</code>
144
+ <p>${s.reason}</p>
145
+ </div>
146
+ `).join('')}
147
+ </div>
148
+ `).join('')}
149
+ </div>
150
+ </body>
151
+ </html>
152
+ `;
153
+ }
154
+
155
+ main().catch(e => {
156
+ console.error('Error:', e);
157
+ process.exit(1);
158
+ });
159
+ ```
160
+
161
+ ### Example 3: Custom Report Generator
162
+
163
+ ```javascript
164
+ // scripts/generate-insights.js
165
+ import PlaywrightAI, {
166
+ analyzeTestFailures,
167
+ utils
168
+ } from '@playwright-ai/insights';
169
+ import fs from 'fs';
170
+
171
+ async function generateInsights() {
172
+ PlaywrightAI.initialize({
173
+ openaiApiKey: process.env.OPENAI_API_KEY,
174
+ debug: true,
175
+ });
176
+
177
+ // Read test history
178
+ const history = JSON.parse(
179
+ fs.readFileSync('./reports/history.json', 'utf-8')
180
+ );
181
+
182
+ // Identify flaky tests
183
+ const flakyTests = history.filter(test => {
184
+ const { isFlaky, confidence } = PlaywrightAI.checkTestFlakiness(test.runs);
185
+ return isFlaky && confidence > 0.6;
186
+ });
187
+
188
+ console.log(`Found ${flakyTests.length} flaky tests`);
189
+
190
+ // Analyze recent failures
191
+ const recentFailures = history
192
+ .filter(t => t.runs[t.runs.length - 1]?.status === 'FAILED')
193
+ .slice(0, 10);
194
+
195
+ const report = await analyzeTestFailures(
196
+ recentFailures.map(t => ({
197
+ testName: t.name,
198
+ error: t.runs[t.runs.length - 1].error,
199
+ domSnapshot: t.lastDomSnapshot,
200
+ }))
201
+ );
202
+
203
+ // Generate summary
204
+ const summary = {
205
+ timestamp: new Date().toISOString(),
206
+ flakyTestsCount: flakyTests.length,
207
+ failuresAnalyzed: report.failures.length,
208
+ averageConfidence: report.summary.averageConfidence,
209
+ topSuggestions: report.suggestions.slice(0, 5),
210
+ };
211
+
212
+ fs.writeFileSync(
213
+ './reports/ai-summary.json',
214
+ JSON.stringify(summary, null, 2)
215
+ );
216
+
217
+ console.log('✅ Summary written to ./reports/ai-summary.json');
218
+ }
219
+
220
+ generateInsights().catch(e => {
221
+ console.error('Error:', e);
222
+ process.exit(1);
223
+ });
224
+ ```
225
+
226
+ ## Integration Patterns
227
+
228
+ ### Pattern 1: Playwright Test Plugin
229
+
230
+ ```javascript
231
+ // plugins/ai-plugin.js
232
+ export function defineConfig(config) {
233
+ return {
234
+ ...config,
235
+ use: {
236
+ ...config.use,
237
+ // Custom plugin setup
238
+ },
239
+ };
240
+ }
241
+ ```
242
+
243
+ ### Pattern 2: GitHub Actions Workflow
244
+
245
+ ```yaml
246
+ # .github/workflows/test-and-analyze.yml
247
+ name: Test with AI Analysis
248
+
249
+ on: [push, pull_request]
250
+
251
+ jobs:
252
+ test:
253
+ runs-on: ubuntu-latest
254
+ steps:
255
+ - uses: actions/checkout@v3
256
+ - uses: actions/setup-node@v3
257
+ with:
258
+ node-version: '18'
259
+
260
+ - run: npm install
261
+ - run: npm test || true
262
+
263
+ - name: Analyze failures with AI
264
+ if: failure()
265
+ env:
266
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
267
+ run: |
268
+ npx playwright-ai analyze \
269
+ --results=./test-results/failures.json \
270
+ --output=./ai-insights.json
271
+
272
+ - name: Upload AI report
273
+ uses: actions/upload-artifact@v3
274
+ if: always()
275
+ with:
276
+ name: ai-insights
277
+ path: ./ai-insights.json
278
+ ```
279
+
280
+ ### Pattern 3: Docker Integration
281
+
282
+ ```dockerfile
283
+ FROM mcr.microsoft.com/playwright:v1.40.0-jammy
284
+
285
+ WORKDIR /app
286
+
287
+ COPY package*.json ./
288
+ RUN npm ci && npm install @playwright-ai/insights
289
+
290
+ COPY . .
291
+
292
+ ENV OPENAI_API_KEY=${OPENAI_API_KEY}
293
+
294
+ RUN npm test
295
+
296
+ RUN npx playwright-ai analyze \
297
+ --results=./test-results/failures.json \
298
+ --output=./ai-insights.json
299
+ ```
300
+
301
+ ## Cost Optimization
302
+
303
+ ```javascript
304
+ // Batch multiple analyses for efficiency
305
+ const batchSize = 10;
306
+ for (let i = 0; i < failures.length; i += batchSize) {
307
+ const batch = failures.slice(i, i + batchSize);
308
+ const report = await analyzeTestFailures(batch);
309
+ // Process batch results
310
+ }
311
+
312
+ // Use caching to avoid re-analyzing
313
+ const cache = new Map();
314
+ async function getAnalysis(failure) {
315
+ const key = JSON.stringify(failure);
316
+ if (cache.has(key)) return cache.get(key);
317
+
318
+ const result = await analyzeTestFailures([failure]);
319
+ cache.set(key, result);
320
+ return result;
321
+ }
322
+ ```
323
+
324
+ See README.md for more examples and API documentation.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Playwright AI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # @playwright-ai/insights
2
+
3
+ AI-powered Playwright test failure analysis and self-healing with automatic locator suggestions.
4
+
5
+ ## Features
6
+
7
+ ✨ **Core Capabilities**
8
+ - 🤖 **AI Failure Analysis** - Analyzes test failures with OpenAI API
9
+ - 🔧 **Self-Healing Locators** - AI-suggested improved selectors
10
+ - 🟣 **Flakiness Detection** - Identify and quarantine flaky tests
11
+ - 📊 **Smart Reports** - HTML reports with AI insights and statistics
12
+ - 🎯 **Minimal Setup** - Just add API key, works with any Playwright framework
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @playwright-ai/insights
18
+ ```
19
+
20
+ Requires Node.js 18+ and an OpenAI API key.
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Initialize Configuration
25
+
26
+ ```javascript
27
+ import PlaywrightAI from '@playwright-ai/insights';
28
+
29
+ PlaywrightAI.initialize({
30
+ openaiApiKey: process.env.OPENAI_API_KEY,
31
+ model: 'gpt-4o-mini',
32
+ enableFlakyDetection: true,
33
+ });
34
+ ```
35
+
36
+ ### 2. Analyze Test Failures
37
+
38
+ ```javascript
39
+ import { analyzeTestFailures } from '@playwright-ai/insights';
40
+
41
+ const failures = [
42
+ {
43
+ testName: 'Login form should accept valid credentials',
44
+ error: 'Timeout waiting for element with id "login-button"',
45
+ domSnapshot: '<html>...</html>',
46
+ screenshotPath: '/path/to/screenshot.png',
47
+ },
48
+ ];
49
+
50
+ const report = await analyzeTestFailures(failures);
51
+
52
+ console.log(report.summary);
53
+ // {
54
+ // totalFailures: 1,
55
+ // locatorIssues: 1,
56
+ // timeoutIssues: 0,
57
+ // assertionIssues: 0,
58
+ // averageConfidence: 82
59
+ // }
60
+
61
+ console.log(report.suggestions);
62
+ // [
63
+ // {
64
+ // testName: 'Login form...',
65
+ // failedLocatorGuess: '#login-button',
66
+ // suggestedLocator: '[data-testid="submitButton"]',
67
+ // confidence: 82,
68
+ // reason: 'data-testid selectors are more stable than IDs...'
69
+ // }
70
+ // ]
71
+ ```
72
+
73
+ ## Usage Examples
74
+
75
+ ### With Playwright Test Hooks
76
+
77
+ Automatically collect and analyze failures:
78
+
79
+ ```javascript
80
+ // tests/hooks.js
81
+ import { test as base } from '@playwright/test';
82
+ import { analyzeTestFailures } from '@playwright-ai/insights';
83
+ import PlaywrightAI from '@playwright-ai/insights';
84
+
85
+ PlaywrightAI.initialize({
86
+ openaiApiKey: process.env.OPENAI_API_KEY,
87
+ });
88
+
89
+ export const test = base.extend({
90
+ captureFailure: async ({}, use) => {
91
+ const failures = [];
92
+
93
+ await use((data) => failures.push(data));
94
+
95
+ if (failures.length > 0) {
96
+ const report = await analyzeTestFailures(failures);
97
+ console.log('AI Report:', report);
98
+ }
99
+ },
100
+ });
101
+ ```
102
+
103
+ ### Directly Analyze a Failure
104
+
105
+ ```javascript
106
+ import { getFailureInsight } from '@playwright-ai/insights';
107
+
108
+ const failure = {
109
+ testName: 'My Test',
110
+ error: 'Element not found: .sidebar-nav > li',
111
+ domSnapshot: pageHTML,
112
+ };
113
+
114
+ const insight = await getFailureInsight(failure);
115
+ console.log(insight.rootCause);
116
+ console.log(insight.suggestions);
117
+ ```
118
+
119
+ ### Detect Flaky Tests
120
+
121
+ ```javascript
122
+ import { checkTestFlakiness } from '@playwright-ai/insights';
123
+
124
+ const history = [
125
+ { status: 'PASSED', timestamp: '2024-01-01' },
126
+ { status: 'FAILED', timestamp: '2024-01-02', failureType: '⏱ Timeout' },
127
+ { status: 'PASSED', timestamp: '2024-01-03' },
128
+ ];
129
+
130
+ const { isFlaky, confidence } = checkTestFlakiness(history);
131
+ console.log(`Flaky: ${isFlaky}, Confidence: ${confidence}`);
132
+ ```
133
+
134
+ ### Get Locator Suggestions
135
+
136
+ ```javascript
137
+ import { suggestLocatorFixes } from '@playwright-ai/insights/agents';
138
+
139
+ const suggestions = await suggestLocatorFixes([
140
+ {
141
+ testName: 'Search test',
142
+ error: 'Locator "#search_box" not found',
143
+ dom: pageHTML,
144
+ },
145
+ ]);
146
+
147
+ suggestions.forEach((s) => {
148
+ console.log(`${s.testName}:`);
149
+ console.log(` Failed: ${s.failedLocatorGuess}`);
150
+ console.log(` Suggested: ${s.suggestedLocator}`);
151
+ console.log(` Confidence: ${s.confidence}%`);
152
+ });
153
+ ```
154
+
155
+ ## CLI Tool
156
+
157
+ Analyze test failures from the command line:
158
+
159
+ ```bash
160
+ # Set your API key
161
+ export OPENAI_API_KEY=sk-...
162
+
163
+ # Analyze failures from JSON file
164
+ npx playwright-ai analyze --results=./test-failures.json
165
+
166
+ # Save report to custom location
167
+ npx playwright-ai analyze --results=failures.json --output=insights.json
168
+
169
+ # Enable debug logging
170
+ npx playwright-ai analyze --results=failures.json --debug
171
+ ```
172
+
173
+ ## API Reference
174
+
175
+ ### `initialize(config: Partial<PlaywrightAIConfig>)`
176
+
177
+ Initialize the library with configuration.
178
+
179
+ **Options:**
180
+ - `openaiApiKey` (required): Your OpenAI API key
181
+ - `model`: 'gpt-4o' | 'gpt-4o-mini' (default) | 'gpt-4-turbo'
182
+ - `enableFlakyDetection`: boolean (default: true)
183
+ - `maxDomSnapshotChars`: number (default: 6000)
184
+ - `temperature`: number (default: 0.2)
185
+ - `debug`: boolean (default: false)
186
+
187
+ ### `analyzeTestFailures(failures: TestFailure[]): Promise<AnalysisReport>`
188
+
189
+ Analyze multiple test failures and generate a comprehensive report.
190
+
191
+ **Returns:**
192
+ ```typescript
193
+ {
194
+ timestamp: string;
195
+ failures: AIAnalysisResult[];
196
+ suggestions: LocatorSuggestion[];
197
+ summary: {
198
+ totalFailures: number;
199
+ locatorIssues: number;
200
+ timeoutIssues: number;
201
+ assertionIssues: number;
202
+ averageConfidence: number;
203
+ };
204
+ }
205
+ ```
206
+
207
+ ### `getFailureInsight(failure: TestFailure): Promise<AIAnalysisResult>`
208
+
209
+ Get AI analysis for a single test failure.
210
+
211
+ ### `checkTestFlakiness(testHistory): { isFlaky: boolean; confidence: number }`
212
+
213
+ Check if a test is flaky based on its run history.
214
+
215
+ ### `utils`
216
+
217
+ Access to utility functions:
218
+ - `classifyFailure(error: string): FailureType`
219
+ - `isLocatorRelated(error: string): boolean`
220
+ - `isFlaky(history): boolean`
221
+ - `calculateFlakyConfidence(history): number`
222
+ - `logger`, `setDebugMode(enabled: boolean)`, `setConfig()`
223
+
224
+ ## Types
225
+
226
+ ```typescript
227
+ interface TestFailure {
228
+ testName: string;
229
+ error: string;
230
+ errorType?: string;
231
+ stack?: string;
232
+ domSnapshot?: string;
233
+ screenshot?: string;
234
+ }
235
+
236
+ interface AIAnalysisResult {
237
+ testName: string;
238
+ rootCause: string;
239
+ suggestions: string[];
240
+ confidence: number;
241
+ failureType: FailureType;
242
+ }
243
+
244
+ interface LocatorSuggestion {
245
+ failedLocatorGuess: string;
246
+ suggestedLocator: string;
247
+ confidence: number;
248
+ reason: string;
249
+ testName?: string;
250
+ }
251
+ ```
252
+
253
+ ## Environment Variables
254
+
255
+ - `OPENAI_API_KEY` - Your OpenAI API key (required)
256
+ - `DEBUG` - Enable debug logging: `DEBUG=true`
257
+
258
+ ## Pricing & Costs
259
+
260
+ Uses OpenAI's **gpt-4o-mini** model by default (most cost-effective):
261
+ - ~$0.015 per 1M input tokens
262
+ - ~$0.06 per 1M output tokens
263
+
264
+ Typical cost per failure analysis: **$0.001 - $0.003**
265
+
266
+ ## Best Practices
267
+
268
+ 1. **Batch Analysis**: Send multiple failures at once for efficiency
269
+ 2. **Capture DOM**: Include DOM snapshots for better locator suggestions
270
+ 3. **Set Debug Mode**: Use `debug: true` during development
271
+ 4. **Cache Results**: Store analysis results to avoid re-analyzing
272
+ 5. **Use data-testid**: Tests using data-testid attributes get better suggestions
273
+
274
+ ## Limitations
275
+
276
+ - DOM snapshots capped at 6000 characters
277
+ - OpenAI API rate limits apply
278
+ - Requires internet connectivity
279
+ - Works best with descriptive error messages
280
+
281
+ ## License
282
+
283
+ MIT
284
+
285
+ ## Support
286
+
287
+ - GitHub: https://github.com/playwright-ai/insights
288
+ - Issues: https://github.com/playwright-ai/insights/issues
289
+ - Docs: https://playwright-ai.dev