@vizzly-testing/cli 0.8.0 → 0.9.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.
Files changed (70) hide show
  1. package/README.md +26 -13
  2. package/dist/cli.js +25 -1
  3. package/dist/client/index.js +77 -11
  4. package/dist/commands/init.js +23 -17
  5. package/dist/commands/tdd-daemon.js +312 -0
  6. package/dist/commands/tdd.js +45 -14
  7. package/dist/reporter/reporter-bundle.css +1 -0
  8. package/dist/reporter/reporter-bundle.iife.js +57 -0
  9. package/dist/server/handlers/api-handler.js +98 -30
  10. package/dist/server/handlers/tdd-handler.js +264 -77
  11. package/dist/server/http-server.js +358 -15
  12. package/dist/services/html-report-generator.js +77 -0
  13. package/dist/services/report-generator/report.css +56 -0
  14. package/dist/services/screenshot-server.js +6 -3
  15. package/dist/services/server-manager.js +2 -9
  16. package/dist/services/tdd-service.js +188 -25
  17. package/dist/services/test-runner.js +43 -1
  18. package/dist/types/commands/tdd-daemon.d.ts +18 -0
  19. package/dist/types/container/index.d.ts +1 -3
  20. package/dist/types/reporter/src/components/app-router.d.ts +3 -0
  21. package/dist/types/reporter/src/components/comparison/comparison-actions.d.ts +5 -0
  22. package/dist/types/reporter/src/components/comparison/comparison-card.d.ts +6 -0
  23. package/dist/types/reporter/src/components/comparison/comparison-list.d.ts +6 -0
  24. package/dist/types/reporter/src/components/comparison/comparison-viewer.d.ts +4 -0
  25. package/dist/types/reporter/src/components/comparison/view-mode-selector.d.ts +4 -0
  26. package/dist/types/reporter/src/components/comparison/viewer-modes/onion-viewer.d.ts +3 -0
  27. package/dist/types/reporter/src/components/comparison/viewer-modes/overlay-viewer.d.ts +3 -0
  28. package/dist/types/reporter/src/components/comparison/viewer-modes/side-by-side-viewer.d.ts +3 -0
  29. package/dist/types/reporter/src/components/comparison/viewer-modes/toggle-viewer.d.ts +3 -0
  30. package/dist/types/reporter/src/components/dashboard/dashboard-filters.d.ts +16 -0
  31. package/dist/types/reporter/src/components/dashboard/dashboard-header.d.ts +5 -0
  32. package/dist/types/reporter/src/components/dashboard/dashboard-stats.d.ts +4 -0
  33. package/dist/types/reporter/src/components/dashboard/empty-state.d.ts +8 -0
  34. package/dist/types/reporter/src/components/ui/smart-image.d.ts +7 -0
  35. package/dist/types/reporter/src/components/ui/status-badge.d.ts +5 -0
  36. package/dist/types/reporter/src/components/ui/toast.d.ts +4 -0
  37. package/dist/types/reporter/src/components/views/comparisons-view.d.ts +6 -0
  38. package/dist/types/reporter/src/components/views/stats-view.d.ts +6 -0
  39. package/dist/types/reporter/src/hooks/use-baseline-actions.d.ts +5 -0
  40. package/dist/types/reporter/src/hooks/use-comparison-filters.d.ts +20 -0
  41. package/dist/types/reporter/src/hooks/use-image-loader.d.ts +1 -0
  42. package/dist/types/reporter/src/hooks/use-report-data.d.ts +7 -0
  43. package/dist/types/reporter/src/hooks/use-vizzly-api.d.ts +9 -0
  44. package/dist/types/reporter/src/main.d.ts +1 -0
  45. package/dist/types/reporter/src/services/api-client.d.ts +4 -0
  46. package/dist/types/reporter/src/utils/comparison-helpers.d.ts +16 -0
  47. package/dist/types/reporter/src/utils/constants.d.ts +37 -0
  48. package/dist/types/reporter/vite.config.d.ts +2 -0
  49. package/dist/types/reporter/vite.dev.config.d.ts +2 -0
  50. package/dist/types/sdk/index.d.ts +1 -2
  51. package/dist/types/server/handlers/api-handler.d.ts +5 -14
  52. package/dist/types/server/handlers/tdd-handler.d.ts +18 -17
  53. package/dist/types/server/http-server.d.ts +2 -1
  54. package/dist/types/services/base-service.d.ts +1 -2
  55. package/dist/types/services/html-report-generator.d.ts +3 -3
  56. package/dist/types/services/screenshot-server.d.ts +1 -1
  57. package/dist/types/services/server-manager.d.ts +25 -35
  58. package/dist/types/services/tdd-service.d.ts +7 -1
  59. package/dist/types/services/test-runner.d.ts +6 -1
  60. package/dist/types/utils/build-history.d.ts +16 -0
  61. package/dist/types/utils/config-loader.d.ts +1 -1
  62. package/dist/types/utils/console-ui.d.ts +1 -1
  63. package/dist/types/utils/git.d.ts +4 -4
  64. package/dist/types/utils/security.d.ts +2 -1
  65. package/dist/utils/build-history.js +103 -0
  66. package/dist/utils/security.js +14 -5
  67. package/docs/api-reference.md +1 -3
  68. package/docs/getting-started.md +1 -1
  69. package/docs/tdd-mode.md +176 -112
  70. package/package.json +17 -4
