@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,790 @@
1
+ import fs from 'fs';
2
+ import { createRequire } from 'module';
3
+ import SftpClient from 'ssh2-sftp-client';
4
+ import { BaseError, IntegrationError, ValidationError, } from '../functions/errors/index.js';
5
+ import { ExecutionTracker } from '../hubdocs/ExecutionTracker.js';
6
+ import { StatementTracker } from '../hubdocs/StatementTracker.js';
7
+ import { TestContext } from '../testContext/TestContext.js';
8
+ import { UnifiedReportManager } from '../testContext/UnifiedReportManager.js';
9
+ import { Logger } from '../utils/Logger.js';
10
+ import { SSHClient } from './SSHClient.js';
11
+ import path from 'node:path';
12
+ const require = createRequire(import.meta.url);
13
+ // 🤖 IMPORTAÇÃO CRÍTICA: Força inicialização do StatementTracker para projetos SSH
14
+ import '../hubdocs/StatementTracker.js';
15
+ // 🚫 REMOVIDO: import './SSHAutoDisconnect.js' - Causava erro em projetos não-SSH
16
+ // ✅ Desconexão agora é feita no UnifiedTeardown automaticamente
17
+ // 🚫 REMOVIDO: import { installDatabaseInterceptor } from '../utils/DatabaseInterceptor.js'
18
+ /**
19
+ * Classe principal de ações SSH, inspirada no padrão Java Actions.
20
+ * Permite executar comandos, ler saídas, validar resultados e registrar logs/unificados.
21
+ */
22
+ export class SSHActions {
23
+ /** Instância única de SSHClient para uso nas ações */
24
+ static client = null;
25
+ static inicioExecucao;
26
+ static fimExecucao;
27
+ static duracoes = [];
28
+ /**
29
+ * Conecta ao servidor SSH usando chave privada.
30
+ *
31
+ * 🆕 HOST e USERNAME vêm automaticamente do AutoCore Hub!
32
+ * A chave privada é o único parâmetro obrigatório.
33
+ *
34
+ * @param keyPath Caminho para a chave privada.
35
+ * @param options Opções para sobrescrever valores do Hub (opcional)
36
+ */
37
+ // NOTE: Legacy Portuguese-named convenience methods were removed.
38
+ // Use `SSHActions.connectWithKey(relativePath)` or `SSHActions.connectWithPassword(...)` if needed.
39
+ /**
40
+ * Conecta ao SSH usando chave privada relativa ao diretório do projeto.
41
+ *
42
+ * 🆕 HOST e USERNAME vêm automaticamente do AutoCore Hub!
43
+ * Basta chamar TestAnnotations.setSystem('SEU_SISTEMA') antes.
44
+ * A chave privada é o único parâmetro obrigatório (local).
45
+ *
46
+ * @param relativePath Caminho relativo à raiz do projeto (ex: 'secrets/key', './secrets/key')
47
+ * @param options Opções opcionais para sobrescrever valores do Hub
48
+ *
49
+ * @example
50
+ * // ✅ Simples - host/user vêm do Hub, só passa a chave
51
+ * await TestAnnotations.setSystem('SANITY_SSH')
52
+ * await SSHActions.connectWithKey('secrets/UserSistAutBRM')
53
+ *
54
+ * // ✅ Também funciona com ./
55
+ * await SSHActions.connectWithKey('./secrets/UserSistAutBRM')
56
+ *
57
+ * // ✅ Sobrescrevendo valores do Hub se necessário
58
+ * await SSHActions.connectWithKey('secrets/key', { host: 'outro-host.com' })
59
+ */
60
+ static async connectWithKey(relativePath, options) {
61
+ // Se já é caminho absoluto, usa direto
62
+ const cleanPath = path.isAbsolute(relativePath)
63
+ ? relativePath
64
+ : relativePath.startsWith('./')
65
+ ? path.resolve(process.cwd(), relativePath.slice(2))
66
+ : path.resolve(process.cwd(), relativePath);
67
+ // Valida se arquivo existe
68
+ if (!fs.existsSync(cleanPath)) {
69
+ throw new IntegrationError('SSH_KEY_NOT_FOUND', `SSH private key not found: ${cleanPath}`, `Chave privada SSH não encontrada: ${cleanPath}`, undefined, {
70
+ metadata: {
71
+ relativePath,
72
+ absolutePath: cleanPath,
73
+ cwd: process.cwd(),
74
+ action: 'connectWithKey',
75
+ },
76
+ });
77
+ }
78
+ // Create and configure SSH client directly
79
+ if (SSHActions.client) {
80
+ await SSHActions.client.disconnect();
81
+ }
82
+ SSHActions.client = new SSHClient();
83
+ await SSHActions.client.setPrivateKeyPath(cleanPath, options);
84
+ SSHActions.registrarInicioExecucao();
85
+ SSHActions.adicionarLog('Conexão SSH estabelecida com chave privada', 'success');
86
+ Logger.info(`🔑 Usando chave SSH: ${cleanPath}`);
87
+ Logger.info(`🔌 Host/User do Hub: ${process.env.SSH_HOST}@${process.env.SSH_USER}`);
88
+ }
89
+ /**
90
+ * 🆕 Conecta ao servidor SSH usando usuário e senha do AutoCore Hub.
91
+ * Chamado automaticamente pelo setSystem() quando PROJECT_TYPE=SSH.
92
+ *
93
+ * @param host Host do servidor SSH
94
+ * @param port Porta SSH (default: 22)
95
+ * @param username Usuário SSH
96
+ * @param password Senha SSH
97
+ *
98
+ * @example
99
+ * // Conexão manual com senha
100
+ * await SSHActions.conectarComSenha('servidor.com', 22, 'user', 'senha')
101
+ *
102
+ * // Ou use auto-conexão (recomendado):
103
+ * await SSHActions.autoConectar() // Usa credenciais do Hub
104
+ */
105
+ static async connectWithPassword(host, port = 22, username, password) {
106
+ if (SSHActions.client) {
107
+ await SSHActions.client.disconnect();
108
+ }
109
+ SSHActions.client = new SSHClient();
110
+ await SSHActions.client.connectWithPassword(host, port, username, password);
111
+ SSHActions.registrarInicioExecucao();
112
+ SSHActions.adicionarLog(`Conexão SSH estabelecida com usuário/senha em ${host}:${port}`, 'success');
113
+ }
114
+ /**
115
+ * 🆕 Auto-conexão SSH usando credenciais do AutoCore Hub.
116
+ * Usa as variáveis SSH_HOST, SSH_USER e SSH_PASSWORD injetadas pelo setSystem().
117
+ *
118
+ * @throws {IntegrationError} Se as credenciais não estiverem configuradas
119
+ *
120
+ * @example
121
+ * // No teste:
122
+ * test('CT01', async ({}, testInfo) => {
123
+ * TestAnnotations.SSH.testInfo = testInfo
124
+ * await TestAnnotations.setSystem('MEU_SISTEMA_SSH')
125
+ * await SSHActions.autoConnect() // 👈 Usa credenciais do Hub automaticamente
126
+ * await SSHActions.write('ls -la', 'Listar arquivos')
127
+ * })
128
+ */
129
+ static async autoConnect() {
130
+ // Já conectado? Retorna sem fazer nada
131
+ if (SSHActions.client !== null) {
132
+ Logger.info('🔌 SSH já conectado, reutilizando conexão existente');
133
+ return;
134
+ }
135
+ const host = process.env.SSH_HOST;
136
+ const port = Number.parseInt(process.env.SSH_PORT || '22', 10);
137
+ const username = process.env.SSH_USER;
138
+ const password = process.env.SSH_PASSWORD;
139
+ // Validar credenciais obrigatórias
140
+ if (!host || host === 'não definido') {
141
+ throw new IntegrationError('SSH_HOST_NOT_CONFIGURED', 'SSH_HOST not configured. Call TestAnnotations.setSystem() first.', `SSH_HOST não configurado. Chame TestAnnotations.setSystem('NOME_DO_SISTEMA') antes de conectar.`, undefined, {
142
+ metadata: {
143
+ SSH_HOST: process.env.SSH_HOST || '(não definido)',
144
+ SSH_USER: process.env.SSH_USER || '(não definido)',
145
+ action: 'autoConnect',
146
+ },
147
+ });
148
+ }
149
+ if (!username || username === 'não definido') {
150
+ throw new IntegrationError('SSH_USER_NOT_CONFIGURED', 'SSH_USER not configured. Call TestAnnotations.setSystem() first.', `SSH_USER não configurado. Chame TestAnnotations.setSystem('NOME_DO_SISTEMA') antes de conectar.`, undefined, {
151
+ metadata: {
152
+ SSH_HOST: process.env.SSH_HOST || '(não definido)',
153
+ SSH_USER: process.env.SSH_USER || '(não definido)',
154
+ action: 'autoConnect',
155
+ },
156
+ });
157
+ }
158
+ if (!password || password === 'não definido') {
159
+ throw new IntegrationError('SSH_PASSWORD_NOT_CONFIGURED', 'SSH_PASSWORD not configured. Call TestAnnotations.setSystem() first or use connectWithKey() for key-based auth.', `SSH_PASSWORD não configurado. Chame TestAnnotations.setSystem('NOME_DO_SISTEMA') ou use connectWithKey() para autenticação por chave.`, undefined, {
160
+ metadata: {
161
+ SSH_HOST: process.env.SSH_HOST || '(não definido)',
162
+ SSH_USER: process.env.SSH_USER || '(não definido)',
163
+ action: 'autoConnect',
164
+ },
165
+ });
166
+ }
167
+ Logger.bloco('🔌 Auto-conexão SSH usando credenciais do Hub');
168
+ Logger.info(`Host: ${host}`);
169
+ Logger.info(`Porta: ${port}`);
170
+ Logger.info(`Usuário: ${username}`);
171
+ Logger.info(`Senha: ********`);
172
+ await SSHActions.connectWithPassword(host, port, username, password);
173
+ Logger.success(`✅ SSH conectado automaticamente em ${host}:${port}`);
174
+ }
175
+ /**
176
+ * 🆕 Verifica se o cliente SSH está conectado.
177
+ * @returns true se conectado, false caso contrário
178
+ */
179
+ static isConnected() {
180
+ return SSHActions.client !== null;
181
+ }
182
+ /**
183
+ * 🆕 Garante que o cliente SSH está conectado, tentando auto-conexão se necessário.
184
+ * @param actionName Nome da ação para mensagens de erro
185
+ * @throws IntegrationError se não conseguir conectar
186
+ */
187
+ static async ensureConnected(actionName) {
188
+ if (SSHActions.client)
189
+ return;
190
+ Logger.info('🔌 SSH não conectado, tentando auto-conexão...');
191
+ try {
192
+ await SSHActions.autoConnect();
193
+ }
194
+ catch (autoConnectError) {
195
+ throw new IntegrationError('SSH_NOT_CONNECTED', `SSH client is not connected and auto-connect failed. Call SSHActions.autoConnect() or SSHActions.connectWithKey() first.`, `Cliente SSH não conectado e auto-conexão falhou. Chame SSHActions.autoConnect() ou SSHActions.connectWithKey() antes de executar comandos.\n\nDica: Verifique se SSH_HOST, SSH_USER e SSH_PASSWORD estão configurados no ambiente.\n\nErro: ${autoConnectError}`, autoConnectError instanceof Error ? autoConnectError : undefined, { metadata: { action: actionName, autoConnectError: String(autoConnectError) } });
196
+ }
197
+ }
198
+ /**
199
+ * Desconecta do servidor SSH.
200
+ */
201
+ static async desconectar() {
202
+ if (SSHActions.client) {
203
+ await SSHActions.client.disconnect();
204
+ SSHActions.client = null;
205
+ SSHActions.adicionarLog('Conexão SSH encerrada', 'info');
206
+ }
207
+ }
208
+ /**
209
+ * Envia um comando SSH para o servidor remoto.
210
+ * @param command Comando SSH a ser enviado.
211
+ * @param descriptionToAction Descrição da ação, usada no relatório.
212
+ * @returns this
213
+ */
214
+ static async write(command, descriptionToAction) {
215
+ // 🆕 AUTO-CONEXÃO: Se não estiver conectado, tenta conectar automaticamente
216
+ await SSHActions.ensureConnected('write');
217
+ // 🆕 CRÍTICO: Registrar início de execução SSH se ainda não foi registrado
218
+ if (!SSHActions.inicioExecucao) {
219
+ SSHActions.registrarInicioExecucao();
220
+ Logger.info('⏱️ Início da execução SSH registrado');
221
+ }
222
+ const startTime = Date.now();
223
+ // 🆕 Interceptar para AutoDocs com ExecutionTracker
224
+ const sshCommand = {
225
+ command,
226
+ output: '',
227
+ host: process.env.SSH_HOST || 'ssh-server',
228
+ timestamp: new Date().toISOString(),
229
+ testName: TestContext.getSafeTestInfo()?.title || 'SSH Command',
230
+ user: process.env.SSH_USER || 'user',
231
+ duration: 0,
232
+ exitCode: 0,
233
+ };
234
+ try {
235
+ // Registrar no ExecutionTracker
236
+ const testInfo = TestContext.getSafeTestInfo();
237
+ await SSHActions.client.write(command, descriptionToAction);
238
+ const duration = Date.now() - startTime;
239
+ // 🆕 Atualizar comando SSH com sucesso
240
+ sshCommand.duration = duration;
241
+ sshCommand.output = 'Comando enviado com sucesso';
242
+ sshCommand.exitCode = 0;
243
+ // 🆕 Registrar no ExecutionTracker
244
+ ExecutionTracker.trackSSH(sshCommand);
245
+ // 📝 NOVO: Registrar ação automaticamente no Statement ativo
246
+ try {
247
+ StatementTracker.recordAction('SSH', `${descriptionToAction}: ${command}`, true, duration, {
248
+ command,
249
+ });
250
+ }
251
+ catch (error) {
252
+ // Falha silenciosa - não afetar funcionalidade principal
253
+ }
254
+ SSHActions.adicionarLog(`${descriptionToAction} >> ${command}`, 'info');
255
+ return SSHActions;
256
+ }
257
+ catch (error) {
258
+ const duration = Date.now() - startTime;
259
+ // 🆕 Atualizar comando SSH com erro
260
+ sshCommand.duration = duration;
261
+ sshCommand.output = `Erro: ${error}`;
262
+ sshCommand.exitCode = 1;
263
+ // 🆕 Registrar no ExecutionTracker mesmo com erro
264
+ ExecutionTracker.trackSSH(sshCommand);
265
+ // 📝 NOVO: Registrar ação com falha no Statement ativo
266
+ try {
267
+ StatementTracker.recordAction('SSH', `${descriptionToAction}: ${command}`, false, duration, {
268
+ command,
269
+ });
270
+ }
271
+ catch (error) {
272
+ // Falha silenciosa - não afetar funcionalidade principal
273
+ }
274
+ SSHActions.adicionarLog(`Erro em ${descriptionToAction}: ${error}`, 'error');
275
+ throw error;
276
+ }
277
+ }
278
+ /**
279
+ * Envia um comando SSH e verifica o resultado do comando (usando "$?").
280
+ * @param command Comando SSH a ser enviado.
281
+ * @param descriptionToAction Descrição da ação, usada no relatório.
282
+ * @returns true se sucesso, false caso contrário.
283
+ */
284
+ static async writeAndReturnCommand(command, descriptionToAction) {
285
+ await SSHActions.ensureConnected('writeAndReturnCommand');
286
+ await SSHActions.client.write(`${command}; $?`, descriptionToAction);
287
+ const output = SSHActions.client.read(descriptionToAction);
288
+ const isSuccess = output.trim().endsWith('0');
289
+ SSHActions.adicionarLog(`${descriptionToAction} >> ${command} - ${isSuccess ? 'Sucesso' : 'Falha'}`, isSuccess ? 'success' : 'error');
290
+ return isSuccess;
291
+ }
292
+ /**
293
+ * Lê a saída do log do servidor remoto.
294
+ * @param descriptionToAction Descrição da ação, usada no relatório.
295
+ * @returns Saída do log como string.
296
+ */
297
+ static read(descriptionToAction) {
298
+ if (!SSHActions.client)
299
+ throw new IntegrationError('SSH_NOT_CONNECTED', 'SSH client is not connected. Use SSHActions.autoConnect() first.', 'Cliente SSH não conectado. Use SSHActions.autoConnect() antes.', undefined, { metadata: { action: 'read' } });
300
+ // Registrar statement no StatementTracker
301
+ let statementTimestamp = null;
302
+ try {
303
+ const { StatementTracker } = require('../hubdocs/StatementTracker.js');
304
+ statementTimestamp = StatementTracker.startStatement('SSHActions', `read: ${descriptionToAction}`);
305
+ }
306
+ catch (error) {
307
+ Logger.warning(`Não foi possível registrar statement no StatementTracker: ${error}`);
308
+ }
309
+ const startTime = Date.now();
310
+ const output = SSHActions.client.read(descriptionToAction);
311
+ const duration = Date.now() - startTime;
312
+ // 🆕 Registrar leitura de SSH no AutoDocs
313
+ // ✅ CORRIGIDO: read() sempre é sucesso se não lança exceção
314
+ const sshCommand = {
315
+ command: `read: ${descriptionToAction}`,
316
+ output,
317
+ host: process.env.SSH_HOST || 'ssh-server',
318
+ timestamp: new Date().toISOString(),
319
+ testName: TestContext.getSafeTestInfo()?.title || 'SSH Read',
320
+ user: process.env.SSH_USER || 'user',
321
+ duration,
322
+ exitCode: 0, // ✅ Sempre 0 se chegou até aqui sem exceção
323
+ };
324
+ ExecutionTracker.trackSSH(sshCommand);
325
+ // 📝 NOVO: Registrar ação automaticamente no Statement ativo
326
+ try {
327
+ StatementTracker.recordAction('SSH', `Read: ${descriptionToAction}`, true, duration);
328
+ }
329
+ catch (error) {
330
+ // Falha silenciosa - não afetar funcionalidade principal
331
+ }
332
+ // Finalizar statement
333
+ if (statementTimestamp) {
334
+ try {
335
+ const { StatementTracker } = require('../hubdocs/StatementTracker.js');
336
+ StatementTracker.finishStatement(statementTimestamp, true, `✅ ${descriptionToAction}: Saída capturada com sucesso`);
337
+ }
338
+ catch (error) {
339
+ Logger.warning(`Não foi possível finalizar statement no StatementTracker: ${error}`);
340
+ }
341
+ }
342
+ SSHActions.adicionarLog(`Leitura: ${descriptionToAction}`, 'info');
343
+ return output;
344
+ }
345
+ /**
346
+ * Verifica a saída do comando enviado ao servidor remoto.
347
+ * @returns true se o comando foi executado com sucesso, false caso contrário.
348
+ */
349
+ static async readOutputCommand() {
350
+ await SSHActions.ensureConnected('readOutputCommand');
351
+ const output = SSHActions.client.read('Verificando saída do comando');
352
+ return output.trim().endsWith('0');
353
+ }
354
+ /**
355
+ * Faz download de arquivo do servidor remoto para o caminho de destino especificado.
356
+ * @param sourcePath Caminho do arquivo no servidor remoto.
357
+ * @param destinyPath Caminho de destino para salvar o arquivo.
358
+ * @param descriptionToAction Descrição da ação, usada no relatório.
359
+ */
360
+ static async download(sourcePath, destinyPath, descriptionToAction) {
361
+ await SSHActions.ensureConnected('download');
362
+ const sftp = new SftpClient();
363
+ const startTime = Date.now();
364
+ // 🆕 Registrar download SSH no AutoDocs
365
+ const sshCommand = {
366
+ command: `download: ${sourcePath} → ${destinyPath}`,
367
+ output: '',
368
+ host: process.env.SSH_HOST || 'ssh-server',
369
+ timestamp: new Date().toISOString(),
370
+ testName: TestContext.getSafeTestInfo()?.title || 'SSH Download',
371
+ user: process.env.SSH_USER || 'user',
372
+ duration: 0,
373
+ exitCode: 1,
374
+ };
375
+ try {
376
+ await sftp.connect({
377
+ host: process.env.SSH_HOST,
378
+ port: Number.parseInt(process.env.SSH_PORT || '22', 10),
379
+ username: process.env.SSH_USER,
380
+ privateKey: fs.readFileSync(process.env.SSH_PRIVATE_KEY_PATH || '', 'utf-8'),
381
+ passphrase: process.env.SSH_PASSPHRASE,
382
+ });
383
+ await sftp.fastGet(sourcePath, destinyPath);
384
+ const duration = Date.now() - startTime;
385
+ // 🆕 Atualizar comando SSH com sucesso
386
+ sshCommand.duration = duration;
387
+ sshCommand.output = `Download concluído: ${sourcePath} → ${destinyPath}`;
388
+ sshCommand.exitCode = 0;
389
+ // 🆕 Registrar no ExecutionTracker
390
+ ExecutionTracker.trackSSH(sshCommand);
391
+ // 📝 NOVO: Registrar ação automaticamente no Statement ativo
392
+ try {
393
+ StatementTracker.recordAction('SSH', `Download: ${sourcePath} → ${destinyPath}`, true, duration, {
394
+ command: `download ${sourcePath}`,
395
+ });
396
+ }
397
+ catch (error) {
398
+ // Falha silenciosa - não afetar funcionalidade principal
399
+ }
400
+ SSHActions.adicionarLog(`Download concluído: ${sourcePath} → ${destinyPath} (${descriptionToAction})`, 'success');
401
+ }
402
+ catch (error) {
403
+ const duration = Date.now() - startTime;
404
+ // 🆕 Atualizar comando SSH com erro
405
+ sshCommand.duration = duration;
406
+ sshCommand.output = `Erro no download: ${error}`;
407
+ sshCommand.exitCode = 1;
408
+ // 🆕 Registrar no ExecutionTracker mesmo com erro
409
+ ExecutionTracker.trackSSH(sshCommand);
410
+ // 📝 NOVO: Registrar ação automaticamente no Statement ativo (erro)
411
+ try {
412
+ StatementTracker.recordAction('SSH', `Download FALHOU: ${sourcePath} → ${destinyPath}`, false, duration, {
413
+ command: `download ${sourcePath}`,
414
+ });
415
+ }
416
+ catch (recordError) {
417
+ // Falha silenciosa - não afetar funcionalidade principal
418
+ }
419
+ SSHActions.adicionarLog(`Erro no download: ${error}`, 'error');
420
+ if (error instanceof BaseError) {
421
+ throw error;
422
+ }
423
+ throw new IntegrationError('SSH_DOWNLOAD_FAILED', `SSH download failed: ${error}`, `Falha no download SSH: ${error}`, error instanceof Error ? error : new Error(String(error)), { metadata: { sourcePath, destinyPath, action: descriptionToAction } });
424
+ }
425
+ finally {
426
+ await sftp.end();
427
+ }
428
+ }
429
+ /**
430
+ * Registra o início da execução e limpa o contexto SSH.
431
+ */
432
+ static registrarInicioExecucao() {
433
+ SSHActions.inicioExecucao = new Date();
434
+ Logger.info('⏱️ Início da execução SSH registrado');
435
+ }
436
+ /**
437
+ * Registra o fim da execução.
438
+ */
439
+ static registrarFimExecucao() {
440
+ SSHActions.fimExecucao = new Date();
441
+ if (SSHActions.inicioExecucao) {
442
+ const duration = (SSHActions.fimExecucao.getTime() -
443
+ SSHActions.inicioExecucao.getTime()) /
444
+ 1000;
445
+ Logger.info(`⏱️ Execução SSH concluída em ${duration.toFixed(2)}s`);
446
+ }
447
+ }
448
+ /**
449
+ * Registra um evento de log no contexto SSH.
450
+ * @param message Mensagem de log.
451
+ */
452
+ static logEvent(message) {
453
+ const testInfo = TestContext.getSafeTestInfo();
454
+ if (testInfo?.title) {
455
+ try {
456
+ UnifiedReportManager.adicionarLog(testInfo.title, message);
457
+ }
458
+ catch {
459
+ Logger.info(`📝 SSH Log: ${message}`);
460
+ }
461
+ }
462
+ else {
463
+ Logger.info(`📝 SSH Log: ${message}`);
464
+ }
465
+ if (testInfo &&
466
+ testInfo.annotations &&
467
+ Array.isArray(testInfo.annotations)) {
468
+ testInfo.annotations.push({ type: 'log', description: message });
469
+ }
470
+ }
471
+ /**
472
+ * Registra a duração de um teste SSH.
473
+ * @param nome Nome do teste.
474
+ * @param duracao Duração em milissegundos.
475
+ */
476
+ static registrarDuracaoDoTeste(nome, duracao) {
477
+ SSHActions.duracoes.push({ nome, duracao });
478
+ Logger.info(`⏱️ Duração registrada para "${nome}": ${duracao}ms`);
479
+ const testInfo = TestContext.getSafeTestInfo();
480
+ if (testInfo?.title) {
481
+ try {
482
+ UnifiedReportManager.setTestDuration(testInfo.title, duracao / 1000);
483
+ }
484
+ catch { }
485
+ }
486
+ }
487
+ /**
488
+ * Valida se a saída contém o texto esperado.
489
+ * @param output Saída do comando SSH.
490
+ * @param expected Texto esperado.
491
+ * @param message Mensagem descritiva da validação.
492
+ * @throws {Error} Se o texto não for encontrado.
493
+ */
494
+ static validateContains(output, expected, message) {
495
+ // Registrar statement no StatementTracker
496
+ let statementTimestamp = null;
497
+ try {
498
+ const { StatementTracker } = require('../hubdocs/StatementTracker.js');
499
+ statementTimestamp = StatementTracker.startStatement('SSHActions', `validateContains: ${message}`);
500
+ }
501
+ catch (error) {
502
+ Logger.warning(`Não foi possível registrar statement no StatementTracker: ${error}`);
503
+ }
504
+ if (!output.includes(expected)) {
505
+ const errorMsg = `❌ ${message}: esperado conter "${expected}", mas não encontrado.`;
506
+ SSHActions.logEvent(errorMsg);
507
+ Logger.error(message);
508
+ if (statementTimestamp) {
509
+ try {
510
+ const { StatementTracker } = require('../hubdocs/StatementTracker.js');
511
+ StatementTracker.finishStatement(statementTimestamp, false, errorMsg);
512
+ }
513
+ catch (error) {
514
+ Logger.warning(`Não foi possível finalizar statement no StatementTracker: ${error}`);
515
+ }
516
+ }
517
+ throw new ValidationError('SSH_VALIDATION_CONTAINS_FAILED', `Validation failed: expected to contain "${expected}", but not found`, `${message}: esperado conter "${expected}", mas não encontrado.`, undefined, { metadata: { expected, actual: output, context: message } });
518
+ }
519
+ const successMsg = `✅ ${message}: encontrado "${expected}"`;
520
+ SSHActions.logEvent(successMsg);
521
+ Logger.success(successMsg);
522
+ if (statementTimestamp) {
523
+ try {
524
+ const { StatementTracker } = require('../hubdocs/StatementTracker.js');
525
+ StatementTracker.finishStatement(statementTimestamp, true, successMsg);
526
+ }
527
+ catch (error) {
528
+ Logger.warning(`Não foi possível finalizar statement no StatementTracker: ${error}`);
529
+ }
530
+ }
531
+ }
532
+ /**
533
+ * Valida se a saída NÃO contém o texto especificado.
534
+ * @param output Saída do comando SSH.
535
+ * @param notExpected Texto que não deve estar presente.
536
+ * @param message Mensagem descritiva da validação.
537
+ * @throws {Error} Se o texto for encontrado.
538
+ */
539
+ static validateNotContains(output, notExpected, message) {
540
+ if (output.includes(notExpected)) {
541
+ const errorMsg = `❌ ${message}: não esperado encontrar "${notExpected}", mas foi encontrado.`;
542
+ SSHActions.logEvent(errorMsg);
543
+ Logger.error(message);
544
+ throw new ValidationError('SSH_VALIDATION_NOT_CONTAINS_FAILED', `Validation failed: not expected to find "${notExpected}", but was found`, `${message}: não esperado encontrar "${notExpected}", mas foi encontrado.`, undefined, { metadata: { notExpected, actual: output, context: message } });
545
+ }
546
+ const successMsg = `✅ ${message}: "${notExpected}" não encontrado (como esperado)`;
547
+ SSHActions.logEvent(successMsg);
548
+ Logger.success(successMsg);
549
+ }
550
+ /**
551
+ * Valida se a saída corresponde a uma expressão regular.
552
+ * @param output Saída do comando SSH.
553
+ * @param pattern Padrão regex.
554
+ * @param message Mensagem descritiva da validação.
555
+ * @throws {Error} Se a saída não corresponder ao padrão.
556
+ */
557
+ static validateMatches(output, pattern, message) {
558
+ if (!pattern.test(output)) {
559
+ const errorMsg = `❌ ${message}: saída não corresponde ao padrão ${pattern.toString()}`;
560
+ SSHActions.logEvent(errorMsg);
561
+ Logger.error(message);
562
+ throw new Error(`${message}: saída não corresponde ao padrão ${pattern.toString()}`);
563
+ }
564
+ const successMsg = `✅ ${message}: saída corresponde ao padrão ${pattern.toString()}`;
565
+ SSHActions.logEvent(successMsg);
566
+ Logger.success(successMsg);
567
+ }
568
+ /**
569
+ * Adiciona log personalizado ao contexto SSH.
570
+ * @param mensagem Mensagem de log.
571
+ * @param tipo Tipo do log ('info', 'success', 'error', 'warning').
572
+ */
573
+ static adicionarLog(mensagem, tipo = 'info') {
574
+ const emojis = {
575
+ info: 'ℹ️',
576
+ success: '✅',
577
+ error: '❌',
578
+ warning: '⚠️',
579
+ };
580
+ const emoji = emojis[tipo];
581
+ const logEntry = `${emoji} ${mensagem}`;
582
+ SSHActions.logEvent(logEntry);
583
+ switch (tipo) {
584
+ case 'error':
585
+ Logger.error(mensagem);
586
+ break;
587
+ case 'success':
588
+ Logger.success(mensagem);
589
+ break;
590
+ case 'warning':
591
+ Logger.warning(mensagem);
592
+ break;
593
+ default:
594
+ Logger.info(mensagem);
595
+ }
596
+ }
597
+ /**
598
+ * Anexa o relatório final do teste SSH ao UnifiedReportManager.
599
+ */
600
+ static async anexarRelatorioFinal() {
601
+ try {
602
+ await UnifiedReportManager.finalizarTeste();
603
+ }
604
+ catch (error) {
605
+ Logger.error('❌ Erro ao anexar relatórios finais via UnifiedReportManager', error);
606
+ }
607
+ }
608
+ /**
609
+ * Limpa todos os dados e métricas SSH.
610
+ */
611
+ static limparTudo() {
612
+ SSHActions.duracoes = [];
613
+ SSHActions.inicioExecucao = undefined;
614
+ SSHActions.fimExecucao = undefined;
615
+ Logger.info('🗂️ Todos os dados SSH limpos');
616
+ }
617
+ /**
618
+ * Obtém estatísticas do teste SSH atual.
619
+ * @returns Objeto com total de logs, sucessos, erros, comandos executados e duração total.
620
+ */
621
+ static obterEstatisticas() {
622
+ const testInfo = TestContext.getSafeTestInfo();
623
+ let logs = [];
624
+ if (testInfo?.title) {
625
+ try {
626
+ const teste = UnifiedReportManager.getMetrics().testes.find((t) => t.nome === testInfo.title);
627
+ logs = teste?.logs || [];
628
+ }
629
+ catch {
630
+ logs = [];
631
+ }
632
+ }
633
+ return {
634
+ totalLogs: logs.length,
635
+ sucessos: logs.filter((log) => log.includes('✅')).length,
636
+ erros: logs.filter((log) => log.includes('❌')).length,
637
+ comandosExecutados: SSHActions.duracoes.length,
638
+ duracaoTotal: SSHActions.duracoes.reduce((total, item) => total + item.duracao, 0),
639
+ };
640
+ }
641
+ /**
642
+ * Verifica se há logs registrados para o teste SSH atual.
643
+ * @returns true se houver logs, false caso contrário.
644
+ */
645
+ static temLogs() {
646
+ const testInfo = TestContext.getSafeTestInfo();
647
+ if (testInfo?.title) {
648
+ try {
649
+ const teste = UnifiedReportManager.getMetrics().testes.find((t) => t.nome === testInfo.title);
650
+ return (teste?.logs || []).length > 0;
651
+ }
652
+ catch {
653
+ return false;
654
+ }
655
+ }
656
+ return false;
657
+ }
658
+ /**
659
+ * Obtém todos os logs registrados para o teste SSH atual.
660
+ * @returns Array de logs.
661
+ */
662
+ static obterLogs() {
663
+ const testInfo = TestContext.getSafeTestInfo();
664
+ if (testInfo?.title) {
665
+ try {
666
+ const teste = UnifiedReportManager.getMetrics().testes.find((t) => t.nome === testInfo.title);
667
+ return [...(teste?.logs || [])];
668
+ }
669
+ catch {
670
+ return [];
671
+ }
672
+ }
673
+ return [];
674
+ }
675
+ /**
676
+ * Verifica se houve falhas no teste SSH atual.
677
+ * @returns true se houver falhas, false caso contrário.
678
+ */
679
+ static temFalhas() {
680
+ const logs = SSHActions.obterLogs();
681
+ return logs.some((log) => log.includes('❌'));
682
+ }
683
+ /**
684
+ * Obtém um resumo do teste SSH atual.
685
+ * @returns Objeto com informações de logs, falhas, estatísticas e datas.
686
+ */
687
+ static obterResumo() {
688
+ return {
689
+ temLogs: SSHActions.temLogs(),
690
+ temFalhas: SSHActions.temFalhas(),
691
+ estatisticas: SSHActions.obterEstatisticas(),
692
+ inicioExecucao: SSHActions.inicioExecucao,
693
+ fimExecucao: SSHActions.fimExecucao,
694
+ };
695
+ }
696
+ /**
697
+ * Indica se o SSHActions foi utilizado no teste atual.
698
+ * @returns true se utilizado, false caso contrário.
699
+ */
700
+ static foiUtilizado() {
701
+ return Boolean(SSHActions.inicioExecucao) || SSHActions.duracoes.length > 0;
702
+ }
703
+ /**
704
+ * Obtém métricas resumidas do teste SSH atual.
705
+ * @returns Objeto com comandosExecutados, sucessos, erros e duracaoTotal.
706
+ */
707
+ static getMetrics() {
708
+ const stats = SSHActions.obterEstatisticas();
709
+ return {
710
+ comandosExecutados: stats.comandosExecutados,
711
+ sucessos: stats.sucessos,
712
+ erros: stats.erros,
713
+ duracaoTotal: stats.duracaoTotal,
714
+ };
715
+ }
716
+ /**
717
+ * Valida se a saída contém o texto esperado dentro de um timeout.
718
+ * @param output Saída do comando SSH.
719
+ * @param expected Texto esperado.
720
+ * @param message Mensagem descritiva da validação.
721
+ * @param timeout Tempo máximo em ms para aguardar.
722
+ * @throws {Error} Se o texto não for encontrado no tempo especificado.
723
+ */
724
+ static async validateContainsWithTimeout(output, expected, message, timeout = TestContext.getProjectTimeout()) {
725
+ const startTime = Date.now();
726
+ while (Date.now() - startTime < timeout) {
727
+ if (output.includes(expected)) {
728
+ const successMsg = `✅ ${message}: encontrado "${expected}" em ${Date.now() - startTime}ms`;
729
+ SSHActions.logEvent(successMsg);
730
+ Logger.success(successMsg);
731
+ return;
732
+ }
733
+ await new Promise((resolve) => setTimeout(resolve, 100));
734
+ }
735
+ const errorMsg = `❌ ${message}: timeout aguardando "${expected}" (${timeout}ms)`;
736
+ SSHActions.logEvent(errorMsg);
737
+ Logger.error(message);
738
+ throw new Error(`${message}: timeout aguardando "${expected}"`);
739
+ }
740
+ /**
741
+ * Valida se todos os textos esperados estão presentes na saída.
742
+ * @param output Saída do comando SSH.
743
+ * @param expectedTexts Array de textos esperados.
744
+ * @param message Mensagem descritiva da validação.
745
+ * @throws {Error} Se algum texto não for encontrado.
746
+ */
747
+ static validateContainsAll(output, expectedTexts, message) {
748
+ const missing = expectedTexts.filter((text) => !output.includes(text));
749
+ if (missing.length > 0) {
750
+ const errorMsg = `❌ ${message}: textos não encontrados: ${missing.join(', ')}`;
751
+ SSHActions.logEvent(errorMsg);
752
+ Logger.error(message);
753
+ throw new Error(`${message}: textos não encontrados: ${missing.join(', ')}`);
754
+ }
755
+ const successMsg = `✅ ${message}: todos os textos encontrados (${expectedTexts.length} itens)`;
756
+ SSHActions.logEvent(successMsg);
757
+ Logger.success(successMsg);
758
+ }
759
+ /**
760
+ * Valida se pelo menos um dos textos esperados está presente na saída.
761
+ * @param output Saída do comando SSH.
762
+ * @param expectedTexts Array de textos esperados.
763
+ * @param message Mensagem descritiva da validação.
764
+ * @throws {Error} Se nenhum texto for encontrado.
765
+ */
766
+ static validateContainsAny(output, expectedTexts, message) {
767
+ const found = expectedTexts.filter((text) => output.includes(text));
768
+ if (found.length === 0) {
769
+ const errorMsg = `❌ ${message}: nenhum dos textos esperados encontrado: ${expectedTexts.join(', ')}`;
770
+ SSHActions.logEvent(errorMsg);
771
+ Logger.error(message);
772
+ throw new Error(`${message}: nenhum dos textos esperados encontrado`);
773
+ }
774
+ const successMsg = `✅ ${message}: encontrado(s): ${found.join(', ')}`;
775
+ SSHActions.logEvent(successMsg);
776
+ Logger.success(successMsg);
777
+ }
778
+ }
779
+ // 🚫 AUTO-ATIVAÇÃO REMOVIDA: SSHActions são métodos internos que não devem ser interceptados
780
+ // SSHActions.validateContains(), .write(), etc. não são CTs válidos e devem ser filtrados
781
+ // A interceptação foi removida para evitar falsos CTs nos relatórios
782
+ // CTs reais vêm das classes Statement (StatementsSSH, etc.) via InterceptacaoMagica.ts
783
+ // CÓDIGO REMOVIDO:
784
+ // try {
785
+ // installDatabaseInterceptor(SSHActions, 'SSHActions')
786
+ // } catch (error) {
787
+ // if (process.env.AUTOCORE_DEBUG_LOGS === 'true') {
788
+ // process.stderr.write(`[DatabaseInterceptor] Falha na auto-ativação SSHActions: ${String(error)}\n`)
789
+ // }
790
+ // }