@sridharkikkeri/playwright-common 1.0.23 → 1.0.24
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/CLEAN_IMPORTS.md +0 -184
- package/HEALING_CACHE_STRATEGY.md +0 -222
- package/NPM_PUBLISHING.md +0 -213
- package/PUBLISHED.md +0 -153
- package/QUICK_FIX.md +0 -40
- package/VISUAL_TESTING.md +0 -319
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sridharkikkeri/playwright-common",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"description": "Production-grade Playwright framework with AI-powered self-healing, visual regression, and enterprise features",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/CLEAN_IMPORTS.md
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# Clean Import Guide (v1.0.1+)
|
|
2
|
-
|
|
3
|
-
## ✅ What Changed in v1.0.1
|
|
4
|
-
|
|
5
|
-
**Before (v1.0.0):**
|
|
6
|
-
```typescript
|
|
7
|
-
// ❌ Ugly deep imports
|
|
8
|
-
import { test } from '@sridharkikkeri/playwright-common/dist/com/healthedge/common/fixtures/fixtures';
|
|
9
|
-
import { BasePage } from '@sridharkikkeri/playwright-common/dist/com/healthedge/common/core/pages/BasePage';
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
**After (v1.0.1):**
|
|
13
|
-
```typescript
|
|
14
|
-
// ✅ Clean barrel imports
|
|
15
|
-
import { test, BasePage, VisualTesting } from '@sridharkikkeri/playwright-common';
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Usage Examples
|
|
21
|
-
|
|
22
|
-
### Basic Test
|
|
23
|
-
```typescript
|
|
24
|
-
import { test } from '@sridharkikkeri/playwright-common';
|
|
25
|
-
|
|
26
|
-
test('My test', async ({ page }) => {
|
|
27
|
-
await page.goto('https://example.com');
|
|
28
|
-
});
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Page Object Pattern
|
|
32
|
-
```typescript
|
|
33
|
-
import { BasePage } from '@sridharkikkeri/playwright-common';
|
|
34
|
-
import { Page } from '@playwright/test';
|
|
35
|
-
|
|
36
|
-
export class LoginPage extends BasePage {
|
|
37
|
-
constructor(page: Page) {
|
|
38
|
-
super(page, 'LoginPage');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private readonly username = this.element('#username');
|
|
42
|
-
private readonly loginBtn = this.element('button[type="submit"]');
|
|
43
|
-
|
|
44
|
-
async login(user: string) {
|
|
45
|
-
await this.username.fill(user, 'Enter username');
|
|
46
|
-
await this.loginBtn.click('Click login');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Visual Testing
|
|
52
|
-
```typescript
|
|
53
|
-
import { test, VisualTesting } from '@sridharkikkeri/playwright-common';
|
|
54
|
-
|
|
55
|
-
test('Visual regression', async ({ page }) => {
|
|
56
|
-
const visual = new VisualTesting(page);
|
|
57
|
-
await page.goto('/dashboard');
|
|
58
|
-
await visual.compareFullPage({ name: 'dashboard' });
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### API Testing
|
|
63
|
-
```typescript
|
|
64
|
-
import { test, ApiClient } from '@sridharkikkeri/playwright-common';
|
|
65
|
-
|
|
66
|
-
test('API test', async ({ request }) => {
|
|
67
|
-
const client = new ApiClient(request);
|
|
68
|
-
const response = await client.get('/api/users/1');
|
|
69
|
-
expect(response.status).toBe(200);
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Configuration
|
|
74
|
-
```typescript
|
|
75
|
-
import { ConfigManager } from '@sridharkikkeri/playwright-common';
|
|
76
|
-
|
|
77
|
-
const config = ConfigManager.getConfig();
|
|
78
|
-
console.log(config.healingEnabled); // true
|
|
79
|
-
console.log(config.environment); // 'dev'
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Localization
|
|
83
|
-
```typescript
|
|
84
|
-
import { Localization } from '@sridharkikkeri/playwright-common';
|
|
85
|
-
|
|
86
|
-
const message = Localization.get('welcome_message', 'en');
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Allure Reporting
|
|
90
|
-
```typescript
|
|
91
|
-
import { AllureUtil } from '@sridharkikkeri/playwright-common';
|
|
92
|
-
|
|
93
|
-
await AllureUtil.step('Custom step', async () => {
|
|
94
|
-
// Your logic
|
|
95
|
-
AllureUtil.attachJson('Data', { key: 'value' });
|
|
96
|
-
});
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## All Available Exports
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
import {
|
|
105
|
-
// Testing
|
|
106
|
-
test,
|
|
107
|
-
|
|
108
|
-
// Pages
|
|
109
|
-
BasePage,
|
|
110
|
-
LoginPage,
|
|
111
|
-
|
|
112
|
-
// Wrappers
|
|
113
|
-
ElementWrapper,
|
|
114
|
-
|
|
115
|
-
// Self-Healing
|
|
116
|
-
ActionOrchestrator,
|
|
117
|
-
LocatorHealing,
|
|
118
|
-
ElementProfileStore,
|
|
119
|
-
|
|
120
|
-
// API
|
|
121
|
-
ApiClient,
|
|
122
|
-
AuthStrategy,
|
|
123
|
-
CookieAuth,
|
|
124
|
-
OAuth2Auth,
|
|
125
|
-
|
|
126
|
-
// Visual
|
|
127
|
-
VisualTesting,
|
|
128
|
-
|
|
129
|
-
// Config
|
|
130
|
-
ConfigManager,
|
|
131
|
-
|
|
132
|
-
// i18n
|
|
133
|
-
Localization,
|
|
134
|
-
|
|
135
|
-
// Reporting
|
|
136
|
-
AllureUtil,
|
|
137
|
-
|
|
138
|
-
// Utils
|
|
139
|
-
Logger,
|
|
140
|
-
ErrorUtils
|
|
141
|
-
} from '@sridharkikkeri/playwright-common';
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## TypeScript Support
|
|
147
|
-
|
|
148
|
-
Full TypeScript support with auto-completion:
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
import { BasePage } from '@sridharkikkeri/playwright-common';
|
|
152
|
-
// ^
|
|
153
|
-
// VS Code will show type hints and documentation
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Migration from v1.0.0 to v1.0.1
|
|
159
|
-
|
|
160
|
-
**Find and replace in your project:**
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
# Old pattern
|
|
164
|
-
@sridharkikkeri/playwright-common/dist/com/healthedge/common/
|
|
165
|
-
|
|
166
|
-
# New pattern
|
|
167
|
-
@sridharkikkeri/playwright-common
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
**Or use this script:**
|
|
171
|
-
```bash
|
|
172
|
-
find . -name "*.ts" -type f -exec sed -i '' \
|
|
173
|
-
's|@sridharkikkeri/playwright-common/dist/com/healthedge/common/[^'"'"']*|@sridharkikkeri/playwright-common|g' {} +
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Installation
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
npm install @sridharkikkeri/playwright-common@latest
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**Package URL:** https://www.npmjs.com/package/@sridharkikkeri/playwright-common
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
# Self-Healing Cache Strategy
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
The framework's self-healing mechanism uses an in-memory cache to store element profiles and healed selectors, enabling intelligent locator recovery without repeated AI calls.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Architecture
|
|
9
|
-
|
|
10
|
-
### 1. Element Profile Store
|
|
11
|
-
**Location**: `ElementProfileStore.ts`
|
|
12
|
-
|
|
13
|
-
**Purpose**: Maintains a runtime cache of element "fingerprints" captured during successful interactions.
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
interface ElementProfile {
|
|
17
|
-
selector: string; // Original selector
|
|
18
|
-
intent: string; // Human-readable action intent
|
|
19
|
-
attributes: Record<string, string>; // DOM attributes snapshot
|
|
20
|
-
lastHealedSelector?: string; // Last successful healed selector
|
|
21
|
-
healingFailed?: boolean; // Flag if healing exhausted
|
|
22
|
-
failureType?: string; // Reason for healing failure
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Key**: `{pageName}:{intent}` (e.g., `LoginPage:Click Login Button`)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Caching Flow
|
|
31
|
-
|
|
32
|
-
### Phase 1: Profile Capture (Success Path)
|
|
33
|
-
```
|
|
34
|
-
User Action → Element Found → Capture Attributes → Store Profile
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**When**: After every successful element interaction
|
|
38
|
-
**What's Stored**:
|
|
39
|
-
- Original selector
|
|
40
|
-
- Element tag, text, id, class, data-* attributes
|
|
41
|
-
- Action intent for context
|
|
42
|
-
|
|
43
|
-
### Phase 2: Healing Attempt (Failure Path)
|
|
44
|
-
```
|
|
45
|
-
Selector Fails → Check Cache → Use lastHealedSelector → If Fails → AI Healing → Update Cache
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Decision Tree**:
|
|
49
|
-
1. **Cache Hit + Valid Healed Selector**: Use cached healed selector (fast path)
|
|
50
|
-
2. **Cache Hit + Failed Flag**: Skip healing, fail fast
|
|
51
|
-
3. **Cache Miss or Stale**: Trigger AI healing via LLM
|
|
52
|
-
|
|
53
|
-
### Phase 3: AI Healing (Expensive Path)
|
|
54
|
-
```
|
|
55
|
-
Extract Profile → LLM Analysis → Generate New Selector → Validate → Cache Result
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**LLM Input**:
|
|
59
|
-
- Element attributes from profile
|
|
60
|
-
- Page context (pageName)
|
|
61
|
-
- Action intent
|
|
62
|
-
- DOM snapshot (optional)
|
|
63
|
-
|
|
64
|
-
**LLM Output**: Alternative selector candidates
|
|
65
|
-
|
|
66
|
-
**Validation**: Test each candidate; first success is cached
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Cache Lifecycle
|
|
71
|
-
|
|
72
|
-
### Scope
|
|
73
|
-
- **Per Test Run**: Cache is in-memory, resets between test executions
|
|
74
|
-
- **Per Worker**: Isolated cache per Playwright worker (no cross-worker sharing)
|
|
75
|
-
|
|
76
|
-
### Persistence
|
|
77
|
-
**Current**: No persistence (ephemeral)
|
|
78
|
-
|
|
79
|
-
**Future Enhancement**: Serialize to `.healing-cache.json` for cross-run reuse
|
|
80
|
-
```json
|
|
81
|
-
{
|
|
82
|
-
"LoginPage:Click Login Button": {
|
|
83
|
-
"lastHealedSelector": "button[data-testid='login-submit']",
|
|
84
|
-
"timestamp": 1704067200000,
|
|
85
|
-
"successRate": 0.95
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## Performance Optimization
|
|
93
|
-
|
|
94
|
-
### 1. Fast Path (Cache Hit)
|
|
95
|
-
- **Latency**: ~5ms (in-memory lookup)
|
|
96
|
-
- **Cost**: $0
|
|
97
|
-
- **Success Rate**: 85-90% for stable apps
|
|
98
|
-
|
|
99
|
-
### 2. Slow Path (AI Healing)
|
|
100
|
-
- **Latency**: 2-5 seconds (LLM API call)
|
|
101
|
-
- **Cost**: ~$0.001-0.01 per healing
|
|
102
|
-
- **Success Rate**: 70-80% for moderate DOM changes
|
|
103
|
-
|
|
104
|
-
### 3. Fail Fast
|
|
105
|
-
- **Latency**: ~10ms
|
|
106
|
-
- **Triggered**: When `healingFailed=true` in cache
|
|
107
|
-
- **Prevents**: Repeated expensive AI calls for permanently broken elements
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Configuration
|
|
112
|
-
|
|
113
|
-
### Global Toggle
|
|
114
|
-
```json
|
|
115
|
-
// framework.config.json
|
|
116
|
-
{
|
|
117
|
-
"healingEnabled": true // Master switch
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Per-Action Override
|
|
122
|
-
```typescript
|
|
123
|
-
// Disable healing for a specific action
|
|
124
|
-
await this.loginBtn.withHealing(false).click();
|
|
125
|
-
|
|
126
|
-
// Force healing even if globally disabled
|
|
127
|
-
await this.dynamicElement.withHealing(true).click();
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## Cache Invalidation
|
|
133
|
-
|
|
134
|
-
### Automatic Invalidation
|
|
135
|
-
- Test run completion (cache cleared)
|
|
136
|
-
- Worker restart
|
|
137
|
-
|
|
138
|
-
### Manual Invalidation
|
|
139
|
-
```typescript
|
|
140
|
-
// Clear specific profile
|
|
141
|
-
ElementProfileStore.clearProfile('LoginPage', 'Click Login Button');
|
|
142
|
-
|
|
143
|
-
// Clear all profiles for a page
|
|
144
|
-
ElementProfileStore.clearPage('LoginPage');
|
|
145
|
-
|
|
146
|
-
// Nuclear option: clear entire cache
|
|
147
|
-
ElementProfileStore.clearAll();
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Monitoring & Debugging
|
|
153
|
-
|
|
154
|
-
### Healing Metrics
|
|
155
|
-
```typescript
|
|
156
|
-
const stats = ElementProfileStore.getStats();
|
|
157
|
-
console.log(stats);
|
|
158
|
-
// {
|
|
159
|
-
// totalProfiles: 45,
|
|
160
|
-
// healedCount: 12,
|
|
161
|
-
// failedCount: 2,
|
|
162
|
-
// cacheHitRate: 0.73
|
|
163
|
-
// }
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Allure Reporting
|
|
167
|
-
Healing events are automatically logged:
|
|
168
|
-
- ✅ **Cache Hit**: "Used cached healed selector"
|
|
169
|
-
- 🔄 **AI Healing**: "Triggered AI healing (took 3.2s)"
|
|
170
|
-
- ❌ **Healing Failed**: "Exhausted healing attempts"
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## Best Practices
|
|
175
|
-
|
|
176
|
-
### 1. Meaningful Intents
|
|
177
|
-
```typescript
|
|
178
|
-
// ❌ Bad: Generic intent
|
|
179
|
-
await this.btn.click('click');
|
|
180
|
-
|
|
181
|
-
// ✅ Good: Descriptive intent
|
|
182
|
-
await this.btn.click('Submit Login Form');
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### 2. Stable Attributes
|
|
186
|
-
Prefer selectors with stable attributes:
|
|
187
|
-
- `data-testid`
|
|
188
|
-
- `aria-label`
|
|
189
|
-
- `id` (if not auto-generated)
|
|
190
|
-
|
|
191
|
-
### 3. Healing Budget
|
|
192
|
-
Set a healing attempt limit to prevent infinite loops:
|
|
193
|
-
```typescript
|
|
194
|
-
// In ActionOrchestrator
|
|
195
|
-
const MAX_HEALING_ATTEMPTS = 3;
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Troubleshooting
|
|
201
|
-
|
|
202
|
-
### Issue: High AI Healing Costs
|
|
203
|
-
**Solution**: Increase cache persistence, improve selector stability
|
|
204
|
-
|
|
205
|
-
### Issue: Low Healing Success Rate
|
|
206
|
-
**Solution**: Enrich element profiles with more attributes, improve LLM prompt
|
|
207
|
-
|
|
208
|
-
### Issue: Stale Cached Selectors
|
|
209
|
-
**Solution**: Add TTL (time-to-live) to cached entries
|
|
210
|
-
```typescript
|
|
211
|
-
profile.expiresAt = Date.now() + 24 * 60 * 60 * 1000; // 24h
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Future Enhancements
|
|
217
|
-
|
|
218
|
-
1. **Persistent Cache**: Save to disk for cross-run reuse
|
|
219
|
-
2. **Distributed Cache**: Redis/Memcached for multi-worker sharing
|
|
220
|
-
3. **ML-Based Healing**: Train a model on historical healing data
|
|
221
|
-
4. **Visual Healing**: Use screenshot comparison for element identification
|
|
222
|
-
5. **Healing Analytics Dashboard**: Visualize healing patterns and costs
|
package/NPM_PUBLISHING.md
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
# NPM Publishing Guide
|
|
2
|
-
|
|
3
|
-
## Package Information
|
|
4
|
-
- **Name**: `@healthedge/playwright-common`
|
|
5
|
-
- **Version**: `1.0.0`
|
|
6
|
-
- **Size**: ~34 KB (compressed)
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Pre-Publish Checklist
|
|
11
|
-
|
|
12
|
-
✅ TypeScript compiled to `dist/`
|
|
13
|
-
✅ Type definitions generated
|
|
14
|
-
✅ Documentation included (README, HEALING_CACHE_STRATEGY, VISUAL_TESTING)
|
|
15
|
-
✅ Project generator script included
|
|
16
|
-
✅ Test files excluded from package
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Publishing Steps
|
|
21
|
-
|
|
22
|
-
### 1. Enable 2FA on NPM Account (Web Interface)
|
|
23
|
-
**NPM no longer supports TOTP via CLI. Use web interface:**
|
|
24
|
-
|
|
25
|
-
1. Go to https://www.npmjs.com/settings/YOUR_USERNAME/tfa
|
|
26
|
-
2. Click "Add 2FA Method"
|
|
27
|
-
3. Choose "Authenticator App" or "Security Key"
|
|
28
|
-
4. Follow setup instructions
|
|
29
|
-
5. Save backup codes
|
|
30
|
-
|
|
31
|
-
**OR use Automation Token (recommended for publishing):**
|
|
32
|
-
1. Go to https://www.npmjs.com/settings/YOUR_USERNAME/tokens
|
|
33
|
-
2. Click "Generate New Token"
|
|
34
|
-
3. Select **"Automation"** type (bypasses 2FA)
|
|
35
|
-
4. Copy token and save securely
|
|
36
|
-
5. Use token for publishing:
|
|
37
|
-
```bash
|
|
38
|
-
npm config set //registry.npmjs.org/:_authToken YOUR_TOKEN
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 2. Test Package Locally
|
|
42
|
-
```bash
|
|
43
|
-
# Build the package
|
|
44
|
-
npm run build
|
|
45
|
-
|
|
46
|
-
# Test package contents
|
|
47
|
-
npm pack --dry-run
|
|
48
|
-
|
|
49
|
-
# Create tarball for local testing
|
|
50
|
-
npm pack
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 3. Test in Another Project
|
|
54
|
-
```bash
|
|
55
|
-
# In another project directory
|
|
56
|
-
npm install /path/to/healthedge-playwright-common-1.0.0.tgz
|
|
57
|
-
|
|
58
|
-
# Test imports
|
|
59
|
-
import { BasePage, VisualTesting, test } from '@healthedge/playwright-common';
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 4. Login to NPM
|
|
63
|
-
```bash
|
|
64
|
-
# If using automation token, skip this step
|
|
65
|
-
# Token is already configured in step 1
|
|
66
|
-
|
|
67
|
-
# If using 2FA with authenticator app:
|
|
68
|
-
npm login
|
|
69
|
-
# Enter credentials + 2FA code when prompted
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### 5. Publish to NPM
|
|
73
|
-
```bash
|
|
74
|
-
# With automation token (no 2FA prompt)
|
|
75
|
-
npm publish --access public
|
|
76
|
-
|
|
77
|
-
# With 2FA authenticator (enter code when prompted)
|
|
78
|
-
npm publish --access public
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### 6. Verify Publication
|
|
82
|
-
```bash
|
|
83
|
-
npm view @healthedge/playwright-common
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Installation (After Publishing)
|
|
89
|
-
|
|
90
|
-
### For End Users
|
|
91
|
-
```bash
|
|
92
|
-
# Install the framework
|
|
93
|
-
npm install @healthedge/playwright-common
|
|
94
|
-
|
|
95
|
-
# Create new project
|
|
96
|
-
npx create-healthedge-tests my-project
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Usage
|
|
100
|
-
```typescript
|
|
101
|
-
import { test, BasePage, VisualTesting } from '@healthedge/playwright-common';
|
|
102
|
-
|
|
103
|
-
test('My test', async ({ page }) => {
|
|
104
|
-
// Use framework features
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## Version Management
|
|
111
|
-
|
|
112
|
-
### Update Version
|
|
113
|
-
```bash
|
|
114
|
-
# Patch (1.0.0 -> 1.0.1)
|
|
115
|
-
npm version patch
|
|
116
|
-
|
|
117
|
-
# Minor (1.0.0 -> 1.1.0)
|
|
118
|
-
npm version minor
|
|
119
|
-
|
|
120
|
-
# Major (1.0.0 -> 2.0.0)
|
|
121
|
-
npm version major
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Publish Update
|
|
125
|
-
```bash
|
|
126
|
-
npm run build
|
|
127
|
-
npm publish
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## CI/CD Publishing (GitHub Actions)
|
|
133
|
-
|
|
134
|
-
```yaml
|
|
135
|
-
name: Publish to NPM
|
|
136
|
-
|
|
137
|
-
on:
|
|
138
|
-
release:
|
|
139
|
-
types: [created]
|
|
140
|
-
|
|
141
|
-
jobs:
|
|
142
|
-
publish:
|
|
143
|
-
runs-on: ubuntu-latest
|
|
144
|
-
steps:
|
|
145
|
-
- uses: actions/checkout@v3
|
|
146
|
-
- uses: actions/setup-node@v3
|
|
147
|
-
with:
|
|
148
|
-
node-version: '18'
|
|
149
|
-
registry-url: 'https://registry.npmjs.org'
|
|
150
|
-
|
|
151
|
-
- run: npm ci
|
|
152
|
-
- run: npm run build
|
|
153
|
-
- run: npm publish --access public
|
|
154
|
-
env:
|
|
155
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Troubleshooting
|
|
161
|
-
|
|
162
|
-
### Issue: 403 Forbidden - 2FA required
|
|
163
|
-
**Solution**: Use Automation Token (easiest)
|
|
164
|
-
1. Go to https://www.npmjs.com/settings/YOUR_USERNAME/tokens
|
|
165
|
-
2. Generate "Automation" token
|
|
166
|
-
3. Configure:
|
|
167
|
-
```bash
|
|
168
|
-
npm config set //registry.npmjs.org/:_authToken YOUR_TOKEN
|
|
169
|
-
npm publish --access public
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Issue: TOTP 2FA no longer supported via CLI
|
|
173
|
-
**Solution**: NPM deprecated CLI-based 2FA setup. Use web interface at https://www.npmjs.com/settings/YOUR_USERNAME/tfa or use Automation tokens instead.
|
|
174
|
-
|
|
175
|
-
### Issue: Package name already exists
|
|
176
|
-
**Solution**: Change package name in `package.json` or use scoped name like `@yourorg/playwright-common`
|
|
177
|
-
|
|
178
|
-
### Issue: Build fails
|
|
179
|
-
**Solution**: Run `npm run build` and fix TypeScript errors
|
|
180
|
-
|
|
181
|
-
### Issue: Large package size
|
|
182
|
-
**Solution**: Check `.npmignore` to exclude unnecessary files
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## Package Registry Alternatives
|
|
187
|
-
|
|
188
|
-
### GitHub Packages
|
|
189
|
-
```bash
|
|
190
|
-
# Update package.json
|
|
191
|
-
"publishConfig": {
|
|
192
|
-
"registry": "https://npm.pkg.github.com"
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
# Publish
|
|
196
|
-
npm publish
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Private Registry (Artifactory, Verdaccio)
|
|
200
|
-
```bash
|
|
201
|
-
npm config set registry https://your-registry.com
|
|
202
|
-
npm publish
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## Post-Publish
|
|
208
|
-
|
|
209
|
-
1. Update README with installation instructions
|
|
210
|
-
2. Create GitHub release with changelog
|
|
211
|
-
3. Announce on team channels
|
|
212
|
-
4. Update documentation site
|
|
213
|
-
5. Monitor npm download stats: `npm view @healthedge/playwright-common`
|
package/PUBLISHED.md
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# 🎉 Package Published Successfully!
|
|
2
|
-
|
|
3
|
-
## Package Details
|
|
4
|
-
- **Name**: `@sridharkikkeri/playwright-common`
|
|
5
|
-
- **Version**: `1.0.0`
|
|
6
|
-
- **Published**: ✅ Live on NPM
|
|
7
|
-
- **Size**: 131.3 kB (unpacked), 33.9 kB (tarball)
|
|
8
|
-
- **NPM Page**: https://www.npmjs.com/package/@sridharkikkeri/playwright-common
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
### For End Users
|
|
15
|
-
```bash
|
|
16
|
-
# Install the framework (use latest for clean imports)
|
|
17
|
-
npm install @sridharkikkeri/playwright-common@latest
|
|
18
|
-
|
|
19
|
-
# Or create new project with generator
|
|
20
|
-
npx create-healthedge-tests my-project
|
|
21
|
-
cd my-project
|
|
22
|
-
npm install
|
|
23
|
-
npm run test:dev
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Clean Imports (v1.0.1+)
|
|
27
|
-
```typescript
|
|
28
|
-
// ✅ Clean barrel imports
|
|
29
|
-
import { test, BasePage, VisualTesting } from '@sridharkikkeri/playwright-common';
|
|
30
|
-
|
|
31
|
-
// ❌ Don't use deep imports (v1.0.0 style)
|
|
32
|
-
import { test } from '@sridharkikkeri/playwright-common/dist/com/healthedge/common/...';
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
See [CLEAN_IMPORTS.md](./CLEAN_IMPORTS.md) for complete usage guide.
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Usage Examples
|
|
40
|
-
|
|
41
|
-
### Basic Test
|
|
42
|
-
```typescript
|
|
43
|
-
import { test, BasePage } from '@sridharkikkeri/playwright-common';
|
|
44
|
-
|
|
45
|
-
test('My first test', async ({ page }) => {
|
|
46
|
-
await page.goto('https://example.com');
|
|
47
|
-
// Your test logic
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Visual Regression
|
|
52
|
-
```typescript
|
|
53
|
-
import { test, VisualTesting } from '@sridharkikkeri/playwright-common';
|
|
54
|
-
|
|
55
|
-
test('Visual check', async ({ page }) => {
|
|
56
|
-
const visual = new VisualTesting(page);
|
|
57
|
-
await page.goto('/dashboard');
|
|
58
|
-
await visual.compareFullPage({ name: 'dashboard' });
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Page Object Pattern
|
|
63
|
-
```typescript
|
|
64
|
-
import { BasePage } from '@sridharkikkeri/playwright-common';
|
|
65
|
-
|
|
66
|
-
export class LoginPage extends BasePage {
|
|
67
|
-
constructor(page) {
|
|
68
|
-
super(page, 'LoginPage');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private readonly username = this.element('#username');
|
|
72
|
-
private readonly password = this.element('#password');
|
|
73
|
-
private readonly loginBtn = this.element('button[type="submit"]');
|
|
74
|
-
|
|
75
|
-
async login(user: string, pass: string) {
|
|
76
|
-
await this.username.fill(user, 'Enter username');
|
|
77
|
-
await this.password.fill(pass, 'Enter password');
|
|
78
|
-
await this.loginBtn.click('Click login');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Features Included
|
|
86
|
-
|
|
87
|
-
✅ **AI-Powered Self-Healing** - Automatic locator recovery
|
|
88
|
-
✅ **Visual Regression Testing** - Built-in snapshot comparison
|
|
89
|
-
✅ **Environment Configs** - dev, qa, auto, staging, prod
|
|
90
|
-
✅ **API Testing** - Robust ApiClient with auth strategies
|
|
91
|
-
✅ **Allure Reporting** - Integrated test reporting
|
|
92
|
-
✅ **Localization (i18n)** - Multi-language support
|
|
93
|
-
✅ **Enterprise Fixtures** - Zero-boilerplate test setup
|
|
94
|
-
✅ **Project Generator** - Bootstrap new projects instantly
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Documentation
|
|
99
|
-
|
|
100
|
-
- [README](https://github.com/healthedge/playwright-framework#readme)
|
|
101
|
-
- [Healing Cache Strategy](./HEALING_CACHE_STRATEGY.md)
|
|
102
|
-
- [Visual Testing Guide](./VISUAL_TESTING.md)
|
|
103
|
-
- [NPM Publishing Guide](./NPM_PUBLISHING.md)
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Next Steps
|
|
108
|
-
|
|
109
|
-
### Update Package
|
|
110
|
-
```bash
|
|
111
|
-
# Bump version
|
|
112
|
-
npm version patch # 1.0.0 -> 1.0.1
|
|
113
|
-
npm version minor # 1.0.0 -> 1.1.0
|
|
114
|
-
npm version major # 1.0.0 -> 2.0.0
|
|
115
|
-
|
|
116
|
-
# Rebuild and publish
|
|
117
|
-
npm run build
|
|
118
|
-
npm publish --access public
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Share with Team
|
|
122
|
-
```bash
|
|
123
|
-
# Share installation command
|
|
124
|
-
npm install @sridharkikkeri/playwright-common
|
|
125
|
-
|
|
126
|
-
# Or share project generator
|
|
127
|
-
npx create-healthedge-tests my-project
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## Stats & Monitoring
|
|
133
|
-
|
|
134
|
-
**View package stats:**
|
|
135
|
-
- NPM page: https://www.npmjs.com/package/@sridharkikkeri/playwright-common
|
|
136
|
-
- Download stats: https://npm-stat.com/charts.html?package=@sridharkikkeri/playwright-common
|
|
137
|
-
|
|
138
|
-
**Monitor usage:**
|
|
139
|
-
```bash
|
|
140
|
-
npm view @sridharkikkeri/playwright-common
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Support
|
|
146
|
-
|
|
147
|
-
For issues or questions:
|
|
148
|
-
- GitHub Issues: https://github.com/healthedge/playwright-framework/issues
|
|
149
|
-
- Email: sridharkikkeri@gmail.com
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
**Congratulations! Your framework is now available to the world! 🚀**
|
package/QUICK_FIX.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Quick Fix: NPM Token Issue
|
|
2
|
-
|
|
3
|
-
## Steps to Publish
|
|
4
|
-
|
|
5
|
-
1. **Generate NEW Automation Token:**
|
|
6
|
-
- Go to: https://www.npmjs.com/settings/sridharkikkeri/tokens
|
|
7
|
-
- Click "Generate New Token"
|
|
8
|
-
- Select **"Automation"** (NOT Classic or Publish)
|
|
9
|
-
- Copy the token
|
|
10
|
-
|
|
11
|
-
2. **Clear old config and set new token:**
|
|
12
|
-
```bash
|
|
13
|
-
npm config delete //registry.npmjs.org/:_authToken
|
|
14
|
-
npm config set //registry.npmjs.org/:_authToken YOUR_NEW_TOKEN_HERE
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
3. **Verify token works:**
|
|
18
|
-
```bash
|
|
19
|
-
npm whoami
|
|
20
|
-
# Should show: sridharkikkeri
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
4. **Publish:**
|
|
24
|
-
```bash
|
|
25
|
-
npm publish --access public
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Alternative: Use unscoped name (no @ prefix)
|
|
29
|
-
|
|
30
|
-
If token issues persist, change package name to unscoped:
|
|
31
|
-
|
|
32
|
-
In `package.json`:
|
|
33
|
-
```json
|
|
34
|
-
"name": "playwright-common-healthedge"
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Then publish:
|
|
38
|
-
```bash
|
|
39
|
-
npm publish
|
|
40
|
-
```
|
package/VISUAL_TESTING.md
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
# Visual Regression Testing
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
The framework includes built-in visual regression testing using Playwright's snapshot comparison, wrapped in `VisualTesting` utility with Allure integration.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Quick Start
|
|
9
|
-
|
|
10
|
-
### 1. Basic Usage
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
import { test } from '@healthedge/common';
|
|
14
|
-
import { VisualTesting } from '@healthedge/common';
|
|
15
|
-
|
|
16
|
-
test('Visual regression - Homepage', async ({ page }) => {
|
|
17
|
-
const visual = new VisualTesting(page);
|
|
18
|
-
|
|
19
|
-
await page.goto('https://example.com');
|
|
20
|
-
|
|
21
|
-
// Compare full page
|
|
22
|
-
await visual.compareFullPage({ name: 'homepage' });
|
|
23
|
-
});
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### 2. Element-Specific Comparison
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
test('Visual regression - Login button', async ({ page }) => {
|
|
30
|
-
const visual = new VisualTesting(page);
|
|
31
|
-
const loginBtn = page.locator('#login-btn');
|
|
32
|
-
|
|
33
|
-
await visual.compareElement(loginBtn, {
|
|
34
|
-
name: 'login-button',
|
|
35
|
-
threshold: 0.02 // Allow 2% difference
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### 3. Masking Dynamic Content
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
test('Visual regression - Mask timestamps', async ({ page }) => {
|
|
44
|
-
const visual = new VisualTesting(page);
|
|
45
|
-
|
|
46
|
-
await page.goto('/dashboard');
|
|
47
|
-
|
|
48
|
-
// Mask elements that change frequently
|
|
49
|
-
await visual.compareFullPage({
|
|
50
|
-
name: 'dashboard',
|
|
51
|
-
mask: [
|
|
52
|
-
page.locator('.timestamp'),
|
|
53
|
-
page.locator('.user-avatar'),
|
|
54
|
-
page.locator('[data-dynamic="true"]')
|
|
55
|
-
]
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## API Reference
|
|
63
|
-
|
|
64
|
-
### compareFullPage(options?)
|
|
65
|
-
Compare entire page screenshot against baseline.
|
|
66
|
-
|
|
67
|
-
**Options:**
|
|
68
|
-
- `name`: Snapshot filename (default: 'full-page')
|
|
69
|
-
- `threshold`: Max pixel difference ratio 0-1 (default: 0.01)
|
|
70
|
-
- `mask`: Array of locators to mask
|
|
71
|
-
- `fullPage`: Capture full scrollable page (default: true)
|
|
72
|
-
|
|
73
|
-
### compareElement(locator, options?)
|
|
74
|
-
Compare specific element screenshot.
|
|
75
|
-
|
|
76
|
-
**Options:**
|
|
77
|
-
- `name`: Snapshot filename (default: 'element')
|
|
78
|
-
- `threshold`: Max pixel difference ratio 0-1 (default: 0.01)
|
|
79
|
-
|
|
80
|
-
### compareViewport(options?)
|
|
81
|
-
Compare visible viewport only (no scrolling).
|
|
82
|
-
|
|
83
|
-
**Options:**
|
|
84
|
-
- `name`: Snapshot filename (default: 'viewport')
|
|
85
|
-
- `threshold`: Max pixel difference ratio 0-1 (default: 0.01)
|
|
86
|
-
- `mask`: Array of locators to mask
|
|
87
|
-
|
|
88
|
-
### captureBaseline(name, fullPage?)
|
|
89
|
-
Manually capture baseline (for documentation purposes).
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## Workflow
|
|
94
|
-
|
|
95
|
-
### 1. Create Baselines (First Run)
|
|
96
|
-
```bash
|
|
97
|
-
# Generate baseline snapshots
|
|
98
|
-
npx playwright test --update-snapshots
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Baselines are stored in `**/__snapshots__/` directories.
|
|
102
|
-
|
|
103
|
-
### 2. Run Visual Tests
|
|
104
|
-
```bash
|
|
105
|
-
# Compare against baselines
|
|
106
|
-
npx playwright test
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 3. Review Failures
|
|
110
|
-
When visual tests fail, Playwright generates:
|
|
111
|
-
- **Actual**: Current screenshot
|
|
112
|
-
- **Expected**: Baseline screenshot
|
|
113
|
-
- **Diff**: Highlighted differences
|
|
114
|
-
|
|
115
|
-
Located in: `test-results/*/`
|
|
116
|
-
|
|
117
|
-
### 4. Update Baselines
|
|
118
|
-
```bash
|
|
119
|
-
# Update specific test
|
|
120
|
-
npx playwright test visual.spec.ts --update-snapshots
|
|
121
|
-
|
|
122
|
-
# Update all
|
|
123
|
-
npx playwright test --update-snapshots
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Configuration
|
|
129
|
-
|
|
130
|
-
### Playwright Config
|
|
131
|
-
```typescript
|
|
132
|
-
// playwright.config.ts
|
|
133
|
-
export default defineConfig({
|
|
134
|
-
expect: {
|
|
135
|
-
toHaveScreenshot: {
|
|
136
|
-
maxDiffPixels: 100, // Max different pixels
|
|
137
|
-
threshold: 0.2, // Per-pixel color threshold
|
|
138
|
-
animations: 'disabled', // Disable CSS animations
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Per-Test Override
|
|
145
|
-
```typescript
|
|
146
|
-
await visual.compareFullPage({
|
|
147
|
-
threshold: 0.05, // Allow 5% difference for this test
|
|
148
|
-
});
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Best Practices
|
|
154
|
-
|
|
155
|
-
### 1. Stable Test Data
|
|
156
|
-
```typescript
|
|
157
|
-
// ❌ Bad: Random data causes failures
|
|
158
|
-
await page.fill('#name', Math.random().toString());
|
|
159
|
-
|
|
160
|
-
// ✅ Good: Fixed test data
|
|
161
|
-
await page.fill('#name', 'Test User');
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### 2. Mask Dynamic Content
|
|
165
|
-
```typescript
|
|
166
|
-
// Mask timestamps, user-specific data, ads
|
|
167
|
-
await visual.compareFullPage({
|
|
168
|
-
mask: [
|
|
169
|
-
page.locator('.timestamp'),
|
|
170
|
-
page.locator('.ad-banner'),
|
|
171
|
-
page.locator('[data-user-id]')
|
|
172
|
-
]
|
|
173
|
-
});
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### 3. Wait for Stability
|
|
177
|
-
```typescript
|
|
178
|
-
// Wait for animations/loading
|
|
179
|
-
await page.waitForLoadState('networkidle');
|
|
180
|
-
await page.waitForTimeout(500); // Allow CSS transitions
|
|
181
|
-
|
|
182
|
-
await visual.compareFullPage();
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### 4. Descriptive Names
|
|
186
|
-
```typescript
|
|
187
|
-
// ❌ Bad
|
|
188
|
-
await visual.compareFullPage({ name: 'test1' });
|
|
189
|
-
|
|
190
|
-
// ✅ Good
|
|
191
|
-
await visual.compareFullPage({ name: 'checkout-page-logged-in' });
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### 5. Cross-Browser Baselines
|
|
195
|
-
```bash
|
|
196
|
-
# Generate baselines per browser
|
|
197
|
-
npx playwright test --update-snapshots --project=chromium
|
|
198
|
-
npx playwright test --update-snapshots --project=firefox
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Snapshots are stored separately: `homepage-chromium.png`, `homepage-firefox.png`
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
## CI/CD Integration
|
|
206
|
-
|
|
207
|
-
### GitHub Actions
|
|
208
|
-
```yaml
|
|
209
|
-
- name: Run Visual Tests
|
|
210
|
-
run: npx playwright test
|
|
211
|
-
|
|
212
|
-
- name: Upload Visual Diffs
|
|
213
|
-
if: failure()
|
|
214
|
-
uses: actions/upload-artifact@v3
|
|
215
|
-
with:
|
|
216
|
-
name: visual-diffs
|
|
217
|
-
path: test-results/
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Baseline Management
|
|
221
|
-
**Option 1**: Commit baselines to Git
|
|
222
|
-
```bash
|
|
223
|
-
git add **/__snapshots__/
|
|
224
|
-
git commit -m "Update visual baselines"
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**Option 2**: Store in artifact repository (S3, Artifactory)
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## Troubleshooting
|
|
232
|
-
|
|
233
|
-
### Issue: Flaky Visual Tests
|
|
234
|
-
**Causes:**
|
|
235
|
-
- Animations not disabled
|
|
236
|
-
- Fonts not loaded
|
|
237
|
-
- Network requests pending
|
|
238
|
-
|
|
239
|
-
**Solution:**
|
|
240
|
-
```typescript
|
|
241
|
-
await page.waitForLoadState('networkidle');
|
|
242
|
-
await page.evaluate(() => document.fonts.ready);
|
|
243
|
-
await page.waitForTimeout(500);
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Issue: Cross-Platform Differences
|
|
247
|
-
**Cause**: Font rendering differs between OS
|
|
248
|
-
|
|
249
|
-
**Solution**: Run tests in Docker with consistent environment
|
|
250
|
-
```dockerfile
|
|
251
|
-
FROM mcr.microsoft.com/playwright:v1.42.0-focal
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### Issue: Large Snapshot Files
|
|
255
|
-
**Solution**: Use viewport comparison instead of full page
|
|
256
|
-
```typescript
|
|
257
|
-
await visual.compareViewport({ name: 'above-fold' });
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## Example Test Suite
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
import { test } from '@healthedge/common';
|
|
266
|
-
import { VisualTesting } from '@healthedge/common';
|
|
267
|
-
|
|
268
|
-
test.describe('Visual Regression Suite', () => {
|
|
269
|
-
test.beforeEach(async ({ page }) => {
|
|
270
|
-
await page.goto('/');
|
|
271
|
-
await page.waitForLoadState('networkidle');
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test('Homepage - Desktop', async ({ page }) => {
|
|
275
|
-
const visual = new VisualTesting(page);
|
|
276
|
-
await visual.compareFullPage({ name: 'homepage-desktop' });
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
test('Homepage - Mobile', async ({ page }) => {
|
|
280
|
-
await page.setViewportSize({ width: 375, height: 667 });
|
|
281
|
-
const visual = new VisualTesting(page);
|
|
282
|
-
await visual.compareFullPage({ name: 'homepage-mobile' });
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
test('Login Modal', async ({ page }) => {
|
|
286
|
-
const visual = new VisualTesting(page);
|
|
287
|
-
await page.click('#login-btn');
|
|
288
|
-
|
|
289
|
-
const modal = page.locator('.login-modal');
|
|
290
|
-
await visual.compareElement(modal, { name: 'login-modal' });
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
test('Dashboard - Mask Dynamic', async ({ page }) => {
|
|
294
|
-
const visual = new VisualTesting(page);
|
|
295
|
-
await page.goto('/dashboard');
|
|
296
|
-
|
|
297
|
-
await visual.compareFullPage({
|
|
298
|
-
name: 'dashboard',
|
|
299
|
-
mask: [
|
|
300
|
-
page.locator('.last-login-time'),
|
|
301
|
-
page.locator('.notification-badge')
|
|
302
|
-
]
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
## Allure Integration
|
|
311
|
-
|
|
312
|
-
Visual test results automatically appear in Allure reports:
|
|
313
|
-
- ✅ **Passed**: Green checkmark
|
|
314
|
-
- ❌ **Failed**: Diff image attached
|
|
315
|
-
- 📸 **Baseline**: Attached for reference
|
|
316
|
-
|
|
317
|
-
```bash
|
|
318
|
-
npm run report # View in Allure
|
|
319
|
-
```
|