@capillarytech/cap-ui-dev-tools 0.0.4 → 1.2.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,506 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Report Enhancer Configuration
6
+ * @typedef {Object} ReportEnhancerConfig
7
+ * @property {boolean} [ENABLE_FEATURE] - Master feature flag - if false, replay enhancement is completely disabled (default: true)
8
+ * @property {string} [recordingsDir] - Directory where recordings are stored
9
+ * @property {string} [reportsDir] - Directory where HTML reports are located
10
+ * @property {string} [playerCSSPath] - Path to CapVision player CSS file
11
+ * @property {string} [playerScriptPath] - Path to CapVision player script file
12
+ * @property {string} [consoleReplayPluginPath] - Path to console replay plugin
13
+ * @property {string} [networkReplayPluginPath] - Path to network replay plugin
14
+ * @property {number} [playerWidth] - Player width in pixels
15
+ * @property {number} [playerHeight] - Player height in pixels
16
+ * @property {boolean} [autoPlay] - Auto-play recordings on load
17
+ * @property {string[]} [enabledClusters] - Only enhance for these clusters (empty = all)
18
+ * @property {string[]} [enabledModules] - Only enhance for these modules (empty = all)
19
+ */
20
+
21
+ /**
22
+ * Recording Data Interface
23
+ * @typedef {Object} RecordingData
24
+ * @property {string} filename - Recording filename
25
+ * @property {Object} data - Recording data object
26
+ * @property {string} data.testName - Test name
27
+ * @property {number} data.recordingNumber - Recording number/sequence
28
+ * @property {string} data.timestamp - ISO timestamp
29
+ * @property {number} data.totalEvents - Total events in recording
30
+ * @property {Array} data.events - Array of CapVision events
31
+ */
32
+
33
+ /**
34
+ * Default Configuration
35
+ * @type {ReportEnhancerConfig}
36
+ */
37
+ const DEFAULT_ENHANCER_CONFIG = {
38
+ ENABLE_FEATURE: true,
39
+ recordingsDir: path.join(process.cwd(), 'reports', 'recordings'),
40
+ reportsDir: path.join(process.cwd(), 'reports', 'html-reports'),
41
+ playerCSSPath: path.join(__dirname, '../assets/capvision-player.css'),
42
+ playerScriptPath: path.join(__dirname, '../assets/capvision-player.min.js'),
43
+ consoleReplayPluginPath: path.join(__dirname, '../assets/capvision-plugins/console-replay.min.js'),
44
+ networkReplayPluginPath: path.join(__dirname, '../assets/capvision-plugins/network-replay.min.js'),
45
+ playerWidth: 800,
46
+ playerHeight: 460,
47
+ autoPlay: false,
48
+ enabledClusters: [],
49
+ enabledModules: []
50
+ };
51
+
52
+ /**
53
+ * Report Enhancer Class
54
+ * Enhances HTML reports with CapVision player functionality
55
+ * @class
56
+ */
57
+ class ReportEnhancer {
58
+ /**
59
+ * Create a new Report Enhancer instance
60
+ * @param {ReportEnhancerConfig} [config={}] - Enhancer configuration
61
+ */
62
+ constructor(config = {}) {
63
+ /** @type {ReportEnhancerConfig} */
64
+ this.config = { ...DEFAULT_ENHANCER_CONFIG, ...config };
65
+ }
66
+
67
+ /**
68
+ * Update configuration
69
+ * @param {Partial<ReportEnhancerConfig>} config - Configuration updates
70
+ */
71
+ updateConfig(config) {
72
+ this.config = { ...this.config, ...config };
73
+ }
74
+
75
+ /**
76
+ * Get current configuration
77
+ * @returns {ReportEnhancerConfig} Current configuration object
78
+ */
79
+ getConfig() {
80
+ return { ...this.config };
81
+ }
82
+
83
+ /**
84
+ * Check if enhancement should be enabled for current cluster
85
+ * @private
86
+ * @param {string} [cluster] - Override cluster (defaults to process.env.cluster)
87
+ * @returns {boolean} True if enabled for cluster
88
+ */
89
+ isEnabledForCluster(cluster) {
90
+ if (this.config.enabledClusters.length === 0) {
91
+ return true;
92
+ }
93
+
94
+ const currentCluster = cluster || process.env.cluster;
95
+ return currentCluster ? this.config.enabledClusters.includes(currentCluster) : false;
96
+ }
97
+
98
+ /**
99
+ * Check if enhancement should be enabled for current module
100
+ * @private
101
+ * @param {string} [module] - Override module (defaults to process.env.module)
102
+ * @returns {boolean} True if enabled for module
103
+ */
104
+ isEnabledForModule(module) {
105
+ if (this.config.enabledModules.length === 0) {
106
+ return true;
107
+ }
108
+
109
+ const currentModule = module || process.env.module;
110
+ return currentModule ? this.config.enabledModules.includes(currentModule) : false;
111
+ }
112
+
113
+ /**
114
+ * Check if enhancement is enabled
115
+ * @param {string} [cluster] - Override cluster check
116
+ * @param {string} [module] - Override module check
117
+ * @returns {boolean} True if enhancement enabled
118
+ */
119
+ isEnhancementEnabled(cluster, module) {
120
+ return this.isEnabledForCluster(cluster) && this.isEnabledForModule(module);
121
+ }
122
+
123
+ /**
124
+ * Get available recordings
125
+ * @private
126
+ * @returns {RecordingData[]} Array of recording data objects
127
+ */
128
+ getAvailableRecordings() {
129
+ try {
130
+ if (!fs.existsSync(this.config.recordingsDir)) {
131
+ return [];
132
+ }
133
+
134
+ const files = fs.readdirSync(this.config.recordingsDir);
135
+ const recordingFiles = files.filter(file => file.endsWith('.json'));
136
+
137
+ const recordings = [];
138
+ for (const file of recordingFiles) {
139
+ try {
140
+ const filePath = path.join(this.config.recordingsDir, file);
141
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
142
+ recordings.push({
143
+ filename: file,
144
+ data: data
145
+ });
146
+ } catch (error) {
147
+ console.error(`🔴 Failed to read recording file ${file}:`, error.message);
148
+ }
149
+ }
150
+
151
+ return recordings;
152
+ } catch (error) {
153
+ console.error('🔴 Failed to get recordings:', error.message);
154
+ return [];
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Add inline recording players to HTML content
160
+ * @private
161
+ * @param {string} htmlContent - Original HTML content
162
+ * @param {RecordingData[]} recordings - Array of recordings to add
163
+ * @returns {string} Modified HTML content with players
164
+ */
165
+ addInlineRecordingPlayers(htmlContent, recordings) {
166
+ if (recordings.length === 0) {
167
+ return htmlContent;
168
+ }
169
+
170
+ const testHeaderRegex = /(<tr class="test-header">[\s\S]*?<\/tr>)/;
171
+
172
+ return htmlContent.replace(testHeaderRegex, (match) => {
173
+ const recordingPlayersHTML = recordings.map((recording, index) => {
174
+ const testName = recording.data.testName || 'Unknown Test';
175
+ const recordingNumber = recording.data.recordingNumber || (index + 1);
176
+ const displayName = recording.data.testName
177
+ ? `${testName} (Recording #${recordingNumber})`
178
+ : recording.filename;
179
+
180
+ return `
181
+ <tr class="test-row recording">
182
+ <td colspan="2">
183
+ <div class="recordingWrapper" style="padding: 15px; background: #f8f9fa; margin: 10px 0;">
184
+ <h4 style="margin: 0 0 10px 0; color: #007bff; font-size: 16px;">
185
+ 🎬 Session Recording: ${displayName}
186
+ </h4>
187
+ <div class="recording-info" style="margin-bottom: 10px; font-size: 12px; color: #666;">
188
+ Events: ${recording.data.totalEvents} | Timestamp: ${recording.data.timestamp} | File: ${recording.filename}
189
+ </div>
190
+ <div id="capvision-player-inline-${index}" class="capvision-player-inline" style="width: 100%; max-width: ${this.config.playerWidth + 200}px; height: ${this.config.playerHeight + 100}px; border: 1px solid #ddd; border-radius: 8px; background: #fff;">
191
+ <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #666;">
192
+ Loading recording player...
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </td>
197
+ </tr>`;
198
+ }).join('');
199
+
200
+ return match + recordingPlayersHTML;
201
+ });
202
+ }
203
+
204
+ /**
205
+ * Generate CapVision player HTML and JavaScript
206
+ * @private
207
+ * @param {RecordingData[]} recordings - Array of recordings to embed
208
+ * @returns {string} HTML/JavaScript string to inject
209
+ */
210
+ generateCapVisionPlayerHTML(recordings) {
211
+ // Read bundled assets
212
+ let playerCSS = '';
213
+ try {
214
+ playerCSS = fs.readFileSync(this.config.playerCSSPath, 'utf8');
215
+ } catch (error) {
216
+ console.warn('⚠️ Failed to load CapVision player CSS:', error.message);
217
+ }
218
+
219
+ let playerScript = '';
220
+ try {
221
+ playerScript = fs.readFileSync(this.config.playerScriptPath, 'utf8');
222
+ } catch (error) {
223
+ console.warn('⚠️ Failed to load CapVision player script:', error.message);
224
+ }
225
+
226
+ let consoleReplayPlugin = '';
227
+ try {
228
+ consoleReplayPlugin = fs.readFileSync(this.config.consoleReplayPluginPath, 'utf8');
229
+ } catch (error) {
230
+ console.warn('⚠️ Failed to load console replay plugin:', error.message);
231
+ }
232
+
233
+ // Read bundled network replay plugin
234
+ let networkReplayPlugin = '';
235
+ try {
236
+ networkReplayPlugin = fs.readFileSync(this.config.networkReplayPluginPath, 'utf8');
237
+ } catch (error) {
238
+ console.warn('⚠️ Failed to load network replay plugin:', error.message);
239
+ }
240
+
241
+ return `
242
+ <!-- CapVision Player CSS (Bundled) -->
243
+ <style>
244
+ ${playerCSS}
245
+ </style>
246
+
247
+ <!-- CapVision Player Script (Bundled) -->
248
+ <script>
249
+ ${playerScript}
250
+ </script>
251
+
252
+ <!-- Console Replay Plugin (Bundled) -->
253
+ <script>
254
+ ${consoleReplayPlugin}
255
+ </script>
256
+
257
+ <!-- Network Replay Plugin (Bundled) -->
258
+ <script>
259
+ ${networkReplayPlugin}
260
+ </script>
261
+
262
+ <script>
263
+ // CapVision Player Integration Script for Inline Players
264
+ (function() {
265
+ const recordings = ${JSON.stringify(recordings)};
266
+ let players = [];
267
+
268
+ // Initialize all inline players
269
+ function initializeInlinePlayers() {
270
+ recordings.forEach((recording, index) => {
271
+ const playerContainer = document.getElementById(\`capvision-player-inline-\${index}\`);
272
+ if (playerContainer) {
273
+ try {
274
+ console.log('🟡 Initializing inline player for recording:', recording.filename);
275
+
276
+ // Clear loading message
277
+ playerContainer.innerHTML = '';
278
+
279
+ // Build plugins array for replay
280
+ const plugins = [];
281
+
282
+ // Add console replay plugin if available
283
+ if (window.rrwebPluginConsoleReplay) {
284
+ try {
285
+ const replayOptions = { level: ['log', 'info', 'warn', 'error'] };
286
+ let consolePlugin;
287
+
288
+ // Handle different export patterns
289
+ if (typeof window.rrwebPluginConsoleReplay === 'function') {
290
+ consolePlugin = window.rrwebPluginConsoleReplay(replayOptions);
291
+ } else if (window.rrwebPluginConsoleReplay.getReplayConsolePlugin) {
292
+ consolePlugin = window.rrwebPluginConsoleReplay.getReplayConsolePlugin(replayOptions);
293
+ } else if (window.rrwebPluginConsoleReplay.default) {
294
+ consolePlugin = window.rrwebPluginConsoleReplay.default(replayOptions);
295
+ }
296
+
297
+ if (consolePlugin) {
298
+ plugins.push(consolePlugin);
299
+ }
300
+ } catch (error) {
301
+ console.warn('⚠️ Failed to initialize console replay plugin:', error.message);
302
+ }
303
+ }
304
+
305
+ // Add network replay plugin if available
306
+ if (window.rrwebPluginNetworkReplay) {
307
+ try {
308
+ console.log('🟡 Initializing network replay plugin...');
309
+ const networkReplayOptions = {
310
+ showPanel: true,
311
+ maxEntries: 100,
312
+ position: 'bottom-right'
313
+ };
314
+ let networkPlugin;
315
+
316
+ // Handle different export patterns
317
+ if (typeof window.rrwebPluginNetworkReplay === 'function') {
318
+ networkPlugin = window.rrwebPluginNetworkReplay(networkReplayOptions);
319
+ console.log('🟢 Network replay plugin initialized (function pattern)');
320
+ } else if (window.rrwebPluginNetworkReplay.getReplayNetworkPlugin) {
321
+ networkPlugin = window.rrwebPluginNetworkReplay.getReplayNetworkPlugin(networkReplayOptions);
322
+ console.log('🟢 Network replay plugin initialized (getReplayNetworkPlugin pattern)');
323
+ } else if (window.rrwebPluginNetworkReplay.default) {
324
+ networkPlugin = window.rrwebPluginNetworkReplay.default(networkReplayOptions);
325
+ console.log('🟢 Network replay plugin initialized (default pattern)');
326
+ }
327
+
328
+ if (networkPlugin) {
329
+ console.log('🟡 Network plugin structure:', {
330
+ hasHandler: typeof networkPlugin.handler === 'function',
331
+ hasOnBuild: typeof networkPlugin.onBuild === 'function',
332
+ keys: Object.keys(networkPlugin)
333
+ });
334
+ plugins.push(networkPlugin);
335
+ console.log('🟢 Network replay plugin added to plugins array');
336
+ } else {
337
+ console.warn('⚠️ Network replay plugin is null or undefined');
338
+ }
339
+ } catch (error) {
340
+ console.error('🔴 Failed to initialize network replay plugin:', error);
341
+ console.error('🔴 Error stack:', error.stack);
342
+ }
343
+ } else {
344
+ console.warn('⚠️ window.rrwebPluginNetworkReplay not found');
345
+ }
346
+
347
+ // Create RRWeb player
348
+ const player = new rrwebPlayer({
349
+ target: playerContainer,
350
+ props: {
351
+ events: recording.data.events,
352
+ width: ${this.config.playerWidth},
353
+ height: ${this.config.playerHeight},
354
+ autoPlay: ${this.config.autoPlay},
355
+ speed: 1,
356
+ showController: true,
357
+ mouseTail: true,
358
+ plugins: plugins.length > 0 ? plugins : undefined,
359
+ insertStyleRules: [
360
+ '.replayer-wrapper { border-radius: 8px; width: 100%; height: 100%; }',
361
+ '.replayer-mouse { z-index: 1000; }',
362
+ '.replayer-controller { background: rgba(0,0,0,0.8); border-radius: 4px; }',
363
+ '.replayer-controller button { color: white; }',
364
+ '.replayer-wrapper { background: white; }'
365
+ ]
366
+ }
367
+ });
368
+
369
+ players[index] = player;
370
+
371
+ console.log('🟢 Successfully initialized inline player for recording:', recording.filename);
372
+
373
+ } catch (error) {
374
+ console.error('🔴 Failed to initialize inline player for recording:', recording.filename, error);
375
+ playerContainer.innerHTML = \`
376
+ <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #dc3545; font-size: 16px; flex-direction: column;">
377
+ <div>❌ Failed to load recording</div>
378
+ <div style="font-size: 12px; margin-top: 5px;">\${error.message}</div>
379
+ </div>
380
+ \`;
381
+ }
382
+ }
383
+ });
384
+ }
385
+
386
+ // Initialize players when DOM is ready
387
+ if (document.readyState === 'loading') {
388
+ document.addEventListener('DOMContentLoaded', initializeInlinePlayers);
389
+ } else {
390
+ initializeInlinePlayers();
391
+ }
392
+
393
+ // Cleanup function
394
+ window.addEventListener('beforeunload', function() {
395
+ players.forEach(player => {
396
+ if (player && player.destroy) {
397
+ player.destroy();
398
+ }
399
+ });
400
+ });
401
+
402
+ console.log('🟢 CapVision Player integration loaded with', recordings.length, 'recording(s)');
403
+
404
+ })();
405
+ </script>
406
+ `;
407
+ }
408
+
409
+ /**
410
+ * Enhance a single HTML report with CapVision player
411
+ * @async
412
+ * @param {string} reportPath - Path to HTML report file
413
+ * @returns {Promise<void>}
414
+ */
415
+ async enhanceReport(reportPath) {
416
+ try {
417
+ // Check master feature flag first
418
+ if (this.config.ENABLE_FEATURE === false) {
419
+ console.log('🟡 CapVision feature disabled (ENABLE_FEATURE=false), skipping report enhancement');
420
+ return;
421
+ }
422
+
423
+ console.log('🟡 Enhancing HTML report with CapVision player:', reportPath);
424
+
425
+ if (!fs.existsSync(reportPath)) {
426
+ console.log('🟡 HTML report not found, skipping enhancement');
427
+ return;
428
+ }
429
+
430
+ const recordings = this.getAvailableRecordings();
431
+ if (recordings.length === 0) {
432
+ console.log('🟡 No CapVision recordings found, skipping enhancement');
433
+ return;
434
+ }
435
+
436
+ let htmlContent = fs.readFileSync(reportPath, 'utf8');
437
+
438
+ // Add inline players
439
+ htmlContent = this.addInlineRecordingPlayers(htmlContent, recordings);
440
+
441
+ // Add player scripts and CSS
442
+ const capVisionPlayerHTML = this.generateCapVisionPlayerHTML(recordings);
443
+ const bodyEndIndex = htmlContent.lastIndexOf('</body>');
444
+
445
+ if (bodyEndIndex === -1) {
446
+ console.log('🟡 Could not find </body> tag, appending to end');
447
+ htmlContent += capVisionPlayerHTML;
448
+ } else {
449
+ htmlContent = htmlContent.slice(0, bodyEndIndex) + capVisionPlayerHTML + htmlContent.slice(bodyEndIndex);
450
+ }
451
+
452
+ fs.writeFileSync(reportPath, htmlContent);
453
+
454
+ console.log('🟢 Successfully enhanced HTML report with CapVision player');
455
+ console.log(`🟢 Found ${recordings.length} recording(s) to integrate`);
456
+
457
+ } catch (error) {
458
+ console.error('🔴 Failed to enhance HTML report:', error.message);
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Enhance all HTML reports in the reports directory
464
+ * @async
465
+ * @returns {Promise<void>}
466
+ */
467
+ async enhanceAllReports() {
468
+ try {
469
+ // Check master feature flag first
470
+ if (this.config.ENABLE_FEATURE === false) {
471
+ console.log('🟡 CapVision feature disabled (ENABLE_FEATURE=false), skipping report enhancement');
472
+ return;
473
+ }
474
+
475
+ if (!this.isEnhancementEnabled()) {
476
+ console.log('🟡 Skipping report enhancement (disabled for current cluster/module)');
477
+ return;
478
+ }
479
+
480
+ if (!fs.existsSync(this.config.reportsDir)) {
481
+ console.log('🟡 Reports directory not found');
482
+ return;
483
+ }
484
+
485
+ const files = fs.readdirSync(this.config.reportsDir);
486
+ const htmlFiles = files.filter(file => file.endsWith('.html'));
487
+
488
+ for (const htmlFile of htmlFiles) {
489
+ const reportPath = path.join(this.config.reportsDir, htmlFile);
490
+ await this.enhanceReport(reportPath);
491
+ }
492
+
493
+ console.log('🟢 Enhanced all HTML reports with CapVision player');
494
+
495
+ } catch (error) {
496
+ console.error('🔴 Failed to enhance reports:', error.message);
497
+ }
498
+ }
499
+ }
500
+
501
+ // Export class and default config
502
+ module.exports = {
503
+ ReportEnhancer,
504
+ DEFAULT_ENHANCER_CONFIG
505
+ };
506
+
@@ -0,0 +1,58 @@
1
+ /**
2
+ * CapVision Recorder Module for @capillarytech/cap-ui-dev-tools
3
+ *
4
+ * Session recording and playback functionality for WebdriverIO tests
5
+ *
6
+ * @module capvision-recorder
7
+ */
8
+
9
+ const path = require('path');
10
+
11
+ // Import core modules
12
+ const { CapVisionRecorder, DEFAULT_CONFIG: CAPVISION_DEFAULT_CONFIG } = require('./core/CapVisionRecorder');
13
+ const { ReportEnhancer, DEFAULT_ENHANCER_CONFIG } = require('./core/ReportEnhancer');
14
+ const {
15
+ WebdriverIOBrowserExecutor,
16
+ WebdriverIOCapVisionRecorder,
17
+ createWDIOCapVisionHooks
18
+ } = require('./adapters/WebdriverIOAdapter');
19
+
20
+ // Update default asset paths to match cap-ui-dev-tools structure
21
+ const ASSET_BASE_PATH = path.join(__dirname, 'assets');
22
+
23
+ CAPVISION_DEFAULT_CONFIG.capVisionScriptPath = path.join(ASSET_BASE_PATH, 'capvision.min.js');
24
+ CAPVISION_DEFAULT_CONFIG.consoleRecordPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/console-record.min.js');
25
+ CAPVISION_DEFAULT_CONFIG.consoleReplayPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/console-replay.min.js');
26
+ CAPVISION_DEFAULT_CONFIG.networkRecordPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/network-record.min.js');
27
+ CAPVISION_DEFAULT_CONFIG.networkReplayPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/network-replay.min.js');
28
+
29
+ DEFAULT_ENHANCER_CONFIG.playerCSSPath = path.join(ASSET_BASE_PATH, 'capvision-player.css');
30
+ DEFAULT_ENHANCER_CONFIG.playerScriptPath = path.join(ASSET_BASE_PATH, 'capvision-player.min.js');
31
+ DEFAULT_ENHANCER_CONFIG.consoleReplayPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/console-replay.min.js');
32
+ DEFAULT_ENHANCER_CONFIG.networkReplayPluginPath = path.join(ASSET_BASE_PATH, 'capvision-plugins/network-replay.min.js');
33
+
34
+ /**
35
+ * Export all CapVision recorder components
36
+ */
37
+ module.exports = {
38
+ // Core classes
39
+ CapVisionRecorder,
40
+ ReportEnhancer,
41
+
42
+ // WebdriverIO adapters
43
+ WebdriverIOBrowserExecutor,
44
+ WebdriverIOCapVisionRecorder,
45
+
46
+ // Convenience helpers
47
+ createWDIOCapVisionHooks,
48
+
49
+ // Default configurations
50
+ CAPVISION_DEFAULT_CONFIG,
51
+ DEFAULT_ENHANCER_CONFIG
52
+ };
53
+
54
+ /**
55
+ * Default export - most commonly used function
56
+ */
57
+ module.exports.default = createWDIOCapVisionHooks;
58
+
package/src/index.js CHANGED
@@ -1,7 +1,34 @@
1
- import '@shared-ui-lib/index.js';
1
+ /**
2
+ * @capillarytech/cap-ui-dev-tools
3
+ *
4
+ * Development tools for Capillary UI projects
5
+ *
6
+ * @module cap-ui-dev-tools
7
+ */
2
8
 
3
- console.log("Webpack entry point loaded.");
9
+ // Webpack Plugin for library hot-reloading
10
+ const LibraryWatcherPlugin = require('./LibraryWatcherPlugin');
4
11
 
5
- if (module.hot) {
6
- module.hot.accept();
7
- }
12
+ // CapVision Recorder for test session recording
13
+ const capVisionRecorder = require('./capvision-recorder');
14
+
15
+ /**
16
+ * Main exports for cap-ui-dev-tools
17
+ */
18
+ module.exports = {
19
+ // Webpack plugin (existing functionality)
20
+ LibraryWatcherPlugin,
21
+
22
+ // CapVision recorder module (new functionality)
23
+ capVisionRecorder,
24
+
25
+ // Convenience exports for CapVision (most commonly used)
26
+ createWDIOCapVisionHooks: capVisionRecorder.createWDIOCapVisionHooks,
27
+ CapVisionRecorder: capVisionRecorder.CapVisionRecorder,
28
+ ReportEnhancer: capVisionRecorder.ReportEnhancer
29
+ };
30
+
31
+ /**
32
+ * Default export - LibraryWatcherPlugin for backward compatibility
33
+ */
34
+ module.exports.default = LibraryWatcherPlugin;
package/architecture.png DELETED
Binary file