@supernal/interface 1.0.9 → 1.0.11

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 (147) hide show
  1. package/dist/cjs/src/browser.js +42 -1
  2. package/dist/cjs/src/browser.js.map +1 -1
  3. package/dist/cjs/src/decorators/ContainerHelpers.js +16 -1
  4. package/dist/cjs/src/decorators/ContainerHelpers.js.map +1 -1
  5. package/dist/cjs/src/decorators/Tool.js +2 -3
  6. package/dist/cjs/src/decorators/Tool.js.map +1 -1
  7. package/dist/cjs/src/testing/graph-tester/core/GraphTester.js +339 -0
  8. package/dist/cjs/src/testing/graph-tester/core/GraphTester.js.map +1 -0
  9. package/dist/cjs/src/testing/graph-tester/core/TestFunction.js +189 -0
  10. package/dist/cjs/src/testing/graph-tester/core/TestFunction.js.map +1 -0
  11. package/dist/cjs/src/testing/graph-tester/core/types.js +24 -0
  12. package/dist/cjs/src/testing/graph-tester/core/types.js.map +1 -0
  13. package/dist/cjs/src/testing/graph-tester/fixtures/index.js +13 -0
  14. package/dist/cjs/src/testing/graph-tester/fixtures/index.js.map +1 -0
  15. package/dist/cjs/src/testing/graph-tester/fixtures/portPool.js +184 -0
  16. package/dist/cjs/src/testing/graph-tester/fixtures/portPool.js.map +1 -0
  17. package/dist/cjs/src/testing/graph-tester/index.js +98 -0
  18. package/dist/cjs/src/testing/graph-tester/index.js.map +1 -0
  19. package/dist/cjs/src/testing/graph-tester/modes/AccessibilityMode.js +230 -0
  20. package/dist/cjs/src/testing/graph-tester/modes/AccessibilityMode.js.map +1 -0
  21. package/dist/cjs/src/testing/graph-tester/modes/PerformanceMode.js +168 -0
  22. package/dist/cjs/src/testing/graph-tester/modes/PerformanceMode.js.map +1 -0
  23. package/dist/cjs/src/testing/graph-tester/modes/SEOMode.js +264 -0
  24. package/dist/cjs/src/testing/graph-tester/modes/SEOMode.js.map +1 -0
  25. package/dist/cjs/src/testing/graph-tester/modes/VisualRegressionMode.js +199 -0
  26. package/dist/cjs/src/testing/graph-tester/modes/VisualRegressionMode.js.map +1 -0
  27. package/dist/cjs/src/testing/graph-tester/modes/index.js +17 -0
  28. package/dist/cjs/src/testing/graph-tester/modes/index.js.map +1 -0
  29. package/dist/cjs/src/testing/graph-tester/reporters/HTMLReporter.js +411 -0
  30. package/dist/cjs/src/testing/graph-tester/reporters/HTMLReporter.js.map +1 -0
  31. package/dist/cjs/src/testing/graph-tester/reporters/JSONReporter.js +127 -0
  32. package/dist/cjs/src/testing/graph-tester/reporters/JSONReporter.js.map +1 -0
  33. package/dist/cjs/src/testing/graph-tester/reporters/MarkdownReporter.js +169 -0
  34. package/dist/cjs/src/testing/graph-tester/reporters/MarkdownReporter.js.map +1 -0
  35. package/dist/cjs/src/testing/graph-tester/reporters/UnifiedReporter.js +118 -0
  36. package/dist/cjs/src/testing/graph-tester/reporters/UnifiedReporter.js.map +1 -0
  37. package/dist/cjs/src/testing/graph-tester/reporters/index.js +17 -0
  38. package/dist/cjs/src/testing/graph-tester/reporters/index.js.map +1 -0
  39. package/dist/cjs/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.js +47 -0
  40. package/dist/cjs/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.js.map +1 -0
  41. package/dist/cjs/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.js +584 -0
  42. package/dist/cjs/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.js.map +1 -0
  43. package/dist/cjs/src/testing/graph-tester/screenshot/ScreenshotAnnotator.js +376 -0
  44. package/dist/cjs/src/testing/graph-tester/screenshot/ScreenshotAnnotator.js.map +1 -0
  45. package/dist/cjs/src/testing/graph-tester/screenshot/index.js +15 -0
  46. package/dist/cjs/src/testing/graph-tester/screenshot/index.js.map +1 -0
  47. package/dist/cjs/src/testing/graph-tester/screenshot/types.js +11 -0
  48. package/dist/cjs/src/testing/graph-tester/screenshot/types.js.map +1 -0
  49. package/dist/cjs/src/testing/selectors.js +1 -1
  50. package/dist/esm/src/browser.d.ts +9 -0
  51. package/dist/esm/src/browser.d.ts.map +1 -1
  52. package/dist/esm/src/browser.js +14 -0
  53. package/dist/esm/src/browser.js.map +1 -1
  54. package/dist/esm/src/decorators/ContainerHelpers.d.ts +2 -1
  55. package/dist/esm/src/decorators/ContainerHelpers.d.ts.map +1 -1
  56. package/dist/esm/src/decorators/ContainerHelpers.js +16 -1
  57. package/dist/esm/src/decorators/ContainerHelpers.js.map +1 -1
  58. package/dist/esm/src/decorators/Tool.d.ts.map +1 -1
  59. package/dist/esm/src/decorators/Tool.js +2 -3
  60. package/dist/esm/src/decorators/Tool.js.map +1 -1
  61. package/dist/esm/src/testing/graph-tester/core/GraphTester.d.ts +110 -0
  62. package/dist/esm/src/testing/graph-tester/core/GraphTester.d.ts.map +1 -0
  63. package/dist/esm/src/testing/graph-tester/core/GraphTester.js +335 -0
  64. package/dist/esm/src/testing/graph-tester/core/GraphTester.js.map +1 -0
  65. package/dist/esm/src/testing/graph-tester/core/TestFunction.d.ts +120 -0
  66. package/dist/esm/src/testing/graph-tester/core/TestFunction.d.ts.map +1 -0
  67. package/dist/esm/src/testing/graph-tester/core/TestFunction.js +184 -0
  68. package/dist/esm/src/testing/graph-tester/core/TestFunction.js.map +1 -0
  69. package/dist/esm/src/testing/graph-tester/core/types.d.ts +331 -0
  70. package/dist/esm/src/testing/graph-tester/core/types.d.ts.map +1 -0
  71. package/dist/esm/src/testing/graph-tester/core/types.js +21 -0
  72. package/dist/esm/src/testing/graph-tester/core/types.js.map +1 -0
  73. package/dist/esm/src/testing/graph-tester/fixtures/index.d.ts +8 -0
  74. package/dist/esm/src/testing/graph-tester/fixtures/index.d.ts.map +1 -0
  75. package/dist/esm/src/testing/graph-tester/fixtures/index.js +7 -0
  76. package/dist/esm/src/testing/graph-tester/fixtures/index.js.map +1 -0
  77. package/dist/esm/src/testing/graph-tester/fixtures/portPool.d.ts +40 -0
  78. package/dist/esm/src/testing/graph-tester/fixtures/portPool.d.ts.map +1 -0
  79. package/dist/esm/src/testing/graph-tester/fixtures/portPool.js +147 -0
  80. package/dist/esm/src/testing/graph-tester/fixtures/portPool.js.map +1 -0
  81. package/dist/esm/src/testing/graph-tester/index.d.ts +84 -0
  82. package/dist/esm/src/testing/graph-tester/index.d.ts.map +1 -0
  83. package/dist/esm/src/testing/graph-tester/index.js +77 -0
  84. package/dist/esm/src/testing/graph-tester/index.js.map +1 -0
  85. package/dist/esm/src/testing/graph-tester/modes/AccessibilityMode.d.ts +40 -0
  86. package/dist/esm/src/testing/graph-tester/modes/AccessibilityMode.d.ts.map +1 -0
  87. package/dist/esm/src/testing/graph-tester/modes/AccessibilityMode.js +193 -0
  88. package/dist/esm/src/testing/graph-tester/modes/AccessibilityMode.js.map +1 -0
  89. package/dist/esm/src/testing/graph-tester/modes/PerformanceMode.d.ts +42 -0
  90. package/dist/esm/src/testing/graph-tester/modes/PerformanceMode.d.ts.map +1 -0
  91. package/dist/esm/src/testing/graph-tester/modes/PerformanceMode.js +131 -0
  92. package/dist/esm/src/testing/graph-tester/modes/PerformanceMode.js.map +1 -0
  93. package/dist/esm/src/testing/graph-tester/modes/SEOMode.d.ts +39 -0
  94. package/dist/esm/src/testing/graph-tester/modes/SEOMode.d.ts.map +1 -0
  95. package/dist/esm/src/testing/graph-tester/modes/SEOMode.js +227 -0
  96. package/dist/esm/src/testing/graph-tester/modes/SEOMode.js.map +1 -0
  97. package/dist/esm/src/testing/graph-tester/modes/VisualRegressionMode.d.ts +83 -0
  98. package/dist/esm/src/testing/graph-tester/modes/VisualRegressionMode.d.ts.map +1 -0
  99. package/dist/esm/src/testing/graph-tester/modes/VisualRegressionMode.js +162 -0
  100. package/dist/esm/src/testing/graph-tester/modes/VisualRegressionMode.js.map +1 -0
  101. package/dist/esm/src/testing/graph-tester/modes/index.d.ts +14 -0
  102. package/dist/esm/src/testing/graph-tester/modes/index.d.ts.map +1 -0
  103. package/dist/esm/src/testing/graph-tester/modes/index.js +10 -0
  104. package/dist/esm/src/testing/graph-tester/modes/index.js.map +1 -0
  105. package/dist/esm/src/testing/graph-tester/reporters/HTMLReporter.d.ts +38 -0
  106. package/dist/esm/src/testing/graph-tester/reporters/HTMLReporter.d.ts.map +1 -0
  107. package/dist/esm/src/testing/graph-tester/reporters/HTMLReporter.js +374 -0
  108. package/dist/esm/src/testing/graph-tester/reporters/HTMLReporter.js.map +1 -0
  109. package/dist/esm/src/testing/graph-tester/reporters/JSONReporter.d.ts +50 -0
  110. package/dist/esm/src/testing/graph-tester/reporters/JSONReporter.d.ts.map +1 -0
  111. package/dist/esm/src/testing/graph-tester/reporters/JSONReporter.js +90 -0
  112. package/dist/esm/src/testing/graph-tester/reporters/JSONReporter.js.map +1 -0
  113. package/dist/esm/src/testing/graph-tester/reporters/MarkdownReporter.d.ts +33 -0
  114. package/dist/esm/src/testing/graph-tester/reporters/MarkdownReporter.d.ts.map +1 -0
  115. package/dist/esm/src/testing/graph-tester/reporters/MarkdownReporter.js +132 -0
  116. package/dist/esm/src/testing/graph-tester/reporters/MarkdownReporter.js.map +1 -0
  117. package/dist/esm/src/testing/graph-tester/reporters/UnifiedReporter.d.ts +30 -0
  118. package/dist/esm/src/testing/graph-tester/reporters/UnifiedReporter.d.ts.map +1 -0
  119. package/dist/esm/src/testing/graph-tester/reporters/UnifiedReporter.js +81 -0
  120. package/dist/esm/src/testing/graph-tester/reporters/UnifiedReporter.js.map +1 -0
  121. package/dist/esm/src/testing/graph-tester/reporters/index.d.ts +14 -0
  122. package/dist/esm/src/testing/graph-tester/reporters/index.d.ts.map +1 -0
  123. package/dist/esm/src/testing/graph-tester/reporters/index.js +10 -0
  124. package/dist/esm/src/testing/graph-tester/reporters/index.js.map +1 -0
  125. package/dist/esm/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.d.ts +33 -0
  126. package/dist/esm/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.d.ts.map +1 -0
  127. package/dist/esm/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.js +43 -0
  128. package/dist/esm/src/testing/graph-tester/screenshot/CanvasAnnotationRenderer.js.map +1 -0
  129. package/dist/esm/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.d.ts +70 -0
  130. package/dist/esm/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.d.ts.map +1 -0
  131. package/dist/esm/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.js +547 -0
  132. package/dist/esm/src/testing/graph-tester/screenshot/HTMLAnnotationRenderer.js.map +1 -0
  133. package/dist/esm/src/testing/graph-tester/screenshot/ScreenshotAnnotator.d.ts +83 -0
  134. package/dist/esm/src/testing/graph-tester/screenshot/ScreenshotAnnotator.d.ts.map +1 -0
  135. package/dist/esm/src/testing/graph-tester/screenshot/ScreenshotAnnotator.js +339 -0
  136. package/dist/esm/src/testing/graph-tester/screenshot/ScreenshotAnnotator.js.map +1 -0
  137. package/dist/esm/src/testing/graph-tester/screenshot/index.d.ts +11 -0
  138. package/dist/esm/src/testing/graph-tester/screenshot/index.d.ts.map +1 -0
  139. package/dist/esm/src/testing/graph-tester/screenshot/index.js +9 -0
  140. package/dist/esm/src/testing/graph-tester/screenshot/index.js.map +1 -0
  141. package/dist/esm/src/testing/graph-tester/screenshot/types.d.ts +331 -0
  142. package/dist/esm/src/testing/graph-tester/screenshot/types.d.ts.map +1 -0
  143. package/dist/esm/src/testing/graph-tester/screenshot/types.js +10 -0
  144. package/dist/esm/src/testing/graph-tester/screenshot/types.js.map +1 -0
  145. package/dist/esm/src/testing/selectors.d.ts +1 -1
  146. package/dist/esm/src/testing/selectors.js +1 -1
  147. package/package.json +19 -6
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Performance testing mode (stub - to be implemented in Phase 2).
3
+ *
4
+ * Will collect Core Web Vitals and Lighthouse metrics.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import type { Page } from '@playwright/test';
9
+ import { TestFunction } from '../core/TestFunction';
10
+ import type { TestContext, TestResult } from '../core/types';
11
+ /**
12
+ * Configuration for performance mode.
13
+ */
14
+ export interface PerformanceConfig {
15
+ /** Output directory */
16
+ outputDir: string;
17
+ /** Whether to run Lighthouse (default: false) */
18
+ lighthouse?: boolean;
19
+ /** Performance thresholds */
20
+ thresholds?: {
21
+ fcp?: number;
22
+ lcp?: number;
23
+ cls?: number;
24
+ tti?: number;
25
+ tbt?: number;
26
+ };
27
+ }
28
+ /**
29
+ * Performance testing mode (stub).
30
+ */
31
+ export declare class PerformanceMode extends TestFunction {
32
+ readonly mode = "performance";
33
+ readonly name = "Performance";
34
+ readonly description = "Collects Core Web Vitals and performance metrics";
35
+ private config;
36
+ constructor(config: PerformanceConfig);
37
+ execute(page: Page, context: TestContext): Promise<TestResult>;
38
+ private sanitizeRoute;
39
+ private ensureDirectory;
40
+ private writeFile;
41
+ }
42
+ //# sourceMappingURL=PerformanceMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerformanceMode.d.ts","sourceRoot":"","sources":["../../../../../../src/testing/graph-tester/modes/PerformanceMode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAElB,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,6BAA6B;IAC7B,UAAU,CAAC,EAAE;QACX,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,WAAW,sDAAsD;IAE1E,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,iBAAiB;IAK/B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAgHpE,OAAO,CAAC,aAAa;YAIP,eAAe;YAKf,SAAS;CAIxB"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Performance testing mode (stub - to be implemented in Phase 2).
3
+ *
4
+ * Will collect Core Web Vitals and Lighthouse metrics.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { TestFunction } from '../core/TestFunction.js';
9
+ /**
10
+ * Performance testing mode (stub).
11
+ */
12
+ export class PerformanceMode extends TestFunction {
13
+ constructor(config) {
14
+ super();
15
+ this.mode = 'performance';
16
+ this.name = 'Performance';
17
+ this.description = 'Collects Core Web Vitals and performance metrics';
18
+ this.config = config;
19
+ }
20
+ async execute(page, context) {
21
+ const startTime = Date.now();
22
+ const errors = [];
23
+ try {
24
+ // Collect Core Web Vitals and performance metrics
25
+ const metrics = await page.evaluate(() => {
26
+ return new Promise((resolve) => {
27
+ const observer = new PerformanceObserver((list) => {
28
+ const entries = list.getEntries();
29
+ // Process entries as they come
30
+ });
31
+ // Use performance API to get navigation timing
32
+ const perfData = performance.getEntriesByType('navigation')[0];
33
+ const paintEntries = performance.getEntriesByType('paint');
34
+ const fcp = paintEntries.find((entry) => entry.name === 'first-contentful-paint')?.startTime;
35
+ // Get layout shift metrics
36
+ const layoutShifts = performance.getEntriesByType('layout-shift');
37
+ const cls = layoutShifts.reduce((sum, entry) => sum + (entry.value || 0), 0);
38
+ // Calculate TTI approximation (when main thread is idle)
39
+ const tti = perfData ? perfData.domInteractive : 0;
40
+ // Get resource timing
41
+ const resources = performance.getEntriesByType('resource');
42
+ const totalSize = resources.reduce((sum, r) => sum + (r.transferSize || 0), 0);
43
+ resolve({
44
+ // Core Web Vitals
45
+ fcp: fcp || 0,
46
+ lcp: 0, // Will be collected via observer
47
+ cls: cls || 0,
48
+ tti: tti || 0,
49
+ tbt: 0, // Total Blocking Time - approximation
50
+ // Additional metrics
51
+ domContentLoaded: perfData?.domContentLoadedEventEnd || 0,
52
+ loadComplete: perfData?.loadEventEnd || 0,
53
+ totalResourceSize: totalSize,
54
+ resourceCount: resources.length,
55
+ // Timing breakdown
56
+ dns: perfData ? perfData.domainLookupEnd - perfData.domainLookupStart : 0,
57
+ tcp: perfData ? perfData.connectEnd - perfData.connectStart : 0,
58
+ ttfb: perfData ? perfData.responseStart - perfData.requestStart : 0,
59
+ });
60
+ });
61
+ });
62
+ // Check thresholds
63
+ const thresholdViolations = [];
64
+ if (this.config.thresholds) {
65
+ if (this.config.thresholds.fcp && metrics.fcp > this.config.thresholds.fcp) {
66
+ thresholdViolations.push({
67
+ severity: 'warning',
68
+ message: `FCP ${metrics.fcp.toFixed(2)}ms exceeds threshold ${this.config.thresholds.fcp}ms`,
69
+ });
70
+ }
71
+ if (this.config.thresholds.lcp && metrics.lcp > this.config.thresholds.lcp) {
72
+ thresholdViolations.push({
73
+ severity: 'warning',
74
+ message: `LCP ${metrics.lcp.toFixed(2)}ms exceeds threshold ${this.config.thresholds.lcp}ms`,
75
+ });
76
+ }
77
+ if (this.config.thresholds.cls && metrics.cls > this.config.thresholds.cls) {
78
+ thresholdViolations.push({
79
+ severity: 'warning',
80
+ message: `CLS ${metrics.cls.toFixed(3)} exceeds threshold ${this.config.thresholds.cls}`,
81
+ });
82
+ }
83
+ if (this.config.thresholds.tti && metrics.tti > this.config.thresholds.tti) {
84
+ thresholdViolations.push({
85
+ severity: 'warning',
86
+ message: `TTI ${metrics.tti.toFixed(2)}ms exceeds threshold ${this.config.thresholds.tti}ms`,
87
+ });
88
+ }
89
+ }
90
+ // Save results
91
+ const outputPath = `${this.config.outputDir}/${this.sanitizeRoute(context.route)}-performance.json`;
92
+ await this.ensureDirectory(this.config.outputDir);
93
+ await this.writeFile(outputPath, JSON.stringify({ route: context.route, metrics, thresholdViolations }, null, 2));
94
+ const duration = Date.now() - startTime;
95
+ return {
96
+ passed: thresholdViolations.length === 0,
97
+ duration,
98
+ errors: thresholdViolations,
99
+ metadata: {
100
+ performance: metrics,
101
+ outputPath,
102
+ },
103
+ };
104
+ }
105
+ catch (error) {
106
+ errors.push({
107
+ severity: 'critical',
108
+ message: `Performance collection failed: ${error instanceof Error ? error.message : String(error)}`,
109
+ stack: error instanceof Error ? error.stack : undefined,
110
+ });
111
+ return {
112
+ passed: false,
113
+ duration: Date.now() - startTime,
114
+ errors,
115
+ metadata: {},
116
+ };
117
+ }
118
+ }
119
+ sanitizeRoute(route) {
120
+ return route.replace(/^\//, '').replace(/\//g, '-') || 'home';
121
+ }
122
+ async ensureDirectory(dir) {
123
+ const fs = await import('fs/promises');
124
+ await fs.mkdir(dir, { recursive: true });
125
+ }
126
+ async writeFile(path, content) {
127
+ const fs = await import('fs/promises');
128
+ await fs.writeFile(path, content, 'utf-8');
129
+ }
130
+ }
131
+ //# sourceMappingURL=PerformanceMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerformanceMode.js","sourceRoot":"","sources":["../../../../../../src/testing/graph-tester/modes/PerformanceMode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAuBpD;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAO/C,YAAY,MAAyB;QACnC,KAAK,EAAE,CAAC;QAPD,SAAI,GAAG,aAAa,CAAC;QACrB,SAAI,GAAG,aAAa,CAAC;QACrB,gBAAW,GAAG,kDAAkD,CAAC;QAMxE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAU,EAAE,OAAoB;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAwC,EAAE,CAAC;QAEvD,IAAI,CAAC;YACH,kDAAkD;YAClD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAiB,EAAE;gBACrD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC7B,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE;wBAChD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;wBAClC,+BAA+B;oBACjC,CAAC,CAAC,CAAC;oBAEH,+CAA+C;oBAC/C,MAAM,QAAQ,GAAG,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAA4C,CAAC;oBAC1G,MAAM,YAAY,GAAG,WAAW,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;oBAE3D,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,wBAAwB,CAAC,EAAE,SAAS,CAAC;oBAE7F,2BAA2B;oBAC3B,MAAM,YAAY,GAAG,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAU,CAAC;oBAC3E,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAE7E,yDAAyD;oBACzD,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;oBAEnD,sBAAsB;oBACtB,MAAM,SAAS,GAAG,WAAW,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;oBAC3D,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAW,EAAE,CAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAE5F,OAAO,CAAC;wBACN,kBAAkB;wBAClB,GAAG,EAAE,GAAG,IAAI,CAAC;wBACb,GAAG,EAAE,CAAC,EAAE,iCAAiC;wBACzC,GAAG,EAAE,GAAG,IAAI,CAAC;wBACb,GAAG,EAAE,GAAG,IAAI,CAAC;wBACb,GAAG,EAAE,CAAC,EAAE,sCAAsC;wBAE9C,qBAAqB;wBACrB,gBAAgB,EAAE,QAAQ,EAAE,wBAAwB,IAAI,CAAC;wBACzD,YAAY,EAAE,QAAQ,EAAE,YAAY,IAAI,CAAC;wBACzC,iBAAiB,EAAE,SAAS;wBAC5B,aAAa,EAAE,SAAS,CAAC,MAAM;wBAE/B,mBAAmB;wBACnB,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;wBACzE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;wBAC/D,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;qBACpE,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,mBAAmB;YACnB,MAAM,mBAAmB,GAAwC,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3B,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;oBAC3E,mBAAmB,CAAC,IAAI,CAAC;wBACvB,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI;qBAC7F,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;oBAC3E,mBAAmB,CAAC,IAAI,CAAC;wBACvB,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI;qBAC7F,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;oBAC3E,mBAAmB,CAAC,IAAI,CAAC;wBACvB,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;qBACzF,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;oBAC3E,mBAAmB,CAAC,IAAI,CAAC;wBACvB,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI;qBAC7F,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,eAAe;YACf,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC;YACpG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAElH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAExC,OAAO;gBACL,MAAM,EAAE,mBAAmB,CAAC,MAAM,KAAK,CAAC;gBACxC,QAAQ;gBACR,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE;oBACR,WAAW,EAAE,OAAO;oBACpB,UAAU;iBACX;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,kCAAkC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;gBACnG,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aACxD,CAAC,CAAC;YACH,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;gBAChC,MAAM;gBACN,QAAQ,EAAE,EAAE;aACb,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,KAAa;QACjC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,GAAW;QACvC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAAe;QACnD,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * SEO testing mode (stub - to be implemented in Phase 2).
3
+ *
4
+ * Will validate meta tags, OpenGraph, and structured data.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import type { Page } from '@playwright/test';
9
+ import { TestFunction } from '../core/TestFunction';
10
+ import type { TestContext, TestResult } from '../core/types';
11
+ /**
12
+ * Configuration for SEO mode.
13
+ */
14
+ export interface SEOConfig {
15
+ /** Output directory */
16
+ outputDir: string;
17
+ /** Required meta tags */
18
+ requiredMetaTags?: string[];
19
+ /** Whether to validate OpenGraph (default: true) */
20
+ validateOpenGraph?: boolean;
21
+ /** Whether to validate Twitter Cards (default: true) */
22
+ validateTwitterCards?: boolean;
23
+ }
24
+ /**
25
+ * SEO testing mode (stub).
26
+ */
27
+ export declare class SEOMode extends TestFunction {
28
+ readonly mode = "seo";
29
+ readonly name = "SEO";
30
+ readonly description = "Validates meta tags and SEO elements";
31
+ private config;
32
+ constructor(config: SEOConfig);
33
+ execute(page: Page, context: TestContext): Promise<TestResult>;
34
+ private calculateScore;
35
+ private sanitizeRoute;
36
+ private ensureDirectory;
37
+ private writeFile;
38
+ }
39
+ //# sourceMappingURL=SEOMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SEOMode.d.ts","sourceRoot":"","sources":["../../../../../../src/testing/graph-tester/modes/SEOMode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAElB,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,qBAAa,OAAQ,SAAQ,YAAY;IACvC,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,WAAW,0CAA0C;IAE9D,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,EAAE,SAAS;IAKvB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAqNpE,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,aAAa;YAIP,eAAe;YAKf,SAAS;CAIxB"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * SEO testing mode (stub - to be implemented in Phase 2).
3
+ *
4
+ * Will validate meta tags, OpenGraph, and structured data.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { TestFunction } from '../core/TestFunction.js';
9
+ /**
10
+ * SEO testing mode (stub).
11
+ */
12
+ export class SEOMode extends TestFunction {
13
+ constructor(config) {
14
+ super();
15
+ this.mode = 'seo';
16
+ this.name = 'SEO';
17
+ this.description = 'Validates meta tags and SEO elements';
18
+ this.config = config;
19
+ }
20
+ async execute(page, context) {
21
+ const startTime = Date.now();
22
+ const errors = [];
23
+ try {
24
+ // Extract SEO metadata
25
+ const seoData = await page.evaluate(() => {
26
+ // Helper to get meta content
27
+ const getMeta = (name) => {
28
+ const meta = document.querySelector(`meta[name="${name}"], meta[property="${name}"]`);
29
+ return meta?.getAttribute('content') || null;
30
+ };
31
+ // Get all meta tags
32
+ const allMeta = {};
33
+ Array.from(document.querySelectorAll('meta')).forEach((meta) => {
34
+ const name = meta.getAttribute('name') || meta.getAttribute('property');
35
+ const content = meta.getAttribute('content');
36
+ if (name && content) {
37
+ allMeta[name] = content;
38
+ }
39
+ });
40
+ // Title and description
41
+ const title = document.querySelector('title')?.textContent || '';
42
+ const description = getMeta('description');
43
+ // OpenGraph
44
+ const og = {
45
+ title: getMeta('og:title'),
46
+ description: getMeta('og:description'),
47
+ image: getMeta('og:image'),
48
+ url: getMeta('og:url'),
49
+ type: getMeta('og:type'),
50
+ siteName: getMeta('og:site_name'),
51
+ };
52
+ // Twitter Cards
53
+ const twitter = {
54
+ card: getMeta('twitter:card'),
55
+ title: getMeta('twitter:title'),
56
+ description: getMeta('twitter:description'),
57
+ image: getMeta('twitter:image'),
58
+ site: getMeta('twitter:site'),
59
+ creator: getMeta('twitter:creator'),
60
+ };
61
+ // Canonical URL
62
+ const canonical = document.querySelector('link[rel="canonical"]')?.getAttribute('href');
63
+ // Heading structure
64
+ const headings = {
65
+ h1: Array.from(document.querySelectorAll('h1')).map((h) => h.textContent?.trim() || ''),
66
+ h2: Array.from(document.querySelectorAll('h2')).map((h) => h.textContent?.trim() || ''),
67
+ h3Count: document.querySelectorAll('h3').length,
68
+ h4Count: document.querySelectorAll('h4').length,
69
+ };
70
+ // Structured data (JSON-LD)
71
+ const structuredData = [];
72
+ Array.from(document.querySelectorAll('script[type="application/ld+json"]')).forEach((script) => {
73
+ try {
74
+ const data = JSON.parse(script.textContent || '{}');
75
+ structuredData.push(data);
76
+ }
77
+ catch {
78
+ // Ignore invalid JSON
79
+ }
80
+ });
81
+ // Images
82
+ const images = Array.from(document.querySelectorAll('img'));
83
+ const imagesWithoutAlt = images.filter((img) => !img.getAttribute('alt')).length;
84
+ // Links
85
+ const links = Array.from(document.querySelectorAll('a'));
86
+ const externalLinks = links.filter((a) => {
87
+ const href = a.getAttribute('href');
88
+ return href && (href.startsWith('http://') || href.startsWith('https://'));
89
+ }).length;
90
+ return {
91
+ title,
92
+ description,
93
+ canonical,
94
+ allMeta,
95
+ og,
96
+ twitter,
97
+ headings,
98
+ structuredData,
99
+ images: {
100
+ total: images.length,
101
+ withoutAlt: imagesWithoutAlt,
102
+ },
103
+ links: {
104
+ total: links.length,
105
+ external: externalLinks,
106
+ },
107
+ };
108
+ });
109
+ // Validate required meta tags
110
+ const missingTags = [];
111
+ if (this.config.requiredMetaTags) {
112
+ for (const tag of this.config.requiredMetaTags) {
113
+ if (!seoData.allMeta[tag]) {
114
+ missingTags.push(tag);
115
+ }
116
+ }
117
+ }
118
+ // Basic SEO validations
119
+ const issues = [];
120
+ if (!seoData.title) {
121
+ issues.push({ severity: 'critical', message: 'Missing page title' });
122
+ }
123
+ else if (seoData.title.length < 30 || seoData.title.length > 60) {
124
+ issues.push({
125
+ severity: 'warning',
126
+ message: `Title length ${seoData.title.length} characters (recommended: 30-60)`,
127
+ });
128
+ }
129
+ if (!seoData.description) {
130
+ issues.push({ severity: 'critical', message: 'Missing meta description' });
131
+ }
132
+ else if (seoData.description.length < 120 || seoData.description.length > 160) {
133
+ issues.push({
134
+ severity: 'warning',
135
+ message: `Description length ${seoData.description.length} characters (recommended: 120-160)`,
136
+ });
137
+ }
138
+ if (seoData.headings.h1.length === 0) {
139
+ issues.push({ severity: 'warning', message: 'Missing H1 heading' });
140
+ }
141
+ else if (seoData.headings.h1.length > 1) {
142
+ issues.push({
143
+ severity: 'warning',
144
+ message: `Multiple H1 headings found (${seoData.headings.h1.length})`,
145
+ });
146
+ }
147
+ if (seoData.images.withoutAlt > 0) {
148
+ issues.push({
149
+ severity: 'warning',
150
+ message: `${seoData.images.withoutAlt} images without alt text`,
151
+ });
152
+ }
153
+ // OpenGraph validation
154
+ if (this.config.validateOpenGraph !== false) {
155
+ if (!seoData.og.title)
156
+ issues.push({ severity: 'warning', message: 'Missing og:title' });
157
+ if (!seoData.og.description)
158
+ issues.push({ severity: 'warning', message: 'Missing og:description' });
159
+ if (!seoData.og.image)
160
+ issues.push({ severity: 'warning', message: 'Missing og:image' });
161
+ }
162
+ // Twitter Cards validation
163
+ if (this.config.validateTwitterCards !== false) {
164
+ if (!seoData.twitter.card)
165
+ issues.push({ severity: 'info', message: 'Missing twitter:card' });
166
+ }
167
+ if (missingTags.length > 0) {
168
+ issues.push({
169
+ severity: 'critical',
170
+ message: `Missing required meta tags: ${missingTags.join(', ')}`,
171
+ });
172
+ }
173
+ // Save results
174
+ const outputPath = `${this.config.outputDir}/${this.sanitizeRoute(context.route)}-seo.json`;
175
+ await this.ensureDirectory(this.config.outputDir);
176
+ await this.writeFile(outputPath, JSON.stringify({
177
+ route: context.route,
178
+ seo: seoData,
179
+ issues,
180
+ score: this.calculateScore(issues),
181
+ }, null, 2));
182
+ const duration = Date.now() - startTime;
183
+ return {
184
+ passed: issues.length === 0,
185
+ duration,
186
+ errors: issues,
187
+ metadata: {
188
+ seo: {
189
+ issueCount: issues.length,
190
+ score: this.calculateScore(issues),
191
+ hasStructuredData: seoData.structuredData.length > 0,
192
+ },
193
+ outputPath,
194
+ },
195
+ };
196
+ }
197
+ catch (error) {
198
+ errors.push({
199
+ severity: 'critical',
200
+ message: `SEO validation failed: ${error instanceof Error ? error.message : String(error)}`,
201
+ stack: error instanceof Error ? error.stack : undefined,
202
+ });
203
+ return {
204
+ passed: false,
205
+ duration: Date.now() - startTime,
206
+ errors,
207
+ metadata: {},
208
+ };
209
+ }
210
+ }
211
+ calculateScore(issues) {
212
+ // Simple scoring: 100 - (10 points per issue)
213
+ return Math.max(0, 100 - issues.length * 10);
214
+ }
215
+ sanitizeRoute(route) {
216
+ return route.replace(/^\//, '').replace(/\//g, '-') || 'home';
217
+ }
218
+ async ensureDirectory(dir) {
219
+ const fs = await import('fs/promises');
220
+ await fs.mkdir(dir, { recursive: true });
221
+ }
222
+ async writeFile(path, content) {
223
+ const fs = await import('fs/promises');
224
+ await fs.writeFile(path, content, 'utf-8');
225
+ }
226
+ }
227
+ //# sourceMappingURL=SEOMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SEOMode.js","sourceRoot":"","sources":["../../../../../../src/testing/graph-tester/modes/SEOMode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Visual regression testing mode.
3
+ *
4
+ * Captures screenshots with element annotations for visual regression testing and AI analysis.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import type { Page } from '@playwright/test';
9
+ import { TestFunction } from '../core/TestFunction';
10
+ import type { TestContext, TestResult } from '../core/types';
11
+ import { type ScreenshotAnnotatorConfig, type HTMLRendererConfig } from '../screenshot';
12
+ /**
13
+ * Configuration for visual regression mode.
14
+ */
15
+ export interface VisualRegressionConfig {
16
+ /** Output directory for screenshots */
17
+ outputDir: string;
18
+ /** Whether to capture full page (default: true) */
19
+ fullPage?: boolean;
20
+ /** Whether to annotate elements (default: true) */
21
+ annotate?: boolean;
22
+ /** Whether to generate HTML overlay (default: true) */
23
+ generateHTML?: boolean;
24
+ /** Whether to include invisible elements (default: false) */
25
+ includeInvisible?: boolean;
26
+ /** Minimum element size to annotate (default: 5px) */
27
+ minElementSize?: number;
28
+ /** Whether to enable AI analysis (enterprise only, default: false) */
29
+ aiAnalyze?: boolean;
30
+ /** Custom screenshot annotator config */
31
+ annotatorConfig?: Partial<ScreenshotAnnotatorConfig>;
32
+ /** Custom HTML renderer config */
33
+ htmlRendererConfig?: Partial<HTMLRendererConfig>;
34
+ }
35
+ /**
36
+ * Visual regression testing mode.
37
+ *
38
+ * Captures full-page screenshots with element annotations, bounding boxes,
39
+ * and generates interactive HTML overlays for review.
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const mode = new VisualRegressionMode({
44
+ * outputDir: './screenshots',
45
+ * annotate: true,
46
+ * generateHTML: true
47
+ * });
48
+ *
49
+ * const tester = new GraphTester({
50
+ * baseUrl: 'http://localhost:3000',
51
+ * routes: [{ route: '/' }],
52
+ * modes: []
53
+ * });
54
+ *
55
+ * tester.registerTestFunction(mode);
56
+ * const results = await tester.runTests();
57
+ * ```
58
+ */
59
+ export declare class VisualRegressionMode extends TestFunction {
60
+ readonly mode = "visual";
61
+ readonly name = "Visual Regression";
62
+ readonly description = "Captures screenshots with element annotations for visual regression testing";
63
+ private config;
64
+ private annotator;
65
+ constructor(config: VisualRegressionConfig);
66
+ /**
67
+ * Setup: Initialize screenshot annotator.
68
+ */
69
+ setup?(page: Page): Promise<void>;
70
+ /**
71
+ * Execute: Capture screenshot and annotations.
72
+ */
73
+ execute(page: Page, context: TestContext): Promise<TestResult>;
74
+ /**
75
+ * Sanitize route for filename.
76
+ */
77
+ private sanitizeRoute;
78
+ /**
79
+ * Validate configuration.
80
+ */
81
+ validate(): string[];
82
+ }
83
+ //# sourceMappingURL=VisualRegressionMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualRegressionMode.d.ts","sourceRoot":"","sources":["../../../../../../src/testing/graph-tester/modes/VisualRegressionMode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACxB,MAAM,eAAe,CAAC;AAGvB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAElB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,yCAAyC;IACzC,eAAe,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAErD,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,IAAI,uBAAuB;IACpC,QAAQ,CAAC,WAAW,iFAAiF;IAErG,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,SAAS,CAAoC;gBAEzC,MAAM,EAAE,sBAAsB;IAa1C;;OAEG;IACG,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvC;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA0FpE;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,QAAQ,IAAI,MAAM,EAAE;CASrB"}