vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1739

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 (202) hide show
  1. package/README.md +240 -0
  2. package/package.json +10 -2
  3. package/src/agents/Agent.js +300 -0
  4. package/src/agents/AgentAdditionService.js +311 -0
  5. package/src/agents/AgentCheckService.js +690 -0
  6. package/src/agents/AgentInstallationService.js +140 -0
  7. package/src/agents/AgentSetupService.js +467 -0
  8. package/src/agents/AgentStatus.js +183 -0
  9. package/src/agents/AgentVerificationService.js +634 -0
  10. package/src/agents/ConfigurationSchemaValidator.js +543 -0
  11. package/src/agents/EnvironmentConfigurationManager.js +602 -0
  12. package/src/agents/InstallationErrorHandler.js +372 -0
  13. package/src/agents/InstallationLog.js +363 -0
  14. package/src/agents/InstallationMethod.js +510 -0
  15. package/src/agents/InstallationOrchestrator.js +352 -0
  16. package/src/agents/InstallationProgressReporter.js +372 -0
  17. package/src/agents/InstallationRetryManager.js +322 -0
  18. package/src/agents/InstallationType.js +254 -0
  19. package/src/agents/OperationTypes.js +310 -0
  20. package/src/agents/PerformanceMetricsCollector.js +493 -0
  21. package/src/agents/SecurityValidationService.js +534 -0
  22. package/src/agents/VerificationTest.js +354 -0
  23. package/src/agents/VerificationType.js +226 -0
  24. package/src/agents/WindowsPermissionHandler.js +518 -0
  25. package/src/agents/config/AgentConfigManager.js +393 -0
  26. package/src/agents/config/AgentDefaultsRegistry.js +373 -0
  27. package/src/agents/config/ConfigValidator.js +281 -0
  28. package/src/agents/discovery/AgentDiscoveryService.js +707 -0
  29. package/src/agents/logging/AgentLogger.js +511 -0
  30. package/src/agents/status/AgentStatusManager.js +481 -0
  31. package/src/agents/storage/FileManager.js +454 -0
  32. package/src/agents/verification/AgentCommunicationTester.js +474 -0
  33. package/src/agents/verification/BaseVerifier.js +430 -0
  34. package/src/agents/verification/CommandVerifier.js +480 -0
  35. package/src/agents/verification/FileOperationVerifier.js +453 -0
  36. package/src/agents/verification/ResultAnalyzer.js +707 -0
  37. package/src/agents/verification/TestRequirementManager.js +495 -0
  38. package/src/agents/verification/VerificationRunner.js +433 -0
  39. package/src/agents/windows/BaseWindowsInstaller.js +441 -0
  40. package/src/agents/windows/ChocolateyInstaller.js +509 -0
  41. package/src/agents/windows/DirectInstaller.js +443 -0
  42. package/src/agents/windows/InstallerFactory.js +391 -0
  43. package/src/agents/windows/NpmInstaller.js +505 -0
  44. package/src/agents/windows/PowerShellInstaller.js +458 -0
  45. package/src/agents/windows/WinGetInstaller.js +390 -0
  46. package/src/analysis/analysis-reporter.js +132 -0
  47. package/src/analysis/boundary-detector.js +712 -0
  48. package/src/analysis/categorizer.js +340 -0
  49. package/src/analysis/codebase-scanner.js +384 -0
  50. package/src/analysis/line-counter.js +513 -0
  51. package/src/analysis/priority-calculator.js +679 -0
  52. package/src/analysis/report/analysis-report.js +250 -0
  53. package/src/analysis/report/package-analyzer.js +278 -0
  54. package/src/analysis/report/recommendation-generator.js +382 -0
  55. package/src/analysis/report/statistics-generator.js +515 -0
  56. package/src/analysis/reports/analysis-report-model.js +101 -0
  57. package/src/analysis/reports/recommendation-generator.js +283 -0
  58. package/src/analysis/reports/report-generators.js +191 -0
  59. package/src/analysis/reports/statistics-calculator.js +231 -0
  60. package/src/analysis/reports/trend-analyzer.js +219 -0
  61. package/src/analysis/strategy-generator.js +814 -0
  62. package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
  63. package/src/config/refactoring-config.js +307 -0
  64. package/src/health-tracking/json-storage.js +38 -2
  65. package/src/ide-integration/applescript-manager-core.js +233 -0
  66. package/src/ide-integration/applescript-manager.cjs +357 -28
  67. package/src/ide-integration/applescript-manager.js +89 -3599
  68. package/src/ide-integration/cdp-manager.js +306 -0
  69. package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
  70. package/src/ide-integration/continuation-handler.js +337 -0
  71. package/src/ide-integration/ide-status-checker.js +292 -0
  72. package/src/ide-integration/macos-ide-manager.js +627 -0
  73. package/src/ide-integration/macos-text-sender.js +528 -0
  74. package/src/ide-integration/response-reader.js +548 -0
  75. package/src/ide-integration/windows-automation-manager.js +121 -0
  76. package/src/ide-integration/windows-ide-manager.js +373 -0
  77. package/src/index.cjs +25 -3
  78. package/src/index.js +15 -1
  79. package/src/llm/direct-llm-manager.cjs +90 -2
  80. package/src/models/compliance-report.js +538 -0
  81. package/src/models/file-analysis.js +681 -0
  82. package/src/models/refactoring-plan.js +770 -0
  83. package/src/monitoring/alert-system.js +834 -0
  84. package/src/monitoring/compliance-progress-tracker.js +437 -0
  85. package/src/monitoring/continuous-scan-notifications.js +661 -0
  86. package/src/monitoring/continuous-scanner.js +279 -0
  87. package/src/monitoring/file-monitor/file-analyzer.js +262 -0
  88. package/src/monitoring/file-monitor/file-monitor.js +237 -0
  89. package/src/monitoring/file-monitor/watcher.js +194 -0
  90. package/src/monitoring/file-monitor.js +17 -0
  91. package/src/monitoring/notification-manager.js +437 -0
  92. package/src/monitoring/scanner-core.js +368 -0
  93. package/src/monitoring/scanner-events.js +214 -0
  94. package/src/monitoring/violation-notification-system.js +515 -0
  95. package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
  96. package/src/refactoring/boundaries/extraction-result.js +285 -0
  97. package/src/refactoring/boundaries/extraction-strategies.js +392 -0
  98. package/src/refactoring/boundaries/module-boundary.js +209 -0
  99. package/src/refactoring/boundary/boundary-detector.js +741 -0
  100. package/src/refactoring/boundary/boundary-types.js +405 -0
  101. package/src/refactoring/boundary/extraction-strategies.js +554 -0
  102. package/src/refactoring/boundary-extraction-result.js +77 -0
  103. package/src/refactoring/boundary-extraction-strategies.js +330 -0
  104. package/src/refactoring/boundary-extractor.js +384 -0
  105. package/src/refactoring/boundary-types.js +46 -0
  106. package/src/refactoring/circular/circular-dependency.js +88 -0
  107. package/src/refactoring/circular/cycle-detection.js +147 -0
  108. package/src/refactoring/circular/dependency-node.js +82 -0
  109. package/src/refactoring/circular/dependency-result.js +107 -0
  110. package/src/refactoring/circular/dependency-types.js +58 -0
  111. package/src/refactoring/circular/graph-builder.js +213 -0
  112. package/src/refactoring/circular/resolution-strategy.js +72 -0
  113. package/src/refactoring/circular/strategy-generator.js +229 -0
  114. package/src/refactoring/circular-dependency-resolver-original.js +809 -0
  115. package/src/refactoring/circular-dependency-resolver.js +200 -0
  116. package/src/refactoring/code-mover.js +761 -0
  117. package/src/refactoring/file-splitter.js +696 -0
  118. package/src/refactoring/functionality-validator.js +816 -0
  119. package/src/refactoring/import-manager.js +774 -0
  120. package/src/refactoring/module-boundary.js +107 -0
  121. package/src/refactoring/refactoring-executor.js +672 -0
  122. package/src/refactoring/refactoring-rollback.js +614 -0
  123. package/src/refactoring/test-validator.js +631 -0
  124. package/src/requirement-management/default-requirement-manager.js +321 -0
  125. package/src/requirement-management/requirement-file-parser.js +159 -0
  126. package/src/requirement-management/requirement-sequencer.js +221 -0
  127. package/src/rui/commands/AgentCommandParser.js +600 -0
  128. package/src/rui/commands/AgentCommands.js +487 -0
  129. package/src/rui/commands/AgentResponseFormatter.js +832 -0
  130. package/src/scripts/verify-full-compliance.js +269 -0
  131. package/src/sync/sync-engine-core.js +1 -0
  132. package/src/sync/sync-engine-remote-handlers.js +135 -0
  133. package/src/task-generation/automated-task-generator.js +351 -0
  134. package/src/task-generation/prioritizer.js +287 -0
  135. package/src/task-generation/task-list-updater.js +215 -0
  136. package/src/task-generation/task-management-integration.js +480 -0
  137. package/src/task-generation/task-manager-integration.js +270 -0
  138. package/src/task-generation/violation-task-generator.js +474 -0
  139. package/src/task-management/continuous-scan-integration.js +342 -0
  140. package/src/timeout-management/index.js +12 -3
  141. package/src/timeout-management/response-time-tracker.js +167 -0
  142. package/src/timeout-management/timeout-calculator.js +159 -0
  143. package/src/timeout-management/timeout-config-manager.js +172 -0
  144. package/src/utils/ast-analyzer.js +417 -0
  145. package/src/utils/current-requirement-manager.js +276 -0
  146. package/src/utils/current-requirement-operations.js +472 -0
  147. package/src/utils/dependency-mapper.js +456 -0
  148. package/src/utils/download-with-progress.js +4 -2
  149. package/src/utils/electron-update-checker.js +4 -1
  150. package/src/utils/file-size-analyzer.js +272 -0
  151. package/src/utils/import-updater.js +280 -0
  152. package/src/utils/refactoring-tools.js +512 -0
  153. package/src/utils/report-generator.js +569 -0
  154. package/src/utils/reports/report-analysis.js +218 -0
  155. package/src/utils/reports/report-types.js +55 -0
  156. package/src/utils/reports/summary-generators.js +102 -0
  157. package/src/utils/requirement-file-management.js +157 -0
  158. package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
  159. package/src/utils/requirement-helpers/requirement-mover.js +414 -0
  160. package/src/utils/requirement-helpers/requirement-parser.js +326 -0
  161. package/src/utils/requirement-helpers/requirement-status.js +320 -0
  162. package/src/utils/requirement-helpers-new.js +55 -0
  163. package/src/utils/requirement-helpers-refactored.js +367 -0
  164. package/src/utils/requirement-helpers.js +291 -1191
  165. package/src/utils/requirement-movement-operations.js +450 -0
  166. package/src/utils/requirement-movement.js +312 -0
  167. package/src/utils/requirement-parsing-helpers.js +56 -0
  168. package/src/utils/requirement-statistics.js +200 -0
  169. package/src/utils/requirement-text-utils.js +58 -0
  170. package/src/utils/rollback/rollback-handlers.js +125 -0
  171. package/src/utils/rollback/rollback-operation.js +63 -0
  172. package/src/utils/rollback/rollback-recorder.js +166 -0
  173. package/src/utils/rollback/rollback-state-manager.js +175 -0
  174. package/src/utils/rollback/rollback-types.js +33 -0
  175. package/src/utils/rollback/rollback-utils.js +110 -0
  176. package/src/utils/rollback-manager-original.js +569 -0
  177. package/src/utils/rollback-manager.js +202 -0
  178. package/src/utils/smoke-test-cli.js +362 -0
  179. package/src/utils/smoke-test-gui.js +351 -0
  180. package/src/utils/smoke-test-orchestrator.js +321 -0
  181. package/src/utils/smoke-test-runner.js +60 -0
  182. package/src/utils/smoke-test-web.js +347 -0
  183. package/src/utils/specification-helpers.js +39 -13
  184. package/src/utils/specification-migration.js +97 -0
  185. package/src/utils/test-runner.js +579 -0
  186. package/src/utils/validation-framework.js +518 -0
  187. package/src/validation/compliance-analyzer.js +197 -0
  188. package/src/validation/compliance-report-generator.js +343 -0
  189. package/src/validation/compliance-reporter.js +711 -0
  190. package/src/validation/compliance-rules.js +127 -0
  191. package/src/validation/constitution-validator-new.js +196 -0
  192. package/src/validation/constitution-validator.js +17 -0
  193. package/src/validation/file-validators.js +170 -0
  194. package/src/validation/line-limit/file-analyzer.js +201 -0
  195. package/src/validation/line-limit/line-limit-validator.js +208 -0
  196. package/src/validation/line-limit/validation-result.js +144 -0
  197. package/src/validation/line-limit-core.js +225 -0
  198. package/src/validation/line-limit-reporter.js +134 -0
  199. package/src/validation/line-limit-result.js +125 -0
  200. package/src/validation/line-limit-validator.js +41 -0
  201. package/src/validation/metrics-calculator.js +660 -0
  202. package/src/sync/sync-engine-backup.js +0 -559
