@silasfmartins/testhub 1.0.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 (296) hide show
  1. package/.github/copilot-instructions.md +520 -0
  2. package/biome.json +37 -0
  3. package/dist/index.d.ts +45 -0
  4. package/dist/index.js +169 -0
  5. package/dist/scripts/consumer-postinstall.d.ts +15 -0
  6. package/dist/scripts/consumer-postinstall.js +785 -0
  7. package/dist/scripts/generate-docs.d.ts +16 -0
  8. package/dist/scripts/generate-docs.js +1363 -0
  9. package/dist/scripts/generate-index.d.ts +2 -0
  10. package/dist/scripts/generate-index.js +314 -0
  11. package/dist/scripts/init-api.d.ts +2 -0
  12. package/dist/scripts/init-api.js +525 -0
  13. package/dist/scripts/init-banco.d.ts +2 -0
  14. package/dist/scripts/init-banco.js +347 -0
  15. package/dist/scripts/init-frontend.d.ts +2 -0
  16. package/dist/scripts/init-frontend.js +627 -0
  17. package/dist/scripts/init-mobile.d.ts +2 -0
  18. package/dist/scripts/init-mobile.js +481 -0
  19. package/dist/scripts/init-scenarios.d.ts +2 -0
  20. package/dist/scripts/init-scenarios.js +846 -0
  21. package/dist/scripts/init-ssh.d.ts +2 -0
  22. package/dist/scripts/init-ssh.js +639 -0
  23. package/dist/scripts/package-versions.d.ts +57 -0
  24. package/dist/scripts/package-versions.js +768 -0
  25. package/dist/scripts/postinstall.d.ts +1 -0
  26. package/dist/scripts/postinstall.js +527 -0
  27. package/dist/scripts/robust-build.d.ts +7 -0
  28. package/dist/scripts/robust-build.js +88 -0
  29. package/dist/scripts/setup-local-packages.d.ts +31 -0
  30. package/dist/scripts/setup-local-packages.js +237 -0
  31. package/dist/scripts/smart-override.d.ts +2 -0
  32. package/dist/scripts/smart-override.js +1360 -0
  33. package/dist/scripts/sync-configs.d.ts +27 -0
  34. package/dist/scripts/sync-configs.js +248 -0
  35. package/dist/scripts/test-biome-parse.d.ts +5 -0
  36. package/dist/scripts/test-biome-parse.js +84 -0
  37. package/dist/scripts/ultracite-setup.d.ts +4 -0
  38. package/dist/scripts/ultracite-setup.js +310 -0
  39. package/dist/scripts/update-all-init-scripts.d.ts +2 -0
  40. package/dist/scripts/update-all-init-scripts.js +52 -0
  41. package/dist/scripts/update-biome-schema.d.ts +15 -0
  42. package/dist/scripts/update-biome-schema.js +124 -0
  43. package/dist/src/AutoCoreFacade.d.ts +145 -0
  44. package/dist/src/AutoCoreFacade.js +217 -0
  45. package/dist/src/api/ApiActions.d.ts +297 -0
  46. package/dist/src/api/ApiActions.js +1905 -0
  47. package/dist/src/api/Certificate.d.ts +60 -0
  48. package/dist/src/api/Certificate.js +79 -0
  49. package/dist/src/api/JsonResponse.d.ts +116 -0
  50. package/dist/src/api/JsonResponse.js +206 -0
  51. package/dist/src/appium/DeviceFarmViewer.d.ts +79 -0
  52. package/dist/src/appium/DeviceFarmViewer.js +1083 -0
  53. package/dist/src/appium/MobileActions.d.ts +347 -0
  54. package/dist/src/appium/MobileActions.js +1632 -0
  55. package/dist/src/appium/MobileConnection.d.ts +160 -0
  56. package/dist/src/appium/MobileConnection.js +772 -0
  57. package/dist/src/config/envLoader.d.ts +123 -0
  58. package/dist/src/config/envLoader.js +361 -0
  59. package/dist/src/config/jest-safe-setup.d.ts +19 -0
  60. package/dist/src/config/jest-safe-setup.js +369 -0
  61. package/dist/src/config/timeouts.d.ts +32 -0
  62. package/dist/src/config/timeouts.js +38 -0
  63. package/dist/src/desktop/DesktopActions.d.ts +46 -0
  64. package/dist/src/desktop/DesktopActions.js +398 -0
  65. package/dist/src/desktop/DesktopConnection.d.ts +32 -0
  66. package/dist/src/desktop/DesktopConnection.js +84 -0
  67. package/dist/src/domain/entities/TestExecution.d.ts +117 -0
  68. package/dist/src/domain/entities/TestExecution.js +150 -0
  69. package/dist/src/domain/entities/TestReport.d.ts +114 -0
  70. package/dist/src/domain/entities/TestReport.js +179 -0
  71. package/dist/src/domain/repositories/ITestRepository.d.ts +196 -0
  72. package/dist/src/domain/repositories/ITestRepository.js +14 -0
  73. package/dist/src/domain/schemas/ValidationSchemas.d.ts +159 -0
  74. package/dist/src/domain/schemas/ValidationSchemas.js +181 -0
  75. package/dist/src/functions/errors/BaseError.d.ts +78 -0
  76. package/dist/src/functions/errors/BaseError.js +245 -0
  77. package/dist/src/functions/errors/ConfigurationError.d.ts +16 -0
  78. package/dist/src/functions/errors/ConfigurationError.js +48 -0
  79. package/dist/src/functions/errors/ErrorCatalog.d.ts +148 -0
  80. package/dist/src/functions/errors/ErrorCatalog.js +157 -0
  81. package/dist/src/functions/errors/GlobalErrorHandler.d.ts +101 -0
  82. package/dist/src/functions/errors/GlobalErrorHandler.js +281 -0
  83. package/dist/src/functions/errors/IntegrationError.d.ts +17 -0
  84. package/dist/src/functions/errors/IntegrationError.js +51 -0
  85. package/dist/src/functions/errors/SecurityError.d.ts +14 -0
  86. package/dist/src/functions/errors/SecurityError.js +42 -0
  87. package/dist/src/functions/errors/SystemError.d.ts +12 -0
  88. package/dist/src/functions/errors/SystemError.js +36 -0
  89. package/dist/src/functions/errors/ValidationError.d.ts +14 -0
  90. package/dist/src/functions/errors/ValidationError.js +61 -0
  91. package/dist/src/functions/errors/index.d.ts +12 -0
  92. package/dist/src/functions/errors/index.js +13 -0
  93. package/dist/src/global-setup.d.ts +1 -0
  94. package/dist/src/global-setup.js +1037 -0
  95. package/dist/src/helpers/BancoActions.d.ts +188 -0
  96. package/dist/src/helpers/BancoActions.js +581 -0
  97. package/dist/src/helpers/EnviromentHelper.d.ts +17 -0
  98. package/dist/src/helpers/EnviromentHelper.js +66 -0
  99. package/dist/src/helpers/ParallelExecutionHelper.d.ts +183 -0
  100. package/dist/src/helpers/ParallelExecutionHelper.js +375 -0
  101. package/dist/src/helpers/SyncSignal.d.ts +15 -0
  102. package/dist/src/helpers/SyncSignal.js +44 -0
  103. package/dist/src/hubdocs/CategoryDetector.d.ts +83 -0
  104. package/dist/src/hubdocs/CategoryDetector.js +401 -0
  105. package/dist/src/hubdocs/DirectStatementInterceptor.d.ts +54 -0
  106. package/dist/src/hubdocs/DirectStatementInterceptor.js +243 -0
  107. package/dist/src/hubdocs/ExecutionTracker.d.ts +107 -0
  108. package/dist/src/hubdocs/ExecutionTracker.js +702 -0
  109. package/dist/src/hubdocs/HubDocs.d.ts +395 -0
  110. package/dist/src/hubdocs/HubDocs.js +3586 -0
  111. package/dist/src/hubdocs/StatementMethodFilter.d.ts +71 -0
  112. package/dist/src/hubdocs/StatementMethodFilter.js +618 -0
  113. package/dist/src/hubdocs/StatementTracker.d.ts +417 -0
  114. package/dist/src/hubdocs/StatementTracker.js +2419 -0
  115. package/dist/src/hubdocs/SwaggerGenerator.d.ts +59 -0
  116. package/dist/src/hubdocs/SwaggerGenerator.js +405 -0
  117. package/dist/src/hubdocs/index.d.ts +9 -0
  118. package/dist/src/hubdocs/index.js +9 -0
  119. package/dist/src/hubdocs/types.d.ts +114 -0
  120. package/dist/src/hubdocs/types.js +5 -0
  121. package/dist/src/infrastructure/DependencyContainer.d.ts +142 -0
  122. package/dist/src/infrastructure/DependencyContainer.js +250 -0
  123. package/dist/src/infrastructure/adapters/AppiumAdapter.d.ts +168 -0
  124. package/dist/src/infrastructure/adapters/AppiumAdapter.js +468 -0
  125. package/dist/src/infrastructure/adapters/OracleAdapter.d.ts +150 -0
  126. package/dist/src/infrastructure/adapters/OracleAdapter.js +388 -0
  127. package/dist/src/infrastructure/adapters/PlaywrightAdapter.d.ts +192 -0
  128. package/dist/src/infrastructure/adapters/PlaywrightAdapter.js +382 -0
  129. package/dist/src/infrastructure/adapters/SSHAdapter.d.ts +141 -0
  130. package/dist/src/infrastructure/adapters/SSHAdapter.js +428 -0
  131. package/dist/src/interfaces.d.ts +501 -0
  132. package/dist/src/interfaces.js +25 -0
  133. package/dist/src/internal/fakes/__fake-actions__.d.ts +17 -0
  134. package/dist/src/internal/fakes/__fake-actions__.js +21 -0
  135. package/dist/src/internal/fakes/__forbidden__.d.ts +10 -0
  136. package/dist/src/internal/fakes/__forbidden__.js +18 -0
  137. package/dist/src/internal/fakes/__honeypot__.d.ts +15 -0
  138. package/dist/src/internal/fakes/__honeypot__.js +24 -0
  139. package/dist/src/octane/OctaneReporter.d.ts +13 -0
  140. package/dist/src/octane/OctaneReporter.js +61 -0
  141. package/dist/src/playwright/CryptoActions.d.ts +20 -0
  142. package/dist/src/playwright/CryptoActions.js +75 -0
  143. package/dist/src/playwright/EnhancedWebActions.d.ts +7 -0
  144. package/dist/src/playwright/EnhancedWebActions.js +65 -0
  145. package/dist/src/playwright/WebActions.d.ts +1599 -0
  146. package/dist/src/playwright/WebActions.js +11788 -0
  147. package/dist/src/playwright/actions/ActionTimeline.d.ts +36 -0
  148. package/dist/src/playwright/actions/ActionTimeline.js +101 -0
  149. package/dist/src/playwright/actions/RecoveryQueue.d.ts +82 -0
  150. package/dist/src/playwright/actions/RecoveryQueue.js +130 -0
  151. package/dist/src/playwright/actions/SelectorCache.d.ts +53 -0
  152. package/dist/src/playwright/actions/SelectorCache.js +96 -0
  153. package/dist/src/playwright/actions/index.d.ts +13 -0
  154. package/dist/src/playwright/actions/index.js +14 -0
  155. package/dist/src/playwright/actions/types.d.ts +147 -0
  156. package/dist/src/playwright/actions/types.js +5 -0
  157. package/dist/src/playwright/fixtures.d.ts +112 -0
  158. package/dist/src/playwright/fixtures.js +718 -0
  159. package/dist/src/playwright/network-logs-reporter.d.ts +7 -0
  160. package/dist/src/playwright/network-logs-reporter.js +66 -0
  161. package/dist/src/playwright/registerRecoveryWrappers.d.ts +1 -0
  162. package/dist/src/playwright/registerRecoveryWrappers.js +54 -0
  163. package/dist/src/security/BuildSecurity.d.ts +12 -0
  164. package/dist/src/security/BuildSecurity.js +138 -0
  165. package/dist/src/security/EulaProtection.d.ts +70 -0
  166. package/dist/src/security/EulaProtection.js +155 -0
  167. package/dist/src/security/HoneypotManager.d.ts +46 -0
  168. package/dist/src/security/HoneypotManager.js +234 -0
  169. package/dist/src/security/KeysManager.d.ts +36 -0
  170. package/dist/src/security/KeysManager.js +158 -0
  171. package/dist/src/security/ProofOfWorkIntegration.d.ts +64 -0
  172. package/dist/src/security/ProofOfWorkIntegration.js +206 -0
  173. package/dist/src/security/SecurityValidation.d.ts +21 -0
  174. package/dist/src/security/SecurityValidation.js +163 -0
  175. package/dist/src/security/SourceMapProtection.d.ts +55 -0
  176. package/dist/src/security/SourceMapProtection.js +220 -0
  177. package/dist/src/security/protector.d.ts +1 -0
  178. package/dist/src/security/protector.js +97 -0
  179. package/dist/src/ssh/SSHActions.d.ts +262 -0
  180. package/dist/src/ssh/SSHActions.js +790 -0
  181. package/dist/src/ssh/SSHClient.d.ts +99 -0
  182. package/dist/src/ssh/SSHClient.js +409 -0
  183. package/dist/src/statements/BaseStatement.d.ts +38 -0
  184. package/dist/src/statements/BaseStatement.js +78 -0
  185. package/dist/src/testContext/AuthStateManager.d.ts +93 -0
  186. package/dist/src/testContext/AuthStateManager.js +256 -0
  187. package/dist/src/testContext/CoverageManager.d.ts +198 -0
  188. package/dist/src/testContext/CoverageManager.js +917 -0
  189. package/dist/src/testContext/TestAnnotations.d.ts +476 -0
  190. package/dist/src/testContext/TestAnnotations.js +2647 -0
  191. package/dist/src/testContext/TestContext.d.ts +138 -0
  192. package/dist/src/testContext/TestContext.js +369 -0
  193. package/dist/src/testContext/UnifiedHtmlGenerator.d.ts +7 -0
  194. package/dist/src/testContext/UnifiedHtmlGenerator.js +264 -0
  195. package/dist/src/testContext/UnifiedReportManager.d.ts +211 -0
  196. package/dist/src/testContext/UnifiedReportManager.js +1206 -0
  197. package/dist/src/testhub/DynamicConfigManager.d.ts +121 -0
  198. package/dist/src/testhub/DynamicConfigManager.js +320 -0
  199. package/dist/src/testhub/SystemsManager.d.ts +119 -0
  200. package/dist/src/testhub/SystemsManager.js +365 -0
  201. package/dist/src/testhub/TestHubClient.d.ts +335 -0
  202. package/dist/src/testhub/TestHubClient.js +1215 -0
  203. package/dist/src/testhub/TestHubReporter.d.ts +62 -0
  204. package/dist/src/testhub/TestHubReporter.js +576 -0
  205. package/dist/src/testhub/TestHubVars.d.ts +116 -0
  206. package/dist/src/testhub/TestHubVars.js +273 -0
  207. package/dist/src/utils/ActionInterceptor.d.ts +59 -0
  208. package/dist/src/utils/ActionInterceptor.js +741 -0
  209. package/dist/src/utils/ArtifactsCompressor.d.ts +43 -0
  210. package/dist/src/utils/ArtifactsCompressor.js +181 -0
  211. package/dist/src/utils/AutoLogsFinal.d.ts +47 -0
  212. package/dist/src/utils/AutoLogsFinal.js +148 -0
  213. package/dist/src/utils/CodeGenSession.d.ts +114 -0
  214. package/dist/src/utils/CodeGenSession.js +264 -0
  215. package/dist/src/utils/ConfigLogger.d.ts +133 -0
  216. package/dist/src/utils/ConfigLogger.js +611 -0
  217. package/dist/src/utils/CustomReporter.d.ts +22 -0
  218. package/dist/src/utils/CustomReporter.js +352 -0
  219. package/dist/src/utils/DataStore.d.ts +171 -0
  220. package/dist/src/utils/DataStore.js +484 -0
  221. package/dist/src/utils/DatabaseInterceptor.d.ts +19 -0
  222. package/dist/src/utils/DatabaseInterceptor.js +295 -0
  223. package/dist/src/utils/DateHelper.d.ts +16 -0
  224. package/dist/src/utils/DateHelper.js +120 -0
  225. package/dist/src/utils/DateValidator.d.ts +4 -0
  226. package/dist/src/utils/DateValidator.js +51 -0
  227. package/dist/src/utils/DocumentGenerator.d.ts +35 -0
  228. package/dist/src/utils/DocumentGenerator.js +129 -0
  229. package/dist/src/utils/EvidenceCapture.d.ts +90 -0
  230. package/dist/src/utils/EvidenceCapture.js +600 -0
  231. package/dist/src/utils/EvidenceReportGenerator.d.ts +70 -0
  232. package/dist/src/utils/EvidenceReportGenerator.js +799 -0
  233. package/dist/src/utils/FrameManagementUtil.d.ts +42 -0
  234. package/dist/src/utils/FrameManagementUtil.js +75 -0
  235. package/dist/src/utils/GlobalStatementsInterceptor.d.ts +1 -0
  236. package/dist/src/utils/GlobalStatementsInterceptor.js +1 -0
  237. package/dist/src/utils/HTMLTemplate.d.ts +1 -0
  238. package/dist/src/utils/HTMLTemplate.js +1034 -0
  239. package/dist/src/utils/InterceptacaoMagica.d.ts +23 -0
  240. package/dist/src/utils/InterceptacaoMagica.js +365 -0
  241. package/dist/src/utils/LogSanitizer.d.ts +35 -0
  242. package/dist/src/utils/LogSanitizer.js +110 -0
  243. package/dist/src/utils/Logger.d.ts +65 -0
  244. package/dist/src/utils/Logger.js +284 -0
  245. package/dist/src/utils/McpLocalClient.d.ts +141 -0
  246. package/dist/src/utils/McpLocalClient.js +871 -0
  247. package/dist/src/utils/PDFEvidenceGenerator.d.ts +20 -0
  248. package/dist/src/utils/PDFEvidenceGenerator.js +156 -0
  249. package/dist/src/utils/SpecFileAnalyzer.d.ts +35 -0
  250. package/dist/src/utils/SpecFileAnalyzer.js +209 -0
  251. package/dist/src/utils/StatementInterceptor.d.ts +18 -0
  252. package/dist/src/utils/StatementInterceptor.js +87 -0
  253. package/dist/src/utils/StatementLogger.d.ts +33 -0
  254. package/dist/src/utils/StatementLogger.js +113 -0
  255. package/dist/src/utils/StatementsInterceptor.d.ts +1 -0
  256. package/dist/src/utils/StatementsInterceptor.js +1 -0
  257. package/dist/src/utils/TeamsFlushHook.d.ts +17 -0
  258. package/dist/src/utils/TeamsFlushHook.js +168 -0
  259. package/dist/src/utils/TerminalLogCapture.d.ts +158 -0
  260. package/dist/src/utils/TerminalLogCapture.js +531 -0
  261. package/dist/src/utils/TestMethodLogger.d.ts +70 -0
  262. package/dist/src/utils/TestMethodLogger.js +95 -0
  263. package/dist/src/utils/UnifiedTeardown.d.ts +4 -0
  264. package/dist/src/utils/UnifiedTeardown.js +400 -0
  265. package/dist/src/utils/XPathCatalog.d.ts +152 -0
  266. package/dist/src/utils/XPathCatalog.js +350 -0
  267. package/dist/src/utils/generators.d.ts +90 -0
  268. package/dist/src/utils/generators.js +167 -0
  269. package/dist/src/utils/testRecovery/ResilientPlaywright.d.ts +152 -0
  270. package/dist/src/utils/testRecovery/ResilientPlaywright.js +715 -0
  271. package/dist/src/utils/testRecovery/TestRecoveryClient.d.ts +801 -0
  272. package/dist/src/utils/testRecovery/TestRecoveryClient.js +1415 -0
  273. package/dist/src/utils/testRecovery/autoFixCode.d.ts +65 -0
  274. package/dist/src/utils/testRecovery/autoFixCode.js +32 -0
  275. package/dist/vitest.config.d.ts +2 -0
  276. package/dist/vitest.config.js +59 -0
  277. package/dist/wdio.conf.d.ts +1 -0
  278. package/dist/wdio.conf.js +420 -0
  279. package/package.json +137 -0
  280. package/protect-loader.mjs +643 -0
  281. package/scripts/consumer-postinstall.ts +975 -0
  282. package/scripts/generate-index.ts +343 -0
  283. package/scripts/init-api.ts +613 -0
  284. package/scripts/init-banco.ts +437 -0
  285. package/scripts/init-frontend.ts +727 -0
  286. package/scripts/init-mobile.ts +558 -0
  287. package/scripts/init-scenarios.ts +925 -0
  288. package/scripts/init-ssh.ts +734 -0
  289. package/scripts/package-versions.ts +978 -0
  290. package/scripts/postinstall.ts +605 -0
  291. package/scripts/smart-override.ts +1675 -0
  292. package/scripts/sync-configs.ts +302 -0
  293. package/scripts/ultracite-setup.ts +370 -0
  294. package/src/types/globals.d.ts +48 -0
  295. package/tsconfig.json +29 -0
  296. package/types/autocore-sync-signal.d.ts +10 -0
