@capillarytech/cap-ui-dev-tools 1.9.0 → 2.1.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.
package/CAPVISION_USAGE.md
CHANGED
|
@@ -316,6 +316,72 @@ const enhancer = new ReportEnhancer({
|
|
|
316
316
|
await enhancer.enhanceAllReports();
|
|
317
317
|
```
|
|
318
318
|
|
|
319
|
+
## 🎬 Visual Regression Mode (v1.1.0+)
|
|
320
|
+
|
|
321
|
+
### Overview
|
|
322
|
+
|
|
323
|
+
By default, CapVision only saves recordings for **failed tests** to conserve disk space. Visual Regression Mode changes this behavior to save recordings for **all tests** (pass or fail), enabling on-demand visual verification of the application.
|
|
324
|
+
|
|
325
|
+
### Configuration
|
|
326
|
+
|
|
327
|
+
Enable visual regression by setting `saveAllRecordings: true`:
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
const capVisionHooks = createWDIOCapVisionHooks({
|
|
331
|
+
ENABLE_FEATURE: true,
|
|
332
|
+
saveAllRecordings: true, // 👈 Save recordings for ALL tests
|
|
333
|
+
enabledClusters: ['crm-nightly-new'],
|
|
334
|
+
enabledModules: ['creatives'],
|
|
335
|
+
enabledTestTypes: ['sanity', 'regression']
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Environment Variable Integration
|
|
340
|
+
|
|
341
|
+
For on-demand usage, drive `saveAllRecordings` from an environment variable:
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
const isVisualRegression = process.env.VISUAL_REGRESSION === 'true';
|
|
345
|
+
|
|
346
|
+
const capVisionHooks = createWDIOCapVisionHooks({
|
|
347
|
+
ENABLE_FEATURE: process.env.ENABLE_RECORDING === 'true' || isVisualRegression,
|
|
348
|
+
saveAllRecordings: isVisualRegression,
|
|
349
|
+
enabledTestTypes: ['sanity', 'regression'],
|
|
350
|
+
// ... other config
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Then run with:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
VISUAL_REGRESSION=true ENABLE_RECORDING=true npx wdio test/wdio.conf.ts --suite visual-regression
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Behavior Comparison
|
|
361
|
+
|
|
362
|
+
| Scenario | `saveAllRecordings` | Passed Tests | Failed Tests |
|
|
363
|
+
|---|---|---|---|
|
|
364
|
+
| Default mode | `false` | ❌ Not saved | ✅ Saved |
|
|
365
|
+
| Visual regression mode | `true` | ✅ Saved | ✅ Saved |
|
|
366
|
+
|
|
367
|
+
### Console Logging
|
|
368
|
+
|
|
369
|
+
When visual regression mode is active, you'll see:
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
🟡 CapVision visual regression mode active — all recordings will be saved regardless of test result
|
|
373
|
+
🟡 Saving CapVision recording (visual regression mode): Testcase_my_test_flow
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Best Practices
|
|
377
|
+
|
|
378
|
+
1. **Run on-demand only** — Visual regression creates recordings for every test, which uses more disk space
|
|
379
|
+
2. **Use for regression suites** — Point the `visual-regression` suite to your regression test files
|
|
380
|
+
3. **Review recordings in HTML reports** — Open `reports/html-reports/master-report.html` after the run
|
|
381
|
+
4. **Clean up after review** — Old recordings are auto-cleared on the next `onPrepare` call
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
319
385
|
## 🐛 Troubleshooting
|
|
320
386
|
|
|
321
387
|
### No Recordings Created
|
|
@@ -482,7 +548,7 @@ ISC License - Part of @capillarytech/cap-ui-dev-tools
|
|
|
482
548
|
|
|
483
549
|
---
|
|
484
550
|
|
|
485
|
-
**Version**:
|
|
486
|
-
**Module**: `@capillarytech/cap-ui-dev-tools/capvision`
|
|
551
|
+
**Version**: 2.1.0+
|
|
552
|
+
**Module**: `@capillarytech/cap-ui-dev-tools/capvision`
|
|
487
553
|
**Compatibility**: WebdriverIO 7.x, 8.x+
|
|
488
554
|
|
package/README.md
CHANGED
|
@@ -54,7 +54,14 @@ const path = require('path');
|
|
|
54
54
|
|
|
55
55
|
module.exports = {
|
|
56
56
|
mode: 'development',
|
|
57
|
-
|
|
57
|
+
// ... your other webpack config
|
|
58
|
+
|
|
59
|
+
// NO need for a separate resolve.alias block for local development!
|
|
60
|
+
// The plugin handles it for you.
|
|
61
|
+
resolve: {
|
|
62
|
+
// ... any other aliases can stay here
|
|
63
|
+
},
|
|
64
|
+
|
|
58
65
|
plugins: [
|
|
59
66
|
new webpack.HotModuleReplacementPlugin(),
|
|
60
67
|
|
|
@@ -126,6 +133,7 @@ exports.config = {
|
|
|
126
133
|
- ✅ **Console Recording** - Captures console logs with UI interactions
|
|
127
134
|
- ✅ **Privacy First** - Auto-masks sensitive inputs
|
|
128
135
|
- ✅ **Framework Agnostic Core** - Works with WebdriverIO, Playwright, Puppeteer
|
|
136
|
+
- ✅ **Visual Regression Mode** _(v1.1.0)_ - Record ALL tests (pass/fail) for visual verification
|
|
129
137
|
|
|
130
138
|
### Full Documentation
|
|
131
139
|
|
|
@@ -206,6 +214,18 @@ See [CAPVISION_USAGE.md](./CAPVISION_USAGE.md#troubleshooting) for common issues
|
|
|
206
214
|
|
|
207
215
|
## 📝 Changelog
|
|
208
216
|
|
|
217
|
+
### v1.1.0 (2026-02-07)
|
|
218
|
+
- ✨ **NEW**: Visual Regression Mode — `saveAllRecordings` config option
|
|
219
|
+
- ✅ Records ALL tests (pass and fail) when `saveAllRecordings: true`
|
|
220
|
+
- ✅ On-demand visual regression suite support for module-level recording
|
|
221
|
+
- ✅ Automatic mode detection via `VISUAL_REGRESSION` environment variable
|
|
222
|
+
- ✅ Enhanced logging for visual regression mode status
|
|
223
|
+
- 📚 Updated documentation with visual regression usage guide
|
|
224
|
+
|
|
225
|
+
### v2.0.0 (2025-12-20)
|
|
226
|
+
- ✅ Major version bump with package restructuring
|
|
227
|
+
- ✅ Updated dependencies
|
|
228
|
+
|
|
209
229
|
### v1.1.0 (2025-11-12)
|
|
210
230
|
- ✨ **NEW**: Added CapVision session recording module
|
|
211
231
|
- ✅ Support for automatic test recording
|
|
@@ -272,5 +292,5 @@ ISC License
|
|
|
272
292
|
|
|
273
293
|
**Made with ❤️ by Capillary Technologies**
|
|
274
294
|
|
|
275
|
-
**Version**:
|
|
276
|
-
**Includes**: Webpack Hot-Reload Plugin + CapVision Session Recording
|
|
295
|
+
**Version**: 2.1.0
|
|
296
|
+
**Includes**: Webpack Hot-Reload Plugin + CapVision Session Recording + Visual Regression Mode
|
package/package.json
CHANGED
|
@@ -318,7 +318,6 @@ function createWDIOCapVisionHooks(recorderConfig = {}, enhancerConfig = {}) {
|
|
|
318
318
|
// Start recording if enabled
|
|
319
319
|
if (capVisionRecorder.isCapVisionEnabled()) {
|
|
320
320
|
try {
|
|
321
|
-
console.log('🟡 Starting CapVision recording for test:', test.title);
|
|
322
321
|
await capVisionRecorder.startRecording();
|
|
323
322
|
} catch (error) {
|
|
324
323
|
console.error('🔴 Failed to start CapVision recording:', error.message);
|
|
@@ -338,19 +337,8 @@ function createWDIOCapVisionHooks(recorderConfig = {}, enhancerConfig = {}) {
|
|
|
338
337
|
if (capVisionRecorder.isCapVisionEnabled()) {
|
|
339
338
|
try {
|
|
340
339
|
const testName = test.title || 'unknown_test';
|
|
341
|
-
console.log('🟡 Test result:', result.passed);
|
|
342
340
|
const testPassed = result.passed !== false; // Default to true if not specified
|
|
343
341
|
const metadata = await capVisionRecorder.stopRecordingAndSave(testName, testPassed);
|
|
344
|
-
|
|
345
|
-
if (metadata && metadata.totalEvents > 0) {
|
|
346
|
-
if (metadata.filename) {
|
|
347
|
-
console.log(`🟢 CapVision recording saved: ${metadata.totalEvents} events -> ${metadata.filename}`);
|
|
348
|
-
} else {
|
|
349
|
-
console.log(`🟡 CapVision recording discarded (test passed): ${metadata.totalEvents} events`);
|
|
350
|
-
}
|
|
351
|
-
} else {
|
|
352
|
-
console.log('🟨 No CapVision events were captured during test execution');
|
|
353
|
-
}
|
|
354
342
|
} catch (error) {
|
|
355
343
|
console.error('🔴 Failed to save CapVision recording:', error.message);
|
|
356
344
|
}
|
|
@@ -22,6 +22,7 @@ const os = require('os');
|
|
|
22
22
|
* @property {boolean} [collectFonts] - Collect custom fonts
|
|
23
23
|
* @property {boolean} [recordCrossOriginIframes] - Record cross-origin iframes
|
|
24
24
|
* @property {boolean} [useTempFile] - Use temporary file storage instead of sessionStorage
|
|
25
|
+
* @property {boolean} [saveAllRecordings] - When true, save recordings for ALL tests (pass or fail). Used for visual regression mode (default: false)
|
|
25
26
|
* @property {boolean} [recordConsole] - Enable console recording
|
|
26
27
|
* @property {Object} [consoleRecordOptions] - Console recording options
|
|
27
28
|
* @property {string[]} [consoleRecordOptions.level] - Console levels to record
|
|
@@ -40,12 +41,10 @@ const DEFAULT_CONFIG = {
|
|
|
40
41
|
enabledClusters: [],
|
|
41
42
|
enabledModules: [],
|
|
42
43
|
enabledTestTypes: ['smoke', 'sanity', 'regression'],
|
|
43
|
-
|
|
44
44
|
capVisionScriptPath: path.join(__dirname, '../assets/capvision.min.js'),
|
|
45
45
|
consoleRecordPluginPath: path.join(__dirname, '../assets/capvision-plugins/console-record.min.js'),
|
|
46
46
|
consoleReplayPluginPath: path.join(__dirname, '../assets/capvision-plugins/console-replay.min.js'),
|
|
47
47
|
recordingsOutputDir: path.join(process.cwd(), 'reports', 'recordings'),
|
|
48
|
-
|
|
49
48
|
sessionStorageKey: 'capvision_events',
|
|
50
49
|
saveIntervalMs: 60000,
|
|
51
50
|
checkoutIntervalMs: 30000,
|
|
@@ -56,7 +55,7 @@ const DEFAULT_CONFIG = {
|
|
|
56
55
|
collectFonts: true,
|
|
57
56
|
recordCrossOriginIframes: false,
|
|
58
57
|
useTempFile: true,
|
|
59
|
-
|
|
58
|
+
saveAllRecordings: false,
|
|
60
59
|
recordConsole: true,
|
|
61
60
|
consoleRecordOptions: {
|
|
62
61
|
level: ['log', 'info', 'warn', 'error'],
|
|
@@ -147,11 +146,9 @@ class CapVisionRecorder {
|
|
|
147
146
|
const match = testFilePath.match(/\/(smoke|sanity|regression)\//);
|
|
148
147
|
if (match) {
|
|
149
148
|
this.currentTestType = match[1];
|
|
150
|
-
console.log(`🟡 Detected test type from path: ${this.currentTestType}`);
|
|
151
149
|
return this.currentTestType;
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
console.log('🟡 Could not detect test type from path:', testFilePath);
|
|
155
152
|
return null;
|
|
156
153
|
}
|
|
157
154
|
|
|
@@ -174,20 +171,11 @@ class CapVisionRecorder {
|
|
|
174
171
|
}
|
|
175
172
|
|
|
176
173
|
const cluster = currentCluster || process.env.cluster;
|
|
177
|
-
|
|
178
174
|
if (!cluster) {
|
|
179
|
-
console.log('🟡 No cluster specified in environment, CapVision recording disabled');
|
|
180
175
|
return false;
|
|
181
176
|
}
|
|
182
177
|
|
|
183
178
|
const isEnabled = this.config.enabledClusters.includes(cluster);
|
|
184
|
-
|
|
185
|
-
if (isEnabled) {
|
|
186
|
-
console.log(`🟢 CapVision recording enabled for cluster: ${cluster}`);
|
|
187
|
-
} else {
|
|
188
|
-
console.log(`🟡 CapVision recording disabled for cluster: ${cluster}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
179
|
return isEnabled;
|
|
192
180
|
}
|
|
193
181
|
|
|
@@ -202,20 +190,11 @@ class CapVisionRecorder {
|
|
|
202
190
|
}
|
|
203
191
|
|
|
204
192
|
const module = currentModule || process.env.module;
|
|
205
|
-
|
|
206
193
|
if (!module) {
|
|
207
|
-
console.log('🟡 No module specified in environment, CapVision recording disabled');
|
|
208
194
|
return false;
|
|
209
195
|
}
|
|
210
196
|
|
|
211
197
|
const isEnabled = this.config.enabledModules.includes(module);
|
|
212
|
-
|
|
213
|
-
if (isEnabled) {
|
|
214
|
-
console.log(`🟢 CapVision recording enabled for module: ${module}`);
|
|
215
|
-
} else {
|
|
216
|
-
console.log(`🟡 CapVision recording disabled for module: ${module}`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
198
|
return isEnabled;
|
|
220
199
|
}
|
|
221
200
|
|
|
@@ -229,20 +208,11 @@ class CapVisionRecorder {
|
|
|
229
208
|
}
|
|
230
209
|
|
|
231
210
|
const currentTestType = this.getCurrentTestType();
|
|
232
|
-
|
|
233
211
|
if (!currentTestType) {
|
|
234
|
-
console.log('🟡 No test type detected, CapVision recording disabled');
|
|
235
212
|
return false;
|
|
236
213
|
}
|
|
237
214
|
|
|
238
215
|
const isEnabled = this.config.enabledTestTypes.includes(currentTestType);
|
|
239
|
-
|
|
240
|
-
if (isEnabled) {
|
|
241
|
-
console.log(`🟢 CapVision recording enabled for test type: ${currentTestType}`);
|
|
242
|
-
} else {
|
|
243
|
-
console.log(`🟡 CapVision recording disabled for test type: ${currentTestType}`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
216
|
return isEnabled;
|
|
247
217
|
}
|
|
248
218
|
|
|
@@ -258,23 +228,23 @@ class CapVisionRecorder {
|
|
|
258
228
|
console.log('🟡 CapVision feature disabled (ENABLE_FEATURE=false)');
|
|
259
229
|
return false;
|
|
260
230
|
}
|
|
261
|
-
|
|
231
|
+
|
|
262
232
|
const clusterEnabled = this.isCapVisionEnabledForCluster(cluster);
|
|
263
233
|
const moduleEnabled = this.isCapVisionEnabledForModule(module);
|
|
264
234
|
const testTypeEnabled = this.isCapVisionEnabledForTestType();
|
|
265
|
-
|
|
235
|
+
|
|
266
236
|
const isEnabled = clusterEnabled && moduleEnabled && testTypeEnabled;
|
|
267
|
-
|
|
268
|
-
if (isEnabled) {
|
|
269
|
-
console.log('🟢 CapVision recording enabled (all criteria met)');
|
|
270
|
-
} else {
|
|
237
|
+
|
|
238
|
+
if (!isEnabled) {
|
|
271
239
|
const disabledReasons = [];
|
|
272
240
|
if (!clusterEnabled) disabledReasons.push('cluster');
|
|
273
241
|
if (!moduleEnabled) disabledReasons.push('module');
|
|
274
242
|
if (!testTypeEnabled) disabledReasons.push('test type');
|
|
275
243
|
console.log(`🟡 CapVision recording disabled (${disabledReasons.join(', ')} disabled)`);
|
|
244
|
+
} else if (this.config.saveAllRecordings) {
|
|
245
|
+
console.log('🟡 CapVision visual regression mode active — all recordings will be saved regardless of test result');
|
|
276
246
|
}
|
|
277
|
-
|
|
247
|
+
|
|
278
248
|
return isEnabled;
|
|
279
249
|
}
|
|
280
250
|
|
|
@@ -289,7 +259,6 @@ class CapVisionRecorder {
|
|
|
289
259
|
files.forEach((file) => {
|
|
290
260
|
fs.unlinkSync(path.join(recordingsDir, file));
|
|
291
261
|
});
|
|
292
|
-
console.log('🟢 Cleared recordings folder');
|
|
293
262
|
}
|
|
294
263
|
} catch (error) {
|
|
295
264
|
console.error('🔴 Failed to clear recordings folder:', error.message);
|
|
@@ -304,8 +273,6 @@ class CapVisionRecorder {
|
|
|
304
273
|
*/
|
|
305
274
|
saveEventsToFile(events, testName = 'test') {
|
|
306
275
|
try {
|
|
307
|
-
console.log('🟡 Saving CapVision events to file...');
|
|
308
|
-
|
|
309
276
|
const recordingsDir = this.config.recordingsOutputDir;
|
|
310
277
|
|
|
311
278
|
if (!fs.existsSync(recordingsDir)) {
|
|
@@ -321,7 +288,6 @@ class CapVisionRecorder {
|
|
|
321
288
|
// Find existing recordings for this test
|
|
322
289
|
const existingFiles = fs.readdirSync(recordingsDir);
|
|
323
290
|
const testFilePattern = new RegExp(`^${sanitizedTestName}-(\\d+)\\.json$`);
|
|
324
|
-
|
|
325
291
|
let maxNumber = 0;
|
|
326
292
|
existingFiles.forEach((file) => {
|
|
327
293
|
const match = file.match(testFilePattern);
|
|
@@ -347,7 +313,6 @@ class CapVisionRecorder {
|
|
|
347
313
|
};
|
|
348
314
|
|
|
349
315
|
fs.writeFileSync(filepath, JSON.stringify(eventsData, null, 2));
|
|
350
|
-
console.log(`🟢 Saved ${events.length} events to: ${filename}`);
|
|
351
316
|
|
|
352
317
|
return filename;
|
|
353
318
|
|
|
@@ -364,7 +329,6 @@ class CapVisionRecorder {
|
|
|
364
329
|
*/
|
|
365
330
|
createTempFile() {
|
|
366
331
|
const tempDir = path.join(os.tmpdir(), 'capvision-recordings');
|
|
367
|
-
|
|
368
332
|
if (!fs.existsSync(tempDir)) {
|
|
369
333
|
fs.mkdirSync(tempDir, { recursive: true });
|
|
370
334
|
}
|
|
@@ -374,7 +338,6 @@ class CapVisionRecorder {
|
|
|
374
338
|
const tempFilePath = path.join(tempDir, tempFileName);
|
|
375
339
|
|
|
376
340
|
fs.writeFileSync(tempFilePath, JSON.stringify([]), 'utf8');
|
|
377
|
-
console.log(`🟡 Created temp file: ${tempFilePath}`);
|
|
378
341
|
|
|
379
342
|
return tempFilePath;
|
|
380
343
|
}
|
|
@@ -420,7 +383,6 @@ class CapVisionRecorder {
|
|
|
420
383
|
try {
|
|
421
384
|
if (this.tempFilePath && fs.existsSync(this.tempFilePath)) {
|
|
422
385
|
fs.unlinkSync(this.tempFilePath);
|
|
423
|
-
console.log('🟢 Temp file deleted');
|
|
424
386
|
this.tempFilePath = null;
|
|
425
387
|
}
|
|
426
388
|
} catch (error) {
|
|
@@ -440,12 +402,9 @@ class CapVisionRecorder {
|
|
|
440
402
|
}
|
|
441
403
|
|
|
442
404
|
if (!this.isCapVisionEnabled()) {
|
|
443
|
-
console.log("🟡 Skipping CapVision recording (disabled by configuration)");
|
|
444
405
|
return;
|
|
445
406
|
}
|
|
446
407
|
|
|
447
|
-
console.log("🟡 Starting CapVision recording...");
|
|
448
|
-
|
|
449
408
|
// Create temp file if using file-based storage
|
|
450
409
|
if (this.config.useTempFile) {
|
|
451
410
|
this.tempFilePath = this.createTempFile();
|
|
@@ -475,14 +434,10 @@ class CapVisionRecorder {
|
|
|
475
434
|
window.capVisionInitialized = false;
|
|
476
435
|
window.capVisionLastCheckTime = Date.now();
|
|
477
436
|
window.capVisionEvents = [];
|
|
478
|
-
|
|
479
|
-
console.log('🟢 Initialized empty events array for recording');
|
|
480
|
-
|
|
481
437
|
// Inject CapVision script
|
|
482
438
|
const injectScript = () => {
|
|
483
439
|
return new Promise((resolve) => {
|
|
484
440
|
if (window.rrweb) {
|
|
485
|
-
console.log('🟢 CapVision script already loaded');
|
|
486
441
|
resolve();
|
|
487
442
|
return;
|
|
488
443
|
}
|
|
@@ -491,7 +446,6 @@ class CapVisionRecorder {
|
|
|
491
446
|
const script = document.createElement('script');
|
|
492
447
|
script.textContent = capVisionScript;
|
|
493
448
|
document.head.appendChild(script);
|
|
494
|
-
console.log('🟢 CapVision script injected from bundled file');
|
|
495
449
|
resolve();
|
|
496
450
|
} catch (error) {
|
|
497
451
|
console.error('❌ Failed to inject CapVision script:', error.message);
|
|
@@ -534,7 +488,6 @@ class CapVisionRecorder {
|
|
|
534
488
|
const parsed = JSON.parse(saved);
|
|
535
489
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
536
490
|
window.capVisionEvents = parsed;
|
|
537
|
-
console.log(`🟢 Restored ${parsed.length} events from sessionStorage`);
|
|
538
491
|
}
|
|
539
492
|
}
|
|
540
493
|
} catch (error) {
|
|
@@ -602,13 +555,11 @@ class CapVisionRecorder {
|
|
|
602
555
|
const consolePlugin = getConsolePlugin();
|
|
603
556
|
if (consolePlugin) {
|
|
604
557
|
plugins.push(consolePlugin);
|
|
605
|
-
console.log('🟢 Console recording enabled');
|
|
606
558
|
}
|
|
607
559
|
|
|
608
560
|
window.rrwebRecorder = window.rrweb.record({
|
|
609
561
|
emit: (event) => {
|
|
610
562
|
window.capVisionEvents.push(event);
|
|
611
|
-
|
|
612
563
|
if (!config.useTempFile) {
|
|
613
564
|
saveEventsToStorage();
|
|
614
565
|
}
|
|
@@ -627,7 +578,6 @@ class CapVisionRecorder {
|
|
|
627
578
|
|
|
628
579
|
window.capVisionInitialized = true;
|
|
629
580
|
window.capVisionLastCheckTime = Date.now();
|
|
630
|
-
console.log('🟢 CapVision recording started');
|
|
631
581
|
});
|
|
632
582
|
};
|
|
633
583
|
|
|
@@ -636,14 +586,12 @@ class CapVisionRecorder {
|
|
|
636
586
|
window.addEventListener('beforeunload', () => {
|
|
637
587
|
if (!config.useTempFile) {
|
|
638
588
|
saveEventsToStorage();
|
|
639
|
-
console.log('🟡 Events saved to sessionStorage before unload');
|
|
640
589
|
}
|
|
641
590
|
});
|
|
642
591
|
|
|
643
592
|
const checkInterval = setInterval(() => {
|
|
644
593
|
// Check master feature flag first
|
|
645
594
|
if (config.ENABLE_FEATURE === false) {
|
|
646
|
-
console.log('🟡 CapVision feature disabled (ENABLE_FEATURE=false), stopping reinitialization checks');
|
|
647
595
|
clearInterval(checkInterval);
|
|
648
596
|
return;
|
|
649
597
|
}
|
|
@@ -656,7 +604,6 @@ class CapVisionRecorder {
|
|
|
656
604
|
window.capVisionLastCheckTime = now;
|
|
657
605
|
|
|
658
606
|
if (!window.capVisionInitialized || !window.rrwebRecorder) {
|
|
659
|
-
console.log('🟡 CapVision not active, attempting reinitialization...');
|
|
660
607
|
|
|
661
608
|
if (!document.querySelector('script[src*="capvision"]')) {
|
|
662
609
|
injectScript()
|
|
@@ -695,7 +642,6 @@ class CapVisionRecorder {
|
|
|
695
642
|
const events = await this.browserExecutor.execute(() => {
|
|
696
643
|
return window.capVisionEvents || [];
|
|
697
644
|
});
|
|
698
|
-
|
|
699
645
|
if (events && events.length > 0) {
|
|
700
646
|
this.saveToTempFile(events);
|
|
701
647
|
}
|
|
@@ -704,7 +650,6 @@ class CapVisionRecorder {
|
|
|
704
650
|
}
|
|
705
651
|
}, this.config.saveIntervalMs);
|
|
706
652
|
|
|
707
|
-
console.log(`🟢 Periodic file save enabled (every ${this.config.saveIntervalMs}ms)`);
|
|
708
653
|
}
|
|
709
654
|
}
|
|
710
655
|
|
|
@@ -712,7 +657,7 @@ class CapVisionRecorder {
|
|
|
712
657
|
* Stop CapVision recording and save events
|
|
713
658
|
* @async
|
|
714
659
|
* @param {string} [testName='test'] - Name of the test for filename
|
|
715
|
-
* @param {boolean} [testPassed=true] - Whether the test passed. If true, recording is not saved permanently but temp file is still deleted
|
|
660
|
+
* @param {boolean} [testPassed=true] - Whether the test passed. If true and saveAllRecordings is false, recording is not saved permanently but temp file is still deleted. When saveAllRecordings is true (visual regression mode), recordings are saved regardless of test result.
|
|
716
661
|
* @returns {Promise<RecordingMetadata>} Recording metadata
|
|
717
662
|
* @throws {Error} If browser executor not set
|
|
718
663
|
*/
|
|
@@ -722,7 +667,6 @@ class CapVisionRecorder {
|
|
|
722
667
|
}
|
|
723
668
|
|
|
724
669
|
if (!this.isCapVisionEnabled()) {
|
|
725
|
-
console.log("🟡 Skipping CapVision stop (disabled by configuration)");
|
|
726
670
|
return {
|
|
727
671
|
timestamp: new Date().toISOString(),
|
|
728
672
|
totalEvents: 0,
|
|
@@ -730,26 +674,20 @@ class CapVisionRecorder {
|
|
|
730
674
|
};
|
|
731
675
|
}
|
|
732
676
|
|
|
733
|
-
console.log("🟡 Stopping CapVision recording and saving...");
|
|
734
|
-
|
|
735
677
|
// Clear periodic save interval
|
|
736
678
|
if (this.saveIntervalHandle) {
|
|
737
679
|
clearInterval(this.saveIntervalHandle);
|
|
738
680
|
this.saveIntervalHandle = null;
|
|
739
|
-
console.log('🟢 Periodic file save stopped');
|
|
740
681
|
}
|
|
741
682
|
|
|
742
683
|
// Final save
|
|
743
684
|
if (this.config.useTempFile) {
|
|
744
685
|
try {
|
|
745
|
-
console.log('🟡 Performing final save before stopping...');
|
|
746
686
|
const finalEvents = await this.browserExecutor.execute(() => {
|
|
747
687
|
return window.capVisionEvents || [];
|
|
748
688
|
});
|
|
749
|
-
|
|
750
689
|
if (finalEvents && finalEvents.length > 0) {
|
|
751
690
|
this.saveToTempFile(finalEvents);
|
|
752
|
-
console.log(`🟢 Final save: ${finalEvents.length} events written to temp file`);
|
|
753
691
|
}
|
|
754
692
|
} catch (error) {
|
|
755
693
|
console.warn('⚠️ Final save failed:', error.message);
|
|
@@ -764,7 +702,6 @@ class CapVisionRecorder {
|
|
|
764
702
|
// Stop recorder
|
|
765
703
|
if (window.rrwebRecorder) {
|
|
766
704
|
window.rrwebRecorder();
|
|
767
|
-
console.log('🟢 Recorder stopped');
|
|
768
705
|
}
|
|
769
706
|
|
|
770
707
|
// Clean up intervals
|
|
@@ -791,25 +728,25 @@ class CapVisionRecorder {
|
|
|
791
728
|
};
|
|
792
729
|
}, this.config);
|
|
793
730
|
|
|
794
|
-
// Save to permanent location
|
|
731
|
+
// Save to permanent location based on mode:
|
|
732
|
+
// - Visual regression mode (saveAllRecordings=true): save ALL recordings regardless of test result
|
|
733
|
+
// - Normal mode: save only if test failed
|
|
734
|
+
const shouldSave = this.config.saveAllRecordings || !testPassed;
|
|
795
735
|
let savedFilename = '';
|
|
796
736
|
if (this.config.useTempFile && metadata.totalEvents > 0) {
|
|
797
737
|
try {
|
|
798
738
|
const events = this.readFromTempFile();
|
|
799
|
-
|
|
739
|
+
|
|
800
740
|
if (events && events.length > 0) {
|
|
801
|
-
if (
|
|
802
|
-
|
|
741
|
+
if (shouldSave) {
|
|
742
|
+
const saveReason = this.config.saveAllRecordings ? 'visual regression mode' : 'test failed';
|
|
743
|
+
console.log(`🟡 Saving CapVision recording (${saveReason}): ${testName}`);
|
|
803
744
|
savedFilename = this.saveEventsToFile(events, testName);
|
|
804
|
-
console.log(`🟢 Saved ${events.length} events to: ${savedFilename} (test failed)`);
|
|
805
|
-
} else {
|
|
806
|
-
console.log(`🟡 Test passed - skipping permanent save (${events.length} events discarded)`);
|
|
807
745
|
}
|
|
808
746
|
}
|
|
809
|
-
|
|
747
|
+
|
|
810
748
|
// Always delete temp file regardless of test result
|
|
811
749
|
this.deleteTempFile();
|
|
812
|
-
console.log('🟢 Temporary file cleaned up');
|
|
813
750
|
} catch (error) {
|
|
814
751
|
console.error('🔴 Failed to process events from temp file:', error.message);
|
|
815
752
|
// Still try to delete temp file even if there was an error
|
|
@@ -820,9 +757,6 @@ class CapVisionRecorder {
|
|
|
820
757
|
}
|
|
821
758
|
}
|
|
822
759
|
}
|
|
823
|
-
|
|
824
|
-
console.log(`🟢 Recording stopped. Captured ${metadata.totalEvents} events`);
|
|
825
|
-
|
|
826
760
|
return {
|
|
827
761
|
timestamp: metadata.timestamp,
|
|
828
762
|
totalEvents: metadata.totalEvents,
|
|
@@ -842,12 +776,9 @@ class CapVisionRecorder {
|
|
|
842
776
|
}
|
|
843
777
|
|
|
844
778
|
if (!this.isCapVisionEnabled()) {
|
|
845
|
-
console.log("🟡 Skipping CapVision re-initialization (disabled by configuration)");
|
|
846
779
|
return;
|
|
847
780
|
}
|
|
848
781
|
|
|
849
|
-
console.log("🟡 Re-initializing CapVision after page change...");
|
|
850
|
-
|
|
851
782
|
await this.browserExecutor.pause(this.config.pageStabilizationDelayMs);
|
|
852
783
|
|
|
853
784
|
// Read scripts
|
|
@@ -874,7 +805,6 @@ class CapVisionRecorder {
|
|
|
874
805
|
try {
|
|
875
806
|
const tempEvents = this.readFromTempFile();
|
|
876
807
|
eventCount = tempEvents ? tempEvents.length : 0;
|
|
877
|
-
console.log(`🟢 Will restore ${eventCount} events from temp file`);
|
|
878
808
|
} catch (error) {
|
|
879
809
|
console.warn('⚠️ Could not read temp file:', error.message);
|
|
880
810
|
}
|
|
@@ -885,7 +815,6 @@ class CapVisionRecorder {
|
|
|
885
815
|
const injectScript = () => {
|
|
886
816
|
return new Promise((resolve) => {
|
|
887
817
|
if (window.rrweb) {
|
|
888
|
-
console.log('🟢 CapVision script already loaded');
|
|
889
818
|
resolve();
|
|
890
819
|
return;
|
|
891
820
|
}
|
|
@@ -894,7 +823,6 @@ class CapVisionRecorder {
|
|
|
894
823
|
const script = document.createElement('script');
|
|
895
824
|
script.textContent = capVisionScript;
|
|
896
825
|
document.head.appendChild(script);
|
|
897
|
-
console.log('🟢 CapVision script re-injected');
|
|
898
826
|
resolve();
|
|
899
827
|
} catch (error) {
|
|
900
828
|
console.error('❌ Failed to re-inject CapVision script:', error.message);
|
|
@@ -939,7 +867,6 @@ class CapVisionRecorder {
|
|
|
939
867
|
const parsed = JSON.parse(saved);
|
|
940
868
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
941
869
|
window.capVisionEvents = parsed;
|
|
942
|
-
console.log(`🟢 Restored ${parsed.length} events from sessionStorage`);
|
|
943
870
|
}
|
|
944
871
|
}
|
|
945
872
|
} catch (error) {
|
|
@@ -951,9 +878,6 @@ class CapVisionRecorder {
|
|
|
951
878
|
const initializeEventsForFileMode = () => {
|
|
952
879
|
if (config.useTempFile) {
|
|
953
880
|
window.capVisionEvents = [];
|
|
954
|
-
if (count > 0) {
|
|
955
|
-
console.log(`🟢 Temp file has ${count} events`);
|
|
956
|
-
}
|
|
957
881
|
}
|
|
958
882
|
};
|
|
959
883
|
|
|
@@ -1019,10 +943,6 @@ class CapVisionRecorder {
|
|
|
1019
943
|
console.warn('⚠️ Failed to save events to sessionStorage:', error.message);
|
|
1020
944
|
}
|
|
1021
945
|
}
|
|
1022
|
-
|
|
1023
|
-
// if (window.capVisionEvents.length % 10 === 0) {
|
|
1024
|
-
// console.log(`🟡 Captured ${window.capVisionEvents.length} events`);
|
|
1025
|
-
// }
|
|
1026
946
|
},
|
|
1027
947
|
checkoutEveryNms: config.checkoutIntervalMs,
|
|
1028
948
|
recordCanvas: config.recordCanvas,
|
|
@@ -1038,13 +958,11 @@ class CapVisionRecorder {
|
|
|
1038
958
|
|
|
1039
959
|
window.capVisionInitialized = true;
|
|
1040
960
|
window.capVisionLastCheckTime = Date.now();
|
|
1041
|
-
console.log('🟢 CapVision re-started');
|
|
1042
961
|
});
|
|
1043
962
|
};
|
|
1044
963
|
|
|
1045
964
|
const reinitialize = async () => {
|
|
1046
965
|
try {
|
|
1047
|
-
console.log('🟡 Re-initializing...');
|
|
1048
966
|
await injectScript();
|
|
1049
967
|
await injectConsolePlugin(pluginCode);
|
|
1050
968
|
restoreEventsFromStorage();
|
|
@@ -1058,7 +976,6 @@ class CapVisionRecorder {
|
|
|
1058
976
|
reinitialize();
|
|
1059
977
|
}, this.config, eventCount, capVisionScriptCode, consolePluginCode);
|
|
1060
978
|
|
|
1061
|
-
console.log("🟢 Re-initialization complete");
|
|
1062
979
|
}
|
|
1063
980
|
}
|
|
1064
981
|
|
|
@@ -407,7 +407,6 @@ ${recordingPlayersHTML}
|
|
|
407
407
|
const playerContainer = document.getElementById(\`capvision-player-inline-\${index}\`);
|
|
408
408
|
if (playerContainer) {
|
|
409
409
|
try {
|
|
410
|
-
console.log('🟡 Initializing inline player for recording:', recording.filename);
|
|
411
410
|
|
|
412
411
|
// Clear loading message
|
|
413
412
|
playerContainer.innerHTML = '';
|
|
@@ -462,7 +461,6 @@ ${recordingPlayersHTML}
|
|
|
462
461
|
|
|
463
462
|
players[index] = player;
|
|
464
463
|
|
|
465
|
-
console.log('🟢 Successfully initialized inline player for recording:', recording.filename);
|
|
466
464
|
|
|
467
465
|
} catch (error) {
|
|
468
466
|
console.error('🔴 Failed to initialize inline player for recording:', recording.filename, error);
|
|
@@ -493,7 +491,6 @@ ${recordingPlayersHTML}
|
|
|
493
491
|
});
|
|
494
492
|
});
|
|
495
493
|
|
|
496
|
-
console.log('🟢 CapVision Player integration loaded with', recordings.length, 'recording(s)');
|
|
497
494
|
|
|
498
495
|
})();
|
|
499
496
|
</script>
|
|
@@ -514,16 +511,12 @@ ${recordingPlayersHTML}
|
|
|
514
511
|
return;
|
|
515
512
|
}
|
|
516
513
|
|
|
517
|
-
console.log('🟡 Enhancing HTML report with CapVision player:', reportPath);
|
|
518
|
-
|
|
519
514
|
if (!fs.existsSync(reportPath)) {
|
|
520
|
-
console.log('🟡 HTML report not found, skipping enhancement');
|
|
521
515
|
return;
|
|
522
516
|
}
|
|
523
517
|
|
|
524
518
|
const recordings = this.getAvailableRecordings();
|
|
525
519
|
if (recordings.length === 0) {
|
|
526
|
-
console.log('🟡 No CapVision recordings found, skipping enhancement');
|
|
527
520
|
return;
|
|
528
521
|
}
|
|
529
522
|
|
|
@@ -537,7 +530,6 @@ ${recordingPlayersHTML}
|
|
|
537
530
|
const bodyEndIndex = htmlContent.lastIndexOf('</body>');
|
|
538
531
|
|
|
539
532
|
if (bodyEndIndex === -1) {
|
|
540
|
-
console.log('🟡 Could not find </body> tag, appending to end');
|
|
541
533
|
htmlContent += capVisionPlayerHTML;
|
|
542
534
|
} else {
|
|
543
535
|
htmlContent = htmlContent.slice(0, bodyEndIndex) + capVisionPlayerHTML + htmlContent.slice(bodyEndIndex);
|
|
@@ -545,9 +537,6 @@ ${recordingPlayersHTML}
|
|
|
545
537
|
|
|
546
538
|
fs.writeFileSync(reportPath, htmlContent);
|
|
547
539
|
|
|
548
|
-
console.log('🟢 Successfully enhanced HTML report with CapVision player');
|
|
549
|
-
console.log(`🟢 Found ${recordings.length} recording(s) to integrate`);
|
|
550
|
-
|
|
551
540
|
} catch (error) {
|
|
552
541
|
console.error('🔴 Failed to enhance HTML report:', error.message);
|
|
553
542
|
}
|
|
@@ -566,13 +555,7 @@ ${recordingPlayersHTML}
|
|
|
566
555
|
return;
|
|
567
556
|
}
|
|
568
557
|
|
|
569
|
-
// if (!this.isEnhancementEnabled()) {
|
|
570
|
-
// console.log('🟡 Skipping report enhancement (disabled for current cluster/module)');
|
|
571
|
-
// return;
|
|
572
|
-
// }
|
|
573
|
-
|
|
574
558
|
if (!fs.existsSync(this.config.reportsDir)) {
|
|
575
|
-
console.log('🟡 Reports directory not found');
|
|
576
559
|
return;
|
|
577
560
|
}
|
|
578
561
|
|
|
@@ -584,8 +567,6 @@ ${recordingPlayersHTML}
|
|
|
584
567
|
await this.enhanceReport(reportPath);
|
|
585
568
|
}
|
|
586
569
|
|
|
587
|
-
console.log('🟢 Enhanced all HTML reports with CapVision player');
|
|
588
|
-
|
|
589
570
|
} catch (error) {
|
|
590
571
|
console.error('🔴 Failed to enhance reports:', error.message);
|
|
591
572
|
}
|