@@ -0,0 +1,579 @@
1
+ /**
2
+ * Test Runner Integration
3
+ *
4
+ * Integrates with existing test infrastructure to validate refactoring operations.
5
+ * Provides test execution, result analysis, and regression detection.
6
+ */
7
+
8
+ const { execSync, spawn } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ /**
13
+ * Test result types
14
+ */
15
+ const TEST_RESULT_TYPES = {
16
+ PASS: 'pass',
17
+ FAIL: 'fail',
18
+ SKIP: 'skip',
19
+ ERROR: 'error'
20
+ };
21
+
22
+ /**
23
+ * Test runner class
24
+ */
25
+ class TestRunner {
26
+ constructor(options = {}) {
27
+ this.options = {
28
+ testCommand: 'npm test',
29
+ testDir: 'tests',
30
+ timeout: 300000, // 5 minutes
31
+ retries: 0,
32
+ verbose: false,
33
+ ...options
34
+ };
35
+
36
+ this.baselineResults = null;
37
+ this.currentResults = null;
38
+ this.regressionDetected = false;
39
+ }
40
+
41
+ /**
42
+ * Run baseline tests before refactoring
43
+ */
44
+ async runBaseline() {
45
+ console.log('Running baseline tests...');
46
+
47
+ try {
48
+ const results = await this.executeTests();
49
+ this.baselineResults = results;
50
+
51
+ console.log(`Baseline completed: ${results.passed}/${results.total} passed`);
52
+ return results;
53
+ } catch (error) {
54
+ throw new Error(`Baseline test execution failed: ${error.message}`);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Run tests after refactoring
60
+ */
61
+ async runValidation() {
62
+ if (!this.baselineResults) {
63
+ throw new Error('Baseline results not available. Run baseline first.');
64
+ }
65
+
66
+ console.log('Running validation tests...');
67
+
68
+ try {
69
+ const results = await this.executeTests();
70
+ this.currentResults = results;
71
+
72
+ // Compare with baseline
73
+ const comparison = this.compareResults(this.baselineResults, results);
74
+ this.regressionDetected = comparison.hasRegressions;
75
+
76
+ console.log(`Validation completed: ${results.passed}/${results.total} passed`);
77
+
78
+ if (this.regressionDetected) {
79
+ console.log(`⚠️ Regressions detected: ${comparison.regressions.length}`);
80
+ }
81
+
82
+ return {
83
+ results,
84
+ comparison,
85
+ hasRegressions: this.regressionDetected
86
+ };
87
+ } catch (error) {
88
+ throw new Error(`Validation test execution failed: ${error.message}`);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Execute tests and collect results
94
+ */
95
+ async executeTests() {
96
+ return new Promise((resolve, reject) => {
97
+ const startTime = Date.now();
98
+ let output = '';
99
+ let errorOutput = '';
100
+
101
+ try {
102
+ // Use npm test with JSON reporter if available
103
+ const testProcess = spawn('npm', ['test', '--', '--json', '--verbose'], {
104
+ stdio: ['pipe', 'pipe', 'pipe'],
105
+ cwd: process.cwd()
106
+ });
107
+
108
+ testProcess.stdout.on('data', (data) => {
109
+ output += data.toString();
110
+ if (this.options.verbose) {
111
+ process.stdout.write(data);
112
+ }
113
+ });
114
+
115
+ testProcess.stderr.on('data', (data) => {
116
+ errorOutput += data.toString();
117
+ if (this.options.verbose) {
118
+ process.stderr.write(data);
119
+ }
120
+ });
121
+
122
+ testProcess.on('close', (code) => {
123
+ const duration = Date.now() - startTime;
124
+
125
+ try {
126
+ const results = this.parseTestOutput(output, errorOutput, code, duration);
127
+ resolve(results);
128
+ } catch (parseError) {
129
+ // Fallback to basic parsing
130
+ const fallbackResults = this.parseBasicOutput(output, errorOutput, code, duration);
131
+ resolve(fallbackResults);
132
+ }
133
+ });
134
+
135
+ testProcess.on('error', (error) => {
136
+ reject(new Error(`Test process failed: ${error.message}`));
137
+ });
138
+
139
+ // Set timeout
140
+ if (this.options.timeout) {
141
+ setTimeout(() => {
142
+ testProcess.kill('SIGKILL');
143
+ reject(new Error(`Test execution timed out after ${this.options.timeout}ms`));
144
+ }, this.options.timeout);
145
+ }
146
+
147
+ } catch (error) {
148
+ reject(new Error(`Failed to start test process: ${error.message}`));
149
+ }
150
+ });
151
+ }
152
+
153
+ /**
154
+ * Parse test output (Jest JSON format)
155
+ */
156
+ parseTestOutput(stdout, stderr, exitCode, duration) {
157
+ try {
158
+ // Try to parse JSON output
159
+ const jsonMatch = stdout.match(/\{[\s\S]*\}/);
160
+ if (jsonMatch) {
161
+ const jsonData = JSON.parse(jsonMatch[0]);
162
+ return this.parseJestResults(jsonData, duration);
163
+ }
164
+ } catch (error) {
165
+ // JSON parsing failed, fall back to basic parsing
166
+ }
167
+
168
+ return this.parseBasicOutput(stdout, stderr, exitCode, duration);
169
+ }
170
+
171
+ /**
172
+ * Parse Jest results
173
+ */
174
+ parseJestResults(jsonData, duration) {
175
+ const results = {
176
+ total: 0,
177
+ passed: 0,
178
+ failed: 0,
179
+ skipped: 0,
180
+ errors: 0,
181
+ duration,
182
+ suites: [],
183
+ tests: [],
184
+ coverage: null
185
+ };
186
+
187
+ if (jsonData.numTotalTests) {
188
+ results.total = jsonData.numTotalTests;
189
+ results.passed = jsonData.numPassedTests || 0;
190
+ results.failed = jsonData.numFailedTests || 0;
191
+ results.skipped = jsonData.numPendingTests || 0;
192
+ }
193
+
194
+ if (jsonData.testResults) {
195
+ for (const testSuite of jsonData.testResults) {
196
+ const suite = {
197
+ name: testSuite.name,
198
+ file: testSuite.testFilePath,
199
+ passed: 0,
200
+ failed: 0,
201
+ skipped: 0,
202
+ duration: testSuite.perfStats?.end || 0,
203
+ tests: []
204
+ };
205
+
206
+ if (testSuite.assertionResults) {
207
+ for (const test of testSuite.assertionResults) {
208
+ const testResult = {
209
+ title: test.title,
210
+ fullName: test.fullName,
211
+ status: test.status,
212
+ duration: test.duration || 0,
213
+ failureMessages: test.failureMessages || []
214
+ };
215
+
216
+ suite.tests.push(testResult);
217
+ results.tests.push(testResult);
218
+
219
+ switch (test.status) {
220
+ case 'passed':
221
+ suite.passed++;
222
+ break;
223
+ case 'failed':
224
+ suite.failed++;
225
+ break;
226
+ case 'pending':
227
+ suite.skipped++;
228
+ break;
229
+ }
230
+ }
231
+ }
232
+
233
+ results.suites.push(suite);
234
+ }
235
+ }
236
+
237
+ if (jsonData.coverageMap) {
238
+ results.coverage = this.parseCoverageData(jsonData.coverageMap);
239
+ }
240
+
241
+ return results;
242
+ }
243
+
244
+ /**
245
+ * Parse basic test output
246
+ */
247
+ parseBasicOutput(stdout, stderr, exitCode, duration) {
248
+ const results = {
249
+ total: 0,
250
+ passed: 0,
251
+ failed: 0,
252
+ skipped: 0,
253
+ errors: 0,
254
+ duration,
255
+ suites: [],
256
+ tests: [],
257
+ coverage: null
258
+ };
259
+
260
+ // Parse Jest-style output
261
+ const testMatch = stdout.match(/(\d+)\s+tests?\s+(\d+)\s+failed/);
262
+ if (testMatch) {
263
+ results.total = parseInt(testMatch[1]);
264
+ results.failed = parseInt(testMatch[2]);
265
+ results.passed = results.total - results.failed;
266
+ }
267
+
268
+ // Parse pass/fail summary
269
+ const passMatch = stdout.match(/(\d+)\s+passing/);
270
+ if (passMatch) {
271
+ results.passed = parseInt(passMatch[1]);
272
+ }
273
+
274
+ const failMatch = stdout.match(/(\d+)\s+failing/);
275
+ if (failMatch) {
276
+ results.failed = parseInt(failMatch[1]);
277
+ }
278
+
279
+ const skipMatch = stdout.match(/(\d+)\s+skipping/);
280
+ if (skipMatch) {
281
+ results.skipped = parseInt(skipMatch[1]);
282
+ }
283
+
284
+ // Extract individual test results
285
+ const testLines = stdout.split('\n');
286
+ for (const line of testLines) {
287
+ const testMatch = line.match(/^(✓|✗|○)\s+(.+)$/);
288
+ if (testMatch) {
289
+ const status = testMatch[1] === '✓' ? 'passed' :
290
+ testMatch[1] === '✗' ? 'failed' : 'skipped';
291
+ const title = testMatch[2];
292
+
293
+ results.tests.push({
294
+ title,
295
+ status,
296
+ duration: 0,
297
+ failureMessages: status === 'failed' ? [line] : []
298
+ });
299
+ }
300
+ }
301
+
302
+ return results;
303
+ }
304
+
305
+ /**
306
+ * Parse coverage data
307
+ */
308
+ parseCoverageData(coverageMap) {
309
+ const coverage = {
310
+ lines: { total: 0, covered: 0, percentage: 0 },
311
+ functions: { total: 0, covered: 0, percentage: 0 },
312
+ branches: { total: 0, covered: 0, percentage: 0 },
313
+ statements: { total: 0, covered: 0, percentage: 0 }
314
+ };
315
+
316
+ for (const [filePath, fileCoverage] of Object.entries(coverageMap)) {
317
+ // Parse line coverage
318
+ if (fileCoverage.l) {
319
+ const lines = Object.values(fileCoverage.l);
320
+ coverage.lines.total += lines.length;
321
+ coverage.lines.covered += lines.filter(count => count > 0).length;
322
+ }
323
+
324
+ // Parse function coverage
325
+ if (fileCoverage.f) {
326
+ const functions = Object.values(fileCoverage.f);
327
+ coverage.functions.total += functions.length;
328
+ coverage.functions.covered += functions.filter(count => count > 0).length;
329
+ }
330
+
331
+ // Parse branch coverage
332
+ if (fileCoverage.b) {
333
+ for (const branches of Object.values(fileCoverage.b)) {
334
+ coverage.branches.total += branches.length;
335
+ coverage.branches.covered += branches.filter(count => count > 0).length;
336
+ }
337
+ }
338
+
339
+ // Parse statement coverage
340
+ if (fileCoverage.s) {
341
+ const statements = Object.values(fileCoverage.s);
342
+ coverage.statements.total += statements.length;
343
+ coverage.statements.covered += statements.filter(count => count > 0).length;
344
+ }
345
+ }
346
+
347
+ // Calculate percentages
348
+ for (const metric of Object.values(coverage)) {
349
+ metric.percentage = metric.total > 0 ?
350
+ Math.round((metric.covered / metric.total) * 100) : 0;
351
+ }
352
+
353
+ return coverage;
354
+ }
355
+
356
+ /**
357
+ * Compare baseline and current results
358
+ */
359
+ compareResults(baseline, current) {
360
+ const comparison = {
361
+ hasRegressions: false,
362
+ regressions: [],
363
+ improvements: [],
364
+ unchanged: [],
365
+ summary: {
366
+ baseline: {
367
+ total: baseline.total,
368
+ passed: baseline.passed,
369
+ failed: baseline.failed,
370
+ duration: baseline.duration
371
+ },
372
+ current: {
373
+ total: current.total,
374
+ passed: current.passed,
375
+ failed: current.failed,
376
+ duration: current.duration
377
+ }
378
+ }
379
+ };
380
+
381
+ // Check for test count changes
382
+ if (current.total < baseline.total) {
383
+ comparison.regressions.push({
384
+ type: 'missing_tests',
385
+ message: `${baseline.total - current.total} tests are missing`,
386
+ severity: 'high'
387
+ });
388
+ comparison.hasRegressions = true;
389
+ }
390
+
391
+ if (current.total > baseline.total) {
392
+ comparison.improvements.push({
393
+ type: 'new_tests',
394
+ message: `${current.total - baseline.total} new tests added`,
395
+ severity: 'info'
396
+ });
397
+ }
398
+
399
+ // Check for test failures
400
+ if (current.failed > baseline.failed) {
401
+ comparison.regressions.push({
402
+ type: 'new_failures',
403
+ message: `${current.failed - baseline.failed} new test failures`,
404
+ severity: 'high'
405
+ });
406
+ comparison.hasRegressions = true;
407
+ }
408
+
409
+ if (current.failed < baseline.failed) {
410
+ comparison.improvements.push({
411
+ type: 'fixed_failures',
412
+ message: `${baseline.failed - current.failed} test failures fixed`,
413
+ severity: 'good'
414
+ });
415
+ }
416
+
417
+ // Check for performance regression
418
+ const performanceIncrease = current.duration - baseline.duration;
419
+ const performancePercent = (performanceIncrease / baseline.duration) * 100;
420
+
421
+ if (performanceIncrease > 5000 && performancePercent > 10) { // 5s and 10%
422
+ comparison.regressions.push({
423
+ type: 'performance',
424
+ message: `Test execution increased by ${Math.round(performancePercent)}% (${Math.round(performanceIncrease/1000)}s)`,
425
+ severity: 'medium'
426
+ });
427
+ comparison.hasRegressions = true;
428
+ }
429
+
430
+ // Compare individual test results
431
+ const baselineTests = new Map();
432
+ for (const test of baseline.tests) {
433
+ baselineTests.set(test.fullName, test);
434
+ }
435
+
436
+ for (const test of current.tests) {
437
+ const baselineTest = baselineTests.get(test.fullName);
438
+
439
+ if (!baselineTest) {
440
+ comparison.improvements.push({
441
+ type: 'new_test',
442
+ message: `New test: ${test.title}`,
443
+ severity: 'info'
444
+ });
445
+ } else if (baselineTest.status === 'passed' && test.status === 'failed') {
446
+ comparison.regressions.push({
447
+ type: 'test_regression',
448
+ message: `Test now failing: ${test.title}`,
449
+ severity: 'high',
450
+ test: test
451
+ });
452
+ comparison.hasRegressions = true;
453
+ } else if (baselineTest.status === 'failed' && test.status === 'passed') {
454
+ comparison.improvements.push({
455
+ type: 'test_fixed',
456
+ message: `Test now passing: ${test.title}`,
457
+ severity: 'good'
458
+ });
459
+ }
460
+ }
461
+
462
+ return comparison;
463
+ }
464
+
465
+ /**
466
+ * Run specific test files
467
+ */
468
+ async runSpecificTests(testFiles) {
469
+ console.log(`Running ${testFiles.length} specific tests...`);
470
+
471
+ const testArgs = ['test', '--', ...testFiles];
472
+
473
+ return new Promise((resolve, reject) => {
474
+ const startTime = Date.now();
475
+ let output = '';
476
+ let errorOutput = '';
477
+
478
+ const testProcess = spawn('npm', testArgs, {
479
+ stdio: ['pipe', 'pipe', 'pipe'],
480
+ cwd: process.cwd()
481
+ });
482
+
483
+ testProcess.stdout.on('data', (data) => {
484
+ output += data.toString();
485
+ if (this.options.verbose) {
486
+ process.stdout.write(data);
487
+ }
488
+ });
489
+
490
+ testProcess.stderr.on('data', (data) => {
491
+ errorOutput += data.toString();
492
+ if (this.options.verbose) {
493
+ process.stderr.write(data);
494
+ }
495
+ });
496
+
497
+ testProcess.on('close', (code) => {
498
+ const duration = Date.now() - startTime;
499
+ const results = this.parseBasicOutput(output, errorOutput, code, duration);
500
+ resolve(results);
501
+ });
502
+
503
+ testProcess.on('error', (error) => {
504
+ reject(new Error(`Test process failed: ${error.message}`));
505
+ });
506
+ });
507
+ }
508
+
509
+ /**
510
+ * Check if tests are available
511
+ */
512
+ checkTestAvailability() {
513
+ const testPaths = [
514
+ 'package.json',
515
+ 'tests',
516
+ '__tests__',
517
+ 'test',
518
+ 'spec'
519
+ ];
520
+
521
+ for (const testPath of testPaths) {
522
+ if (fs.existsSync(testPath)) {
523
+ return true;
524
+ }
525
+ }
526
+
527
+ return false;
528
+ }
529
+
530
+ /**
531
+ * Get test configuration
532
+ */
533
+ getTestConfig() {
534
+ try {
535
+ const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
536
+ return {
537
+ hasTestScript: !!packageJson.scripts?.test,
538
+ testScript: packageJson.scripts?.test,
539
+ jestConfig: packageJson.jest,
540
+ dependencies: {
541
+ jest: packageJson.dependencies?.jest || packageJson.devDependencies?.jest,
542
+ mocha: packageJson.dependencies?.mocha || packageJson.devDependencies?.mocha,
543
+ jasmine: packageJson.dependencies?.jasmine || packageJson.devDependencies?.jasmine
544
+ }
545
+ };
546
+ } catch (error) {
547
+ return { hasTestScript: false };
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Generate test report
553
+ */
554
+ generateReport() {
555
+ if (!this.currentResults) {
556
+ throw new Error('No test results available. Run tests first.');
557
+ }
558
+
559
+ const report = {
560
+ timestamp: new Date().toISOString(),
561
+ baseline: this.baselineResults,
562
+ current: this.currentResults,
563
+ comparison: this.compareResults(this.baselineResults, this.currentResults),
564
+ config: this.getTestConfig(),
565
+ summary: {
566
+ hasRegressions: this.regressionDetected,
567
+ testCountChanged: this.baselineResults.total !== this.currentResults.total,
568
+ performanceChanged: Math.abs(this.currentResults.duration - this.baselineResults.duration) > 1000
569
+ }
570
+ };
571
+
572
+ return report;
573
+ }
574
+ }
575
+
576
+ module.exports = {
577
+ TestRunner,
578
+ TEST_RESULT_TYPES
579
+ };