@@ -10,6 +10,33 @@ import { HtmlReportGenerator } from './html-report-generator.js';
10
10
  import { sanitizeScreenshotName, validatePathSecurity, safePath, validateScreenshotProperties } from '../utils/security.js';
11
11
  const logger = createServiceLogger('TDD');
12
12
 
13
+ /**
14
+ * Generate a screenshot signature for baseline matching
15
+ * Uses same logic as screenshot-identity.js: name + viewport_width + browser
16
+ */
17
+ function generateScreenshotSignature(name, properties = {}) {
18
+ let parts = [name];
19
+
20
+ // Add viewport width if present
21
+ if (properties.viewport?.width) {
22
+ parts.push(properties.viewport.width.toString());
23
+ }
24
+
25
+ // Add browser if present
26
+ if (properties.browser) {
27
+ parts.push(properties.browser);
28
+ }
29
+ return parts.join('|');
30
+ }
31
+
32
+ /**
33
+ * Create a safe filename from signature
34
+ */
35
+ function signatureToFilename(signature) {
36
+ // Replace pipe separators with underscores for filesystem safety
37
+ return signature.replace(/\|/g, '_');
38
+ }
39
+
13
40
  /**
14
41
  * Create a new TDD service instance
15
42
  */
@@ -153,8 +180,8 @@ export class TddService {
153
180
  const existingShaMap = new Map();
154
181
  if (existingBaseline) {
155
182
  existingBaseline.screenshots.forEach(s => {
156
- if (s.sha256) {
157
- existingShaMap.set(s.name, s.sha256);
183
+ if (s.sha256 && s.signature) {
184
+ existingShaMap.set(s.signature, s.sha256);
158
185
  }
159
186
  });
160
187
  }
@@ -178,11 +205,16 @@ export class TddService {
178
205
  errorCount++;
179
206
  continue;
180
207
  }
181
- const imagePath = safePath(this.baselinePath, `${sanitizedName}.png`);
208
+
209
+ // Generate signature for baseline matching (same as compareScreenshot)
210
+ let properties = validateScreenshotProperties(screenshot.metadata || screenshot.properties || {});
211
+ let signature = generateScreenshotSignature(sanitizedName, properties);
212
+ let filename = signatureToFilename(signature);
213
+ const imagePath = safePath(this.baselinePath, `${filename}.png`);
182
214
 
183
215
  // Check if we already have this file with the same SHA (using metadata)
184
216
  if (existsSync(imagePath) && screenshot.sha256) {
185
- const storedSha = existingShaMap.get(sanitizedName);
217
+ const storedSha = existingShaMap.get(signature);
186
218
  if (storedSha === screenshot.sha256) {
187
219
  logger.debug(`⚡ Skipping ${sanitizedName} - SHA match from metadata`);
188
220
  downloadedCount++; // Count as "downloaded" since we have it
@@ -204,7 +236,10 @@ export class TddService {
204
236
  screenshot,
205
237
  sanitizedName,
206
238
  imagePath,
207
- downloadUrl
239
+ downloadUrl,
240
+ signature,
241
+ filename,
242
+ properties
208
243
  });
209
244
  }
210
245
 
@@ -293,14 +328,18 @@ export class TddService {
293
328
  logger.warn(`Screenshot name sanitization failed for '${s.name}': ${error.message}`);
294
329
  return null; // Skip invalid screenshots
295
330
  }
331
+ let properties = validateScreenshotProperties(s.metadata || s.properties || {});
332
+ let signature = generateScreenshotSignature(sanitizedName, properties);
333
+ let filename = signatureToFilename(signature);
296
334
  return {
297
335
  name: sanitizedName,
298
336
  originalName: s.name,
299
337
  sha256: s.sha256,
300
338
  // Store remote SHA for quick comparison
301
339
  id: s.id,
302
- properties: validateScreenshotProperties(s.metadata || s.properties || {}),
303
- path: safePath(this.baselinePath, `${sanitizedName}.png`),
340
+ properties: properties,
341
+ path: safePath(this.baselinePath, `${filename}.png`),
342
+ signature: signature,
304
343
  originalUrl: s.original_url,
305
344
  fileSize: s.file_size_bytes,
306
345
  dimensions: {
@@ -395,9 +434,13 @@ export class TddService {
395
434
  logger.warn(`Property validation failed for '${sanitizedName}': ${error.message}`);
396
435
  validatedProperties = {};
397
436
  }
398
- const currentImagePath = safePath(this.currentPath, `${sanitizedName}.png`);
399
- const baselineImagePath = safePath(this.baselinePath, `${sanitizedName}.png`);
400
- const diffImagePath = safePath(this.diffPath, `${sanitizedName}.png`);
437
+
438
+ // Generate signature for baseline matching (name + viewport_width + browser)
439
+ const signature = generateScreenshotSignature(sanitizedName, validatedProperties);
440
+ const filename = signatureToFilename(signature);
441
+ const currentImagePath = safePath(this.currentPath, `${filename}.png`);
442
+ const baselineImagePath = safePath(this.baselinePath, `${filename}.png`);
443
+ const diffImagePath = safePath(this.diffPath, `${filename}.png`);
401
444
 
402
445
  // Save current screenshot
403
446
  writeFileSync(currentImagePath, imageBuffer);
@@ -408,11 +451,15 @@ export class TddService {
408
451
  }
409
452
 
410
453
  // Check if baseline exists
411
- if (!existsSync(baselineImagePath)) {
412
- logger.warn(`⚠️ No baseline found for ${sanitizedName} - creating baseline`);
454
+ const baselineExists = existsSync(baselineImagePath);
455
+ if (!baselineExists) {
456
+ logger.debug(`No baseline found for ${sanitizedName} - creating baseline`);
457
+ logger.debug(`Path: ${baselineImagePath}`);
458
+ logger.debug(`Size: ${imageBuffer.length} bytes`);
413
459
 
414
460
  // Copy current screenshot to baseline directory for future comparisons
415
461
  writeFileSync(baselineImagePath, imageBuffer);
462
+ logger.debug(`Created baseline: ${imageBuffer.length} bytes`);
416
463
 
417
464
  // Update or create baseline metadata
418
465
  if (!this.baselineData) {
@@ -430,9 +477,10 @@ export class TddService {
430
477
  const screenshotEntry = {
431
478
  name: sanitizedName,
432
479
  properties: validatedProperties,
433
- path: baselineImagePath
480
+ path: baselineImagePath,
481
+ signature: signature
434
482
  };
435
- const existingIndex = this.baselineData.screenshots.findIndex(s => s.name === sanitizedName);
483
+ const existingIndex = this.baselineData.screenshots.findIndex(s => s.signature === signature);
436
484
  if (existingIndex >= 0) {
437
485
  this.baselineData.screenshots[existingIndex] = screenshotEntry;
438
486
  } else {
@@ -442,7 +490,7 @@ export class TddService {
442
490
  // Save updated metadata
443
491
  const metadataPath = join(this.baselinePath, 'metadata.json');
444
492
  writeFileSync(metadataPath, JSON.stringify(this.baselineData, null, 2));
445
- logger.info(`✅ Created baseline for ${sanitizedName}`);
493
+ logger.debug(`✅ Created baseline for ${sanitizedName}`);
446
494
  const result = {
447
495
  name: sanitizedName,
448
496
  status: 'new',
@@ -454,12 +502,20 @@ export class TddService {
454
502
  this.comparisons.push(result);
455
503
  return result;
456
504
  }
505
+
506
+ // Baseline exists - compare with it
457
507
  try {
458
508
  // Use odiff Node.js API to compare images
459
509
  const {
460
510
  compare
461
511
  } = await import('odiff-bin');
462
- logger.debug(`Comparing ${baselineImagePath} vs ${currentImagePath}`);
512
+
513
+ // Log file sizes for debugging
514
+ const baselineSize = readFileSync(baselineImagePath).length;
515
+ const currentSize = readFileSync(currentImagePath).length;
516
+ logger.debug(`Comparing ${sanitizedName}`);
517
+ logger.debug(`Baseline: ${baselineImagePath} (${baselineSize} bytes)`);
518
+ logger.debug(`Current: ${currentImagePath} (${currentSize} bytes)`);
463
519
  const result = await compare(baselineImagePath, currentImagePath, diffImagePath, {
464
520
  threshold: this.threshold,
465
521
  outputDiffMask: true
@@ -475,7 +531,7 @@ export class TddService {
475
531
  properties: validatedProperties,
476
532
  threshold: this.threshold
477
533
  };
478
- logger.info(`✅ ${colors.green('PASSED')} ${sanitizedName}`);
534
+ logger.debug(`PASSED ${sanitizedName}`);
479
535
  this.comparisons.push(comparison);
480
536
  return comparison;
481
537
  } else {
@@ -672,7 +728,10 @@ export class TddService {
672
728
  logger.warn(`Skipping baseline update for invalid name '${name}': ${error.message}`);
673
729
  continue;
674
730
  }
675
- const baselineImagePath = safePath(this.baselinePath, `${sanitizedName}.png`);
731
+ let validatedProperties = validateScreenshotProperties(comparison.properties || {});
732
+ let signature = generateScreenshotSignature(sanitizedName, validatedProperties);
733
+ let filename = signatureToFilename(signature);
734
+ const baselineImagePath = safePath(this.baselinePath, `${filename}.png`);
676
735
  try {
677
736
  // Copy current screenshot to baseline
678
737
  const currentBuffer = readFileSync(current);
@@ -681,10 +740,11 @@ export class TddService {
681
740
  // Update baseline metadata
682
741
  const screenshotEntry = {
683
742
  name: sanitizedName,
684
- properties: validateScreenshotProperties(comparison.properties || {}),
685
- path: baselineImagePath
743
+ properties: validatedProperties,
744
+ path: baselineImagePath,
745
+ signature: signature
686
746
  };
687
- const existingIndex = this.baselineData.screenshots.findIndex(s => s.name === sanitizedName);
747
+ const existingIndex = this.baselineData.screenshots.findIndex(s => s.signature === signature);
688
748
  if (existingIndex >= 0) {
689
749
  this.baselineData.screenshots[existingIndex] = screenshotEntry;
690
750
  } else {
@@ -732,13 +792,17 @@ export class TddService {
732
792
  };
733
793
  }
734
794
 
795
+ // Generate signature for this screenshot
796
+ let signature = generateScreenshotSignature(name, properties || {});
797
+
735
798
  // Add screenshot to baseline metadata
736
799
  const screenshotEntry = {
737
800
  name,
738
801
  properties: properties || {},
739
- path: baselineImagePath
802
+ path: baselineImagePath,
803
+ signature: signature
740
804
  };
741
- const existingIndex = this.baselineData.screenshots.findIndex(s => s.name === name);
805
+ const existingIndex = this.baselineData.screenshots.findIndex(s => s.signature === signature);
742
806
  if (existingIndex >= 0) {
743
807
  this.baselineData.screenshots[existingIndex] = screenshotEntry;
744
808
  } else {
@@ -783,13 +847,17 @@ export class TddService {
783
847
  };
784
848
  }
785
849
 
850
+ // Generate signature for this screenshot
851
+ let signature = generateScreenshotSignature(name, properties || {});
852
+
786
853
  // Add screenshot to baseline metadata
787
854
  const screenshotEntry = {
788
855
  name,
789
856
  properties: properties || {},
790
- path: baselineImagePath
857
+ path: baselineImagePath,
858
+ signature: signature
791
859
  };
792
- const existingIndex = this.baselineData.screenshots.findIndex(s => s.name === name);
860
+ const existingIndex = this.baselineData.screenshots.findIndex(s => s.signature === signature);
793
861
  if (existingIndex >= 0) {
794
862
  this.baselineData.screenshots[existingIndex] = screenshotEntry;
795
863
  } else {
@@ -811,4 +879,99 @@ export class TddService {
811
879
  logger.info(`🐻 Baseline set for ${name}`);
812
880
  return result;
813
881
  }
882
+
883
+ /**
884
+ * Accept a current screenshot as the new baseline
885
+ * @param {string} name - Screenshot name to accept
886
+ * @returns {Object} Result object
887
+ */
888
+ async acceptBaseline(name) {
889
+ const sanitizedName = sanitizeScreenshotName(name);
890
+ logger.debug(`Starting accept baseline for: ${sanitizedName}`);
891
+
892
+ // Find the comparison to get properties
893
+ let comparison = this.comparisons.find(c => c.name === sanitizedName);
894
+ if (!comparison) {
895
+ throw new Error(`No comparison found for screenshot: ${name}`);
896
+ }
897
+ let properties = comparison.properties || {};
898
+ let signature = generateScreenshotSignature(sanitizedName, properties);
899
+ let filename = signatureToFilename(signature);
900
+
901
+ // Find the current screenshot file
902
+ const currentImagePath = safePath(this.currentPath, `${filename}.png`);
903
+ logger.debug(`Looking for current screenshot at: ${currentImagePath}`);
904
+ if (!existsSync(currentImagePath)) {
905
+ logger.error(`Current screenshot not found at: ${currentImagePath}`);
906
+ throw new Error(`Current screenshot not found: ${name} (looked at ${currentImagePath})`);
907
+ }
908
+
909
+ // Read the current image
910
+ const imageBuffer = readFileSync(currentImagePath);
911
+ logger.debug(`Read current image: ${imageBuffer.length} bytes`);
912
+
913
+ // Create baseline directory if it doesn't exist
914
+ if (!existsSync(this.baselinePath)) {
915
+ mkdirSync(this.baselinePath, {
916
+ recursive: true
917
+ });
918
+ logger.debug(`Created baseline directory: ${this.baselinePath}`);
919
+ }
920
+
921
+ // Update the baseline
922
+ const baselineImagePath = safePath(this.baselinePath, `${filename}.png`);
923
+ logger.debug(`Writing baseline to: ${baselineImagePath}`);
924
+
925
+ // Write the baseline image directly
926
+ writeFileSync(baselineImagePath, imageBuffer);
927
+ logger.debug(`Wrote baseline image: ${imageBuffer.length} bytes`);
928
+
929
+ // Verify the write
930
+ if (existsSync(baselineImagePath)) {
931
+ const writtenSize = readFileSync(baselineImagePath).length;
932
+ logger.debug(`Verified baseline file exists: ${writtenSize} bytes`);
933
+ } else {
934
+ logger.error(`Baseline file does not exist after write!`);
935
+ }
936
+
937
+ // Update baseline metadata
938
+ if (!this.baselineData) {
939
+ this.baselineData = {
940
+ buildId: 'local-baseline',
941
+ buildName: 'Local TDD Baseline',
942
+ environment: 'test',
943
+ branch: 'local',
944
+ threshold: this.threshold,
945
+ screenshots: []
946
+ };
947
+ logger.debug(`Created new baseline metadata`);
948
+ }
949
+
950
+ // Add or update screenshot in baseline metadata
951
+ const screenshotEntry = {
952
+ name: sanitizedName,
953
+ properties: properties,
954
+ path: baselineImagePath,
955
+ signature: signature
956
+ };
957
+ const existingIndex = this.baselineData.screenshots.findIndex(s => s.signature === signature);
958
+ if (existingIndex >= 0) {
959
+ this.baselineData.screenshots[existingIndex] = screenshotEntry;
960
+ logger.debug(`Updated existing metadata entry at index ${existingIndex}`);
961
+ } else {
962
+ this.baselineData.screenshots.push(screenshotEntry);
963
+ logger.debug(`Added new metadata entry (total: ${this.baselineData.screenshots.length})`);
964
+ }
965
+
966
+ // Save updated metadata
967
+ const metadataPath = join(this.baselinePath, 'metadata.json');
968
+ writeFileSync(metadataPath, JSON.stringify(this.baselineData, null, 2));
969
+ logger.debug(`Saved metadata to: ${metadataPath}`);
970
+ logger.debug(`Accepted ${sanitizedName} as new baseline`);
971
+ return {
972
+ name: sanitizedName,
973
+ status: 'accepted',
974
+ message: 'Screenshot accepted as new baseline'
975
+ };
976
+ }
814
977
  }
@@ -14,6 +14,32 @@ export class TestRunner extends BaseService {
14
14
  this.tddService = tddService;
15
15
  this.testProcess = null;
16
16
  }
17
+
18
+ /**
19
+ * Initialize server for daemon mode (no test execution)
20
+ * @param {Object} options - Options for server initialization
21
+ */
22
+ async initialize(options) {
23
+ const {
24
+ tdd,
25
+ daemon
26
+ } = options;
27
+ if (!tdd || !daemon) {
28
+ throw new VizzlyError('Initialize method is only for TDD daemon mode', 'INVALID_MODE');
29
+ }
30
+ try {
31
+ // Start server manager for daemon mode
32
+ await this.serverManager.start(null, tdd, options.setBaseline);
33
+ this.emit('server-ready', {
34
+ port: options.port,
35
+ mode: 'daemon',
36
+ tdd: true
37
+ });
38
+ } catch (error) {
39
+ this.logger.error('Failed to initialize TDD daemon server:', error);
40
+ throw error;
41
+ }
42
+ }
17
43
  async run(options) {
18
44
  const {
19
45
  testCommand,
@@ -100,6 +126,11 @@ export class TestRunner extends BaseService {
100
126
  this.logger.error('Failed to finalize build:', finalizeError);
101
127
  }
102
128
  }
129
+
130
+ // In API mode, get actual screenshot count from handler after flush
131
+ if (!tdd && this.serverManager.server?.getScreenshotCount) {
132
+ screenshotCount = this.serverManager.server.getScreenshotCount(buildId) || 0;
133
+ }
103
134
  try {
104
135
  await this.serverManager.stop();
105
136
  } catch (stopError) {
@@ -182,10 +213,21 @@ export class TestRunner extends BaseService {
182
213
  this.logger.debug(`TDD build ${buildId} finalization skipped (local-only mode)`);
183
214
  }
184
215
  } else {
185
- // API mode: use API service to update build status
216
+ // API mode: flush uploads first, then finalize build
217
+ if (this.serverManager.server?.finishBuild) {
218
+ this.logger.debug(`Flushing uploads for build ${buildId}...`);
219
+ await this.serverManager.server.finishBuild(buildId);
220
+ this.logger.debug(`Upload flush complete for build ${buildId}`);
221
+ }
222
+
223
+ // Then update build status via API
224
+ this.logger.debug(`Finalizing build ${buildId} via API...`);
186
225
  const apiService = await this.createApiService();
187
226
  if (apiService) {
188
227
  await apiService.finalizeBuild(buildId, success, executionTime);
228
+ this.logger.debug(`Build ${buildId} finalized successfully`);
229
+ } else {
230
+ this.logger.warn(`No API service available to finalize build ${buildId}`);
189
231
  }
190
232
  }
191
233
  } catch (error) {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Start TDD server in daemon mode
3
+ * @param {Object} options - Command options
4
+ * @param {Object} globalOptions - Global CLI options
5
+ */
6
+ export function tddStartCommand(options?: any, globalOptions?: any): Promise<void>;
7
+ /**
8
+ * Stop TDD daemon server
9
+ * @param {Object} options - Command options
10
+ * @param {Object} globalOptions - Global CLI options
11
+ */
12
+ export function tddStopCommand(options?: any, globalOptions?: any): Promise<void>;
13
+ /**
14
+ * Check TDD daemon server status
15
+ * @param {Object} options - Command options
16
+ * @param {Object} globalOptions - Global CLI options
17
+ */
18
+ export function tddStatusCommand(options: any, globalOptions?: any): Promise<void>;
@@ -13,8 +13,7 @@ export function createServiceContainer(config: any, command?: string): ServiceCo
13
13
  /**
14
14
  * Service container for dependency injection and lifecycle management
15
15
  */
16
- export class ServiceContainer extends EventEmitter<[never]> {
17
- constructor();
16
+ export class ServiceContainer {
18
17
  services: Map<any, any>;
19
18
  instances: Map<any, any>;
20
19
  starting: Map<any, any>;
@@ -58,4 +57,3 @@ export type ServiceDefinition = {
58
57
  */
59
58
  dependencies?: string[];
60
59
  };
61
- import { EventEmitter } from 'events';
@@ -0,0 +1,3 @@
1
+ export default function AppRouter({ initialData }: {
2
+ initialData: any;
3
+ }): any;
@@ -0,0 +1,5 @@
1
+ export default function ComparisonActions({ onAccept, onReject, disabled, }: {
2
+ onAccept: any;
3
+ onReject: any;
4
+ disabled?: boolean;
5
+ }): any;
@@ -0,0 +1,6 @@
1
+ export default function ComparisonCard({ comparison, onAccept, onReject, userAction, }: {
2
+ comparison: any;
3
+ onAccept: any;
4
+ onReject: any;
5
+ userAction: any;
6
+ }): any;
@@ -0,0 +1,6 @@
1
+ export default function ComparisonList({ comparisons, onAccept, onReject, loadingStates, }: {
2
+ comparisons: any;
3
+ onAccept: any;
4
+ onReject: any;
5
+ loadingStates: any;
6
+ }): any;
@@ -0,0 +1,4 @@
1
+ export default function ComparisonViewer({ comparison, viewMode }: {
2
+ comparison: any;
3
+ viewMode: any;
4
+ }): any;
@@ -0,0 +1,4 @@
1
+ export default function ViewModeSelector({ viewMode, onChange }: {
2
+ viewMode: any;
3
+ onChange: any;
4
+ }): any;
@@ -0,0 +1,3 @@
1
+ export default function OnionViewer({ comparison }: {
2
+ comparison: any;
3
+ }): any;
@@ -0,0 +1,3 @@
1
+ export default function OverlayViewer({ comparison }: {
2
+ comparison: any;
3
+ }): any;
@@ -0,0 +1,3 @@
1
+ export default function SideBySideViewer({ comparison }: {
2
+ comparison: any;
3
+ }): any;
@@ -0,0 +1,3 @@
1
+ export default function ToggleViewer({ comparison }: {
2
+ comparison: any;
3
+ }): any;
@@ -0,0 +1,16 @@
1
+ export default function DashboardFilters({ filter, setFilter, sortBy, setSortBy, searchQuery, setSearchQuery, selectedBrowser, setSelectedBrowser, selectedViewport, setSelectedViewport, availableFilters, counts, onRefresh, loading, }: {
2
+ filter: any;
3
+ setFilter: any;
4
+ sortBy: any;
5
+ setSortBy: any;
6
+ searchQuery: any;
7
+ setSearchQuery: any;
8
+ selectedBrowser: any;
9
+ setSelectedBrowser: any;
10
+ selectedViewport: any;
11
+ setSelectedViewport: any;
12
+ availableFilters: any;
13
+ counts: any;
14
+ onRefresh: any;
15
+ loading: any;
16
+ }): any;
@@ -0,0 +1,5 @@
1
+ export default function DashboardHeader({ loading, onNavigate, currentView }: {
2
+ loading: any;
3
+ onNavigate: any;
4
+ currentView: any;
5
+ }): any;
@@ -0,0 +1,4 @@
1
+ export default function DashboardStats({ summary, baseline }: {
2
+ summary: any;
3
+ baseline: any;
4
+ }): any;
@@ -0,0 +1,8 @@
1
+ export function WaitingForScreenshots(): any;
2
+ export function AllPassed(): any;
3
+ export function NoResults(): any;
4
+ export function ErrorState({ error, onRetry }: {
5
+ error: any;
6
+ onRetry: any;
7
+ }): any;
8
+ export function LoadingState(): any;
@@ -0,0 +1,7 @@
1
+ export default function SmartImage({ src, alt, className, style, onClick }: {
2
+ src: any;
3
+ alt: any;
4
+ className: any;
5
+ style: any;
6
+ onClick: any;
7
+ }): any;
@@ -0,0 +1,5 @@
1
+ export default function StatusBadge({ icon: Icon, label, colorClass, }: {
2
+ icon: any;
3
+ label: any;
4
+ colorClass?: string;
5
+ }): any;
@@ -0,0 +1,4 @@
1
+ export function ToastProvider({ children }: {
2
+ children: any;
3
+ }): any;
4
+ export function useToast(): any;
@@ -0,0 +1,6 @@
1
+ export default function ComparisonsView({ reportData, setReportData, onRefresh, loading, }: {
2
+ reportData: any;
3
+ setReportData: any;
4
+ onRefresh: any;
5
+ loading: any;
6
+ }): any;
@@ -0,0 +1,6 @@
1
+ export default function StatsView({ reportData, setReportData, onRefresh, loading, }: {
2
+ reportData: any;
3
+ setReportData: any;
4
+ onRefresh: any;
5
+ loading: any;
6
+ }): any;
@@ -0,0 +1,5 @@
1
+ export default function useBaselineActions(onUpdate: any): {
2
+ accept: any;
3
+ reject: any;
4
+ loadingStates: any;
5
+ };
@@ -0,0 +1,20 @@
1
+ export default function useComparisonFilters(comparisons?: any[]): {
2
+ filteredComparisons: any;
3
+ filter: any;
4
+ setFilter: any;
5
+ sortBy: any;
6
+ setSortBy: any;
7
+ searchQuery: any;
8
+ setSearchQuery: any;
9
+ selectedBrowser: any;
10
+ setSelectedBrowser: any;
11
+ selectedViewport: any;
12
+ setSelectedViewport: any;
13
+ availableFilters: any;
14
+ counts: {
15
+ all: number;
16
+ failed: number;
17
+ passed: number;
18
+ new: number;
19
+ };
20
+ };
@@ -0,0 +1 @@
1
+ export default function useImageLoader(src: any): any;
@@ -0,0 +1,7 @@
1
+ export default function useReportData(initialData: any): {
2
+ reportData: any;
3
+ setReportData: any;
4
+ loading: any;
5
+ error: any;
6
+ refetch: any;
7
+ };
@@ -0,0 +1,9 @@
1
+ export default function useVizzlyAPI(): {
2
+ acceptBaseline: (screenshotName: any) => Promise<any>;
3
+ rejectBaseline: (screenshotName: any) => Promise<{
4
+ name: any;
5
+ action: string;
6
+ }>;
7
+ fetchReportData: () => Promise<any>;
8
+ loading: any;
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export function fetchReportData(): Promise<any>;
2
+ export function acceptBaseline(screenshotName: any): Promise<any>;
3
+ export function acceptAllBaselines(): Promise<any>;
4
+ export function resetBaselines(): Promise<any>;
@@ -0,0 +1,16 @@
1
+ export function getStatusInfo(comparison: any): {
2
+ type: string;
3
+ label: string;
4
+ description: string;
5
+ icon: React.ForwardRefExoticComponent<any>;
6
+ colorClass: string;
7
+ } | {
8
+ type: string;
9
+ label: string;
10
+ icon: React.ForwardRefExoticComponent<any>;
11
+ colorClass: string;
12
+ description?: undefined;
13
+ };
14
+ export function calculatePassRate(summary: any): number;
15
+ export function sortComparisons(comparisons: any, sortBy: any): any[];
16
+ export function filterComparisons(comparisons: any, filter: any): any;