@@ -0,0 +1,1206 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { StatementTracker } from '../hubdocs/StatementTracker.js';
4
+ import { Logger } from '../utils/Logger.js';
5
+ import { TestAnnotations } from './TestAnnotations.js';
6
+ import { TestContext } from './TestContext.js';
7
+ import { UnifiedHtmlGenerator } from './UnifiedHtmlGenerator.js';
8
+ import { HTMLTemplate } from '../utils/HTMLTemplate.js';
9
+ // 🔗 Import dinâmico do StatementTracker para evitar dependência circular
10
+ const getStatementTrackerData = async () => {
11
+ try {
12
+ return StatementTracker.getReportData();
13
+ }
14
+ catch (error) {
15
+ return null;
16
+ }
17
+ };
18
+ /**
19
+ * Gerenciador unificado de relatórios para todos os tipos de teste
20
+ */
21
+ export class UnifiedReportManager {
22
+ static inicioExecucao;
23
+ static fimExecucao;
24
+ static testes = [];
25
+ static contextoPorTeste = new Map();
26
+ static logsPorTeste = new Map();
27
+ static metadataPorTeste = new Map();
28
+ static duracoesPorTeste = new Map();
29
+ static ctToCnMap = new Map();
30
+ /**
31
+ * ✅ Dados globais estruturados
32
+ */
33
+ static dadosGlobais = {
34
+ totalTestes: 0,
35
+ testesPassados: 0,
36
+ testesFalharam: 0,
37
+ testes: {},
38
+ };
39
+ /**
40
+ * ✅ NOVO: Sistema de detecção automática
41
+ */
42
+ static autoDetectionActive = false;
43
+ static currentTestName = null;
44
+ static testStartTime = null;
45
+ static monitoringInterval = null;
46
+ /**
47
+ * Registra relacionamento entre CT (test.title) e CN (test.describe)
48
+ */
49
+ static registrarCtParaCn(ctName, cnName) {
50
+ if (!ctName || !cnName)
51
+ return;
52
+ UnifiedReportManager.ctToCnMap.set(ctName, cnName);
53
+ }
54
+ static obterCnRegistrado(ctName) {
55
+ if (!ctName)
56
+ return undefined;
57
+ return UnifiedReportManager.ctToCnMap.get(ctName);
58
+ }
59
+ static limparRegistroCt(ctName) {
60
+ if (!ctName)
61
+ return;
62
+ UnifiedReportManager.ctToCnMap.delete(ctName);
63
+ }
64
+ /**
65
+ * ❌ DESABILITADO: Auto-inicialização que causava registro duplicado
66
+ * O registro correto já é feito via TestAnnotations.Api/SSH/Banco/etc
67
+ */
68
+ static autoInit() {
69
+ if (!UnifiedReportManager.autoDetectionActive) {
70
+ UnifiedReportManager.autoDetectionActive = true;
71
+ // 🤖 FORÇA INICIALIZAÇÃO DO STATEMENT TRACKER
72
+ try {
73
+ import('../hubdocs/StatementTracker.js')
74
+ .then(() => {
75
+ // StatementTracker carregado e auto-inicializado
76
+ })
77
+ .catch(() => {
78
+ // Ignorar erro se não conseguir carregar
79
+ });
80
+ }
81
+ catch (error) {
82
+ // Ignorar erro de importação
83
+ }
84
+ // Configurar interceptação de erros automaticamente
85
+ UnifiedReportManager.configurarInterceptacaoErros();
86
+ // ❌ REMOVIDO: Monitoramento automático que registrava CT como teste
87
+ // this.iniciarMonitoramentoAutomatico()
88
+ // this.interceptarTestContext()
89
+ }
90
+ }
91
+ /**
92
+ * ✅ NOVO: Monitoramento automático de mudanças de teste
93
+ */
94
+ static iniciarMonitoramentoAutomatico() {
95
+ UnifiedReportManager.monitoringInterval = setInterval(() => {
96
+ try {
97
+ const testInfo = TestContext.getSafeTestInfo();
98
+ const currentTest = testInfo?.title || null;
99
+ // Detectar mudança de teste
100
+ if (currentTest &&
101
+ currentTest !== UnifiedReportManager.currentTestName) {
102
+ // Finalizar teste anterior se existir
103
+ if (UnifiedReportManager.currentTestName) {
104
+ UnifiedReportManager.finalizarTesteAutomatico(UnifiedReportManager.currentTestName);
105
+ }
106
+ // Iniciar novo teste
107
+ UnifiedReportManager.iniciarTesteAutomatico(currentTest);
108
+ }
109
+ // Detectar fim de teste (quando não há mais TestInfo)
110
+ if (!currentTest && UnifiedReportManager.currentTestName) {
111
+ UnifiedReportManager.finalizarTesteAutomatico(UnifiedReportManager.currentTestName);
112
+ }
113
+ }
114
+ catch (error) {
115
+ // Ignorar erros do monitoramento
116
+ }
117
+ }, 100); // Verificar a cada 100ms
118
+ }
119
+ /**
120
+ * ✅ NOVO: Interceptar TestContext para detectar mudanças automaticamente
121
+ */
122
+ static interceptarTestContext() {
123
+ try {
124
+ // ✅ CORRIGIDO: Verificar se TestContext está disponível antes de interceptar
125
+ if (typeof TestContext === 'undefined' || !TestContext) {
126
+ console.debug('TestContext ainda não está disponível para interceptação');
127
+ return;
128
+ }
129
+ // Interceptar o método setTestInfo do TestContext
130
+ const originalSetTestInfo = TestContext.setTestInfo;
131
+ if (originalSetTestInfo && typeof originalSetTestInfo === 'function') {
132
+ TestContext.setTestInfo = (testInfo) => {
133
+ // Chamar método original
134
+ originalSetTestInfo.call(TestContext, testInfo);
135
+ // Detectar novo teste automaticamente
136
+ if (testInfo?.title) {
137
+ UnifiedReportManager.detectarNovoTeste(testInfo.title);
138
+ }
139
+ };
140
+ }
141
+ }
142
+ catch (error) {
143
+ console.debug('Erro ao interceptar TestContext:', error);
144
+ }
145
+ }
146
+ /**
147
+ * ✅ NOVO: Detectar novo teste automaticamente
148
+ */
149
+ static detectarNovoTeste(testName) {
150
+ if (testName !== UnifiedReportManager.currentTestName) {
151
+ // Finalizar teste anterior se existir
152
+ if (UnifiedReportManager.currentTestName) {
153
+ UnifiedReportManager.finalizarTesteAutomatico(UnifiedReportManager.currentTestName);
154
+ }
155
+ // Iniciar novo teste
156
+ UnifiedReportManager.iniciarTesteAutomatico(testName);
157
+ }
158
+ }
159
+ /**
160
+ * ✅ NOVO: Iniciar teste automaticamente
161
+ */
162
+ static iniciarTesteAutomatico(testName) {
163
+ UnifiedReportManager.currentTestName = testName;
164
+ UnifiedReportManager.testStartTime = Date.now();
165
+ // Registrar teste automaticamente
166
+ UnifiedReportManager.registrarTeste(testName, 'Mixed'); // Detectar tipo depois
167
+ // ❌ REMOVIDO: NÃO chamar StatementTracker.setTestName() aqui!
168
+ // O nome correto (CN do test.describe) já foi setado em TestAnnotations.Api/SSH/Banco/etc
169
+ // Este testName aqui é o CT (test.title), não o CN!
170
+ // Iniciar execução se não iniciada
171
+ if (!UnifiedReportManager.inicioExecucao) {
172
+ UnifiedReportManager.registrarInicioExecucao();
173
+ }
174
+ }
175
+ /**
176
+ * ✅ NOVO: Finalizar teste automaticamente
177
+ */
178
+ static async finalizarTesteAutomatico(testName) {
179
+ // Detectar status baseado em logs
180
+ const logs = UnifiedReportManager.logsPorTeste.get(testName) || [];
181
+ const hasError = logs.some((log) => log.includes('❌') ||
182
+ log.includes('ERRO') ||
183
+ log.includes('Error') ||
184
+ log.includes('failed'));
185
+ const status = hasError ? 'failed' : 'passed';
186
+ // Marcar fim do teste
187
+ await UnifiedReportManager.marcarFimTeste(testName, status);
188
+ // Calcular duração
189
+ if (UnifiedReportManager.testStartTime) {
190
+ const duracao = Date.now() - UnifiedReportManager.testStartTime;
191
+ UnifiedReportManager.setTestDuration(testName, duracao);
192
+ }
193
+ // Reset
194
+ UnifiedReportManager.currentTestName = null;
195
+ UnifiedReportManager.testStartTime = null;
196
+ }
197
+ static setTestContext(testeName, contexto) {
198
+ UnifiedReportManager.contextoPorTeste.set(testeName, contexto);
199
+ }
200
+ static iniciarTeste(testeName, contexto) {
201
+ Logger.info(`🎯 Iniciando teste: ${testeName}`);
202
+ // ✅ IMPORTANTE: Registrar o teste no sistema
203
+ UnifiedReportManager.registrarTeste(testeName, contexto || 'Mixed');
204
+ // Definir teste atual
205
+ UnifiedReportManager.currentTestName = testeName;
206
+ // ✅ CRÍTICO: Informar StatementTracker sobre o nome do teste
207
+ try {
208
+ StatementTracker.setTestName(testeName);
209
+ Logger.success(`✅ Nome do teste "${testeName}" registrado no StatementTracker`);
210
+ }
211
+ catch (error) {
212
+ Logger.warning(`⚠️ Erro ao registrar nome no StatementTracker: ${error}`);
213
+ }
214
+ // Definir contexto se fornecido
215
+ if (contexto) {
216
+ UnifiedReportManager.contextoPorTeste.set(testeName, contexto);
217
+ }
218
+ // Inicializar estruturas de dados para o teste
219
+ if (!UnifiedReportManager.logsPorTeste.has(testeName)) {
220
+ UnifiedReportManager.logsPorTeste.set(testeName, []);
221
+ }
222
+ // Adicionar log inicial
223
+ UnifiedReportManager.adicionarLog(testeName, `🎯 INICIANDO: ${testeName}`);
224
+ // Marcar início do tempo
225
+ UnifiedReportManager.duracoesPorTeste.set(testeName, Date.now());
226
+ Logger.success(`✅ Teste ${testeName} inicializado no contexto ${contexto || 'Mixed'}`);
227
+ }
228
+ static registrarInicioExecucao() {
229
+ if (!UnifiedReportManager.inicioExecucao) {
230
+ UnifiedReportManager.inicioExecucao = new Date();
231
+ Logger.info(`⏱️ Início da execução unificada: ${UnifiedReportManager.inicioExecucao.toLocaleTimeString()}`);
232
+ }
233
+ }
234
+ /**
235
+ * Registra informações do ambiente CI (Azure Pipelines, GitHub Actions, etc)
236
+ * e as anexa como metadados globais para o relatório.
237
+ */
238
+ static registrarCIInfo() {
239
+ try {
240
+ const metadata = {};
241
+ // Azure Pipelines
242
+ if (process.env.AGENT_NAME || process.env.BUILD_REASON) {
243
+ metadata.ciProvider = 'azure-pipelines';
244
+ metadata.agentName = process.env.AGENT_NAME || null;
245
+ metadata.buildReason = process.env.BUILD_REASON || null; // Ex: 'Schedule', 'Manual'
246
+ metadata.requestedFor = process.env.BUILD_REQUESTEDFOR || process.env.BUILD_REQUESTEDFORID || null;
247
+ metadata.buildId = process.env.BUILD_BUILDID || null;
248
+ metadata.project = process.env.SYSTEM_TEAMPROJECT || null;
249
+ metadata.collectionUri = process.env.SYSTEM_COLLECTIONURI || null;
250
+ // Tentativa de descobrir email do usuário que requisitou
251
+ metadata.requestedForEmail = process.env.BUILD_REQUESTEDFOR || process.env.BUILD_REQUESTEDFOREMAIL || null;
252
+ metadata.isScheduled = (process.env.BUILD_REASON || '').toLowerCase() === 'schedule';
253
+ }
254
+ // GitHub Actions
255
+ if (process.env.GITHUB_ACTIONS) {
256
+ metadata.ciProvider = 'github-actions';
257
+ metadata.actor = process.env.GITHUB_ACTOR || null;
258
+ metadata.workflow = process.env.GITHUB_WORKFLOW || null;
259
+ metadata.runId = process.env.GITHUB_RUN_ID || null;
260
+ metadata.eventName = process.env.GITHUB_EVENT_NAME || null;
261
+ // GitHub schedule detection: eventName == 'schedule'
262
+ metadata.isScheduled = (process.env.GITHUB_EVENT_NAME || '').toLowerCase() === 'schedule';
263
+ }
264
+ // Fallbacks: tentar detectar e-mail do usuário a partir de variáveis comuns
265
+ if (!metadata.requestedForEmail) {
266
+ metadata.requestedForEmail = process.env.BUILD_REQUESTEDFOREMAIL || process.env.BUILD_REQUESTEDFOR || process.env.USER_EMAIL || null;
267
+ }
268
+ // Armazenar em dadosGlobais para anexar ao relatório final
269
+ ;
270
+ UnifiedReportManager.dadosGlobais.ciMetadata = metadata;
271
+ Logger.info(`🔗 CI metadata registrada: ${JSON.stringify(metadata)}`);
272
+ }
273
+ catch (error) {
274
+ Logger.warning(`⚠️ Não foi possível registrar CI info: ${error}`);
275
+ }
276
+ }
277
+ static registrarFimExecucao() {
278
+ UnifiedReportManager.fimExecucao = new Date();
279
+ if (UnifiedReportManager.inicioExecucao) {
280
+ const duration = (UnifiedReportManager.fimExecucao.getTime() -
281
+ UnifiedReportManager.inicioExecucao.getTime()) /
282
+ 1000;
283
+ Logger.info(`⏱️ Execução unificada concluída em ${duration.toFixed(2)}s`);
284
+ }
285
+ }
286
+ /**
287
+ * ✅ NOVO: Registra explicitamente um teste no sistema
288
+ */
289
+ static registrarTeste(testName, contextType) {
290
+ if (!testName) {
291
+ Logger.warning('⚠️ Nome do teste vazio, ignorando registrarTeste');
292
+ return;
293
+ }
294
+ // ✅ CRÍTICO: Sempre criar entrada para o teste
295
+ UnifiedReportManager.dadosGlobais.testes[testName] = {
296
+ nome: testName,
297
+ tipo: contextType,
298
+ inicio: new Date(),
299
+ fim: null,
300
+ duracao: 0,
301
+ status: 'running',
302
+ logs: [],
303
+ screenshots: [],
304
+ dados: {},
305
+ };
306
+ // ✅ IMPORTANTE: Incrementar contador
307
+ UnifiedReportManager.dadosGlobais.totalTestes++;
308
+ // ✅ NOVO: Também criar entrada básica no array de testes para relatórios
309
+ const testeExistente = UnifiedReportManager.testes.find((t) => t.nome === testName);
310
+ if (!testeExistente) {
311
+ const novoTeste = {
312
+ nome: testName,
313
+ resultado: 'FAIL', // Assumir FAIL inicialmente, será atualizado
314
+ tipo: contextType,
315
+ duracao: 0,
316
+ logs: [],
317
+ timestamp: new Date(),
318
+ metadata: {},
319
+ };
320
+ UnifiedReportManager.testes.push(novoTeste);
321
+ }
322
+ }
323
+ /**
324
+ * 🆕 HELPER: Obter o nome correto do CN (test.describe) do TestInfo
325
+ */
326
+ static getCNNameFromTestInfo() {
327
+ const testInfo = TestContext.getSafeTestInfo();
328
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
329
+ return testInfo?.titlePath?.[1] || null;
330
+ }
331
+ /**
332
+ * ✅ NOVO: Marca explicitamente o fim de um teste
333
+ */
334
+ static async marcarFimTeste(testName, status, options = {}) {
335
+ const mappedCtName = options.ctName || testName;
336
+ const cnName = options.cnName ||
337
+ UnifiedReportManager.obterCnRegistrado(mappedCtName) ||
338
+ UnifiedReportManager.getCNNameFromTestInfo() ||
339
+ testName;
340
+ if (status === 'passed') {
341
+ await UnifiedReportManager.corrigirStatusCTsQuandoTestePassou(cnName, mappedCtName);
342
+ }
343
+ else if (status === 'failed') {
344
+ await UnifiedReportManager.corrigirStatusCTsQuandoTesteFalha(cnName, mappedCtName, options.errorMessage);
345
+ }
346
+ // Atualizar dadosGlobais
347
+ const testeGlobal = UnifiedReportManager.dadosGlobais.testes[testName];
348
+ if (testeGlobal) {
349
+ testeGlobal.fim = new Date();
350
+ testeGlobal.status = status;
351
+ // Calcular duração
352
+ if (testeGlobal.inicio) {
353
+ testeGlobal.duracao =
354
+ (testeGlobal.fim.getTime() - testeGlobal.inicio.getTime()) / 1000;
355
+ // Atualizar também no Map de durações
356
+ UnifiedReportManager.duracoesPorTeste.set(testName, testeGlobal.duracao * 1000);
357
+ }
358
+ if (status === 'passed') {
359
+ UnifiedReportManager.dadosGlobais.testesPassados++;
360
+ }
361
+ else if (status === 'failed') {
362
+ UnifiedReportManager.dadosGlobais.testesFalharam++;
363
+ }
364
+ }
365
+ // Atualizar também o array de testes
366
+ const testeIndex = UnifiedReportManager.testes.findIndex((t) => t.nome === testName);
367
+ if (testeIndex >= 0) {
368
+ UnifiedReportManager.testes[testeIndex].resultado =
369
+ status === 'passed' ? 'PASS' : 'FAIL';
370
+ // Atualizar logs se existirem
371
+ const logs = UnifiedReportManager.logsPorTeste.get(testName) || [];
372
+ UnifiedReportManager.testes[testeIndex].logs = logs;
373
+ // Atualizar duração corretamente
374
+ UnifiedReportManager.testes[testeIndex].duracao =
375
+ testeGlobal?.duracao ?? 0;
376
+ }
377
+ UnifiedReportManager.limparRegistroCt(mappedCtName);
378
+ // Log de finalização
379
+ Logger.info(`🏁 Finalizado: ${testName} [${status.toUpperCase()}]`);
380
+ }
381
+ /**
382
+ * ✅ NOVO: Corrige status dos CTs quando teste PASSA
383
+ * Marca todos os CTs "running" do teste como "passed"
384
+ */
385
+ static async corrigirStatusCTsQuandoTestePassou(testName, ctName) {
386
+ try {
387
+ StatementTracker.finalizeRunningCTsAsPassed(testName, ctName);
388
+ }
389
+ catch (error) {
390
+ Logger.warning(`⚠️ Erro ao corrigir status dos CTs para teste ${testName}: ${error}`);
391
+ }
392
+ }
393
+ /**
394
+ * ✅ NOVO: Corrige status dos CTs quando teste FALHA
395
+ * Marca todos os CTs "running" do teste como "failed"
396
+ */
397
+ static async corrigirStatusCTsQuandoTesteFalha(testName, ctName, reason) {
398
+ try {
399
+ Logger.info(`🔧 Finalizando CTs "running" como "failed" para teste: ${testName}${ctName ? ` (CT: ${ctName})` : ''}`);
400
+ // Importar StatementTracker dinamicamente (ESModules)
401
+ StatementTracker.finalizeRunningCTsAsFailed(testName, reason || 'Teste falhou - finalizando CTs pendentes', ctName);
402
+ Logger.success(`✅ Status dos CTs corrigido para teste ${testName}`);
403
+ }
404
+ catch (error) {
405
+ Logger.warning(`⚠️ Erro ao corrigir status dos CTs para teste ${testName}: ${error}`);
406
+ }
407
+ }
408
+ static async coletarDadosDoTeste(testeName) {
409
+ const testInfo = TestContext.getSafeTestInfo();
410
+ // ✅ CORREÇÃO CRÍTICA: Buscar pelo CN (test.describe = titlePath[1]), não pelo CT (test.title)
411
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
412
+ const nomeDoCN = testeName || testInfo?.titlePath?.[1] || testInfo?.title;
413
+ if (!nomeDoCN)
414
+ return { cts: [], logs: [], screenshots: [] };
415
+ if (testInfo?.titlePath) {
416
+ Logger.info(` 📋 titlePath completo: ${testInfo.titlePath.join(' > ')}`);
417
+ }
418
+ const contexto = UnifiedReportManager.contextoPorTeste.get(nomeDoCN) || 'Mixed';
419
+ // 🔧 CORREÇÃO COMPLETA: Captura de logs de TODAS as fontes
420
+ let logs = [];
421
+ // ✅ FONTE 1: Logs do Map logsPorTeste
422
+ const logsDoMap = UnifiedReportManager.logsPorTeste.get(nomeDoCN) ?? [];
423
+ if (logsDoMap.length > 0) {
424
+ Logger.info(`📋 Encontrados ${logsDoMap.length} logs no Map`);
425
+ logs.push(...logsDoMap);
426
+ }
427
+ // ✅ FONTE 2: Logs dos dadosGlobais
428
+ const testeGlobal = UnifiedReportManager.dadosGlobais.testes[nomeDoCN];
429
+ if (testeGlobal?.logs && testeGlobal.logs.length > 0) {
430
+ Logger.info(`📋 Encontrados ${testeGlobal.logs.length} logs nos dadosGlobais`);
431
+ logs.push(...testeGlobal.logs);
432
+ }
433
+ // ✅ FONTE 3: Logs do buffer global do console
434
+ if (globalThis.consoleBuffer) {
435
+ const bufferLogs = globalThis.consoleBuffer
436
+ .filter((log) => log.testName === nomeDoCN ||
437
+ log.testName?.includes(nomeDoCN) ||
438
+ nomeDoCN.includes(log.testName || ''))
439
+ .map((log) => log.message);
440
+ if (bufferLogs.length > 0) {
441
+ Logger.info(`📋 Encontrados ${bufferLogs.length} logs no buffer do console`);
442
+ logs.push(...bufferLogs);
443
+ }
444
+ }
445
+ // ✅ FONTE 4: Logs do TestAnnotations (NOVO)
446
+ try {
447
+ const logsCapturados = TestAnnotations.getLogsCapturados();
448
+ if (logsCapturados && logsCapturados.length > 0) {
449
+ Logger.info(`📋 Encontrados ${logsCapturados.length} logs do TestAnnotations`);
450
+ logs.push(...logsCapturados);
451
+ }
452
+ }
453
+ catch (error) {
454
+ Logger.warning(`⚠️ Erro ao capturar logs do TestAnnotations: ${error}`);
455
+ }
456
+ // ✅ FONTE 5: Buscar logs por padrões similares de nome de teste
457
+ const nomeString = String(nomeDoCN || 'Unknown Test');
458
+ const nomesVariacoes = [
459
+ nomeString,
460
+ nomeString.replace(/[^\w\d]/g, ''),
461
+ nomeString.replace(/[^\w\d]/g, '_'),
462
+ nomeString.replace(/\s+/g, '_'),
463
+ nomeString.replace(/\s+/g, ''),
464
+ ];
465
+ for (const nomeVariacao of nomesVariacoes) {
466
+ const logsVariacao = UnifiedReportManager.logsPorTeste.get(nomeVariacao);
467
+ if (logsVariacao && logsVariacao.length > 0) {
468
+ Logger.info(`📋 Encontrados ${logsVariacao.length} logs para variação: ${nomeVariacao}`);
469
+ logs.push(...logsVariacao);
470
+ }
471
+ }
472
+ // 🔧 Remover duplicatas preservando ordem
473
+ logs = [...new Set(logs)];
474
+ // 🆕 Se ainda não temos logs, criar logs informativos básicos
475
+ if (logs.length === 0) {
476
+ logs = [
477
+ `🎯 Iniciando execução do teste: ${nomeDoCN}`,
478
+ `📋 Contexto detectado: ${contexto}`,
479
+ `🕐 Timestamp: ${new Date().toLocaleString('pt-BR')}`,
480
+ 'ℹ️ ATENÇÃO: Logs reais não foram capturados automaticamente',
481
+ '💡 Para capturar logs, use: Logger.info(), console.log(), ou UnifiedReportManager.adicionarLog()',
482
+ `🔧 Debug: Total de variações testadas: ${nomesVariacoes.length}`,
483
+ `📊 Debug: Buffer do console disponível: ${globalThis.consoleBuffer ? 'SIM' : 'NÃO'}`,
484
+ `🎯 Debug: Nome do teste atual: ${UnifiedReportManager.currentTestName || 'NENHUM'}`,
485
+ ];
486
+ }
487
+ else {
488
+ Logger.success(`✅ Total de ${logs.length} logs coletados de todas as fontes`);
489
+ // 🆕 Adicionar logs informativos no início se não existirem
490
+ const logsComInfo = [
491
+ `🎯 Teste: ${nomeDoCN} (${contexto})`,
492
+ `🕐 Início: ${testeGlobal?.inicio ? new Date(testeGlobal.inicio).toLocaleString('pt-BR') : 'N/A'}`,
493
+ `📊 Total de logs capturados: ${logs.length}`,
494
+ '------- LOGS DE EXECUÇÃO -------',
495
+ ...logs,
496
+ ];
497
+ logs = logsComInfo;
498
+ }
499
+ const metadata = UnifiedReportManager.metadataPorTeste.get(nomeDoCN) || {};
500
+ // Buscar duração preferencialmente dos dadosGlobais
501
+ const duracao = testeGlobal?.duracao
502
+ ? testeGlobal.duracao
503
+ : (UnifiedReportManager.duracoesPorTeste.get(nomeDoCN) || 0) / 1000;
504
+ // Determina se há erros nos logs
505
+ const temErroLogs = logs.some((log) => log.includes('❌') ||
506
+ log.includes('FAILED') ||
507
+ log.includes('erro') ||
508
+ log.includes('falhou'));
509
+ // ✅ NOVO: Se o teste tem erro, corrigir CTs "running" antes de coletar
510
+ if (temErroLogs) {
511
+ Logger.info(`🔧 Teste com erro detectado nos logs, corrigindo CTs em execução: ${nomeDoCN}`);
512
+ await UnifiedReportManager.corrigirStatusCTsQuandoTesteFalha(nomeDoCN);
513
+ // Aguardar um pouco para permitir que as correções sejam aplicadas
514
+ await new Promise((resolve) => setTimeout(resolve, 100));
515
+ }
516
+ // 🆕 CRÍTICO: Aguardar que StatementTracker tenha dados prontos
517
+ try {
518
+ await StatementTracker.waitForDataReady();
519
+ Logger.success('✅ StatementTracker pronto para coleta de dados');
520
+ }
521
+ catch (error) {
522
+ Logger.warning(`⚠️ Erro ao aguardar dados do StatementTracker: ${error}`);
523
+ }
524
+ // 🔧 CORREÇÃO CRÍTICA: Busca direta e simples
525
+ const allExecutions = StatementTracker.getExecutions();
526
+ // 🆕 BUSCA SIMPLIFICADA: Pegar CTs do teste específico
527
+ let cts = [];
528
+ let totalCTs = 0;
529
+ let passedCTs = 0;
530
+ let failedCTs = 0;
531
+ let skippedCTs = 0;
532
+ // ✅ CORREÇÃO: Buscar pelo nome do CN (test.describe)
533
+ let testExecution = allExecutions.get(nomeDoCN);
534
+ // 🔍 DEBUG CRÍTICO: Ver todos os nomes registrados
535
+ for (const [key, value] of allExecutions.entries()) {
536
+ Logger.info(` 📋 "${key}" - ${value.totalCTs} CTs`);
537
+ }
538
+ // 🆘 FALLBACK: Se não encontrou exato, tentar busca parcial
539
+ if (!testExecution) {
540
+ // Tentar encontrar por semelhança
541
+ for (const [key, value] of allExecutions.entries()) {
542
+ if (key.includes(nomeDoCN) || nomeDoCN.includes(key)) {
543
+ Logger.info(`🎯 [UnifiedReport] Encontrado por semelhança: "${key}" para "${nomeDoCN}"`);
544
+ testExecution = value;
545
+ break;
546
+ }
547
+ }
548
+ // Se ainda não encontrou, pegar qualquer um que tenha CTs
549
+ if (!testExecution) {
550
+ for (const [key, value] of allExecutions.entries()) {
551
+ if (value.totalCTs > 0) {
552
+ Logger.info(`🆘 [UnifiedReport] Usando primeiro teste com CTs: "${key}"`);
553
+ testExecution = value;
554
+ break;
555
+ }
556
+ }
557
+ }
558
+ }
559
+ if (testExecution && testExecution.cts && testExecution.cts.length > 0) {
560
+ Logger.info(`🎯 Encontrado dados com ${testExecution.cts.length} CTs`); // ✅ CORREÇÃO: Iterar sobre os CTs do teste específico
561
+ cts = testExecution.cts.map((ct, index) => {
562
+ const rawName = ct.ctName || ct.name || '';
563
+ const derivedClass = ct.className ||
564
+ rawName.split('.')[0] ||
565
+ rawName.split('→')[0]?.trim() ||
566
+ 'Unknown';
567
+ const derivedMethod = ct.methodName ||
568
+ rawName.split('.')[1] ||
569
+ rawName.split('→')[1]?.trim() ||
570
+ rawName ||
571
+ 'method';
572
+ const durationMs = typeof ct.duration === 'number'
573
+ ? ct.duration
574
+ : ct.endTime && ct.startTime
575
+ ? ct.endTime - ct.startTime
576
+ : 0;
577
+ return {
578
+ ctId: ct.ctId ||
579
+ ct.ctIdentifier ||
580
+ `CT${(index + 1).toString().padStart(3, '0')}`,
581
+ ctName: rawName || `CT ${index + 1}`,
582
+ ctOrder: ct.ctOrder ?? index + 1,
583
+ status: (ct.status || 'running'),
584
+ duration: durationMs,
585
+ timestamp: ct.startTime ? new Date(ct.startTime) : new Date(),
586
+ startTime: ct.startTime ?? null,
587
+ endTime: ct.endTime ?? (ct.startTime ? ct.startTime + durationMs : null),
588
+ error: ct.error,
589
+ className: derivedClass,
590
+ methodName: derivedMethod,
591
+ systemName: ct.systemName || testExecution.systemName || 'Unknown',
592
+ statements: Array.isArray(ct.statements)
593
+ ? ct.statements.map((stmt) => ({ ...stmt }))
594
+ : [],
595
+ executedActions: Array.isArray(ct.executedActions)
596
+ ? ct.executedActions.map((action) => ({ ...action }))
597
+ : [],
598
+ logs: Array.isArray(ct.logs) ? [...ct.logs] : [],
599
+ };
600
+ });
601
+ // ✅ CORREÇÃO CRÍTICA: Sempre contar TODOS os CTs do array mapeado
602
+ // Não confiar apenas em testExecution.totalCTs pois pode estar desatualizado
603
+ // 🛡️ CRÍTICO: CTs "running" devem ser contados como "failed"
604
+ totalCTs = cts.length;
605
+ passedCTs = cts.filter((ct) => ct.status === 'passed').length;
606
+ failedCTs = cts.filter((ct) => ct.status === 'failed' || ct.status === 'running').length;
607
+ skippedCTs = cts.filter((ct) => ct.status === 'skipped').length;
608
+ }
609
+ else {
610
+ Logger.info(`⚠️ Nenhum CT encontrado para CN "${nomeDoCN}"`);
611
+ Logger.info(`📋 CNs disponíveis no StatementTracker: ${Array.from(allExecutions.keys()).join(', ')}`);
612
+ // 🔍 DEBUG: Verificar total de CNs e detalhes
613
+ for (const [testName, testData] of allExecutions.entries()) {
614
+ Logger.info(` 📋 Teste ${testName}: ${testData.totalCTs} CTs`);
615
+ Logger.info(` ⚠️ Nenhum CT encontrado para ${testName}`);
616
+ }
617
+ }
618
+ // 🆕 CORREÇÃO CRÍTICA: Determinar resultado considerando tanto logs quanto CTs falhados
619
+ // 🛡️ IMPORTANTE: Se tem CT "failed" OU "running", o CN inteiro falhou
620
+ const temCTsFalhados = failedCTs > 0; // Já inclui running porque failedCTs conta running
621
+ const testeFalhou = temErroLogs || temCTsFalhados;
622
+ const resultado = {
623
+ nome: nomeDoCN,
624
+ resultado: testeFalhou ? 'FAIL' : 'PASS',
625
+ tipo: contexto,
626
+ duracao,
627
+ logs, // sempre array
628
+ timestamp: new Date(),
629
+ metadata,
630
+ // 🆕 Dados dos CTs
631
+ cts,
632
+ totalCTs,
633
+ passedCTs,
634
+ failedCTs,
635
+ skippedCTs,
636
+ };
637
+ // Remove teste existente e adiciona o atualizado
638
+ UnifiedReportManager.testes = UnifiedReportManager.testes.filter((t) => t.nome !== nomeDoCN);
639
+ UnifiedReportManager.testes.push(resultado);
640
+ // 🆕 Retornar os dados coletados
641
+ return {
642
+ cts,
643
+ logs,
644
+ screenshots: [], // TODO: implementar screenshots
645
+ totalCTs,
646
+ passedCTs,
647
+ failedCTs,
648
+ skippedCTs,
649
+ };
650
+ }
651
+ static adicionarLog(testeName, message) {
652
+ // 🔧 PROTEÇÃO CRÍTICA ANTI-LOOP: Evitar qualquer recursão
653
+ if (message.includes('[UNIFIED]') ||
654
+ message.includes('[LOG]') ||
655
+ message.includes('📝 Adicionando log para') ||
656
+ message.includes('AutoCore: Sistema') ||
657
+ message.includes('interceptação') ||
658
+ message.includes('interceptar') ||
659
+ UnifiedReportManager._addingLog) {
660
+ return; // Evitar re-processar logs já processados
661
+ }
662
+ // 🔧 MARCAR que estamos adicionando log para evitar recursão
663
+ ;
664
+ UnifiedReportManager._addingLog = true;
665
+ try {
666
+ // 🔧 CRÍTICO: NÃO usar console.log aqui - usar apenas estruturas internas
667
+ if (!UnifiedReportManager.logsPorTeste.has(testeName)) {
668
+ UnifiedReportManager.logsPorTeste.set(testeName, []);
669
+ }
670
+ UnifiedReportManager.logsPorTeste.get(testeName).push(message);
671
+ // ✅ NOVO: Adicionar log aos dadosGlobais também
672
+ if (UnifiedReportManager.dadosGlobais.testes[testeName]) {
673
+ UnifiedReportManager.dadosGlobais.testes[testeName].logs.push(message);
674
+ }
675
+ // ✅ NOVO: Adicionar também ao buffer global se não existir
676
+ if (globalThis.consoleBuffer) {
677
+ ;
678
+ globalThis.consoleBuffer.push({
679
+ testName: testeName,
680
+ message,
681
+ timestamp: new Date().toISOString(),
682
+ type: 'auto-added',
683
+ });
684
+ }
685
+ }
686
+ catch (error) {
687
+ // Evitar qualquer erro que possa causar loop
688
+ }
689
+ finally {
690
+ // 🔧 SEMPRE limpar flag
691
+ ;
692
+ UnifiedReportManager._addingLog = false;
693
+ }
694
+ }
695
+ static setTestMetadata(testeName, metadata) {
696
+ UnifiedReportManager.metadataPorTeste.set(testeName, metadata);
697
+ }
698
+ static setTestDuration(testeName, duracao) {
699
+ UnifiedReportManager.duracoesPorTeste.set(testeName, duracao);
700
+ // ✅ NOVO: Atualizar também nos dadosGlobais
701
+ if (UnifiedReportManager.dadosGlobais.testes[testeName]) {
702
+ UnifiedReportManager.dadosGlobais.testes[testeName].duracao =
703
+ duracao / 1000; // Converter para segundos
704
+ }
705
+ }
706
+ /**
707
+ * ✅ NOVO: Obter logs de um teste específico
708
+ */
709
+ static getTestLogs(testName) {
710
+ return UnifiedReportManager.logsPorTeste.get(testName) || [];
711
+ }
712
+ static async anexarRelatorioIndividual() {
713
+ const testInfo = TestContext.getSafeTestInfo();
714
+ if (!testInfo)
715
+ return;
716
+ const testeName = testInfo.title;
717
+ const testeAtual = UnifiedReportManager.testes.find((t) => t.nome === testeName);
718
+ if (!testeAtual) {
719
+ Logger.warning(`Teste ${testeName} não encontrado para relatório individual`);
720
+ return;
721
+ }
722
+ try {
723
+ const htmlBuffer = await UnifiedHtmlGenerator.generate([testeAtual], UnifiedReportManager.inicioExecucao || new Date(), UnifiedReportManager.fimExecucao || new Date(), true, testeName);
724
+ // Gerar nome de arquivo baseado no nome do teste
725
+ // Exemplo: CT003_Consultar_Cobertura.html
726
+ const safeTestName = testeName
727
+ .replace(/[^\w\d]+/g, '_')
728
+ .replace(/^_+|_+$/g, '');
729
+ const reportDir = path.join(process.cwd(), 'playwright-report');
730
+ if (!fs.existsSync(reportDir)) {
731
+ fs.mkdirSync(reportDir, { recursive: true });
732
+ }
733
+ const reportPath = path.join(reportDir, `${safeTestName}.html`);
734
+ fs.writeFileSync(reportPath, htmlBuffer);
735
+ // Anexar ao contexto do Playwright (útil para CI e UI)
736
+ await testInfo.attach(`${safeTestName}.html`, {
737
+ body: htmlBuffer,
738
+ contentType: 'text/html',
739
+ });
740
+ Logger.success(`📄 Relatório individual salvo e anexado: ${reportPath}`);
741
+ }
742
+ catch (error) {
743
+ Logger.error(`Erro ao gerar relatório individual para ${testeName}`, error);
744
+ }
745
+ }
746
+ /**
747
+ * ✅ CORRIGIDO: Anexa relatório geral unificado
748
+ */
749
+ static async anexarRelatorioGeral() {
750
+ try {
751
+ const testesRegistrados = Object.keys(UnifiedReportManager.dadosGlobais.testes);
752
+ Logger.info(`📊 Verificando testes registrados: ${testesRegistrados.length}`);
753
+ if (testesRegistrados.length === 0) {
754
+ Logger.info('⚠️ Nenhum teste registrado para relatório geral');
755
+ return;
756
+ }
757
+ // ✅ Gerar relatório mesmo com testes que falharam
758
+ Logger.info(`📋 Gerando relatório para ${testesRegistrados.length} teste(s)...`);
759
+ // 🆕 CRÍTICO: Buscar CNs reais do StatementTracker ao invés dos nomes dos testes
760
+ Logger.info('📊 Coletando dados dos CTs para todos os CNs...');
761
+ const allExecutions = StatementTracker.getExecutions();
762
+ const nomesDosCNs = Array.from(allExecutions.keys());
763
+ Logger.info(`📊 CNs detectados no StatementTracker: ${nomesDosCNs.join(', ')}`);
764
+ Logger.info(`📊 Testes registrados no UnifiedReportManager: ${testesRegistrados.join(', ')}`);
765
+ // 🔧 CORREÇÃO: Iterar sobre os CNs do StatementTracker, não sobre testesRegistrados
766
+ for (const nomeDoCN of nomesDosCNs) {
767
+ try {
768
+ await UnifiedReportManager.coletarDadosDoTeste(nomeDoCN);
769
+ }
770
+ catch (error) {
771
+ Logger.warning(`⚠️ Erro ao coletar dados do CN ${nomeDoCN}: ${error}`);
772
+ }
773
+ }
774
+ UnifiedReportManager.testes.forEach((teste, index) => {
775
+ if (teste.cts && teste.cts.length > 0) {
776
+ teste.cts.forEach((ct, ctIndex) => {
777
+ Logger.info(` CT${ctIndex + 1}: ${ct.ctName} (${ct.status})`);
778
+ });
779
+ }
780
+ else {
781
+ Logger.info(` ⚠️ Nenhum CT encontrado para ${teste.nome}`);
782
+ }
783
+ });
784
+ // ✅ NOVO: Gerar HTML do relatório geral
785
+ try {
786
+ const htmlBuffer = await UnifiedHtmlGenerator.generate(UnifiedReportManager.testes, UnifiedReportManager.inicioExecucao || new Date(), UnifiedReportManager.fimExecucao || new Date(), false, 'Relatório Geral');
787
+ // ✅ Salvar arquivo HTML
788
+ const reportDir = path.join(process.cwd(), 'playwright-report');
789
+ if (!fs.existsSync(reportDir)) {
790
+ fs.mkdirSync(reportDir, { recursive: true });
791
+ }
792
+ const reportPath = path.join(reportDir, 'relatorio-geral-unificado.html');
793
+ fs.writeFileSync(reportPath, htmlBuffer);
794
+ Logger.info(`📁 Relatório geral salvo em: ${reportPath}`);
795
+ }
796
+ catch (error) {
797
+ Logger.error('❌ Erro ao gerar arquivo HTML do relatório', error);
798
+ }
799
+ // Logar os dados dos testes
800
+ testesRegistrados.forEach((testName) => {
801
+ const teste = UnifiedReportManager.dadosGlobais.testes[testName];
802
+ Logger.info(` 📄 ${testName}: ${teste.status} (${teste.tipo})`);
803
+ });
804
+ Logger.success('✅ Relatório geral gerado com sucesso!');
805
+ }
806
+ catch (error) {
807
+ Logger.error('❌ Erro ao gerar relatório geral', error);
808
+ }
809
+ }
810
+ /**
811
+ * 🔍 DEBUG: Método para acessar dados globais
812
+ */
813
+ static getDadosGlobais() {
814
+ return UnifiedReportManager.dadosGlobais;
815
+ }
816
+ /**
817
+ * ✅ ÚNICO: Método getMetrics unificado
818
+ */
819
+ static getMetrics() {
820
+ const testesPorTipo = {
821
+ API: 0,
822
+ Frontend: 0,
823
+ Mobile: 0,
824
+ SSH: 0,
825
+ Banco: 0,
826
+ Mixed: 0,
827
+ Scenarios: 0,
828
+ };
829
+ const resultadosPorTipo = {
830
+ API: { passou: 0, falhou: 0 },
831
+ Frontend: { passou: 0, falhou: 0 },
832
+ Mobile: { passou: 0, falhou: 0 },
833
+ SSH: { passou: 0, falhou: 0 },
834
+ Banco: { passou: 0, falhou: 0 },
835
+ Mixed: { passou: 0, falhou: 0 },
836
+ Scenarios: { passou: 0, falhou: 0 }, // Adicione esta linha
837
+ };
838
+ // ✅ USAR dadosGlobais como fonte única da verdade
839
+ Object.values(UnifiedReportManager.dadosGlobais.testes).forEach((teste) => {
840
+ testesPorTipo[teste.tipo]++;
841
+ if (teste.status === 'passed') {
842
+ resultadosPorTipo[teste.tipo].passou++;
843
+ }
844
+ else if (teste.status === 'failed') {
845
+ resultadosPorTipo[teste.tipo].falhou++;
846
+ }
847
+ });
848
+ const duracao = UnifiedReportManager.inicioExecucao && UnifiedReportManager.fimExecucao
849
+ ? (UnifiedReportManager.fimExecucao.getTime() -
850
+ UnifiedReportManager.inicioExecucao.getTime()) /
851
+ 1000
852
+ : 0;
853
+ return {
854
+ totalTestes: UnifiedReportManager.dadosGlobais.totalTestes,
855
+ testesPorTipo,
856
+ resultadosPorTipo,
857
+ inicio: UnifiedReportManager.inicioExecucao,
858
+ fim: UnifiedReportManager.fimExecucao,
859
+ duracao,
860
+ testes: UnifiedReportManager.testes,
861
+ };
862
+ }
863
+ static reset() {
864
+ UnifiedReportManager.testes = [];
865
+ UnifiedReportManager.contextoPorTeste.clear();
866
+ UnifiedReportManager.logsPorTeste.clear();
867
+ UnifiedReportManager.metadataPorTeste.clear();
868
+ UnifiedReportManager.duracoesPorTeste.clear();
869
+ UnifiedReportManager.inicioExecucao = undefined;
870
+ UnifiedReportManager.fimExecucao = undefined;
871
+ // ✅ NOVO: Reset dadosGlobais
872
+ UnifiedReportManager.dadosGlobais = {
873
+ totalTestes: 0,
874
+ testesPassados: 0,
875
+ testesFalharam: 0,
876
+ testes: {},
877
+ };
878
+ }
879
+ static async finalizarTeste(testName, status) {
880
+ try {
881
+ // Se foi chamado com parâmetros, usar a versão específica
882
+ if (testName && status) {
883
+ await UnifiedReportManager.marcarFimTeste(testName, status);
884
+ return;
885
+ }
886
+ // 🆕 Finalizar todos os CTs pendentes antes de coletar dados
887
+ TestAnnotations.finalizarCTAtivo();
888
+ await UnifiedReportManager.coletarDadosDoTeste();
889
+ await UnifiedReportManager.anexarRelatorioIndividual();
890
+ }
891
+ catch (error) {
892
+ Logger.error('❌ Erro ao finalizar teste unificado', error);
893
+ }
894
+ }
895
+ /**
896
+ * ✅ NOVO: Interceptar e registrar erros de teste automaticamente
897
+ * @param testName Nome do teste
898
+ * @param error Erro capturado
899
+ */
900
+ static async registrarErroTeste(testName, error) {
901
+ const errorMessage = typeof error === 'string' ? error : error.message || error.toString();
902
+ Logger.info(`🔴 Erro registrado para ${testName}: ${errorMessage}`);
903
+ // Adicionar log do erro
904
+ UnifiedReportManager.adicionarLog(testName, `❌ ERRO: ${errorMessage}`);
905
+ // ✅ IMPORTANTE: Chamar corrigirStatusCTsQuandoTesteFalha imediatamente
906
+ await UnifiedReportManager.corrigirStatusCTsQuandoTesteFalha(testName);
907
+ // Marcar teste como falhado nos dados globais
908
+ if (UnifiedReportManager.dadosGlobais.testes[testName]) {
909
+ UnifiedReportManager.dadosGlobais.testes[testName].status = 'failed';
910
+ Logger.success(`✅ Status do teste ${testName} atualizado para 'failed'`);
911
+ }
912
+ }
913
+ /**
914
+ * ✅ NOVO: Configurar interceptação global de erros para testes AutoCore
915
+ */
916
+ static configurarInterceptacaoErros() {
917
+ const errorHandler = (error) => {
918
+ const errorMessage = error.message || error.toString();
919
+ // Usar teste atual do monitoramento automático
920
+ const testName = UnifiedReportManager.currentTestName;
921
+ if (testName &&
922
+ (errorMessage.includes('expect') ||
923
+ errorMessage.includes('AssertionError') ||
924
+ errorMessage.includes('Error:'))) {
925
+ Logger.info(`🤖 AutoCore: Erro detectado automaticamente no teste ${testName}`);
926
+ UnifiedReportManager.registrarErroTeste(testName, error).catch((err) => Logger.error('Erro ao registrar erro:', err));
927
+ }
928
+ };
929
+ // Adicionar handlers se ainda não existem
930
+ if (!process.listenerCount('uncaughtException')) {
931
+ process.on('uncaughtException', errorHandler);
932
+ }
933
+ if (!process.listenerCount('unhandledRejection')) {
934
+ process.on('unhandledRejection', (reason) => {
935
+ errorHandler(new Error(`Unhandled Rejection: ${reason}`));
936
+ });
937
+ }
938
+ }
939
+ /**
940
+ * ✅ NOVO: Interceptar logs do console para detectar ações automaticamente
941
+ */
942
+ static interceptarConsole() {
943
+ // 🆕 Criar buffer global para logs se não existir
944
+ if (!globalThis.consoleBuffer) {
945
+ ;
946
+ globalThis.consoleBuffer = [];
947
+ }
948
+ const originalLog = console.log;
949
+ const originalError = console.error;
950
+ const originalInfo = console.info;
951
+ const originalWarn = console.warn;
952
+ console.log = (...args) => {
953
+ const message = args.join(' ');
954
+ // 🔧 CRÍTICO: Evitar recursão infinita com proteções múltiplas
955
+ if (!(message.includes('📝 Adicionando log para') ||
956
+ message.includes('[UNIFIED]') ||
957
+ message.includes('interceptação') ||
958
+ message.includes('AutoCore: Sistema')) &&
959
+ UnifiedReportManager.currentTestName &&
960
+ !UnifiedReportManager._intercepting) {
961
+ ;
962
+ UnifiedReportManager._intercepting = true;
963
+ try {
964
+ ;
965
+ globalThis.consoleBuffer.push({
966
+ testName: UnifiedReportManager.currentTestName,
967
+ message,
968
+ timestamp: new Date().toISOString(),
969
+ type: 'log',
970
+ });
971
+ // 🔧 ADIÇÃO DIRETA SEM chamar adicionarLog para evitar loop
972
+ if (!UnifiedReportManager.logsPorTeste.has(UnifiedReportManager.currentTestName)) {
973
+ UnifiedReportManager.logsPorTeste.set(UnifiedReportManager.currentTestName, []);
974
+ }
975
+ UnifiedReportManager.logsPorTeste
976
+ .get(UnifiedReportManager.currentTestName)
977
+ .push(message);
978
+ }
979
+ finally {
980
+ ;
981
+ UnifiedReportManager._intercepting = false;
982
+ }
983
+ }
984
+ // Chamar console original
985
+ originalLog.apply(console, args);
986
+ };
987
+ console.info = (...args) => {
988
+ const message = args.join(' ');
989
+ if (UnifiedReportManager.currentTestName) {
990
+ ;
991
+ globalThis.consoleBuffer.push({
992
+ testName: UnifiedReportManager.currentTestName,
993
+ message: `ℹ️ ${message}`,
994
+ timestamp: new Date().toISOString(),
995
+ type: 'info',
996
+ });
997
+ // 🔧 EVITAR RECURSÃO: Não chamar adicionarLog que faz console.log
998
+ // this.adicionarLog(this.currentTestName, `ℹ️ ${message}`)
999
+ }
1000
+ originalInfo.apply(console, args);
1001
+ };
1002
+ console.warn = (...args) => {
1003
+ const message = args.join(' ');
1004
+ if (UnifiedReportManager.currentTestName) {
1005
+ ;
1006
+ globalThis.consoleBuffer.push({
1007
+ testName: UnifiedReportManager.currentTestName,
1008
+ message: `⚠️ ${message}`,
1009
+ timestamp: new Date().toISOString(),
1010
+ type: 'warn',
1011
+ });
1012
+ // 🔧 EVITAR RECURSÃO: Não chamar adicionarLog que faz console.log
1013
+ // this.adicionarLog(this.currentTestName, `⚠️ ${message}`)
1014
+ }
1015
+ originalWarn.apply(console, args);
1016
+ };
1017
+ console.error = (...args) => {
1018
+ const message = args.join(' ');
1019
+ // 🆕 Adicionar ao buffer global
1020
+ if (UnifiedReportManager.currentTestName) {
1021
+ ;
1022
+ globalThis.consoleBuffer.push({
1023
+ testName: UnifiedReportManager.currentTestName,
1024
+ message: `❌ ERRO: ${message}`,
1025
+ timestamp: new Date().toISOString(),
1026
+ type: 'error',
1027
+ });
1028
+ // 🔧 EVITAR RECURSÃO: Não chamar adicionarLog que faz console.log
1029
+ // this.adicionarLog(this.currentTestName, `❌ ERRO: ${message}`)
1030
+ // Considerar como falha
1031
+ setTimeout(() => {
1032
+ if (UnifiedReportManager.currentTestName) {
1033
+ UnifiedReportManager.registrarErroTeste(UnifiedReportManager.currentTestName, message).catch((err) => console.error('Erro ao registrar erro:', err));
1034
+ }
1035
+ }, 10);
1036
+ }
1037
+ // Chamar console original
1038
+ originalError.apply(console, args);
1039
+ };
1040
+ }
1041
+ /**
1042
+ * ✅ NOVO: Adiciona um CT ao teste
1043
+ */
1044
+ static adicionarCT(testName, ct) {
1045
+ if (!(testName && ct)) {
1046
+ Logger.warning('⚠️ Nome do teste ou CT vazio, ignorando adicionarCT');
1047
+ return;
1048
+ }
1049
+ // Buscar o teste nos dados globais
1050
+ const testeGlobal = UnifiedReportManager.dadosGlobais.testes[testName];
1051
+ if (testeGlobal) {
1052
+ if (!testeGlobal.cts) {
1053
+ testeGlobal.cts = [];
1054
+ }
1055
+ testeGlobal.cts.push(ct);
1056
+ Logger.info(`📋 CT adicionado ao teste ${testName}: ${ct.id || ct.descricao}`);
1057
+ }
1058
+ // Também adicionar ao array principal de testes
1059
+ const testeArray = UnifiedReportManager.testes.find((t) => t.nome === testName);
1060
+ if (testeArray) {
1061
+ if (!testeArray.cts) {
1062
+ testeArray.cts = [];
1063
+ }
1064
+ testeArray.cts.push(ct);
1065
+ }
1066
+ }
1067
+ /**
1068
+ * ✅ NOVO: Gera o relatório unificado final
1069
+ */
1070
+ static async gerarRelatorioUnificado() {
1071
+ Logger.info('📊 Gerando relatório unificado...');
1072
+ try {
1073
+ // Coletar dados de todos os testes
1074
+ const testesComDados = await Promise.all(UnifiedReportManager.testes.map(async (teste) => {
1075
+ const dadosColetados = await UnifiedReportManager.coletarDadosDoTeste(teste.nome);
1076
+ return {
1077
+ ...teste,
1078
+ cts: dadosColetados.cts || [],
1079
+ logs: dadosColetados.logs || [],
1080
+ screenshots: dadosColetados.screenshots || [],
1081
+ };
1082
+ }));
1083
+ // 🆕 Buscar dados do StatementTracker
1084
+ let ctData = null;
1085
+ let allCNsData = {};
1086
+ try {
1087
+ ctData = await getStatementTrackerData();
1088
+ const allExecutions = StatementTracker.getExecutions();
1089
+ // 🔧 Converter Map para objeto plano (JSON serializable)
1090
+ allCNsData = Object.fromEntries(allExecutions);
1091
+ Logger.info(`📊 gerarRelatorioUnificado: ${Object.keys(allCNsData).length} CNs exportados para template`);
1092
+ }
1093
+ catch (error) {
1094
+ Logger.warning(`⚠️ Erro ao buscar dados do StatementTracker: ${error}`);
1095
+ }
1096
+ // Preparar dados para o template
1097
+ const dadosRelatorio = {
1098
+ testes: testesComDados,
1099
+ titulo: 'Relatório Unificado de Testes',
1100
+ subtitulo: 'Resultados da execução de testes automatizados',
1101
+ totalTestes: UnifiedReportManager.dadosGlobais.totalTestes,
1102
+ testesPassaram: UnifiedReportManager.dadosGlobais.testesPassados,
1103
+ testesFalharam: UnifiedReportManager.dadosGlobais.testesFalharam,
1104
+ projectName: 'TestHUB',
1105
+ environment: 'N/A',
1106
+ executionDate: new Date().toLocaleString('pt-BR'),
1107
+ autocoreVersion: 'v1.1.x',
1108
+ // 🔗 INTEGRAÇÃO: Dados dos CTs detectados automaticamente
1109
+ ctData,
1110
+ allCNsData, // 🆕 Mapa completo de CNs → CTs → Statements → Actions
1111
+ estatisticasPorTipo: {},
1112
+ coresDosTipos: {
1113
+ API: '#3b82f6',
1114
+ Frontend: '#10b981',
1115
+ Mobile: '#f59e0b',
1116
+ SSH: '#ef4444',
1117
+ Banco: '#8b5cf6',
1118
+ Mixed: '#6b7280',
1119
+ },
1120
+ chartLabels: ['Passou', 'Falhou'],
1121
+ chartData: [
1122
+ UnifiedReportManager.dadosGlobais.testesPassados,
1123
+ UnifiedReportManager.dadosGlobais.testesFalharam,
1124
+ ],
1125
+ chartColors: ['#22c55e', '#ef4444'],
1126
+ barLabels: ['Testes'],
1127
+ barData: [UnifiedReportManager.dadosGlobais.totalTestes],
1128
+ pieLabels: ['Passou', 'Falhou'],
1129
+ pieData: [
1130
+ UnifiedReportManager.dadosGlobais.testesPassados,
1131
+ UnifiedReportManager.dadosGlobais.testesFalharam,
1132
+ ],
1133
+ getIconePorTipo: (tipo) => {
1134
+ const icones = {
1135
+ API: '🌐',
1136
+ Frontend: '💻',
1137
+ Mobile: '📱',
1138
+ SSH: '🔐',
1139
+ Banco: '🗃️',
1140
+ Mixed: '🔄',
1141
+ };
1142
+ return icones[tipo] || '📋';
1143
+ },
1144
+ resumo: {
1145
+ totalTestes: UnifiedReportManager.dadosGlobais.totalTestes,
1146
+ testesPassados: UnifiedReportManager.dadosGlobais.testesPassados,
1147
+ testesFalharam: UnifiedReportManager.dadosGlobais.testesFalharam,
1148
+ duracaoTotal: UnifiedReportManager.calcularDuracaoTotal(),
1149
+ timestamp: new Date().toISOString(),
1150
+ },
1151
+ metadata: {
1152
+ inicio: UnifiedReportManager.inicioExecucao?.toISOString(),
1153
+ fim: UnifiedReportManager.fimExecucao?.toISOString(),
1154
+ contextos: UnifiedReportManager.getContextosUnicos(),
1155
+ },
1156
+ };
1157
+ // Gerar HTML usando o template
1158
+ const htmlTemplatePath = path.join(process.cwd(), 'src', 'utils', 'HTMLTemplate.js');
1159
+ const htmlContent = HTMLTemplate(dadosRelatorio);
1160
+ // Salvar arquivo
1161
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1162
+ const nomeArquivo = `relatorio-unificado-${timestamp}.html`;
1163
+ const caminhoCompleto = path.join(process.cwd(), 'docs', nomeArquivo);
1164
+ // Garantir que o diretório existe
1165
+ const dirDocs = path.dirname(caminhoCompleto);
1166
+ if (!fs.existsSync(dirDocs)) {
1167
+ fs.mkdirSync(dirDocs, { recursive: true });
1168
+ }
1169
+ fs.writeFileSync(caminhoCompleto, htmlContent, 'utf8');
1170
+ Logger.info(`✅ Relatório unificado gerado: ${caminhoCompleto}`);
1171
+ Logger.info(`📊 Resumo: ${dadosRelatorio.resumo.totalTestes} testes, ${dadosRelatorio.resumo.testesPassados} passaram, ${dadosRelatorio.resumo.testesFalharam} falharam`);
1172
+ return caminhoCompleto;
1173
+ }
1174
+ catch (error) {
1175
+ Logger.error('❌ Erro ao gerar relatório unificado:', error);
1176
+ return '';
1177
+ }
1178
+ }
1179
+ /**
1180
+ * ✅ HELPER: Calcula duração total
1181
+ */
1182
+ static calcularDuracaoTotal() {
1183
+ if (UnifiedReportManager.inicioExecucao &&
1184
+ UnifiedReportManager.fimExecucao) {
1185
+ const duracao = (UnifiedReportManager.fimExecucao.getTime() -
1186
+ UnifiedReportManager.inicioExecucao.getTime()) /
1187
+ 1000;
1188
+ return `${duracao.toFixed(2)}s`;
1189
+ }
1190
+ return '0s';
1191
+ }
1192
+ /**
1193
+ * ✅ HELPER: Pega contextos únicos
1194
+ */
1195
+ static getContextosUnicos() {
1196
+ const contextos = new Set();
1197
+ UnifiedReportManager.testes.forEach((teste) => {
1198
+ contextos.add(teste.tipo);
1199
+ });
1200
+ return Array.from(contextos);
1201
+ }
1202
+ }
1203
+ // ✅ CRITICAL: Auto-inicialização quando módulo é carregado
1204
+ UnifiedReportManager['autoInit']();
1205
+ // ✅ IMPORTANTE: Interceptar console automaticamente
1206
+ UnifiedReportManager['interceptarConsole']();