@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,2647 @@
1
+ import { ApiActions } from '../api/ApiActions.js';
2
+ import { MobileConnection } from '../appium/MobileConnection.js';
3
+ import { BancoActions } from '../helpers/BancoActions.js';
4
+ import { StatementTracker } from '../hubdocs/StatementTracker.js';
5
+ import { SSHActions } from '../ssh/SSHActions.js';
6
+ import { ativarInterceptacaoMagica } from '../utils/InterceptacaoMagica.js';
7
+ import { interceptAllStatements } from '../utils/StatementInterceptor.js';
8
+ import { ativarStatementLogs } from '../utils/StatementLogger.js';
9
+ import { TerminalLogCapture } from '../utils/TerminalLogCapture.js';
10
+ import { CoverageManager } from './CoverageManager.js';
11
+ import { TestContext } from './TestContext.js';
12
+ import { DynamicConfigManager } from '../testhub/DynamicConfigManager.js';
13
+ import { UnifiedReportManager, } from './UnifiedReportManager.js';
14
+ import SystemsManager from '../testhub/SystemsManager.js';
15
+ import DesktopConnection from '../desktop/DesktopConnection.js';
16
+ /**
17
+ * 🆕 HELPER CRÍTICO: Garante que TerminalLogCapture está ativo no worker atual
18
+ * Em multi-worker do Playwright, cada worker é um processo separado
19
+ * e precisa iniciar sua própria instância de captura de logs.
20
+ * @param testName Nome do teste (CN) para associar logs
21
+ * @param ctName Nome do CT atual (opcional)
22
+ */
23
+ function ensureTerminalLogCaptureActive(testName, ctName) {
24
+ try {
25
+ // Sempre chamar start() - ele tem verificação interna para evitar duplicação
26
+ TerminalLogCapture.start();
27
+ globalThis.TerminalLogCapture = TerminalLogCapture;
28
+ // Definir o teste atual para associar logs
29
+ TerminalLogCapture.setCurrentTest(testName);
30
+ // Definir o CT atual se fornecido
31
+ if (ctName) {
32
+ TerminalLogCapture.setCurrentCT(ctName);
33
+ }
34
+ }
35
+ catch {
36
+ // Silenciosamente ignorar erro
37
+ }
38
+ }
39
+ /**
40
+ * Map para rastrear início dos testes
41
+ */
42
+ const testStartTimes = new Map();
43
+ /**
44
+ * Tracking de CT ativo atual
45
+ */
46
+ let currentActiveCT = null;
47
+ /**
48
+ * Flags para evitar loop infinito de interceptadores
49
+ */
50
+ const interceptorsAtivos = new Set();
51
+ /**
52
+ * 🛑 Flag global para parar execução ao falhar
53
+ * Pode ser ativada no escopo do test.describe() para aplicar a todos os CTs
54
+ */
55
+ let stopOnFailureEnabled = false;
56
+ /**
57
+ * � CRÍTICO: Importar interceptador universal para garantir ativação
58
+ */
59
+ // Sistema automático ativo - interceptação agora é automática via StatementTracker
60
+ // AutoStatementInterceptor foi removido, tudo é automático agora
61
+ /**
62
+ * �🆕 Sistema de captura de logs de ações de CTs
63
+ */
64
+ const originalConsoleLog = console.log;
65
+ const originalConsoleInfo = console.info;
66
+ const originalConsoleWarn = console.warn;
67
+ const originalConsoleError = console.error;
68
+ let logsCapturados = [];
69
+ let interceptacaoLogsAtiva = false;
70
+ const LOGS_GLOBAL_KEYS = ['logsCapturados', '__AUTOCORE_LOGS_CAPTURADOS__'];
71
+ function atualizarReferenciaGlobalDosLogs() {
72
+ try {
73
+ for (const key of LOGS_GLOBAL_KEYS) {
74
+ ;
75
+ globalThis[key] = logsCapturados;
76
+ }
77
+ }
78
+ catch {
79
+ // Não deve quebrar fluxo se globalThis não estiver disponível
80
+ }
81
+ }
82
+ atualizarReferenciaGlobalDosLogs();
83
+ /**
84
+ * 🆕 Interceptar logs do console para capturar ações de CTs
85
+ */
86
+ function interceptarLogs() {
87
+ if (interceptacaoLogsAtiva)
88
+ return;
89
+ interceptacaoLogsAtiva = true;
90
+ console.log = (...args) => {
91
+ const message = args
92
+ .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))
93
+ .join(' ');
94
+ // ✅ CORRIGIDO: Capturar TODOS os logs durante execução de CT (não apenas alguns emojis)
95
+ // Excluir apenas logs internos do sistema que não são relevantes para o usuário
96
+ const isInternalLog = message.includes('[DEBUG]') ||
97
+ message.includes('node_modules') ||
98
+ message.includes('webpack') ||
99
+ message.includes('Module build') ||
100
+ message.startsWith('Failed to load');
101
+ if (!isInternalLog) {
102
+ logsCapturados.push(`[${new Date().toISOString()}] ${message}`);
103
+ atualizarReferenciaGlobalDosLogs();
104
+ // Também registrar no UnifiedReportManager se possível
105
+ try {
106
+ const testInfo = TestContext.getSafeTestInfo();
107
+ if (testInfo?.title) {
108
+ UnifiedReportManager.adicionarLog(testInfo.title, message);
109
+ }
110
+ }
111
+ catch {
112
+ // Ignorar erro se TestContext não estiver disponível
113
+ }
114
+ }
115
+ // Chamar console.log original
116
+ originalConsoleLog.apply(console, args);
117
+ };
118
+ console.info = (...args) => {
119
+ const message = args
120
+ .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))
121
+ .join(' ');
122
+ // ✅ Capturar todos os console.info
123
+ logsCapturados.push(`[${new Date().toISOString()}] INFO: ${message}`);
124
+ atualizarReferenciaGlobalDosLogs();
125
+ try {
126
+ const testInfo = TestContext.getSafeTestInfo();
127
+ if (testInfo?.title) {
128
+ UnifiedReportManager.adicionarLog(testInfo.title, `INFO: ${message}`);
129
+ }
130
+ }
131
+ catch {
132
+ // Ignorar erro
133
+ }
134
+ originalConsoleInfo.apply(console, args);
135
+ };
136
+ }
137
+ /**
138
+ * Classe unificada para configurar contextos de teste e integração com UnifiedReportManager.
139
+ * Permite configurar automaticamente o contexto do teste (API, Frontend, Mobile, SSH, Banco, Mixed),
140
+ * registrar logs, metadados, screenshots e garantir limpeza automática de sessões mobile.
141
+ *
142
+ * ✅ AGORA COM SISTEMA AUTOMÁTICO - Não precisa configurar nada manualmente!
143
+ */
144
+ export class TestAnnotations {
145
+ /**
146
+ * Opções do runner para testes desktop
147
+ * - attachWindow: se true, tentará iniciar/atacar uma janela da aplicação
148
+ * - closeWindow: se true, fechará a aplicação ao final do CT
149
+ * - app_path: caminho para o executável a ser iniciado
150
+ */
151
+ static runnerOptions = {};
152
+ /**
153
+ * Define opções do runner (attachWindow, closeWindow, app_path)
154
+ */
155
+ static async setRunnerOptions(options) {
156
+ this.runnerOptions = { ...(this.runnerOptions || {}), ...(options || {}) };
157
+ // Se attachWindow for true e app_path fornecido, tentar iniciar a app
158
+ try {
159
+ if (this.runnerOptions.attachWindow && this.runnerOptions.app_path) {
160
+ await DesktopConnection.startApp(this.runnerOptions.app_path);
161
+ }
162
+ }
163
+ catch (e) {
164
+ console.warn('⚠️ Falha ao iniciar aplicação via setRunnerOptions:', e);
165
+ }
166
+ }
167
+ /**
168
+ * ✅ REMOVIDO: inicializarAutoCore - Agora é automático!
169
+ * O sistema se inicializa sozinho quando o módulo é carregado.
170
+ */
171
+ /**
172
+ * 🛑 Ativa o modo "parar ao falhar" globalmente.
173
+ * Quando ativado, se um CT falhar, os próximos CTs não serão executados.
174
+ * Pode ser chamado no escopo do test.describe() para aplicar a todos os CTs do CN.
175
+ * @param enabled - true para ativar, false para desativar (padrão: true)
176
+ */
177
+ static stopOnFailure(enabled = true) {
178
+ stopOnFailureEnabled = enabled;
179
+ console.log(`🛑 [STOP-ON-FAILURE] ${enabled ? 'ATIVADO' : 'DESATIVADO'} globalmente`);
180
+ }
181
+ /**
182
+ * 🛑 Verifica se o modo "parar ao falhar" está ativo.
183
+ * @returns true se stopOnFailure está ativo
184
+ */
185
+ static isStopOnFailureEnabled() {
186
+ return stopOnFailureEnabled;
187
+ }
188
+ /**
189
+ * 🎯 NOVO: Captura CT diretamente do contexto do Playwright e registra automaticamente
190
+ */
191
+ static capturarCTDoPlaywright(cnName, ctName, testInfo) {
192
+ try {
193
+ // 🕐 NOVO: Capturar tempo de início para cálculo de duração
194
+ const ctStartTime = Date.now();
195
+ StatementTracker.startCT(ctName);
196
+ testInfo.__autocoreCtName = ctName;
197
+ testInfo.__autocoreCnName = cnName;
198
+ // Registrar relação CT ↔ CN para uso na finalização mesmo após troca de contexto
199
+ UnifiedReportManager.registrarCtParaCn(ctName, cnName);
200
+ // 2. Registrar que o CT foi detectado pelo Playwright
201
+ StatementTracker.recordAction('OTHER', `CT detectado pelo Playwright: ${ctName}`, true, undefined, {
202
+ method: 'Playwright Detection',
203
+ url: testInfo.file,
204
+ });
205
+ // 3. Configurar finalização automática quando o teste terminar
206
+ const originalAttach = testInfo.attach;
207
+ let ctFinalizado = false;
208
+ testInfo.attach = async function (name, options) {
209
+ // Interceptar attach para detectar fim do teste
210
+ const result = await originalAttach.call(this, name, options);
211
+ if (!ctFinalizado &&
212
+ (name.includes('screenshot') || name.includes('trace'))) {
213
+ // ⏱️ NOVO: Calcular duração real do teste
214
+ const ctEndTime = Date.now();
215
+ const ctDuration = ctEndTime - ctStartTime;
216
+ console.log(`⏱️ [DURAÇÃO] CT executado em ${ctDuration}ms`);
217
+ // Determinar status baseado no estado do teste
218
+ const success = testInfo.status === 'passed' || testInfo.status === undefined;
219
+ const errorMessage = testInfo.status === 'failed' ? 'Teste falhou' : undefined;
220
+ console.log(`🏁 [PLAYWRIGHT-CT] Status do teste: ${testInfo.status}`);
221
+ StatementTracker.endCT(ctName, success, errorMessage);
222
+ // Fechar app se configurado no runner
223
+ try {
224
+ if (TestAnnotations.runnerOptions?.closeWindow) {
225
+ await DesktopConnection.closeApp();
226
+ }
227
+ }
228
+ catch (e) {
229
+ console.warn('⚠️ Falha ao fechar app após CT:', e);
230
+ }
231
+ ctFinalizado = true;
232
+ }
233
+ return result;
234
+ };
235
+ // 4. Configurar timeout para finalizar CT caso não seja finalizado
236
+ setTimeout(() => {
237
+ if (!ctFinalizado) {
238
+ // ⏱️ NOVO: Calcular duração mesmo no timeout
239
+ const ctEndTime = Date.now();
240
+ const ctDuration = ctEndTime - ctStartTime;
241
+ console.log(`⏱️ [DURAÇÃO] CT executado em ${ctDuration}ms (timeout)`);
242
+ const success = testInfo.status === 'passed' || testInfo.status === undefined;
243
+ StatementTracker.endCT(ctName, success);
244
+ // Fechar app se configurado no runner (fire-and-forget)
245
+ try {
246
+ if (TestAnnotations.runnerOptions?.closeWindow) {
247
+ DesktopConnection.closeApp().catch(() => { });
248
+ }
249
+ }
250
+ catch { }
251
+ ctFinalizado = true;
252
+ }
253
+ }, 60_000); // 60 segundos
254
+ }
255
+ catch (error) {
256
+ console.error(`❌ [PLAYWRIGHT-CT] Erro ao capturar CT: ${error}`);
257
+ }
258
+ }
259
+ /**
260
+ * Detecta automaticamente o contexto principal do projeto a partir das variáveis de ambiente.
261
+ * @returns O tipo de contexto principal detectado.
262
+ */
263
+ static detectProjectContext() {
264
+ // 1. Verificar PROJECT_TYPE explícito
265
+ const projectType = process.env.PROJECT_TYPE?.toUpperCase();
266
+ if (projectType) {
267
+ switch (projectType) {
268
+ case 'API':
269
+ return 'API';
270
+ case 'FRONTEND':
271
+ case 'WEB':
272
+ return 'Frontend';
273
+ case 'MOBILE':
274
+ return 'Mobile';
275
+ case 'SSH':
276
+ return 'SSH';
277
+ case 'BANCO':
278
+ case 'DATABASE':
279
+ return 'Banco';
280
+ case 'SCENARIOS':
281
+ return 'Scenarios';
282
+ default:
283
+ return 'Mixed';
284
+ }
285
+ }
286
+ // 2. 🔍 NOVA DETECÇÃO: Baseada no contexto real executado
287
+ try {
288
+ // Verificar se tem page Playwright ativo
289
+ const testContextPage = TestContext._page;
290
+ if (testContextPage && typeof testContextPage.goto === 'function') {
291
+ return 'Frontend';
292
+ }
293
+ }
294
+ catch { }
295
+ try {
296
+ // Verificar se tem driver mobile ativo
297
+ const mobileDriver = TestContext.appiumDriver;
298
+ if (mobileDriver) {
299
+ return 'Mobile';
300
+ }
301
+ }
302
+ catch { }
303
+ // 3. Detecção baseada em variáveis de ambiente
304
+ if (process.env.PLAYWRIGHT_BROWSERS_PATH || process.env.PWDEBUG) {
305
+ return 'Frontend';
306
+ }
307
+ if (process.env.APPIUM_HOME || process.env.DEVICEFARM_API_KEY) {
308
+ return 'Mobile';
309
+ }
310
+ // 4. Fallback: detectar por estrutura de arquivos
311
+ const projectStructure = process.cwd();
312
+ if (projectStructure.includes('mobile') ||
313
+ projectStructure.includes('appium')) {
314
+ return 'Mobile';
315
+ }
316
+ if (projectStructure.includes('frontend') ||
317
+ projectStructure.includes('e2e') ||
318
+ projectStructure.includes('ui')) {
319
+ return 'Frontend';
320
+ }
321
+ if (projectStructure.includes('api') &&
322
+ !projectStructure.includes('frontend')) {
323
+ return 'API';
324
+ }
325
+ // 5. Default: Mixed para projetos indefinidos
326
+ return 'Mixed';
327
+ }
328
+ /**
329
+ * Configuração automática do contexto do teste.
330
+ * Detecta o contexto, configura interceptadores e registra logs/metadados.
331
+ */
332
+ static Auto = {
333
+ set testInfo(testInfo) {
334
+ // 🆕 CRÍTICO: Garantir que TestContext está disponível globalmente
335
+ // Especialmente importante para projetos consumidores
336
+ const TestContext = globalThis.__TEST_CONTEXT__;
337
+ if (TestContext &&
338
+ typeof TestContext.ensureGlobalAvailability === 'function') {
339
+ TestContext.ensureGlobalAvailability();
340
+ }
341
+ TestContext.setTestInfo(testInfo);
342
+ // ✅ CRÍTICO: Detectar CN e CT baseado na estrutura do titlePath
343
+ // titlePath[0] = filename ou describe principal
344
+ // titlePath[1] = describe (CN) ou test (CT) se só 2 níveis
345
+ // titlePath[2] = test (CT) se 3 níveis
346
+ let cnName;
347
+ let ctName;
348
+ if (testInfo.titlePath && testInfo.titlePath.length >= 3) {
349
+ // 🎯 ESTRUTURA: [filename, describe/CN, test/CT]
350
+ cnName = testInfo.titlePath[1];
351
+ ctName = testInfo.titlePath[2];
352
+ }
353
+ else if (testInfo.titlePath && testInfo.titlePath.length === 2) {
354
+ // 🎯 ESTRUTURA: [describe/CN, test/CT] - Caso do arquivo fornecido
355
+ cnName = testInfo.titlePath[0];
356
+ ctName = testInfo.titlePath[1];
357
+ }
358
+ else {
359
+ // 🎯 FALLBACK: usar title como CT
360
+ cnName = testInfo.title;
361
+ ctName = testInfo.title;
362
+ }
363
+ StatementTracker.setTestName(cnName);
364
+ console.log(`🏷️ [AUTO] StatementTracker inicializado para CN: "${cnName}"`);
365
+ console.log(`🎯 [AUTO] CT detectado do Playwright: "${ctName}"`);
366
+ // 🆕 CRÍTICO: Capturar e registrar CT automaticamente do contexto do Playwright
367
+ TestAnnotations.capturarCTDoPlaywright(cnName, ctName, testInfo);
368
+ // 🆕 INICIAR INTERCEPTAÇÃO DE LOGS ANTES DE TUDO
369
+ interceptarLogs();
370
+ // 1. Detectar contexto principal
371
+ const contextoPrincipal = TestAnnotations.detectProjectContext();
372
+ // 2. Detectar se é realmente mixed (múltiplos tipos necessários)
373
+ const isMixed = TestAnnotations.detectIfMixed();
374
+ const contextoFinal = isMixed ? 'Mixed' : contextoPrincipal;
375
+ testStartTimes.set(cnName, Date.now());
376
+ UnifiedReportManager.setTestContext(cnName, contextoFinal);
377
+ // 3. Configurar interceptadores inteligentemente
378
+ if (isMixed) {
379
+ TestAnnotations.setupAllInterceptors(cnName);
380
+ UnifiedReportManager.adicionarLog(cnName, '🔀 Contexto Mixed detectado - Múltiplos tipos habilitados');
381
+ }
382
+ else {
383
+ TestAnnotations.setupSpecificInterceptor(cnName, contextoPrincipal);
384
+ UnifiedReportManager.adicionarLog(cnName, `🤖 Contexto ${contextoPrincipal} detectado automaticamente`);
385
+ }
386
+ // 🆕 ESSENCIAL: Configurar interceptação de statements
387
+ TestAnnotations.setupStatementInterception(cnName);
388
+ TestAnnotations.setupTestFinalization(testInfo);
389
+ },
390
+ };
391
+ /**
392
+ * Detecta se o projeto é realmente mixed (múltiplos contextos).
393
+ * @returns true se for mixed, false caso contrário.
394
+ */
395
+ static detectIfMixed() {
396
+ const indicators = [
397
+ process.env.USE_MIXED === 'true',
398
+ process.env.PROJECT_TYPE?.toUpperCase() === 'MIXED',
399
+ process.env.PROJECT_TYPE?.toUpperCase() === 'SCENARIOS',
400
+ !!(process.env.BASE_URL && process.env.SSH_HOST),
401
+ !!(process.env.BASE_URL_APIGTW && process.env.DB_HOST),
402
+ process.cwd().includes('-scenarios') ||
403
+ process.cwd().includes('-cenarios'),
404
+ ];
405
+ return indicators.some((indicator) => indicator);
406
+ }
407
+ /**
408
+ * Configura interceptador seguro para um contexto específico.
409
+ * @param testName Nome do teste.
410
+ * @param contexto Contexto do teste.
411
+ */
412
+ static setupSpecificInterceptor(testName, contexto) {
413
+ switch (contexto) {
414
+ case 'API':
415
+ TestAnnotations.setupSafeInterceptor(testName, 'API', ApiActions.logEvent.bind(ApiActions), ApiActions, 'logEvent');
416
+ break;
417
+ case 'Banco':
418
+ TestAnnotations.setupSafeInterceptor(testName, 'BANCO', BancoActions.logEvent.bind(BancoActions), BancoActions, 'logEvent');
419
+ break;
420
+ case 'SSH':
421
+ TestAnnotations.setupSafeInterceptor(testName, 'SSH', SSHActions.logEvent.bind(SSHActions), SSHActions, 'logEvent');
422
+ break;
423
+ case 'Frontend':
424
+ case 'Mobile':
425
+ // Frontend e Mobile não precisam de interceptadores específicos
426
+ break;
427
+ }
428
+ }
429
+ /**
430
+ * Configura interceptadores para todos os contextos (usado em projetos mixed).
431
+ * @param testName Nome do teste.
432
+ */
433
+ static setupAllInterceptors(testName) {
434
+ TestAnnotations.setupSafeInterceptor(testName, 'API', ApiActions.logEvent.bind(ApiActions), ApiActions, 'logEvent');
435
+ TestAnnotations.setupSafeInterceptor(testName, 'SSH', SSHActions.logEvent.bind(SSHActions), SSHActions, 'logEvent');
436
+ TestAnnotations.setupSafeInterceptor(testName, 'BANCO', BancoActions.logEvent.bind(BancoActions), BancoActions, 'logEvent');
437
+ }
438
+ /**
439
+ * Configura finalização automática do teste para registrar duração.
440
+ * @param testInfo TestInfo do Playwright.
441
+ */
442
+ static setupTestFinalization(testInfo) {
443
+ const testName = testInfo.title;
444
+ // 🔧 NOVO: Detectar se é um test.describe (CN) ou test() (CT)
445
+ // Só configurar finalização para CTs individuais, NÃO para CNs
446
+ const titlePath = testInfo.titlePath || [];
447
+ const isIndividualTest = titlePath.length <= 2; // Arquivo + Test = 2 níveis
448
+ const isCTInsideDescribe = titlePath.length === 3; // Arquivo + Describe + Test = CT
449
+ // 🛡️ PROTEÇÃO: Não configurar finalização múltipla para CTs dentro de test.describe
450
+ // O CustomReporter já gerencia a finalização do CN completo
451
+ if (isCTInsideDescribe) {
452
+ return;
453
+ }
454
+ // ✅ NOVO: Interceptar erros não capturados para detectar falhas
455
+ const originalErrorHandler = process.listeners('uncaughtException');
456
+ const originalRejectionHandler = process.listeners('unhandledRejection');
457
+ const testFailureDetector = (error) => {
458
+ const errorMessage = error.message || error.toString();
459
+ if (errorMessage.includes(testName) ||
460
+ errorMessage.includes('AssertionError') ||
461
+ errorMessage.includes('expect')) {
462
+ console.log(`🔴 Falha detectada no teste ${testName}: ${errorMessage}`);
463
+ UnifiedReportManager.adicionarLog(testName, `❌ Erro capturado: ${errorMessage}`);
464
+ // Marcar teste como falhado imediatamente
465
+ UnifiedReportManager.marcarFimTeste(testName, 'failed').catch((e) => console.warn(`⚠️ Erro ao marcar teste como falhado: ${e}`));
466
+ }
467
+ };
468
+ // Adicionar listeners temporários para o teste atual
469
+ process.on('uncaughtException', testFailureDetector);
470
+ process.on('unhandledRejection', testFailureDetector);
471
+ // ✅ NOVO: Configurar monitoramento de status do teste
472
+ // ⚠️ PROTEÇÃO: Wrappear em try/catch para evitar unhandled rejections
473
+ // que podem marcar o teste como failed indevidamente
474
+ setTimeout(async () => {
475
+ try {
476
+ // Remover listeners temporários após finalização
477
+ process.removeListener('uncaughtException', testFailureDetector);
478
+ process.removeListener('unhandledRejection', testFailureDetector);
479
+ const startTime = testStartTimes.get(testName);
480
+ if (startTime) {
481
+ const duration = (Date.now() - startTime) / 1000;
482
+ UnifiedReportManager.setTestDuration(testName, duration);
483
+ try {
484
+ // Aguardar um pouco para permitir que o Playwright processe o status
485
+ await new Promise((resolve) => setTimeout(resolve, 200));
486
+ let testStatus = 'passed';
487
+ const playwrightStatus = testInfo.status;
488
+ if (playwrightStatus === 'failed' ||
489
+ playwrightStatus === 'timedOut' ||
490
+ playwrightStatus === 'interrupted') {
491
+ testStatus = 'failed';
492
+ }
493
+ else if (playwrightStatus === 'skipped') {
494
+ testStatus = 'skipped';
495
+ }
496
+ else if (playwrightStatus === 'passed') {
497
+ testStatus = 'passed';
498
+ }
499
+ if (testInfo.errors && testInfo.errors.length > 0) {
500
+ testStatus = 'failed';
501
+ }
502
+ // Fallback: analisar logs apenas se ainda não detectamos falha
503
+ if (testStatus === 'passed' && TestContext.getSafeTestInfo()) {
504
+ const currentTestInfo = TestContext.getSafeTestInfo();
505
+ if (currentTestInfo && currentTestInfo.title === testName) {
506
+ const logs = UnifiedReportManager.getTestLogs(testName);
507
+ const hasErrorLogs = logs.some((log) => log.includes('❌') ||
508
+ log.includes('FAILED') ||
509
+ log.includes('erro') ||
510
+ log.includes('falhou') ||
511
+ log.includes('Error') ||
512
+ log.includes('AssertionError'));
513
+ if (hasErrorLogs) {
514
+ testStatus = 'failed';
515
+ }
516
+ }
517
+ }
518
+ const detectedCnName = testInfo.__autocoreCnName ||
519
+ testInfo.titlePath?.[1] ||
520
+ testName;
521
+ const detectedCtName = testInfo.__autocoreCtName ||
522
+ testInfo.titlePath?.[2] ||
523
+ testInfo.title;
524
+ const errorDetails = testStatus === 'failed'
525
+ ? testInfo.errors?.[0]?.message ||
526
+ testInfo.error?.message ||
527
+ 'Playwright test failed'
528
+ : undefined;
529
+ if (detectedCtName) {
530
+ try {
531
+ const executions = StatementTracker.getExecutions();
532
+ const testEntry = executions.get(detectedCnName);
533
+ const runningCT = testEntry?.cts.find((ct) => ct.name === detectedCtName && ct.status === 'running');
534
+ if (runningCT) {
535
+ StatementTracker.endCT(detectedCtName, testStatus !== 'failed', errorDetails);
536
+ }
537
+ }
538
+ catch (trackerError) {
539
+ console.warn(`⚠️ [PLAYWRIGHT-CT] Erro ao finalizar CT ${detectedCtName}:`, trackerError);
540
+ }
541
+ }
542
+ console.log(`🔍 Status detectado para ${testName}: ${testStatus}`);
543
+ await UnifiedReportManager.marcarFimTeste(testName, testStatus, {
544
+ cnName: detectedCnName,
545
+ ctName: detectedCtName,
546
+ errorMessage: errorDetails,
547
+ });
548
+ }
549
+ catch (error) {
550
+ console.warn(`⚠️ Erro ao detectar status do teste ${testName}:`, error);
551
+ await UnifiedReportManager.marcarFimTeste(testName, 'passed', {
552
+ cnName: testInfo.__autocoreCnName ||
553
+ testInfo.titlePath?.[1] ||
554
+ testName,
555
+ ctName: testInfo.__autocoreCtName ||
556
+ testInfo.titlePath?.[2] ||
557
+ testInfo.title,
558
+ });
559
+ }
560
+ await TestAnnotations.finalizeCoverageForTest(testName, testInfo, duration * 1000);
561
+ testStartTimes.delete(testName);
562
+ }
563
+ }
564
+ catch (fatalError) {
565
+ // ⚠️ PROTEÇÃO: Capturar qualquer erro para evitar unhandled rejection
566
+ // que pode marcar o teste como failed indevidamente
567
+ console.warn(`⚠️ [setupTestFinalization] Erro não-fatal durante finalização de "${testName}":`, fatalError);
568
+ }
569
+ }, 100);
570
+ }
571
+ /**
572
+ * ✅ NOVO: Configura cobertura automática para teste Frontend
573
+ * @param testInfo TestInfo do Playwright
574
+ */
575
+ static setupFrontendCoverage(testInfo) {
576
+ const testName = testInfo.title;
577
+ // Aguardar um pouco para página estar disponível
578
+ setTimeout(async () => {
579
+ try {
580
+ // ✅ VERIFICAR SE TESTCONTEXT.PAGE ESTÁ DISPONÍVEL
581
+ if (!TestContext.isPageInitialized()) {
582
+ console.warn(`TestContext.page não está inicializado para ${testName}, pulando cobertura frontend`);
583
+ return;
584
+ }
585
+ const currentPage = TestContext.page;
586
+ if (currentPage && currentPage.coverage) {
587
+ await CoverageManager.startFrontendCoverage(currentPage, testName);
588
+ }
589
+ }
590
+ catch (error) {
591
+ console.warn(`Erro ao configurar cobertura para ${testName}:`, error);
592
+ }
593
+ }, 200);
594
+ }
595
+ /**
596
+ * ✅ NOVO: Finaliza e registra cobertura para um teste
597
+ * @param testName Nome do teste
598
+ * @param testInfo TestInfo do teste
599
+ * @param duration Duração do teste em ms
600
+ */
601
+ static async finalizeCoverageForTest(testName, testInfo, duration) {
602
+ try {
603
+ // 🎯 FINALIZAR CT ATIVO ANTES DE TERMINAR O TESTE
604
+ TestAnnotations.finalizarCTAtivo();
605
+ // Determinar tipo do teste baseado no contexto
606
+ const metrics = UnifiedReportManager.getMetrics();
607
+ const contextType = metrics.testes.find((t) => t.nome === testName)?.tipo || 'Frontend';
608
+ // Obter página se disponível
609
+ let currentPage;
610
+ try {
611
+ currentPage = TestContext.page;
612
+ }
613
+ catch {
614
+ // Página não disponível
615
+ }
616
+ // Registrar cobertura
617
+ await CoverageManager.registerTestCoverage(testName, contextType, currentPage, duration);
618
+ }
619
+ catch (error) {
620
+ console.warn(`Erro ao finalizar cobertura para ${testName}:`, error);
621
+ }
622
+ }
623
+ /**
624
+ * 🆕 Configura interceptação automática de todas as classes Statements
625
+ */
626
+ static setupStatementInterception(testName) {
627
+ try {
628
+ // 1. 🚨 INTERCEPTAÇÃO IMEDIATA - Antes de tudo!
629
+ TestAnnotations.setupImmediateInterception();
630
+ // 2. Configurar interceptação global
631
+ // StatementTracker não precisa setupGlobalInterception
632
+ // 3. Registrar o teste no sistema
633
+ UnifiedReportManager.registrarTeste(testName, 'API');
634
+ // 4. 🚀 DETECTAR AUTOMATICAMENTE classes Statement do projeto
635
+ const detectedStatements = TestAnnotations.detectStatementClassesFromCallStack();
636
+ if (detectedStatements.length > 0) {
637
+ detectedStatements.forEach((className, index) => {
638
+ console.log(` ${index + 1}. ${className}`);
639
+ });
640
+ console.log('');
641
+ // 🔥 INTERCEPTAÇÃO FORÇADA IMEDIATA para projeto real
642
+ TestAnnotations.forceInterceptRealProjectStatements(detectedStatements);
643
+ }
644
+ else {
645
+ // 🚫 NÃO usar fallback hardcoded - confiar na interceptação universal
646
+ }
647
+ // 5. Interceptar constructor global para capturar instanciações
648
+ TestAnnotations.setupConstructorInterception(detectedStatements);
649
+ // 6. 🚨 INTERCEPTAÇÃO UNIVERSAL MAIS AGRESSIVA
650
+ TestAnnotations.setupUniversalStatementInterception();
651
+ // TestAnnotations.setupRealTimeMethodInterception() // DESABILITADO - causa stack overflow
652
+ // 7. Métodos legacy para compatibilidade
653
+ try {
654
+ interceptAllStatements();
655
+ // Interceptação agora é automática via StatementTracker
656
+ // setupModuleInterception()
657
+ // StatementTracker não precisa autoDetectStatements
658
+ }
659
+ catch (legacyError) {
660
+ console.warn(`⚠️ Aviso: Métodos legacy falharam: ${legacyError}`);
661
+ }
662
+ }
663
+ catch (error) {
664
+ console.error(`❌ Erro ao configurar interceptação de Statements: ${error}`);
665
+ }
666
+ }
667
+ /**
668
+ * 🚨 Interceptação imediata - Configurada ANTES de qualquer import
669
+ */
670
+ static setupImmediateInterception() {
671
+ try {
672
+ // 🔥 Interceptar console.info para capturar quando statements são executados
673
+ const originalConsoleInfo = console.info;
674
+ console.info = (...args) => {
675
+ const message = args.join(' ');
676
+ // 🎯 Capturar APENAS métodos que realmente são Statement execution
677
+ if (message.includes('Executando o método:')) {
678
+ // 🔍 FILTRO RIGOROSO: Verificar se realmente é de classe Statement
679
+ const methodMatches = message.match(/Executando o método:\s*(\w+)/i);
680
+ if (methodMatches && methodMatches[1]) {
681
+ const methodName = methodMatches[1];
682
+ // Só interceptar métodos típicos de Statement classes
683
+ const validStatementMethods = [
684
+ 'getToken',
685
+ 'get_token',
686
+ 'token',
687
+ 'auth',
688
+ 'authenticate',
689
+ 'consulta',
690
+ 'consultaEndereco',
691
+ 'consultaCobertura',
692
+ 'validar',
693
+ 'validarCNPJ',
694
+ 'criarCliente',
695
+ 'createContact',
696
+ 'create',
697
+ 'post',
698
+ 'put',
699
+ 'delete',
700
+ 'request',
701
+ ];
702
+ const isValidStatementMethod = validStatementMethods.some((valid) => methodName.toLowerCase().includes(valid.toLowerCase()));
703
+ if (isValidStatementMethod) {
704
+ originalConsoleInfo('📋 === CT EM EXECUÇÃO === [INTERCEPTADO!]');
705
+ originalConsoleInfo(` 🎯 Método Statement interceptado: ${message}`);
706
+ originalConsoleInfo(` ⏰ [${new Date().toISOString()}] Execução detectada`);
707
+ originalConsoleInfo(' 📊 Status: INTERCEPTADO COM SUCESSO');
708
+ }
709
+ }
710
+ }
711
+ // 🚫 REMOVIDO: Detecção hardcoded - usar apenas métodos dinâmicos
712
+ // Removido fallback com métodos específicos hardcoded
713
+ // Sistema agora só intercepta quando detecta padrões reais de Statement execution
714
+ return originalConsoleInfo.apply(console, args);
715
+ };
716
+ // 🔥 Interceptar também console.log padrão - COM PROTEÇÃO ANTI-LOOP
717
+ const originalConsoleLog = console.log;
718
+ const intercepting = false; // Flag para evitar recursão
719
+ const detectedSteps = new Set(); // Cache para evitar repetições
720
+ console.log = function (...args) {
721
+ const message = args.join(' ');
722
+ // 🚨 PROTEÇÃO ANTI-LOOP: Se já estamos interceptando, apenas execute o original
723
+ if (intercepting) {
724
+ return originalConsoleLog.apply(console, args);
725
+ }
726
+ // 🚀 DETECTAR EXECUÇÃO DE MÉTODOS CT
727
+ if (message.includes('Executando o método:')) {
728
+ const methodMatch = message.match(/Executando o método:\s*(.+)/);
729
+ if (methodMatch) {
730
+ const methodName = methodMatch[1].trim();
731
+ // ✅ DETECTAR CLASSE STATEMENT DO STACK TRACE
732
+ let className = 'Statement';
733
+ try {
734
+ const stack = new Error().stack || '';
735
+ // Procurar por "Statements<Nome>" no stack
736
+ const stackMatch = stack.match(/Statements(\w+)\.(\w+)/);
737
+ if (stackMatch) {
738
+ className = `Statements${stackMatch[1]}`;
739
+ }
740
+ }
741
+ catch {
742
+ // Ignorar erro, usar className padrão
743
+ }
744
+ // ✅ CORREÇÃO: Usar novo sistema de Statements
745
+ StatementTracker.ensureCTCreated();
746
+ StatementTracker.startStatement(className, methodName);
747
+ // ❌ REMOVIDO: handleMethodExecution causava logs duplicados
748
+ // O log já é feito pelo StatementTracker
749
+ }
750
+ }
751
+ // ✅ DETECTAR FINALIZAÇÃO DE STATEMENT COM SUCESSO
752
+ if (message.includes('[ STEP ]') &&
753
+ message.includes('[ PASSED ]') &&
754
+ !message.includes('Validação do status') &&
755
+ !message.includes('Validação')) {
756
+ const stepMatch = message.match(/\[\s*STEP\s*\]\s*(.+?)\s*\[\s*PASSED\s*\]/);
757
+ if (stepMatch) {
758
+ const stepName = stepMatch[1].trim();
759
+ StatementTracker.finishStatement(Date.now(), true);
760
+ }
761
+ }
762
+ // ❌ DETECTAR FINALIZAÇÃO DE STATEMENT COM ERRO
763
+ if (message.includes('[ STEP ]') && message.includes('[ FAILED ]')) {
764
+ const stepMatch = message.match(/\[\s*STEP\s*\]\s*(.+?)\s*\[\s*FAILED\s*\]/);
765
+ if (stepMatch) {
766
+ const stepName = stepMatch[1].trim();
767
+ // ❌ REMOVIDO: Log duplicado - já aparece no [ STEP ] [ FAILED ]
768
+ StatementTracker.finishStatement(Date.now(), false, stepName);
769
+ }
770
+ }
771
+ // � DETECTAR ERROS DE VALIDAÇÃO - NOVO!
772
+ if ((message.includes('❌ Validação falhou:') ||
773
+ message.includes('Validação falhou:')) &&
774
+ !message.includes('ERRO DE VALIDAÇÃO DETECTADO') &&
775
+ !message.includes('CT FALHOU:') &&
776
+ !this._processingError) {
777
+ TestAnnotations.handleValidationError(message);
778
+ }
779
+ // �📡 DETECTAR INÍCIO DE REQUESTS
780
+ if (message.includes('🔄 Executando POST:') ||
781
+ message.includes('🔄 Executando GET:')) {
782
+ // ❌ REMOVIDO: Log duplicado de "NOVA REQUEST INICIADA"
783
+ // O log já aparece no ApiActions quando a requisição é feita
784
+ }
785
+ // 🎯 FILTRO ULTRA-RIGOROSO: APENAS logs que realmente indicam execução de CT
786
+ if (message.includes('STEP') &&
787
+ (message.includes('PASSED') || message.includes('FAILED'))) {
788
+ // � PRIMEIRA VERIFICAÇÃO: EXCLUIR validações genéricas que não são CTs
789
+ const isGenericValidation = message.includes('Validação do status') ||
790
+ message.includes('Validação da resposta') ||
791
+ message.includes('Validação de status') ||
792
+ message.includes('Validação de') ||
793
+ message.includes('Validação') ||
794
+ message.includes('Validation of') ||
795
+ message.includes('Validation') ||
796
+ message.includes('Assert') ||
797
+ message.includes('Expect') ||
798
+ message.includes('Check') ||
799
+ message.includes('Verify') ||
800
+ message.includes('status code') ||
801
+ message.includes('response validation') ||
802
+ message.includes('campo obrigatório') ||
803
+ message.includes('campo') ||
804
+ message.includes('Schema') ||
805
+ message.includes('Assertion');
806
+ // 🔍 SEGUNDA VERIFICAÇÃO: Só permitir se realmente é de uma requisição/ação Statement
807
+ const isValidStatementStep = message.includes('Requisição Token') ||
808
+ message.includes('Requisição de') ||
809
+ message.includes('Request Token') ||
810
+ message.includes('Request') ||
811
+ message.includes('POST') ||
812
+ message.includes('GET') ||
813
+ message.includes('PUT') ||
814
+ message.includes('DELETE') ||
815
+ message.includes('Token FTTH') ||
816
+ message.includes('Massa SFA') ||
817
+ message.includes('Auth') ||
818
+ message.includes('API Call') ||
819
+ message.includes('Service Call');
820
+ // ✅ SÓ INTERCEPTAR se é Statement válido E NÃO é validação genérica
821
+ if (isValidStatementStep && !isGenericValidation) {
822
+ const stepHash = message.substring(0, 100); // Usar primeiros 100 chars como hash
823
+ }
824
+ }
825
+ return originalConsoleLog.apply(console, args);
826
+ };
827
+ }
828
+ catch (error) {
829
+ console.warn(`⚠️ [IMEDIATO] Erro na interceptação imediata: ${error}`);
830
+ }
831
+ }
832
+ /**
833
+ * 🔥 Interceptação em tempo real de métodos Statement
834
+ */
835
+ static setupRealTimeMethodInterception() {
836
+ try {
837
+ console.log('🔥 === INTERCEPTAÇÃO EM TEMPO REAL ===');
838
+ // 🎯 Interceptar QUALQUER chamada de método que contenha padrões Statement
839
+ const originalApply = Function.prototype.apply;
840
+ const originalCall = Function.prototype.call;
841
+ Function.prototype.apply = function (thisArg, argsArray) {
842
+ // Verificar se é um método de classe Statement
843
+ if (thisArg &&
844
+ thisArg.constructor &&
845
+ thisArg.constructor.name.includes('Statement')) {
846
+ const className = thisArg.constructor.name;
847
+ const methodName = this.name || 'método_desconhecido';
848
+ console.log(`📋 === CT EM EXECUÇÃO === ${className}.${methodName}()`);
849
+ console.log(` 🎯 [TEMPO REAL] Detectada execução: ${className}.${methodName}()`);
850
+ console.log(` ⏰ [${new Date().toISOString()}] Iniciando execução...`);
851
+ // Executar com tracking
852
+ const startTime = Date.now();
853
+ try {
854
+ const result = originalApply.call(this, thisArg, argsArray);
855
+ const duration = Date.now() - startTime;
856
+ console.log(` ✅ [${new Date().toISOString()}] Finalizada: ${className}.${methodName}() - ${duration}ms`);
857
+ console.log('📋 === CT FINALIZADA ===');
858
+ return result;
859
+ }
860
+ catch (error) {
861
+ const duration = Date.now() - startTime;
862
+ console.log(` ❌ [${new Date().toISOString()}] Erro: ${className}.${methodName}() - ${duration}ms`);
863
+ console.log('📋 === CT COM ERRO ===');
864
+ throw error;
865
+ }
866
+ }
867
+ return originalApply.call(this, thisArg, argsArray);
868
+ };
869
+ Function.prototype.call = function (thisArg, ...args) {
870
+ // Verificar se é um método de classe Statement
871
+ if (thisArg &&
872
+ thisArg.constructor &&
873
+ thisArg.constructor.name.includes('Statement')) {
874
+ const className = thisArg.constructor.name;
875
+ const methodName = this.name || 'método_desconhecido';
876
+ console.log(`📋 === CT EM EXECUÇÃO === ${className}.${methodName}()`);
877
+ console.log(` 🎯 [TEMPO REAL] Detectada execução: ${className}.${methodName}()`);
878
+ console.log(` ⏰ [${new Date().toISOString()}] Iniciando execução...`);
879
+ // Executar com tracking
880
+ const startTime = Date.now();
881
+ try {
882
+ const result = originalCall.call(this, thisArg, ...args);
883
+ const duration = Date.now() - startTime;
884
+ console.log(` ✅ [${new Date().toISOString()}] Finalizada: ${className}.${methodName}() - ${duration}ms`);
885
+ console.log('📋 === CT FINALIZADA ===');
886
+ return result;
887
+ }
888
+ catch (error) {
889
+ const duration = Date.now() - startTime;
890
+ console.log(` ❌ [${new Date().toISOString()}] Erro: ${className}.${methodName}() - ${duration}ms`);
891
+ console.log('📋 === CT COM ERRO ===');
892
+ throw error;
893
+ }
894
+ }
895
+ return originalCall.call(this, thisArg, ...args);
896
+ };
897
+ console.log('🔧 [TEMPO REAL] Interceptação de métodos configurada');
898
+ }
899
+ catch (error) {
900
+ console.warn(`⚠️ [TEMPO REAL] Erro na interceptação: ${error}`);
901
+ }
902
+ }
903
+ /**
904
+ * 🆕 Intercepta constructors de classes Statement para capturar instanciações
905
+ */
906
+ static setupConstructorInterception(statementClasses) {
907
+ try {
908
+ // Interceptar contexto global para capturar imports/instanciações
909
+ const contexts = [globalThis];
910
+ // Adicionar outros contextos se disponíveis
911
+ try {
912
+ const windowObj = globalThis.window;
913
+ if (windowObj)
914
+ contexts.push(windowObj);
915
+ const globalObj = globalThis.global;
916
+ if (globalObj)
917
+ contexts.push(globalObj);
918
+ }
919
+ catch {
920
+ // Ignorar se não disponíveis
921
+ }
922
+ for (const context of contexts) {
923
+ for (const className of statementClasses) {
924
+ try {
925
+ // Verificar se a classe existe no contexto
926
+ const OriginalClass = context[className];
927
+ if (typeof OriginalClass === 'function') {
928
+ console.log(`🔍 Encontrada classe: ${className} - preparando interceptação`);
929
+ // Criar versão interceptada
930
+ const InterceptedClass = StatementTracker.interceptStatement(OriginalClass);
931
+ // Substituir no contexto
932
+ context[className] = InterceptedClass;
933
+ console.log(`✅ Classe ${className} interceptada com sucesso`);
934
+ }
935
+ }
936
+ catch (error) {
937
+ // Ignorar erros individuais de classes
938
+ console.warn(`⚠️ Erro ao interceptar ${className}: ${error}`);
939
+ }
940
+ }
941
+ }
942
+ // Interceptação dinâmica usando Proxy para capturar instanciações futuras
943
+ TestAnnotations.setupDynamicInterception(statementClasses);
944
+ }
945
+ catch (error) {
946
+ console.error(`❌ Erro na interceptação de constructors: ${error}`);
947
+ }
948
+ }
949
+ /**
950
+ * 🚀 Detecta automaticamente classes Statement via análise de arquivo .spec.ts
951
+ */
952
+ static detectStatementClassesFromCallStack() {
953
+ const detectedClasses = new Set();
954
+ try {
955
+ const testInfo = TestContext.getSafeTestInfo();
956
+ if (testInfo?.file) {
957
+ const testFile = testInfo.file;
958
+ console.log(`📁 Arquivo de teste detectado: ${testFile}`);
959
+ // 🎯 NOVA ABORDAGEM: Análise robusta do arquivo .spec.ts
960
+ const newClasses = TestAnnotations.detectStatementClassesFromSpecFile(testFile);
961
+ newClasses.forEach((cls) => detectedClasses.add(cls));
962
+ }
963
+ // 🔄 Fallback: Analisar contexto global - APENAS se realmente necessário
964
+ if (detectedClasses.size === 0) {
965
+ TestAnnotations.detectStatementClassesFromGlobal(detectedClasses);
966
+ }
967
+ }
968
+ catch (error) {
969
+ console.warn(`⚠️ Erro ao detectar classes Statement: ${error}`);
970
+ }
971
+ const classArray = Array.from(detectedClasses);
972
+ return classArray;
973
+ }
974
+ /**
975
+ * 🎯 Detecta classes Statement de um arquivo .spec.ts específico
976
+ */
977
+ static detectStatementClassesFromSpecFile(testFile) {
978
+ const detectedClasses = new Set();
979
+ try {
980
+ // 🔄 COMPATÍVEL COM ESM: Usar dynamic imports
981
+ const fs = globalThis.require?.('fs') ||
982
+ globalThis.fs ||
983
+ TestAnnotations.getFileSystemModule();
984
+ if (!fs) {
985
+ return TestAnnotations.detectStatementClassesFromTestContext();
986
+ }
987
+ const path = globalThis.require?.('path') ||
988
+ globalThis.path ||
989
+ TestAnnotations.getPathModule();
990
+ // 📂 Tentar diferentes caminhos para encontrar o arquivo
991
+ const possiblePaths = [
992
+ testFile,
993
+ testFile.replace('C:\\Users\\A0169497\\PlayWright\\comp-autocore-v1\\', './'),
994
+ './tests/' + testFile.split('\\').pop(),
995
+ './test/' + testFile.split('\\').pop(),
996
+ './' + testFile.split('\\').pop(),
997
+ ];
998
+ let content = '';
999
+ for (const filePath of possiblePaths) {
1000
+ try {
1001
+ if (fs.existsSync && fs.existsSync(filePath)) {
1002
+ content = fs.readFileSync(filePath, 'utf-8');
1003
+ console.log(`📖 Analisando arquivo: ${filePath}`);
1004
+ break;
1005
+ }
1006
+ }
1007
+ catch (fileError) {
1008
+ // Continua tentando outros caminhos
1009
+ }
1010
+ }
1011
+ if (!content) {
1012
+ console.warn(`⚠️ Não foi possível ler o arquivo de teste: ${testFile}`);
1013
+ console.log('🔄 Aguardando detecção dinâmica durante execução...');
1014
+ // � REMOVIDO: Fallback hardcoded - retornar vazio para forçar detecção real
1015
+ return [];
1016
+ }
1017
+ // 🔍 PADRÕES DE DETECÇÃO ROBUSTOS
1018
+ // 1. Exports da própria classe: export class StatementsToken
1019
+ const exportClassRegex = /export\s+class\s+(\w*Statement\w*)/g;
1020
+ let exportMatch;
1021
+ while ((exportMatch = exportClassRegex.exec(content)) !== null) {
1022
+ if (exportMatch[1]) {
1023
+ detectedClasses.add(exportMatch[1]);
1024
+ console.log(`🎯 Classe Statement encontrada via export: ${exportMatch[1]}`);
1025
+ }
1026
+ }
1027
+ // 2. Imports diretos: import { StatementsToken } from "..."
1028
+ const importDirectRegex = /import\s*{\s*([^}]*)\s*}\s*from\s*['"]/g;
1029
+ let importMatch;
1030
+ while ((importMatch = importDirectRegex.exec(content)) !== null) {
1031
+ const importedItems = importMatch[1].split(',');
1032
+ importedItems.forEach((item) => {
1033
+ const cleanItem = item.trim();
1034
+ if (cleanItem.includes('Statement') ||
1035
+ cleanItem.startsWith('Statements')) {
1036
+ detectedClasses.add(cleanItem);
1037
+ console.log(`🎯 Classe Statement encontrada via import: ${cleanItem}`);
1038
+ }
1039
+ });
1040
+ }
1041
+ // 3. Instanciações: new StatementsToken(), new StatementsConsultaEndereco()
1042
+ const newStatementRegex = /new\s+(\w*Statement\w*)\s*\(/g;
1043
+ let newMatch;
1044
+ while ((newMatch = newStatementRegex.exec(content)) !== null) {
1045
+ if (newMatch[1]) {
1046
+ detectedClasses.add(newMatch[1]);
1047
+ console.log(`🎯 Classe Statement encontrada via new: ${newMatch[1]}`);
1048
+ }
1049
+ }
1050
+ // 4. Await new: await new StatementsToken()
1051
+ const awaitNewRegex = /await\s+new\s+(\w*Statement\w*)\s*\(/g;
1052
+ let awaitMatch;
1053
+ while ((awaitMatch = awaitNewRegex.exec(content)) !== null) {
1054
+ if (awaitMatch[1]) {
1055
+ detectedClasses.add(awaitMatch[1]);
1056
+ console.log(`🎯 Classe Statement encontrada via await new: ${awaitMatch[1]}`);
1057
+ }
1058
+ }
1059
+ }
1060
+ catch (error) {
1061
+ console.warn(`⚠️ Erro ao analisar arquivo .spec.ts: ${error}`);
1062
+ // 🚫 REMOVIDO: Fallback - retornar vazio para forçar detecção real
1063
+ return [];
1064
+ }
1065
+ return Array.from(detectedClasses);
1066
+ }
1067
+ /**
1068
+ * 🌐 Interceptar classes Statement disponíveis no globalThis
1069
+ */
1070
+ static interceptGlobalStatements() {
1071
+ try {
1072
+ console.log('🔍 [Global] Procurando classes Statement no globalThis...');
1073
+ const globalObj = globalThis;
1074
+ const foundClasses = [];
1075
+ // Procurar no globalThis por classes que seguem padrões Statement
1076
+ for (const key in globalObj) {
1077
+ try {
1078
+ const value = globalObj[key];
1079
+ if (typeof value === 'function' && value.prototype) {
1080
+ const className = value.name || key;
1081
+ // Detectar padrões de Statement
1082
+ const isStatementClass = className &&
1083
+ (className.startsWith('Statements') ||
1084
+ className.includes('Statement') ||
1085
+ className.endsWith('Statement') ||
1086
+ className.match(/^\w*Statements?\w*$/));
1087
+ if (isStatementClass) {
1088
+ console.log(`🎯 [Global] Classe Statement encontrada: ${className}`);
1089
+ foundClasses.push(className);
1090
+ // Interceptar a classe diretamente
1091
+ try {
1092
+ const InterceptedClass = StatementTracker.interceptStatement(value);
1093
+ globalObj[key] = InterceptedClass;
1094
+ console.log(`✅ [Global] ${className} interceptado com sucesso`);
1095
+ }
1096
+ catch (error) {
1097
+ console.warn(`⚠️ [Global] Erro ao interceptar ${className}:`, error);
1098
+ }
1099
+ }
1100
+ }
1101
+ }
1102
+ catch (error) {
1103
+ // Ignorar erros individuais
1104
+ }
1105
+ }
1106
+ console.log(`🎯 [Global] ${foundClasses.length} classes Statement interceptadas: ${foundClasses.join(', ')}`);
1107
+ // ✅ NOVO: Interceptar construtores dinamicamente usando Proxy
1108
+ TestAnnotations.setupDynamicConstructorInterception();
1109
+ }
1110
+ catch (error) {
1111
+ console.warn('⚠️ [Global] Erro na interceptação global:', error);
1112
+ }
1113
+ }
1114
+ /**
1115
+ * ✨ NOVO: Interceptação dinâmica de construtores Statement
1116
+ */
1117
+ static setupDynamicConstructorInterception() {
1118
+ try {
1119
+ console.log('🪄 [Dynamic] Configurando interceptação dinâmica de construtores...');
1120
+ // 🎯 Interceptar Function.prototype.constructor para capturar 'new'
1121
+ const originalConstructor = Function.prototype.constructor;
1122
+ // 🎁 Interceptar criação de instâncias via Proxy no globalThis
1123
+ const originalGlobalDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Function');
1124
+ if (originalGlobalDescriptor) {
1125
+ Object.defineProperty(globalThis, 'Function', {
1126
+ value: new Proxy(Function, {
1127
+ construct(target, args, newTarget) {
1128
+ const instance = Reflect.construct(target, args, newTarget);
1129
+ // Se a função criada é uma classe Statement, interceptar
1130
+ if (typeof instance === 'function' &&
1131
+ instance.name &&
1132
+ (instance.name.includes('Statement') ||
1133
+ instance.name.includes('Statements'))) {
1134
+ console.log(`🪄 [Dynamic] Interceptando construtor Statement: ${instance.name}`);
1135
+ return StatementTracker.interceptStatement(instance);
1136
+ }
1137
+ return instance;
1138
+ },
1139
+ }),
1140
+ configurable: true,
1141
+ writable: true,
1142
+ });
1143
+ }
1144
+ console.log('✅ [Dynamic] Interceptação dinâmica ativada');
1145
+ }
1146
+ catch (error) {
1147
+ console.warn('⚠️ [Dynamic] Erro na interceptação dinâmica:', error);
1148
+ }
1149
+ }
1150
+ /**
1151
+ * ✨ NOVO: Interceptar classes Statement já importadas nos módulos
1152
+ */
1153
+ static interceptImportedStatements() {
1154
+ try {
1155
+ console.log('🔍 [ImportedStatements] Procurando classes Statement importadas...');
1156
+ // 1️⃣ ESTRATÉGIA: Interceptar via require.cache (Node.js modules)
1157
+ if (typeof require !== 'undefined' && require.cache) {
1158
+ const moduleIds = Object.keys(require.cache);
1159
+ console.log(`🔍 [ImportedStatements] Analisando ${moduleIds.length} módulos carregados...`);
1160
+ for (const moduleId of moduleIds) {
1161
+ try {
1162
+ // Verificar se o módulo contém "Statement" no caminho
1163
+ if (moduleId.includes('Statement') ||
1164
+ moduleId.includes('statements')) {
1165
+ console.log(`🎯 [ImportedStatements] Módulo Statement encontrado: ${moduleId}`);
1166
+ const moduleExports = require.cache[moduleId]?.exports;
1167
+ if (moduleExports && typeof moduleExports === 'object') {
1168
+ // Procurar por classes exportadas
1169
+ for (const [exportName, exportValue] of Object.entries(moduleExports)) {
1170
+ if (typeof exportValue === 'function' &&
1171
+ exportName.includes('Statement') &&
1172
+ exportValue.prototype) {
1173
+ console.log(`🎯 [ImportedStatements] Classe Statement importada: ${exportName}`);
1174
+ // Interceptar a classe diretamente
1175
+ try {
1176
+ const InterceptedClass = StatementTracker.interceptStatement(exportValue);
1177
+ moduleExports[exportName] = InterceptedClass;
1178
+ console.log(`✅ [ImportedStatements] ${exportName} interceptado com sucesso!`);
1179
+ }
1180
+ catch (error) {
1181
+ console.warn(`⚠️ [ImportedStatements] Erro ao interceptar ${exportName}:`, error);
1182
+ }
1183
+ }
1184
+ }
1185
+ }
1186
+ }
1187
+ }
1188
+ catch (error) {
1189
+ // Ignorar erros individuais de módulos
1190
+ }
1191
+ }
1192
+ }
1193
+ // 2️⃣ ESTRATÉGIA: Interceptar via globalThis (ES modules)
1194
+ const globalObj = globalThis;
1195
+ for (const key in globalObj) {
1196
+ try {
1197
+ const value = globalObj[key];
1198
+ if (typeof value === 'function' &&
1199
+ value.prototype &&
1200
+ key.includes('Statement')) {
1201
+ console.log(`🎯 [ImportedStatements] Statement global: ${key}`);
1202
+ try {
1203
+ const InterceptedClass = StatementTracker.interceptStatement(value);
1204
+ globalObj[key] = InterceptedClass;
1205
+ console.log(`✅ [ImportedStatements] ${key} interceptado globalmente!`);
1206
+ }
1207
+ catch (error) {
1208
+ console.warn(`⚠️ [ImportedStatements] Erro ao interceptar global ${key}:`, error);
1209
+ }
1210
+ }
1211
+ }
1212
+ catch (error) {
1213
+ // Ignorar erros
1214
+ }
1215
+ }
1216
+ console.log('✅ [ImportedStatements] Interceptação de módulos importados concluída');
1217
+ }
1218
+ catch (error) {
1219
+ console.warn('⚠️ [ImportedStatements] Erro na interceptação de módulos:', error);
1220
+ }
1221
+ }
1222
+ /**
1223
+ * 🔄 Detecta classes Statement do contexto atual do teste (fallback ESM)
1224
+ */
1225
+ static detectStatementClassesFromTestContext() {
1226
+ const detectedClasses = new Set();
1227
+ try {
1228
+ // Analisar stack trace para encontrar classes Statement
1229
+ const stack = new Error().stack || '';
1230
+ // 🎯 FILTROS RIGOROSOS: Evitar métodos do sistema próprio
1231
+ const systemMethods = [
1232
+ 'detectStatementClassesFromTestContext',
1233
+ 'detectStatementClassesFromSpecFile',
1234
+ 'detectStatementClassesFromCallStack',
1235
+ 'setupStatementInterception',
1236
+ 'setupDynamicInterception',
1237
+ 'loadStatementClassFromPath',
1238
+ 'makeStatementClassGloballyAvailable',
1239
+ ];
1240
+ // Procurar padrões de Statement no stack
1241
+ const statementRegex = /(\w*Statement\w*)/g;
1242
+ let match;
1243
+ while ((match = statementRegex.exec(stack)) !== null) {
1244
+ const className = match[1];
1245
+ // 🚫 FILTRAR métodos do sistema
1246
+ if (className &&
1247
+ className !== 'Statement' &&
1248
+ className.length > 3 &&
1249
+ !systemMethods.includes(className) &&
1250
+ !className.includes('detect') &&
1251
+ !className.includes('setup') &&
1252
+ !className.includes('load') &&
1253
+ !className.includes('make') &&
1254
+ !className.includes('get')) {
1255
+ detectedClasses.add(className);
1256
+ console.log(`🎯 Classe Statement real encontrada no stack: ${className}`);
1257
+ }
1258
+ }
1259
+ }
1260
+ catch (error) {
1261
+ console.warn(`⚠️ Erro na análise de contexto: ${error}`);
1262
+ }
1263
+ return Array.from(detectedClasses);
1264
+ }
1265
+ /**
1266
+ * 🛠️ Obtém módulo fs compatível com ESM
1267
+ */
1268
+ static getFileSystemModule() {
1269
+ try {
1270
+ // Tentar diferentes formas de acessar fs
1271
+ if (typeof process !== 'undefined' && process.versions?.node) {
1272
+ return eval('require')('fs');
1273
+ }
1274
+ }
1275
+ catch { }
1276
+ return null;
1277
+ }
1278
+ /**
1279
+ * 🛠️ Obtém módulo path compatível com ESM
1280
+ */
1281
+ static getPathModule() {
1282
+ try {
1283
+ if (typeof process !== 'undefined' && process.versions?.node) {
1284
+ return eval('require')('path');
1285
+ }
1286
+ }
1287
+ catch { }
1288
+ // Fallback manual para path
1289
+ return {
1290
+ basename: (p) => p.split(/[\\/]/).pop() || '',
1291
+ dirname: (p) => p.substring(0, p.lastIndexOf('/')) ||
1292
+ p.substring(0, p.lastIndexOf('\\')),
1293
+ join: (...args) => args.join('/'),
1294
+ resolve: (...args) => args.join('/'),
1295
+ };
1296
+ }
1297
+ /**
1298
+ * 🌐 Detecta classes Statement do contexto global - APENAS análise real
1299
+ */
1300
+ static detectStatementClassesFromGlobal(detectedClasses) {
1301
+ try {
1302
+ // 🔍 ANÁLISE RIGOROSA: Só aceitar classes que realmente parecem Statement
1303
+ const contexts = [
1304
+ globalThis,
1305
+ globalThis.global,
1306
+ globalThis.window,
1307
+ ].filter(Boolean);
1308
+ for (const context of contexts) {
1309
+ try {
1310
+ const propertyNames = Object.getOwnPropertyNames(context);
1311
+ for (const key of propertyNames) {
1312
+ try {
1313
+ const value = context[key];
1314
+ // 🎯 FILTROS MAIS AGRESSIVOS para identificar classes Statement reais
1315
+ if (typeof value === 'function' &&
1316
+ key.length > 4 && // Reduzido para detectar mais classes
1317
+ (key.includes('Statement') ||
1318
+ key.startsWith('Statements') ||
1319
+ key.endsWith('Statement') ||
1320
+ key.endsWith('Statements') ||
1321
+ /^[A-Z][a-zA-Z]*Statement[s]?/.test(key)) && // Padrão mais amplo
1322
+ !key.includes('Test') &&
1323
+ !key.includes('Mock') &&
1324
+ !key.includes('Fake') &&
1325
+ !key.includes('Stub') &&
1326
+ !key.includes('Proxy') &&
1327
+ !key.includes('Wrapper') &&
1328
+ !key.includes('Helper') &&
1329
+ !key.includes('Util') &&
1330
+ !key.includes('Base') &&
1331
+ !key.includes('Abstract')) {
1332
+ // 🔍 VALIDAÇÃO MAIS FLEXÍVEL: Verificar se tem métodos típicos de Statement ou é uma classe válida
1333
+ const prototype = value.prototype;
1334
+ if (prototype) {
1335
+ const methods = Object.getOwnPropertyNames(prototype);
1336
+ const hasStatementMethods = methods.some((method) => method.includes('get') ||
1337
+ method.includes('post') ||
1338
+ method.includes('put') ||
1339
+ method.includes('delete') ||
1340
+ method.includes('consulta') ||
1341
+ method.includes('validar') ||
1342
+ method.includes('criar') ||
1343
+ method.includes('request') ||
1344
+ method.includes('execute') ||
1345
+ method.includes('buscar') ||
1346
+ method.includes('obter') ||
1347
+ method.includes('enviar') ||
1348
+ method.includes('processar') ||
1349
+ method.includes('realizar') ||
1350
+ method.includes('executar'));
1351
+ // 🚀 ACEITAR se tem métodos Statement OU se é uma classe que parece Statement
1352
+ const hasConstructor = methods.includes('constructor');
1353
+ const isStatementLike = hasConstructor &&
1354
+ (hasStatementMethods || methods.length > 2);
1355
+ if (isStatementLike) {
1356
+ detectedClasses.add(key);
1357
+ console.log(`\n🎯 Classe Statement detectada: ${key}`);
1358
+ if (hasStatementMethods) {
1359
+ console.log(` 📋 Métodos relevantes encontrados: ${methods
1360
+ .filter((m) => m.includes('get') ||
1361
+ m.includes('post') ||
1362
+ m.includes('consulta') ||
1363
+ m.includes('validar') ||
1364
+ m.includes('criar') ||
1365
+ m.includes('request'))
1366
+ .slice(0, 3)
1367
+ .join(', ')}`);
1368
+ }
1369
+ }
1370
+ }
1371
+ }
1372
+ }
1373
+ catch {
1374
+ // Ignorar propriedades que causam erro ao acessar
1375
+ }
1376
+ }
1377
+ }
1378
+ catch {
1379
+ // Ignorar contextos problemáticos
1380
+ }
1381
+ }
1382
+ }
1383
+ catch (error) {
1384
+ console.warn(`⚠️ Erro ao analisar contexto global: ${error}`);
1385
+ }
1386
+ }
1387
+ /**
1388
+ * 🌐 Configuração universal que intercepta qualquer instanciação de classe com padrão Statement
1389
+ */
1390
+ static setupUniversalStatementInterception() {
1391
+ try {
1392
+ // 🚀 INTERCEPTAÇÃO CRÍTICA: Interceptar Function constructor
1393
+ const originalFunction = globalThis.Function;
1394
+ // 🎯 INTERCEPTAÇÃO DE CONSTRUCTOR GLOBAL
1395
+ const originalConstruct = Reflect.construct;
1396
+ if (typeof Reflect !== 'undefined' && originalConstruct) {
1397
+ ;
1398
+ Reflect.construct = function (target, argumentsList, newTarget) {
1399
+ const instance = originalConstruct.call(this, target, argumentsList, newTarget);
1400
+ if (typeof target === 'function') {
1401
+ const className = target.name;
1402
+ if (className &&
1403
+ (className.includes('Statement') ||
1404
+ className.includes('statement'))) {
1405
+ console.log(`🎯 Interceptando via Reflect.construct: ${className}`);
1406
+ return StatementTracker.interceptStatement(instance.constructor);
1407
+ }
1408
+ }
1409
+ return instance;
1410
+ };
1411
+ }
1412
+ // 🚀 NOVA ABORDAGEM: Interceptar eval para capturar imports dinâmicos
1413
+ const originalEval = globalThis.eval;
1414
+ globalThis.eval = function (code) {
1415
+ const result = originalEval.call(this, code);
1416
+ // Se o código contém Statement classes
1417
+ if (code.includes('Statement') && typeof result === 'function') {
1418
+ const className = result.name;
1419
+ if (className && className.includes('Statement')) {
1420
+ console.log(`🔍 Classe Statement detectada via eval: ${className}`);
1421
+ TestAnnotations.interceptClassDirectly(result, className);
1422
+ }
1423
+ }
1424
+ return result;
1425
+ };
1426
+ // 🌐 INTERCEPTAÇÃO UNIVERSAL DE NEW - SIMPLIFICADA
1427
+ try {
1428
+ // Usar abordagem mais simples via monkey patching
1429
+ }
1430
+ catch (constructorError) {
1431
+ console.warn(`⚠️ Erro na interceptação de constructor: ${constructorError}`);
1432
+ }
1433
+ }
1434
+ catch (error) {
1435
+ console.warn(`⚠️ Erro na interceptação universal: ${error}`);
1436
+ }
1437
+ }
1438
+ /**
1439
+ * 🎯 Intercepta uma classe diretamente no momento da descoberta
1440
+ */
1441
+ static interceptClassDirectly(ClassToIntercept, className) {
1442
+ try {
1443
+ if (typeof ClassToIntercept !== 'function') {
1444
+ return;
1445
+ }
1446
+ console.log(`🔧 Interceptando classe diretamente: ${className}`);
1447
+ // Substituir todos os métodos da classe
1448
+ const prototype = ClassToIntercept.prototype;
1449
+ const methodNames = Object.getOwnPropertyNames(prototype);
1450
+ for (const methodName of methodNames) {
1451
+ if (methodName !== 'constructor' &&
1452
+ typeof prototype[methodName] === 'function') {
1453
+ const originalMethod = prototype[methodName];
1454
+ prototype[methodName] = function (...args) {
1455
+ const statementName = `${className}.${methodName}`;
1456
+ console.log(`🎯 Executando Statement: ${statementName}`);
1457
+ // ✅ CORREÇÃO: Garantir que existe um CT ativo antes de executar statement
1458
+ StatementTracker.ensureCTCreated();
1459
+ // ✅ CORREÇÃO: Registrar statement dentro do CT, não criar novo CT
1460
+ StatementTracker.startStatement(className, methodName);
1461
+ try {
1462
+ const result = originalMethod.apply(this, args);
1463
+ // Se é Promise
1464
+ if (result && typeof result.then === 'function') {
1465
+ return result
1466
+ .then((res) => {
1467
+ StatementTracker.finishStatement(Date.now(), true);
1468
+ return res;
1469
+ })
1470
+ .catch((err) => {
1471
+ StatementTracker.finishStatement(Date.now(), false, err?.message || 'Erro desconhecido');
1472
+ throw err;
1473
+ });
1474
+ }
1475
+ // Método síncrono
1476
+ StatementTracker.finishStatement(Date.now(), true);
1477
+ return result;
1478
+ }
1479
+ catch (error) {
1480
+ StatementTracker.finishStatement(Date.now(), false, error?.message || 'Erro desconhecido');
1481
+ throw error;
1482
+ }
1483
+ };
1484
+ }
1485
+ }
1486
+ console.log(`✅ Classe ${className} interceptada diretamente com sucesso`);
1487
+ }
1488
+ catch (error) {
1489
+ console.warn(`⚠️ Erro ao interceptar classe ${className}: ${error}`);
1490
+ }
1491
+ }
1492
+ /**
1493
+ * 🏗️ Criar instância interceptada
1494
+ */
1495
+ static createInterceptedInstance(instance, className) {
1496
+ try {
1497
+ // Interceptar métodos da instância
1498
+ const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(instance));
1499
+ for (const methodName of methodNames) {
1500
+ if (methodName !== 'constructor' &&
1501
+ typeof instance[methodName] === 'function') {
1502
+ const originalMethod = instance[methodName];
1503
+ instance[methodName] = function (...args) {
1504
+ const statementName = `${className}.${methodName}`;
1505
+ console.log(`🎯 Executando Statement: ${statementName}`);
1506
+ // ✅ CORREÇÃO: Garantir que existe um CT ativo antes de executar statement
1507
+ StatementTracker.ensureCTCreated();
1508
+ // ✅ CORREÇÃO: Registrar statement dentro do CT, não criar novo CT
1509
+ StatementTracker.startStatement(className, methodName);
1510
+ try {
1511
+ const result = originalMethod.apply(this, args);
1512
+ // Se é Promise
1513
+ if (result && typeof result.then === 'function') {
1514
+ return result
1515
+ .then((res) => {
1516
+ StatementTracker.finishStatement(Date.now(), true);
1517
+ return res;
1518
+ })
1519
+ .catch((err) => {
1520
+ StatementTracker.finishStatement(Date.now(), false, err?.message || 'Erro desconhecido');
1521
+ throw err;
1522
+ });
1523
+ }
1524
+ // Método síncrono
1525
+ StatementTracker.finishStatement(Date.now(), true);
1526
+ return result;
1527
+ }
1528
+ catch (error) {
1529
+ StatementTracker.finishStatement(Date.now(), false, error?.message || 'Erro desconhecido');
1530
+ throw error;
1531
+ }
1532
+ };
1533
+ }
1534
+ }
1535
+ return instance;
1536
+ }
1537
+ catch (error) {
1538
+ console.warn(`⚠️ Erro ao criar instância interceptada: ${error}`);
1539
+ return instance;
1540
+ }
1541
+ }
1542
+ /**
1543
+ * 🌐 Configuração universal de interceptação de constructor
1544
+ */
1545
+ static setupUniversalConstructorInterception() {
1546
+ try {
1547
+ // 🎯 INTERCEPTAÇÃO GLOBAL DO NEW
1548
+ const originalReflectConstruct = Reflect.construct;
1549
+ if (typeof Reflect !== 'undefined' && originalReflectConstruct) {
1550
+ Reflect.construct = function (target, argumentsList, newTarget) {
1551
+ const instance = originalReflectConstruct.call(this, target, argumentsList, newTarget);
1552
+ // Se é uma classe Statement
1553
+ if (typeof target === 'function' &&
1554
+ target.name &&
1555
+ (target.name.includes('Statement') ||
1556
+ target.name.includes('statement'))) {
1557
+ console.log(`🚀 NEW ${target.name}() interceptado universalmente`);
1558
+ return TestAnnotations.createInterceptedInstance(instance, target.name);
1559
+ }
1560
+ return instance;
1561
+ };
1562
+ }
1563
+ console.log('🌐 Interceptação universal de constructor configurada');
1564
+ }
1565
+ catch (error) {
1566
+ console.warn(`⚠️ Erro na interceptação universal de constructor: ${error}`);
1567
+ }
1568
+ }
1569
+ /**
1570
+ * 🚀 Monitoramento contínuo de instanciações de Statement durante o teste
1571
+ */
1572
+ static setupContinuousStatementMonitoring(testName) {
1573
+ try {
1574
+ // Configurar um observador de mudanças no contexto global
1575
+ const monitoringInterval = setInterval(() => {
1576
+ try {
1577
+ // Verificar se há novas classes Statement no contexto global
1578
+ const contexts = [
1579
+ globalThis,
1580
+ globalThis.global,
1581
+ globalThis.window,
1582
+ ].filter(Boolean);
1583
+ for (const context of contexts) {
1584
+ Object.getOwnPropertyNames(context).forEach((propName) => {
1585
+ try {
1586
+ const prop = context[propName];
1587
+ if (typeof prop === 'function' &&
1588
+ (propName.includes('Statement') ||
1589
+ propName.includes('statement')) &&
1590
+ !prop._alreadyIntercepted) {
1591
+ // Marcar como interceptada para evitar loop
1592
+ ;
1593
+ prop._alreadyIntercepted = true;
1594
+ // Interceptar usando Proxy no contexto
1595
+ context[propName] = new Proxy(prop, {
1596
+ construct(target, args, newTarget) {
1597
+ console.log(`🚀 NEW ${propName}() interceptado durante execução`);
1598
+ // Criar instância original
1599
+ const instance = Reflect.construct(target, args, newTarget);
1600
+ // Retornar versão interceptada
1601
+ return StatementTracker.interceptStatement(instance.constructor);
1602
+ },
1603
+ });
1604
+ }
1605
+ }
1606
+ catch {
1607
+ // Ignorar propriedades problemáticas
1608
+ }
1609
+ });
1610
+ }
1611
+ }
1612
+ catch (error) {
1613
+ console.warn(`⚠️ Erro no monitoramento contínuo: ${error}`);
1614
+ }
1615
+ }, 500); // Verificar a cada 500ms
1616
+ // Limpar o monitoramento após 30 segundos
1617
+ setTimeout(() => {
1618
+ clearInterval(monitoringInterval);
1619
+ }, 30_000);
1620
+ }
1621
+ catch (error) {
1622
+ console.error(`❌ Erro ao configurar monitoramento contínuo: ${error}`);
1623
+ }
1624
+ }
1625
+ /**
1626
+ * 🆕 Configuração dinâmica para interceptar instanciações em tempo real
1627
+ */
1628
+ static setupDynamicInterception(statementClasses) {
1629
+ try {
1630
+ // 🎯 NOVA ABORDAGEM: Interceptar diretamente no contexto global usando substituição de classe
1631
+ for (const className of statementClasses) {
1632
+ try {
1633
+ const contexts = [
1634
+ globalThis,
1635
+ globalThis.global,
1636
+ globalThis.window,
1637
+ ].filter(Boolean);
1638
+ for (const context of contexts) {
1639
+ if (context[className] &&
1640
+ typeof context[className] === 'function') {
1641
+ const OriginalClass = context[className];
1642
+ console.log(`🔧 Configurando interceptação real para: ${className}`);
1643
+ // Criar uma nova classe que substitui a original completamente
1644
+ const InterceptedClass = (...args) => {
1645
+ console.log(`🚀 NEW ${className}() interceptado em tempo real!`);
1646
+ // Criar instância original
1647
+ const instance = new OriginalClass(...args);
1648
+ // Interceptar TODOS os métodos da instância
1649
+ const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(instance));
1650
+ for (const methodName of methodNames) {
1651
+ if (methodName !== 'constructor' &&
1652
+ typeof instance[methodName] === 'function') {
1653
+ const originalMethod = instance[methodName];
1654
+ instance[methodName] = function (...methodArgs) {
1655
+ // ❌ REMOVIDO: startCT/endCT - Statements não são CTs!
1656
+ // Um Statement é um método DENTRO de um CT (test())
1657
+ // O StatementTracker.interceptStatement() já gerencia isso corretamente
1658
+ // ❌ REMOVIDO: Log duplicado - o StatementTracker já faz o log
1659
+ // Apenas executar o método original sem criar CT falso
1660
+ return originalMethod.apply(this, methodArgs);
1661
+ };
1662
+ }
1663
+ }
1664
+ return instance;
1665
+ };
1666
+ // Preservar prototype e propriedades estáticas
1667
+ InterceptedClass.prototype = OriginalClass.prototype;
1668
+ Object.setPrototypeOf(InterceptedClass, OriginalClass);
1669
+ // Substituir no contexto
1670
+ context[className] = InterceptedClass;
1671
+ console.log(`✅ Interceptação direta configurada para: ${className}`);
1672
+ }
1673
+ }
1674
+ }
1675
+ catch (error) {
1676
+ console.warn(`⚠️ Erro ao configurar interceptação direta para ${className}: ${error}`);
1677
+ }
1678
+ }
1679
+ }
1680
+ catch (error) {
1681
+ console.warn(`⚠️ Erro na interceptação dinâmica: ${error}`);
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Configura interceptador seguro para registrar logs no UnifiedReportManager.
1686
+ * @param testName Nome do teste.
1687
+ * @param className Nome da classe/contexto.
1688
+ * @param originalMethod Método original de log.
1689
+ * @param targetClass Classe alvo.
1690
+ * @param methodName Nome do método.
1691
+ */
1692
+ static setupSafeInterceptor(testName, className, originalMethod, targetClass, methodName) {
1693
+ const interceptorKey = `${className}-${testName}`;
1694
+ if (interceptorsAtivos.has(interceptorKey)) {
1695
+ return;
1696
+ }
1697
+ interceptorsAtivos.add(interceptorKey);
1698
+ targetClass[methodName] = (message) => {
1699
+ try {
1700
+ originalMethod.call(targetClass, message);
1701
+ }
1702
+ catch {
1703
+ // Ignorar erros do método original
1704
+ }
1705
+ try {
1706
+ const prefixedMessage = className !== 'Mixed' ? `[${className}] ${message}` : message;
1707
+ UnifiedReportManager.adicionarLog(testName, prefixedMessage);
1708
+ }
1709
+ catch {
1710
+ // Ignorar erros do UnifiedReportManager
1711
+ }
1712
+ };
1713
+ setTimeout(() => {
1714
+ interceptorsAtivos.delete(interceptorKey);
1715
+ }, 30_000);
1716
+ }
1717
+ // ============================================
1718
+ // 🌐 INTEGRAÇÃO TESTHUB - SELEÇÃO DE SISTEMA
1719
+ // ============================================
1720
+ /**
1721
+ * 🌐 Seleciona o sistema do TestHub para o teste.
1722
+ * O sistema deve ser selecionado ANTES de usar qualquer ação (API, Frontend, SSH, Banco).
1723
+ * As configurações (URLs, credenciais, hosts) serão injetadas automaticamente.
1724
+ *
1725
+ * @param systemName Nome do sistema (use o enum Systems para IntelliSense)
1726
+ * @param environmentName Nome do ambiente (opcional, usa process.env.ENV se não fornecido)
1727
+ *
1728
+ * @example
1729
+ * // IMPORTANTE: Na primeira execução, use string diretamente:
1730
+ * await TestAnnotations.setSystem("AUTENTICA_IN_HML")
1731
+ *
1732
+ * // Após primeira execução, o enum será gerado e você pode usar:
1733
+ * import { Systems } from "../.rbqa/SystemsEnum"
1734
+ * await TestAnnotations.setSystem(Systems.AUTENTICA_IN_HML) // 👈 IntelliSense disponível
1735
+ *
1736
+ * // Exemplo completo:
1737
+ * test("CT001", async ({}, testInfo) => {
1738
+ * TestAnnotations.Api.testInfo = testInfo
1739
+ * await TestAnnotations.setSystem(Systems.AUTENTICA_IN_HML)
1740
+ *
1741
+ * // Agora as URLs e credenciais estão configuradas automaticamente
1742
+ * await new StatementsToken().getToken()
1743
+ * })
1744
+ */
1745
+ static async setSystem(systemName, environmentName) {
1746
+ // Aguarda criação do browser se foi solicitada (Frontend/Mixed)
1747
+ await TestContext.ensurePage();
1748
+ try {
1749
+ // ✅ VALIDAÇÃO: Verificar se systemName foi fornecido
1750
+ if (!systemName ||
1751
+ systemName === 'undefined' ||
1752
+ typeof systemName !== 'string') {
1753
+ throw new Error(`
1754
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1755
+ ❌ NOME DO SISTEMA INVÁLIDO
1756
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1757
+
1758
+ O parâmetro "systemName" é obrigatório e deve ser uma string válida.
1759
+
1760
+ Valor recebido: ${JSON.stringify(systemName)} (tipo: ${typeof systemName})
1761
+
1762
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1763
+ 💡 POSSÍVEIS CAUSAS:
1764
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1765
+
1766
+ 1. ❌ Tentou importar Systems do framework:
1767
+ import { Systems } from "@silasfmartins/testhub" // ← ERRADO!
1768
+
1769
+ 2. ❌ Tentou usar Systems antes de gerar o enum:
1770
+ import { Systems } from "../.rbqa/SystemsEnum" // ← Arquivo não existe!
1771
+ await TestAnnotations.setSystem(Systems.AUTENTICA_IN_HML)
1772
+
1773
+ 3. ❌ Esqueceu de passar o parâmetro:
1774
+ await TestAnnotations.setSystem() // ← systemName obrigatório!
1775
+
1776
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1777
+ ✅ SOLUÇÃO - PRIMEIRA EXECUÇÃO:
1778
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1779
+
1780
+ Use STRING diretamente (sem import do enum):
1781
+
1782
+ import { TestAnnotations } from "@silasfmartins/testhub"
1783
+
1784
+ test("Meu teste", async ({}, testInfo) => {
1785
+ TestAnnotations.Api.testInfo = testInfo
1786
+ await TestAnnotations.setSystem("AUTENTICA_IN_HML") // ← String direta
1787
+ })
1788
+
1789
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1790
+ ✅ SOLUÇÃO - PRÓXIMAS EXECUÇÕES (com IntelliSense):
1791
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1792
+
1793
+ Após a primeira execução, o arquivo .rbqa/SystemsEnum.ts será gerado.
1794
+ Então você pode importar o enum DO SEU PROJETO (NÃO do framework):
1795
+
1796
+ import { TestAnnotations } from "@silasfmartins/testhub"
1797
+ import { Systems } from "../.rbqa/SystemsEnum" // ← Do projeto!
1798
+
1799
+ test("Meu teste", async ({}, testInfo) => {
1800
+ TestAnnotations.Api.testInfo = testInfo
1801
+ await TestAnnotations.setSystem(Systems.AUTENTICA_IN_HML) // ← Com IntelliSense!
1802
+ })
1803
+
1804
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1805
+ `);
1806
+ }
1807
+ // 2. Inicializar SystemsManager (carrega lista de sistemas do backend)
1808
+ const systemsManager = SystemsManager.getInstance();
1809
+ await systemsManager.initialize();
1810
+ // 3. Obter tipo de projeto do ambiente
1811
+ // ⚠️ IMPORTANTE: Para projetos Scenarios, não filtrar por tipo de ambiente
1812
+ // Scenarios podem usar sistemas de qualquer tipo (API, Mobile, etc.)
1813
+ const detectedProjectType = process.env.PROJECT_TYPE || 'API';
1814
+ const isScenarios = detectedProjectType === 'Scenarios';
1815
+ // Se for Scenarios, não passar projectType para permitir qualquer tipo de ambiente
1816
+ const projectType = isScenarios
1817
+ ? undefined
1818
+ : detectedProjectType;
1819
+ console.log(`🔍 Tipo de projeto detectado: ${detectedProjectType}${isScenarios ? ' (permitindo qualquer tipo de ambiente)' : ''}`);
1820
+ // 4. Selecionar sistema (valida e carrega configurações)
1821
+ const selectedSystem = await systemsManager.selectSystem(systemName, environmentName, projectType);
1822
+ // 5. Injetar configurações automaticamente
1823
+ const configManager = DynamicConfigManager.getInstance();
1824
+ // Injetar em process.env para compatibilidade com código legado
1825
+ configManager.injectIntoEnvironment();
1826
+ // Registrar informações do CI (Azure/GitHub) — útil para identificar quem iniciou a execução
1827
+ try {
1828
+ UnifiedReportManager.registrarCIInfo();
1829
+ }
1830
+ catch (error) {
1831
+ console.warn('⚠️ Falha ao registrar CI info:', error);
1832
+ }
1833
+ // Injetar baseURL no Playwright se for teste WEB
1834
+ if (detectedProjectType === 'WEB' || detectedProjectType === 'FRONTEND') {
1835
+ configManager.injectPlaywrightBaseUrl();
1836
+ }
1837
+ // 🆕 Auto-conectar SSH se for projeto SSH
1838
+ // IMPORTANTE: Usa detectedProjectType (sempre definido), não projectType (pode ser undefined)
1839
+ // Auto-conectar quando:
1840
+ // - o projeto explicitamente é do tipo SSH, OU
1841
+ // - o sistema selecionado contém informações típicas de SSH (host, username, password, privateKeyPath)
1842
+ // Isso evita que projetos Frontend/Mixed que executam cenários SSH precisem definir PROJECT_TYPE=SSH.
1843
+ try {
1844
+ // Auto-conexão SSH foi desativada: os usuários devem chamar
1845
+ // manualmente `SSHActions.connectWithKey(...)` ou usar `SSHActions` diretamente.
1846
+ // Isto evita conexões automáticas indesejadas.
1847
+ // Exemplo recomendado no teste:
1848
+ // await SSHActions.connectWithKey('secrets/UserSistAutBRM')
1849
+ // Ou configure o SSH_KEY_PATH e chame manualmente:
1850
+ // await SSHActions.connectWithKey(process.env.SSH_KEY_PATH)
1851
+ }
1852
+ catch (sshError) {
1853
+ console.warn(`⚠️ [SSH] Não foi possível auto-conectar: ${sshError}`);
1854
+ console.warn('💡 Use SSHActions.connectWithKey() manualmente (ex: await SSHActions.connectWithKey("secrets/UserSistAutBRM"))');
1855
+ }
1856
+ // 6. Registrar no relatório
1857
+ try {
1858
+ const testInfo = TestContext.getSafeTestInfo();
1859
+ if (testInfo?.title) {
1860
+ const cnName = testInfo.titlePath?.[1] || testInfo.title;
1861
+ UnifiedReportManager.adicionarLog(cnName, `🌐 Sistema configurado: ${selectedSystem.name} (${selectedSystem.environmentName})`);
1862
+ }
1863
+ }
1864
+ catch {
1865
+ // Ignorar se TestContext não estiver disponível ainda
1866
+ }
1867
+ // 7. 🆕 Registrar sistema no StatementTracker para captura nos CTs
1868
+ try {
1869
+ StatementTracker.setCurrentSystem(selectedSystem.name);
1870
+ }
1871
+ catch (error) {
1872
+ console.warn('⚠️ Não foi possível registrar sistema no StatementTracker:', error);
1873
+ }
1874
+ // 8. 🔧 CRÍTICO: Limpar cache de contextos para garantir novo baseURL
1875
+ try {
1876
+ await ApiActions.clearContextCache();
1877
+ }
1878
+ catch (error) {
1879
+ console.warn('⚠️ Não foi possível limpar cache de contextos:', error);
1880
+ }
1881
+ console.log(`✅ Sistema ${systemName} configurado com sucesso!`);
1882
+ }
1883
+ catch (error) {
1884
+ console.error(`❌ Erro ao configurar sistema: ${error}`);
1885
+ throw new Error(`Falha ao configurar sistema "${systemName}": ${error instanceof Error ? error.message : String(error)}`);
1886
+ }
1887
+ }
1888
+ /**
1889
+ * 🌐 Obtém a URL do sistema atualmente configurado.
1890
+ * Deve ser chamado APÓS setSystem().
1891
+ *
1892
+ * @returns URL do sistema ou undefined se nenhum sistema foi configurado
1893
+ *
1894
+ * @example
1895
+ * await TestAnnotations.setSystem("AUTENTICA_IN_HML")
1896
+ * const url = TestAnnotations.getSystemUrl()
1897
+ * console.log(url) // "https://autenticainthml.redecorp.br"
1898
+ */
1899
+ static getSystemUrl() {
1900
+ try {
1901
+ const systemsManager = SystemsManager.getInstance();
1902
+ const config = systemsManager.getSystemConfig();
1903
+ return config?.baseUrl;
1904
+ }
1905
+ catch (error) {
1906
+ console.warn(`⚠️ Erro ao obter URL do sistema: ${error}`);
1907
+ return undefined;
1908
+ }
1909
+ }
1910
+ /**
1911
+ * 🌐 Obtém as configurações completas do sistema atualmente configurado.
1912
+ * Deve ser chamado APÓS setSystem().
1913
+ *
1914
+ * @returns Configurações do sistema ou null se nenhum sistema foi configurado
1915
+ *
1916
+ * @example
1917
+ * await TestAnnotations.setSystem("AUTENTICA_IN_HML")
1918
+ * const config = TestAnnotations.getSystemConfig()
1919
+ * console.log(config?.baseUrl) // "https://autenticainthml.redecorp.br"
1920
+ * console.log(config?.username) // "usuario"
1921
+ */
1922
+ static getSystemConfig() {
1923
+ try {
1924
+ const systemsManager = SystemsManager.getInstance();
1925
+ return systemsManager.getSystemConfig();
1926
+ }
1927
+ catch (error) {
1928
+ console.warn(`⚠️ Erro ao obter configuração do sistema: ${error}`);
1929
+ return null;
1930
+ }
1931
+ }
1932
+ /**
1933
+ * Configura um teste como API, com interceptador e logs.
1934
+ */
1935
+ static Api = {
1936
+ set testInfo(testInfo) {
1937
+ TestContext.setTestType('API');
1938
+ TestContext.setTestInfo(testInfo);
1939
+ // ✅ CRÍTICO: Detectar CN e CT baseado na estrutura do titlePath
1940
+ let cnName;
1941
+ let ctName;
1942
+ if (testInfo.titlePath && testInfo.titlePath.length >= 3) {
1943
+ cnName = testInfo.titlePath[1];
1944
+ ctName = testInfo.titlePath[2];
1945
+ }
1946
+ else if (testInfo.titlePath && testInfo.titlePath.length === 2) {
1947
+ cnName = testInfo.titlePath[0];
1948
+ ctName = testInfo.titlePath[1];
1949
+ }
1950
+ else {
1951
+ cnName = testInfo.title;
1952
+ ctName = testInfo.title;
1953
+ }
1954
+ StatementTracker.setTestName(cnName);
1955
+ // 🆕 CRÍTICO: Capturar e registrar CT automaticamente
1956
+ TestAnnotations.capturarCTDoPlaywright(cnName, ctName, testInfo);
1957
+ testStartTimes.set(cnName, Date.now());
1958
+ UnifiedReportManager.setTestContext(cnName, 'API');
1959
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
1960
+ ensureTerminalLogCaptureActive(cnName, ctName);
1961
+ // 🔍 NOVO: Ativar logs automáticos de Statements
1962
+ ativarStatementLogs();
1963
+ ativarInterceptacaoMagica();
1964
+ // 🆕 INTERCEPTAÇÃO AUTOMÁTICA DE STATEMENTS
1965
+ TestAnnotations.setupStatementInterception(cnName);
1966
+ // 🚀 MONITORAMENTO CONTÍNUO - interceptar novas instanciações
1967
+ TestAnnotations.setupContinuousStatementMonitoring(cnName);
1968
+ TestAnnotations.setupSafeInterceptor(cnName, 'API', ApiActions.logEvent.bind(ApiActions), ApiActions, 'logEvent');
1969
+ TestAnnotations.setupTestFinalization(testInfo);
1970
+ },
1971
+ };
1972
+ /**
1973
+ * Configura um teste como Frontend, com logs e cobertura automática.
1974
+ */
1975
+ static Frontend = {
1976
+ /**
1977
+ * Configura contexto Frontend com TestInfo e cobertura automática
1978
+ * @param testInfo TestInfo do Playwright
1979
+ * @param enableCoverage Se deve habilitar cobertura automática (padrão: true)
1980
+ */
1981
+ configure(testInfo, enableCoverage = true) {
1982
+ TestContext.setTestType('Frontend');
1983
+ TestContext.setTestInfo(testInfo);
1984
+ // ✅ CRÍTICO: Detectar CN e CT baseado na estrutura do titlePath
1985
+ let cnName;
1986
+ let ctName;
1987
+ if (testInfo.titlePath && testInfo.titlePath.length >= 3) {
1988
+ cnName = testInfo.titlePath[1];
1989
+ ctName = testInfo.titlePath[2];
1990
+ }
1991
+ else if (testInfo.titlePath && testInfo.titlePath.length === 2) {
1992
+ cnName = testInfo.titlePath[0];
1993
+ ctName = testInfo.titlePath[1];
1994
+ }
1995
+ else {
1996
+ cnName = testInfo.title;
1997
+ ctName = testInfo.title;
1998
+ }
1999
+ StatementTracker.setTestName(cnName);
2000
+ console.log(`🏷️ [FRONTEND] StatementTracker inicializado para CN: "${cnName}"`);
2001
+ testStartTimes.set(cnName, Date.now());
2002
+ UnifiedReportManager.setTestContext(cnName, 'Frontend');
2003
+ // 🆕 CRÍTICO: Capturar e registrar CT automaticamente
2004
+ TestAnnotations.capturarCTDoPlaywright(cnName, ctName, testInfo);
2005
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
2006
+ ensureTerminalLogCaptureActive(cnName, ctName);
2007
+ UnifiedReportManager.adicionarLog(cnName, `🌐 Inicializando contexto Frontend (cobertura: ${enableCoverage ? 'ON' : 'OFF'})`);
2008
+ // ✅ NOVO: Configurar cobertura automática se habilitada
2009
+ if (enableCoverage) {
2010
+ TestAnnotations.setupFrontendCoverage(testInfo);
2011
+ }
2012
+ // 🔍 NOVO: Ativar logs automáticos de Statements
2013
+ ativarStatementLogs();
2014
+ ativarInterceptacaoMagica();
2015
+ TestAnnotations.setupTestFinalization(testInfo);
2016
+ },
2017
+ /**
2018
+ * 🆕 Inicializa contexto Frontend com page e testInfo em uma única chamada
2019
+ * @param options Objeto com page e testInfo do Playwright
2020
+ * @example
2021
+ * test('CT001', async ({ page }, testInfo) => {
2022
+ * TestAnnotations.Frontend.init({ page, testInfo })
2023
+ * await TestAnnotations.setSystem('MEU_SISTEMA')
2024
+ * await new MinhaPage().minhaAcao()
2025
+ * })
2026
+ */
2027
+ init(options) {
2028
+ // ✅ Setar page no TestContext PRIMEIRO
2029
+ TestContext.setPage(options.page);
2030
+ // Depois configurar o resto
2031
+ this.configure(options.testInfo, options.enableCoverage ?? true);
2032
+ },
2033
+ // Propriedade legacy para compatibilidade (requer TestContext.setPage manual)
2034
+ set testInfo(testInfo) {
2035
+ // Dispara criação lazy do browser (só quando fixture está ativo)
2036
+ TestContext.requestBrowserCreation();
2037
+ this.configure(testInfo, true);
2038
+ },
2039
+ };
2040
+ // Removed `Front` alias: use `Frontend` instead
2041
+ /**
2042
+ * Configura um teste como Mobile, com limpeza automática de sessão.
2043
+ */
2044
+ static Mobile = {
2045
+ set testInfo(testInfo) {
2046
+ TestContext.setTestType('Mobile');
2047
+ TestContext.setTestInfo(testInfo);
2048
+ // ✅ CRÍTICO: Usar CN (test.describe = titlePath[1]) como identificador do teste
2049
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
2050
+ const cnName = testInfo.titlePath?.[1] || testInfo.title;
2051
+ StatementTracker.setTestName(cnName);
2052
+ console.log(`🏷️ [MOBILE] StatementTracker inicializado para CN: "${cnName}"`);
2053
+ testStartTimes.set(cnName, Date.now());
2054
+ UnifiedReportManager.setTestContext(cnName, 'Mobile');
2055
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
2056
+ ensureTerminalLogCaptureActive(cnName);
2057
+ UnifiedReportManager.adicionarLog(cnName, '📱 Inicializando contexto Mobile');
2058
+ // 🔍 NOVO: Ativar logs automáticos de Statements
2059
+ ativarStatementLogs();
2060
+ ativarInterceptacaoMagica();
2061
+ TestAnnotations.setupMobileAutoCleanup(testInfo);
2062
+ TestAnnotations.setupTestFinalization(testInfo);
2063
+ },
2064
+ };
2065
+ /**
2066
+ * Configura limpeza automática para testes mobile.
2067
+ * @param testInfo TestInfo do Playwright.
2068
+ */
2069
+ static setupMobileAutoCleanup(testInfo) {
2070
+ const originalAttach = testInfo.attach;
2071
+ let sessionClosed = false;
2072
+ testInfo.attach = async function (name, options) {
2073
+ if (!sessionClosed &&
2074
+ (name.includes('stdout') ||
2075
+ name.includes('stderr') ||
2076
+ name.includes('trace'))) {
2077
+ setTimeout(async () => {
2078
+ if (!sessionClosed) {
2079
+ sessionClosed = true;
2080
+ try {
2081
+ await MobileConnection.closeSession();
2082
+ UnifiedReportManager.adicionarLog(testInfo.title, '✅ Sessão mobile encerrada automaticamente');
2083
+ }
2084
+ catch (error) {
2085
+ UnifiedReportManager.adicionarLog(testInfo.title, `⚠️ Erro ao encerrar sessão mobile: ${String(error)}`);
2086
+ }
2087
+ }
2088
+ }, 100);
2089
+ }
2090
+ return originalAttach.call(this, name, options);
2091
+ };
2092
+ setTimeout(async () => {
2093
+ if (!sessionClosed) {
2094
+ sessionClosed = true;
2095
+ try {
2096
+ const hasActiveSession = MobileConnection.isConnected();
2097
+ if (hasActiveSession) {
2098
+ await MobileConnection.closeSession();
2099
+ UnifiedReportManager.adicionarLog(testInfo.title, '✅ Sessão mobile encerrada automaticamente (timeout)');
2100
+ }
2101
+ }
2102
+ catch {
2103
+ // Silenciosamente limpar em caso de erro
2104
+ }
2105
+ }
2106
+ }, 35_000);
2107
+ }
2108
+ /**
2109
+ * Método utilitário para configurar mobile capabilities.
2110
+ * @param capabilities Objeto de capabilities do dispositivo.
2111
+ */
2112
+ static async setupMobileCapabilities(capabilities) {
2113
+ const testInfo = TestContext.getSafeTestInfo();
2114
+ if (testInfo?.title) {
2115
+ UnifiedReportManager.adicionarLog(testInfo.title, `🔧 Configurando capabilities para ${capabilities.platformName}`);
2116
+ try {
2117
+ const fullCapabilities = {
2118
+ ...capabilities,
2119
+ deviceName: capabilities.deviceId, // deviceName é obrigatório
2120
+ };
2121
+ await MobileConnection.createSession(fullCapabilities);
2122
+ UnifiedReportManager.adicionarLog(testInfo.title, `✅ Sessão mobile criada - Device: ${capabilities.deviceId}`);
2123
+ }
2124
+ catch (error) {
2125
+ UnifiedReportManager.adicionarLog(testInfo.title, `❌ Erro ao criar sessão mobile: ${String(error)}`);
2126
+ throw error;
2127
+ }
2128
+ }
2129
+ }
2130
+ /**
2131
+ * Configura um teste como SSH, com interceptador e logs.
2132
+ */
2133
+ static SSH = {
2134
+ set testInfo(testInfo) {
2135
+ TestContext.setTestType('SSH');
2136
+ TestContext.setTestInfo(testInfo);
2137
+ // ✅ CRÍTICO: Usar CN (test.describe = titlePath[1]) como identificador do teste
2138
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
2139
+ const cnName = testInfo.titlePath?.[1] || testInfo.title;
2140
+ StatementTracker.setTestName(cnName);
2141
+ console.log(`🏷️ [SSH] StatementTracker inicializado para CN: "${cnName}"`);
2142
+ testStartTimes.set(cnName, Date.now());
2143
+ UnifiedReportManager.setTestContext(cnName, 'SSH');
2144
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
2145
+ ensureTerminalLogCaptureActive(cnName);
2146
+ TestAnnotations.setupSafeInterceptor(cnName, 'SSH', SSHActions.logEvent.bind(SSHActions), SSHActions, 'logEvent');
2147
+ UnifiedReportManager.adicionarLog(cnName, '🔧 Inicializando contexto SSH');
2148
+ // 🔍 CRITICAL: Ativar interceptação ANTES de qualquer coisa
2149
+ ativarStatementLogs();
2150
+ ativarInterceptacaoMagica();
2151
+ // ✅ SSH: Interceptar classes Statement globais E importadas
2152
+ TestAnnotations.interceptGlobalStatements();
2153
+ TestAnnotations.interceptImportedStatements();
2154
+ console.log('🌟 Interceptação mágica ativada - Statements serão logados automaticamente');
2155
+ TestAnnotations.setupTestFinalization(testInfo);
2156
+ },
2157
+ };
2158
+ /**
2159
+ * Configura um teste como Banco, com interceptador e logs.
2160
+ */
2161
+ static Banco = {
2162
+ set testInfo(testInfo) {
2163
+ TestContext.setTestType('Banco');
2164
+ TestContext.setTestInfo(testInfo);
2165
+ // ✅ CRÍTICO: Usar CN (test.describe = titlePath[1]) como identificador do teste
2166
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
2167
+ const cnName = testInfo.titlePath?.[1] || testInfo.title;
2168
+ StatementTracker.setTestName(cnName);
2169
+ console.log(`🏷️ [BANCO] StatementTracker inicializado para CN: "${cnName}"`);
2170
+ testStartTimes.set(cnName, Date.now());
2171
+ UnifiedReportManager.setTestContext(cnName, 'Banco');
2172
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
2173
+ ensureTerminalLogCaptureActive(cnName);
2174
+ TestAnnotations.setupSafeInterceptor(cnName, 'BANCO', BancoActions.logEvent.bind(BancoActions), BancoActions, 'logEvent');
2175
+ UnifiedReportManager.adicionarLog(cnName, '🗄️ Inicializando contexto Banco de Dados');
2176
+ // 🔍 NOVO: Ativar logs automáticos de Statements
2177
+ ativarStatementLogs();
2178
+ ativarInterceptacaoMagica();
2179
+ TestAnnotations.setupTestFinalization(testInfo);
2180
+ },
2181
+ };
2182
+ /**
2183
+ * Configura um teste como Mixed, com interceptadores e limpeza automática.
2184
+ */
2185
+ static Mixed = {
2186
+ set testInfo(testInfo) {
2187
+ TestContext.setTestType('Mixed');
2188
+ // Dispara criação lazy do browser (só quando fixture está ativo)
2189
+ TestContext.requestBrowserCreation();
2190
+ TestContext.setTestInfo(testInfo);
2191
+ // ✅ CRÍTICO: Usar CN (test.describe = titlePath[1]) como identificador do teste
2192
+ // titlePath[0] = filename, titlePath[1] = CN (test.describe), titlePath[2] = CT (test)
2193
+ const cnName = testInfo.titlePath?.[1] || testInfo.title;
2194
+ StatementTracker.setTestName(cnName);
2195
+ console.log(`🏷️ [MIXED] StatementTracker inicializado para CN: "${cnName}"`);
2196
+ testStartTimes.set(cnName, Date.now());
2197
+ UnifiedReportManager.setTestContext(cnName, 'Mixed');
2198
+ // 🆕 CRÍTICO: Garantir TerminalLogCapture ativo no worker (multi-worker support)
2199
+ ensureTerminalLogCaptureActive(cnName);
2200
+ TestAnnotations.setupAllInterceptors(cnName);
2201
+ UnifiedReportManager.adicionarLog(cnName, '🔀 Inicializando contexto Mixed - Múltiplos tipos habilitados');
2202
+ // 🔍 NOVO: Ativar logs automáticos de Statements
2203
+ ativarStatementLogs();
2204
+ ativarInterceptacaoMagica();
2205
+ TestAnnotations.setupMobileAutoCleanup(testInfo);
2206
+ TestAnnotations.setupTestFinalization(testInfo);
2207
+ },
2208
+ };
2209
+ /**
2210
+ * Adiciona um log ao UnifiedReportManager para o teste.
2211
+ * @param testName Nome do teste.
2212
+ * @param message Mensagem de log.
2213
+ * @param tipo Tipo do log ('info', 'success', 'error', 'warning').
2214
+ */
2215
+ static addLog(testName, message, tipo = 'info') {
2216
+ const emojis = { info: 'ℹ️', success: '✅', error: '❌', warning: '⚠️' };
2217
+ UnifiedReportManager.adicionarLog(testName, `${emojis[tipo]} ${message}`);
2218
+ }
2219
+ /**
2220
+ * Define metadados para o teste no UnifiedReportManager.
2221
+ * @param testName Nome do teste.
2222
+ * @param metadata Objeto de metadados.
2223
+ */
2224
+ static setMetadata(testName, metadata) {
2225
+ UnifiedReportManager.setTestMetadata(testName, metadata);
2226
+ }
2227
+ /**
2228
+ * Define a duração do teste no UnifiedReportManager.
2229
+ * @param testName Nome do teste.
2230
+ * @param duracao Duração em segundos.
2231
+ */
2232
+ static setDuration(testName, duracao) {
2233
+ UnifiedReportManager.setTestDuration(testName, duracao);
2234
+ }
2235
+ /**
2236
+ * Obtém o contexto atual do teste.
2237
+ * @returns O tipo de contexto ou null.
2238
+ */
2239
+ static getCurrentTestContext() {
2240
+ const testInfo = TestContext.getSafeTestInfo();
2241
+ if (testInfo?.title) {
2242
+ const metrics = UnifiedReportManager.getMetrics();
2243
+ const teste = metrics.testes.find((t) => t.nome === testInfo.title);
2244
+ return teste?.tipo || null;
2245
+ }
2246
+ return null;
2247
+ }
2248
+ /**
2249
+ * Marca o teste como falha no UnifiedReportManager.
2250
+ * @param testName Nome do teste.
2251
+ * @param reason Motivo da falha (opcional).
2252
+ */
2253
+ static markTestAsFailed(testName, reason) {
2254
+ const errorMessage = reason
2255
+ ? `❌ Teste falhou: ${reason}`
2256
+ : '❌ Teste marcado como falha';
2257
+ UnifiedReportManager.adicionarLog(testName, errorMessage);
2258
+ }
2259
+ /**
2260
+ * Marca o teste como sucesso no UnifiedReportManager.
2261
+ * @param testName Nome do teste.
2262
+ * @param message Mensagem de sucesso (opcional).
2263
+ */
2264
+ static markTestAsSuccess(testName, message) {
2265
+ const successMessage = message
2266
+ ? `✅ ${message}`
2267
+ : '✅ Teste concluído com sucesso';
2268
+ UnifiedReportManager.adicionarLog(testName, successMessage);
2269
+ }
2270
+ /**
2271
+ * Adiciona um screenshot ao relatório do teste.
2272
+ * @param testName Nome do teste.
2273
+ * @param screenshotName Nome do screenshot.
2274
+ * @param buffer Buffer da imagem.
2275
+ */
2276
+ static async addScreenshot(testName, screenshotName, buffer) {
2277
+ try {
2278
+ const testInfo = TestContext.getSafeTestInfo();
2279
+ if (testInfo) {
2280
+ await testInfo.attach(`📸 ${screenshotName}`, {
2281
+ body: buffer,
2282
+ contentType: 'image/png',
2283
+ });
2284
+ UnifiedReportManager.adicionarLog(testName, `📸 Screenshot capturado: ${screenshotName}`);
2285
+ }
2286
+ }
2287
+ catch (error) {
2288
+ UnifiedReportManager.adicionarLog(testName, `❌ Erro ao anexar screenshot: ${error}`);
2289
+ }
2290
+ }
2291
+ /**
2292
+ * Obtém estatísticas globais dos testes.
2293
+ * @returns Objeto com total, concluídos, ativos e por tipo.
2294
+ */
2295
+ static getGlobalStats() {
2296
+ const metrics = UnifiedReportManager.getMetrics();
2297
+ return {
2298
+ totalTests: metrics.totalTestes,
2299
+ completedTests: metrics.testes.length,
2300
+ activeTests: testStartTimes.size,
2301
+ testsByType: metrics.testesPorTipo,
2302
+ };
2303
+ }
2304
+ /**
2305
+ * Limpa interceptadores ativos (debug).
2306
+ */
2307
+ static clearInterceptors() {
2308
+ interceptorsAtivos.clear();
2309
+ console.log('🧹 Interceptadores limpos');
2310
+ }
2311
+ /**
2312
+ * Obtém interceptadores ativos (debug).
2313
+ * @returns Array de chaves de interceptadores ativos.
2314
+ */
2315
+ static getActiveInterceptors() {
2316
+ return Array.from(interceptorsAtivos);
2317
+ }
2318
+ /**
2319
+ * 🔥 FORÇA interceptação direta das classes Statement do projeto real
2320
+ */
2321
+ static forceInterceptRealProjectStatements(statementClasses) {
2322
+ try {
2323
+ console.log('🔥 === INTERCEPTAÇÃO FORÇADA PARA PROJETO REAL ===');
2324
+ // 🎯 Estratégia 1: Interceptar require/import para capturar no momento do carregamento
2325
+ const originalRequire = globalThis.require;
2326
+ if (originalRequire) {
2327
+ ;
2328
+ globalThis.require = function (modulePath) {
2329
+ const result = originalRequire.apply(this, arguments);
2330
+ // Se o módulo carregado contém classes Statement
2331
+ if (result && typeof result === 'object') {
2332
+ for (const exportName of Object.keys(result)) {
2333
+ if (statementClasses.includes(exportName) &&
2334
+ typeof result[exportName] === 'function') {
2335
+ console.log(`🎯 [REQUIRE] Interceptando classe Statement: ${exportName}`);
2336
+ result[exportName] =
2337
+ TestAnnotations.createForceInterceptedClass(result[exportName], exportName);
2338
+ console.log(`✅ [REQUIRE] ${exportName} interceptada com sucesso`);
2339
+ }
2340
+ }
2341
+ }
2342
+ return result;
2343
+ };
2344
+ }
2345
+ // 🎯 Estratégia 2: Monitorar globals com throttling para evitar spam
2346
+ let lastMonitorTime = 0;
2347
+ const monitorThrottleTime = 1000; // 1 segundo entre verificações
2348
+ const monitoringInterval = setInterval(() => {
2349
+ const now = Date.now();
2350
+ if (now - lastMonitorTime < monitorThrottleTime) {
2351
+ return; // Skip se muito recente
2352
+ }
2353
+ lastMonitorTime = now;
2354
+ statementClasses.forEach((className) => {
2355
+ const contexts = [
2356
+ globalThis,
2357
+ globalThis.global,
2358
+ globalThis.window,
2359
+ ].filter(Boolean);
2360
+ for (const context of contexts) {
2361
+ if (context[className] &&
2362
+ typeof context[className] === 'function' &&
2363
+ !context[className]._alreadyForceIntercepted) {
2364
+ console.log(`🔥 [MONITOR] Encontrada classe Statement não interceptada: ${className}`);
2365
+ const OriginalClass = context[className];
2366
+ const InterceptedClass = TestAnnotations.createForceInterceptedClass(OriginalClass, className);
2367
+ InterceptedClass._alreadyForceIntercepted = true;
2368
+ // Substituir no contexto
2369
+ context[className] = InterceptedClass;
2370
+ console.log(`✅ [MONITOR] ${className} interceptada e substituída`);
2371
+ }
2372
+ }
2373
+ });
2374
+ }, 500); // Verificar a cada 500ms (reduzido de 100ms)
2375
+ // Parar o monitoramento após 10 segundos
2376
+ setTimeout(() => {
2377
+ clearInterval(monitoringInterval);
2378
+ console.log('🕐 [MONITOR] Monitoramento de interceptação finalizado');
2379
+ }, 10_000);
2380
+ console.log(`🚀 [FORÇA] Interceptação forçada configurada para ${statementClasses.length} classes`);
2381
+ }
2382
+ catch (error) {
2383
+ console.warn(`⚠️ [FORÇA] Erro na interceptação forçada: ${error}`);
2384
+ }
2385
+ }
2386
+ /**
2387
+ * 🎯 Cria uma versão completamente interceptada de uma classe Statement
2388
+ */
2389
+ static createForceInterceptedClass(OriginalClass, className) {
2390
+ try {
2391
+ console.log(`🔧 [FORÇA] Criando interceptação para: ${className}`);
2392
+ // Criar nova classe que substitui completamente a original
2393
+ const ForceInterceptedClass = (...args) => {
2394
+ console.log(`🚀 [FORÇA] NEW ${className}() INTERCEPTADO DEFINITIVAMENTE!`);
2395
+ console.log('📋 === CT EM EXECUÇÃO === [INTERCEPTAÇÃO FORÇADA]');
2396
+ console.log(` 🎯 Classe: ${className}`);
2397
+ console.log(` ⏰ [${new Date().toISOString()}] Instância criada`);
2398
+ console.log(' 🚀 FUNCIONANDO NO PROJETO REAL!');
2399
+ // Criar instância original
2400
+ const instance = new OriginalClass(...args);
2401
+ // Interceptar TODOS os métodos da instância
2402
+ const proto = Object.getPrototypeOf(instance);
2403
+ const methodNames = Object.getOwnPropertyNames(proto);
2404
+ for (const methodName of methodNames) {
2405
+ if (methodName !== 'constructor' &&
2406
+ typeof instance[methodName] === 'function') {
2407
+ const originalMethod = instance[methodName];
2408
+ instance[methodName] = function (...methodArgs) {
2409
+ // ✅ CORRIGIDO: NÃO chamar startCT/endCT aqui!
2410
+ // O StatementTracker.interceptStatement() já faz isso automaticamente
2411
+ console.log(`📋 === STATEMENT EM EXECUÇÃO === ${className}.${methodName}()`);
2412
+ console.log(` 🎯 [FORÇA] Método interceptado: ${methodName}()`);
2413
+ console.log(` ⏰ [${new Date().toISOString()}] Iniciando execução...`);
2414
+ console.log(' 🚀 CAPTURADO NO PROJETO REAL!');
2415
+ const startTime = Date.now();
2416
+ try {
2417
+ const result = originalMethod.apply(this, methodArgs);
2418
+ // Se é Promise
2419
+ if (result && typeof result.then === 'function') {
2420
+ return result
2421
+ .then((res) => {
2422
+ const duration = Date.now() - startTime;
2423
+ console.log(` ✅ [${new Date().toISOString()}] Finalizada: ${className}.${methodName}() - ${duration}ms`);
2424
+ console.log(` 📊 Resultado: ${typeof res === 'boolean' ? (res ? 'true (PASS)' : 'false (FAIL)') : res ? 'success' : 'null/undefined'}`);
2425
+ console.log('📋 === STATEMENT FINALIZADA ===');
2426
+ return res;
2427
+ })
2428
+ .catch((err) => {
2429
+ const duration = Date.now() - startTime;
2430
+ console.log(` ❌ [${new Date().toISOString()}] Erro: ${className}.${methodName}() - ${duration}ms`);
2431
+ console.log('📋 === STATEMENT COM ERRO ===');
2432
+ throw err;
2433
+ });
2434
+ }
2435
+ // Método síncrono
2436
+ const duration = Date.now() - startTime;
2437
+ console.log(` ✅ [${new Date().toISOString()}] Finalizada: ${className}.${methodName}() - ${duration}ms`);
2438
+ console.log(` 📊 Resultado: ${typeof result === 'boolean' ? (result ? 'true (PASS)' : 'false (FAIL)') : result ? 'success' : 'null/undefined'}`);
2439
+ console.log('📋 === STATEMENT FINALIZADA ===');
2440
+ return result;
2441
+ }
2442
+ catch (error) {
2443
+ const duration = Date.now() - startTime;
2444
+ console.log(` ❌ [${new Date().toISOString()}] Erro: ${className}.${methodName}() - ${duration}ms`);
2445
+ console.log(` 🔍 Erro: ${error?.message || 'Erro desconhecido'}`);
2446
+ console.log('📋 === STATEMENT COM ERRO ===');
2447
+ throw error;
2448
+ }
2449
+ };
2450
+ }
2451
+ }
2452
+ return instance;
2453
+ };
2454
+ // Preservar prototype e propriedades estáticas
2455
+ ForceInterceptedClass.prototype = OriginalClass.prototype;
2456
+ Object.setPrototypeOf(ForceInterceptedClass, OriginalClass);
2457
+ // Copiar propriedades estáticas
2458
+ Object.getOwnPropertyNames(OriginalClass).forEach((prop) => {
2459
+ if (prop !== 'length' && prop !== 'name' && prop !== 'prototype') {
2460
+ try {
2461
+ ;
2462
+ ForceInterceptedClass[prop] = OriginalClass[prop];
2463
+ }
2464
+ catch {
2465
+ // Ignorar propriedades que não podem ser copiadas
2466
+ }
2467
+ }
2468
+ });
2469
+ console.log(`✅ [FORÇA] Classe ${className} completamente interceptada`);
2470
+ return ForceInterceptedClass;
2471
+ }
2472
+ catch (error) {
2473
+ console.warn(`⚠️ [FORÇA] Erro ao criar interceptação para ${className}: ${error}`);
2474
+ return OriginalClass;
2475
+ }
2476
+ }
2477
+ /**
2478
+ * 🚀 Gerencia execução de métodos CT detectados via log
2479
+ */
2480
+ static handleMethodExecution(methodName) {
2481
+ try {
2482
+ // ❌ REMOVIDO: Logs de finalização de CT antigos aqui
2483
+ // O log estava aparecendo DEPOIS do "NOVO CT INICIADO" porque é executado
2484
+ // no início da função. A finalização correta é feita pelo StatementTracker.finalizarCT()
2485
+ // que é chamado pelo CustomReporter quando o teste termina.
2486
+ // ✅ CORREÇÃO: Não criar CT aqui - deixar o StatementTracker.ensureCTCreated() gerenciar
2487
+ // O CT será criado automaticamente na primeira statement pelo interceptStatement()
2488
+ // Aqui apenas registramos o Statement ativo para compatibilidade
2489
+ currentActiveCT = {
2490
+ name: methodName,
2491
+ startTime: Date.now(),
2492
+ statement: methodName,
2493
+ };
2494
+ // ❌ REMOVIDO: Logs duplicados de "NOVO CT INICIADO"
2495
+ // O StatementTracker.startCT já faz os logs necessários
2496
+ // ❌ REMOVIDO: Não criar CT aqui - StatementTracker.ensureCTCreated() faz isso
2497
+ // StatementTracker.startCT(formattedCtName) ← ESTAVA CRIANDO CT PARA CADA STATEMENT!
2498
+ // ✅ CORRIGIDO: Usar nome do método original, não ID aleatório
2499
+ currentActiveCT.name = methodName;
2500
+ }
2501
+ catch (error) {
2502
+ console.warn(`⚠️ Erro ao gerenciar execução de método: ${error}`);
2503
+ }
2504
+ }
2505
+ /**
2506
+ * 🚨 NOVO: Gerencia erros de validação detectados via log
2507
+ */
2508
+ static handleValidationError(errorMessage) {
2509
+ // 🔧 DESABILITADO TEMPORARIAMENTE PARA EVITAR LOOP INFINITO
2510
+ // Este método estava causando spam de "❌ ERRO DE VALIDAÇÃO DETECTADO (sem CT ativo)"
2511
+ // Vamos simplificar e não processar esses erros automaticamente
2512
+ return;
2513
+ }
2514
+ /**
2515
+ * 🏁 Finaliza o CT ativo quando o teste termina
2516
+ */
2517
+ static finalizarCTAtivo() {
2518
+ try {
2519
+ // 1. Finalizar CT ativo do TestAnnotations (sistema legado)
2520
+ if (currentActiveCT) {
2521
+ const duration = ((Date.now() - currentActiveCT.startTime) /
2522
+ 1000).toFixed(2);
2523
+ const currentTime = new Date().toLocaleTimeString('pt-BR');
2524
+ console.log(`\n✅ CT FINALIZADO (FIM DO TESTE): ${currentActiveCT.statement}`);
2525
+ console.log(` ⏱️ Duração: ${duration}s`);
2526
+ console.log(` 🕐 Finalizado: ${currentTime}\n`);
2527
+ // ❌ REMOVIDO: StatementTracker.endCT() - O teardown já finaliza todos os CTs automaticamente
2528
+ // O método finalizarCTAtivo() é do sistema legado e não deve interferir com StatementTracker
2529
+ // Limpar CT ativo
2530
+ currentActiveCT = null;
2531
+ }
2532
+ // ❌ REMOVIDO: Finalização manual de CTs
2533
+ // O UnifiedTeardown.run() já faz isso automaticamente chamando finalizeRunningCTsAsFailed()
2534
+ // Não precisamos fazer aqui para evitar duplicação e erros
2535
+ // 🆕 3. Adicionar logs capturados ao relatório final
2536
+ try {
2537
+ const testInfo = TestContext.getSafeTestInfo();
2538
+ if (testInfo?.title && logsCapturados.length > 0) {
2539
+ // Adicionar header para seção de logs de ações
2540
+ UnifiedReportManager.adicionarLog(testInfo.title, '\n📋 === LOGS DE AÇÕES DE CTs ===');
2541
+ // Adicionar todos os logs capturados
2542
+ for (const log of logsCapturados) {
2543
+ UnifiedReportManager.adicionarLog(testInfo.title, log);
2544
+ }
2545
+ console.log(`📊 Adicionados ${logsCapturados.length} logs de ações ao relatório`);
2546
+ }
2547
+ }
2548
+ catch (error) {
2549
+ console.warn(`⚠️ Erro ao adicionar logs capturados: ${error}`);
2550
+ }
2551
+ // 🆕 4. Restaurar console original e limpar logs
2552
+ TestAnnotations.restaurarConsoleOriginal();
2553
+ }
2554
+ catch (error) {
2555
+ console.warn(`⚠️ Erro na finalização de CTs: ${error}`);
2556
+ }
2557
+ }
2558
+ /**
2559
+ * 🆕 Restaurar console original e limpar dados
2560
+ */
2561
+ static restaurarConsoleOriginal() {
2562
+ try {
2563
+ if (interceptacaoLogsAtiva) {
2564
+ console.log = originalConsoleLog;
2565
+ console.info = originalConsoleInfo;
2566
+ console.warn = originalConsoleWarn;
2567
+ console.error = originalConsoleError;
2568
+ interceptacaoLogsAtiva = false;
2569
+ logsCapturados = [];
2570
+ atualizarReferenciaGlobalDosLogs();
2571
+ console.log('🔧 Console original restaurado e logs limpos');
2572
+ }
2573
+ }
2574
+ catch (error) {
2575
+ console.warn(`⚠️ Erro ao restaurar console: ${error}`);
2576
+ }
2577
+ }
2578
+ /**
2579
+ * 🆕 Obter logs capturados (para debugging)
2580
+ */
2581
+ static getLogsCapturados() {
2582
+ return [...logsCapturados];
2583
+ }
2584
+ // ============================================
2585
+ // 🔐 MÉTODOS DE AUTENTICAÇÃO E STORAGE STATE
2586
+ // ============================================
2587
+ /**
2588
+ * 💾 Salva o estado de autenticação atual (cookies + localStorage + sessionStorage)
2589
+ * @param filePath Caminho opcional para salvar (padrão: ./test-results/auth/auth-state.json)
2590
+ * @example
2591
+ * // Após fazer login
2592
+ * await TestAnnotations.saveAuthState('./auth/admin-user.json')
2593
+ */
2594
+ static async saveAuthState(filePath) {
2595
+ return await TestContext.saveAuthState(filePath);
2596
+ }
2597
+ /**
2598
+ * 🔄 Restaura o estado de autenticação salvo
2599
+ * @param filePath Caminho do arquivo de estado
2600
+ * @example
2601
+ * // Antes de rodar testes
2602
+ * await TestAnnotations.restoreAuthState('./auth/admin-user.json')
2603
+ */
2604
+ static async restoreAuthState(filePath) {
2605
+ await TestContext.restoreAuthState(filePath);
2606
+ }
2607
+ /**
2608
+ * 🧹 Limpa todo o estado de autenticação
2609
+ * @example
2610
+ * // Logout completo
2611
+ * await TestAnnotations.clearAuthState()
2612
+ */
2613
+ static async clearAuthState() {
2614
+ await TestContext.clearAuthState();
2615
+ }
2616
+ /**
2617
+ * 📄 Verifica se existe um arquivo de estado salvo
2618
+ * @param filePath Caminho do arquivo
2619
+ */
2620
+ static authStateExists(filePath) {
2621
+ return TestContext.authStateExists(filePath);
2622
+ }
2623
+ /**
2624
+ * 🔍 Lê o estado salvo sem aplicar
2625
+ * @param filePath Caminho do arquivo
2626
+ */
2627
+ static readAuthState(filePath) {
2628
+ return TestContext.readAuthState(filePath);
2629
+ }
2630
+ /**
2631
+ * 🗑️ Remove um arquivo de estado
2632
+ * @param filePath Caminho do arquivo
2633
+ */
2634
+ static deleteAuthState(filePath) {
2635
+ return TestContext.deleteAuthState(filePath);
2636
+ }
2637
+ /**
2638
+ * 📋 Lista todos os estados salvos
2639
+ */
2640
+ static listAuthStates() {
2641
+ return TestContext.listAuthStates();
2642
+ }
2643
+ }
2644
+ // Removed uppercase aliases: keep only the typed properties (Api, Frontend, Mobile, Banco)
2645
+ // Exportar também as classes individuais para uso direto
2646
+ export const { Api, Frontend, Mobile, SSH, Banco, Mixed, Auto, } = TestAnnotations;
2647
+ // NOTE: Uppercase aliases removed. Use `Api`, `Frontend`, `Mobile`, `Banco` (camelCase) imports instead.