@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,772 @@
1
+ import { HttpsProxyAgent } from 'https-proxy-agent';
2
+ import { remote } from 'webdriverio';
3
+ import { GlobalErrorHandler } from '../functions/errors/index.js';
4
+ import { TestContext } from '../testContext/TestContext.js';
5
+ import { Logger } from '../utils/Logger.js';
6
+ import { DeviceFarmViewer } from './DeviceFarmViewer.js';
7
+ import https from 'node:https';
8
+ import { setGlobalDispatcher, Agent } from 'undici';
9
+ import path from 'node:path';
10
+ import fs from 'node:fs';
11
+ /**
12
+ * ✅ ULTRA-RADICAL MobileConnection - VERSION 2.0 FIXED
13
+ *
14
+ * MELHORIAS MANTIDAS:
15
+ * - 🔥 Ultra-radical closeSession() com múltiplas estratégias de disconnection
16
+ * - 🔥 Force-kill DeviceFarm sessions via múltiplos endpoints API
17
+ * - 🔥 Aggressive cleanup: garbage collection, timers, global vars, event listeners
18
+ * - 📱 Screenshot integration com DeviceFarmViewer (1s polling)
19
+ * - 🔧 Consumer project detection e cross-project operations
20
+ * - 🌐 Simple connection strategies com proxy/direct fallback
21
+ * - 📋 Playwright report integration
22
+ * - 🛡️ SSL/certificate handling simplificado
23
+ * - ⚡ Optimized WebDriverIO configurations
24
+ * - 🔑 API key interna (usuário não precisa configurar)
25
+ *
26
+ * CORRIGIDO:
27
+ * - ❌ Removido require() - 100% ESModules
28
+ * - ❌ Conectividade simplificada baseada na versão que funcionava
29
+ * - ❌ SSL killer mais simples e efetivo
30
+ * - ❌ Fetch com configurações corretas
31
+ */
32
+ export class MobileConnection {
33
+ static driver = null;
34
+ static remoteHost = process.env.DEVICEFARM_HOST || 'devicefarm-qa.com.br';
35
+ static remotePort = Number.parseInt(process.env.DEVICEFARM_PORT || '443');
36
+ static remotePath = process.env.DEVICEFARM_PATH || '/api/mobile/wd/hub';
37
+ static proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null;
38
+ // ✅ API KEY INTERNA - Usuário não precisa configurar mais
39
+ static apiKey = process.env.DEVICEFARM_API_KEY || '75ec082d-f22c-4b17-b872-1a0d4791fa40';
40
+ // ✅ ULTRA-RADICAL SESSION TRACKING
41
+ static activeSessionId = null;
42
+ static connectionTimestamp = Date.now();
43
+ static forceCleanupExecuted = false;
44
+ static _isConnected = false;
45
+ static _currentCapabilities = null;
46
+ /**
47
+ * ✅ MAIN CONNECTION METHOD - Ultra-optimized with simple fallback strategies
48
+ */
49
+ static async connect(capabilities) {
50
+ try {
51
+ // 🚫 Initialize SSL killer first
52
+ await MobileConnection.initializeGlobalSSLKiller();
53
+ Logger.bloco('🔧 Iniciando Conexão Mobile com DeviceFarm');
54
+ Logger.info(`🎯 Host: ${MobileConnection.remoteHost}:${MobileConnection.remotePort}`);
55
+ Logger.info(`🔑 API Key: ${MobileConnection.apiKey.substring(0, 8)}...`);
56
+ // ✅ VALIDAÇÃO DE CAPABILITIES
57
+ MobileConnection.validateCapabilities(capabilities);
58
+ MobileConnection._currentCapabilities = capabilities;
59
+ // ✅ VERIFICAR CONECTIVIDADE SIMPLES
60
+ const connectivityResults = await MobileConnection.checkDeviceFarmConnectivityWithFallback();
61
+ if (!connectivityResults.success) {
62
+ throw new Error('❌ DeviceFarm não acessível com nenhuma estratégia de conectividade');
63
+ }
64
+ // ✅ CONECTAR USANDO ESTRATÉGIA SIMPLES
65
+ const driver = await MobileConnection.createSimpleConnection(capabilities, connectivityResults.useProxy);
66
+ if (!driver?.sessionId) {
67
+ throw new Error('❌ Falha ao criar sessão mobile');
68
+ }
69
+ MobileConnection.driver = driver;
70
+ MobileConnection.activeSessionId = driver.sessionId;
71
+ MobileConnection._isConnected = true;
72
+ // ✅ CONFIGURAR VISUALIZAÇÃO AUTOMÁTICA COM 1 SEGUNDO POLLING
73
+ await MobileConnection.setupAutomaticVisualization(capabilities);
74
+ Logger.success(`Conexão mobile estabelecida: ${driver.sessionId}`);
75
+ return driver;
76
+ }
77
+ catch (error) {
78
+ const errorMsg = error instanceof Error ? error.message : String(error);
79
+ // ✅ USAR ERROR HANDLER ADEQUADO
80
+ const errorHandler = GlobalErrorHandler.getInstance();
81
+ const errorToHandle = error instanceof Error ? error : new Error(String(error));
82
+ errorHandler.handleError(errorToHandle, {
83
+ context: 'MobileConnection.connect',
84
+ operation: 'Device connection',
85
+ severity: 'high',
86
+ metadata: { capabilities },
87
+ });
88
+ // ✅ TROUBLESHOOTING INFO
89
+ MobileConnection.logTroubleshootingInfo();
90
+ throw new Error(`❌ Falha na conexão mobile: ${errorMsg}`);
91
+ }
92
+ }
93
+ /**
94
+ * 🔥 ULTRA-RADICAL SESSION TERMINATION - AGGRESSIVE MULTI-LEVEL DISCONNECTION
95
+ *
96
+ * Estratégias implementadas:
97
+ * 1. Stop DeviceFarmViewer
98
+ * 2. Force-close via DeviceFarm API
99
+ * 3. Driver termination (deleteSession, quit, closeApp) com timeouts
100
+ * 4. HTTP/HTTPS agent destruction
101
+ * 5. Force-kill all DeviceFarm sessions
102
+ * 6. Ultra-aggressive cleanup (GC, timers, globals, listeners)
103
+ */
104
+ static async closeSession() {
105
+ const sessionId = MobileConnection.activeSessionId || MobileConnection.driver?.sessionId;
106
+ if (sessionId) {
107
+ Logger.info(`🎯 Session ID a ser terminada: ${sessionId}`);
108
+ }
109
+ // ✅ ESTRATÉGIA 1: STOP DEVICEFARM VIEWER
110
+ try {
111
+ await DeviceFarmViewer.stop();
112
+ Logger.success('DeviceFarmViewer parado');
113
+ }
114
+ catch (error) {
115
+ Logger.warning(`Erro ao parar DeviceFarmViewer: ${String(error)}`);
116
+ }
117
+ // ✅ ESTRATÉGIA 2: FORCE-CLOSE VIA DEVICEFARM API
118
+ if (sessionId) {
119
+ try {
120
+ await MobileConnection.forceCloseSessionViaAPI(sessionId);
121
+ Logger.success('Force-close via API concluído');
122
+ }
123
+ catch (error) {
124
+ Logger.warning(`Erro no force-close via API: ${String(error)}`);
125
+ }
126
+ }
127
+ // ✅ ESTRATÉGIA 3: DRIVER TERMINATION COM MÚLTIPLOS MÉTODOS
128
+ if (MobileConnection.driver) {
129
+ try {
130
+ Logger.info('🔌 Iniciando terminação do driver...');
131
+ // Múltiplas tentativas de fechamento
132
+ const terminationMethods = [
133
+ {
134
+ name: 'deleteSession',
135
+ method: () => MobileConnection.driver.deleteSession(),
136
+ },
137
+ {
138
+ name: 'closeApp',
139
+ method: () => MobileConnection.driver.closeApp &&
140
+ MobileConnection.driver.closeApp(),
141
+ },
142
+ ];
143
+ for (const { name, method } of terminationMethods) {
144
+ try {
145
+ await Promise.race([
146
+ method(),
147
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 10_000)),
148
+ ]);
149
+ Logger.success(`✅ ${name} concluído`);
150
+ break; // Se um funcionou, não precisa tentar os outros
151
+ }
152
+ catch (error) {
153
+ Logger.warning(`⚠️ ${name} falhou: ${String(error)}`);
154
+ }
155
+ }
156
+ }
157
+ catch (error) {
158
+ Logger.warning(`⚠️ Erro na terminação do driver: ${String(error)}`);
159
+ }
160
+ }
161
+ // ✅ ESTRATÉGIA 5: FORCE-KILL ALL DEVICEFARM SESSIONS
162
+ try {
163
+ await MobileConnection.forceKillAllDeviceFarmSessions();
164
+ }
165
+ catch (error) {
166
+ Logger.warning(`⚠️ Erro no force-kill all sessions: ${String(error)}`);
167
+ }
168
+ // ✅ ESTRATÉGIA 6: ULTRA-AGGRESSIVE CLEANUP
169
+ try {
170
+ await MobileConnection.forceCleanup();
171
+ }
172
+ catch (error) {
173
+ Logger.warning(`⚠️ Erro no ultra-aggressive cleanup: ${String(error)}`);
174
+ }
175
+ // ✅ RESET INTERNAL STATE
176
+ MobileConnection.driver = null;
177
+ MobileConnection.activeSessionId = null;
178
+ MobileConnection._isConnected = false;
179
+ MobileConnection.forceCleanupExecuted = true;
180
+ }
181
+ /**
182
+ * 🔥 FORCE-CLOSE SESSION VIA DEVICEFARM API
183
+ */
184
+ static async forceCloseSessionViaAPI(sessionId) {
185
+ const endpoints = [
186
+ `/api/mobile/sessions/${sessionId}/force-close`,
187
+ `/api/mobile/sessions/${sessionId}/terminate`,
188
+ `/api/sessions/${sessionId}/close`,
189
+ `/api/mobile/force-disconnect/${sessionId}`,
190
+ ];
191
+ for (const endpoint of endpoints) {
192
+ try {
193
+ const url = `https://${MobileConnection.remoteHost}${endpoint}`;
194
+ const response = await fetch(url, {
195
+ method: 'POST',
196
+ headers: {
197
+ 'X-API-Key': MobileConnection.apiKey,
198
+ 'Content-Type': 'application/json',
199
+ },
200
+ });
201
+ if (response.ok) {
202
+ Logger.success(`✅ Force-close bem-sucedido: ${endpoint}`);
203
+ return;
204
+ }
205
+ }
206
+ catch (error) {
207
+ Logger.warning(`⚠️ Force-close falhou ${endpoint}: ${String(error)}`);
208
+ }
209
+ }
210
+ }
211
+ /**
212
+ * 💀 FORCE-KILL ALL DEVICEFARM SESSIONS - NUCLEAR OPTION
213
+ */
214
+ static async forceKillAllDeviceFarmSessions() {
215
+ const killEndpoints = [
216
+ '/api/mobile/sessions/kill-all',
217
+ '/api/mobile/force-disconnect',
218
+ '/api/sessions/cleanup',
219
+ '/api/mobile/emergency-shutdown',
220
+ '/api/admin/force-cleanup',
221
+ ];
222
+ for (const endpoint of killEndpoints) {
223
+ try {
224
+ const url = `https://${MobileConnection.remoteHost}${endpoint}`;
225
+ const response = await fetch(url, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'X-API-Key': MobileConnection.apiKey,
229
+ 'Content-Type': 'application/json',
230
+ },
231
+ });
232
+ if (response.ok) {
233
+ Logger.info(`✅ Force-kill endpoint funcionou: ${endpoint}`);
234
+ }
235
+ }
236
+ catch (error) {
237
+ // Silencioso para endpoints de emergência
238
+ }
239
+ }
240
+ }
241
+ /**
242
+ * 🧹 ULTRA-AGGRESSIVE FORCE CLEANUP - NUCLEAR CLEANUP OPTION (ESModules Fixed)
243
+ */
244
+ static async forceCleanup() {
245
+ if (MobileConnection.forceCleanupExecuted) {
246
+ return;
247
+ }
248
+ // ✅ 1. GARBAGE COLLECTION FORÇADO
249
+ try {
250
+ if (typeof globalThis.gc === 'function') {
251
+ globalThis.gc();
252
+ }
253
+ }
254
+ catch (error) {
255
+ // GC pode não estar disponível
256
+ }
257
+ // ✅ 2. CLEAR ALL TIMERS E INTERVALS
258
+ try {
259
+ // ESModules way - sem require() - fix timeout type
260
+ const highestTimeoutId = Number(setTimeout(() => { }, 0));
261
+ for (let i = 0; i <= highestTimeoutId; i++) {
262
+ clearTimeout(i);
263
+ clearInterval(i);
264
+ }
265
+ }
266
+ catch (error) {
267
+ Logger.warning(`⚠️ Erro ao limpar timers: ${String(error)}`);
268
+ }
269
+ // ✅ 3. CLEAR GLOBAL VARIABLES (ESModules compatible)
270
+ try {
271
+ // ESModules não tem require.cache - usar strategy alternativa
272
+ const keysToDelete = Object.keys(globalThis).filter((key) => key.includes('webdriverio') ||
273
+ key.includes('appium') ||
274
+ key.includes('selenium') ||
275
+ key.includes('devicefarm') ||
276
+ key.startsWith('mobile'));
277
+ keysToDelete.forEach((key) => {
278
+ try {
279
+ delete globalThis[key];
280
+ }
281
+ catch {
282
+ // Ignorar se não conseguir deletar
283
+ }
284
+ });
285
+ }
286
+ catch (error) {
287
+ Logger.warning(`⚠️ Erro ao limpar variáveis globais: ${String(error)}`);
288
+ }
289
+ // ✅ 4. REMOVE EVENT LISTENERS
290
+ try {
291
+ if (typeof process !== 'undefined' && process.removeAllListeners) {
292
+ const events = [
293
+ 'exit',
294
+ 'SIGINT',
295
+ 'SIGTERM',
296
+ 'uncaughtException',
297
+ 'unhandledRejection',
298
+ ];
299
+ events.forEach((event) => {
300
+ try {
301
+ process.removeAllListeners(event);
302
+ }
303
+ catch {
304
+ // Ignorar se não conseguir remover
305
+ }
306
+ });
307
+ }
308
+ }
309
+ catch (error) {
310
+ Logger.warning(`⚠️ Erro ao remover event listeners: ${String(error)}`);
311
+ }
312
+ // ✅ 5. FORCE MEMORY RELEASE
313
+ try {
314
+ // Forçar liberação de memória
315
+ MobileConnection.driver = null;
316
+ MobileConnection.activeSessionId = null;
317
+ MobileConnection._isConnected = false;
318
+ // Set imediato para garantir que GC rode
319
+ setImmediate(() => {
320
+ if (typeof globalThis.gc === 'function') {
321
+ globalThis.gc();
322
+ }
323
+ });
324
+ }
325
+ catch (error) {
326
+ Logger.warning(`⚠️ Erro na liberação de memória: ${String(error)}`);
327
+ }
328
+ // ✅ 6. WAIT AND FINAL GC
329
+ try {
330
+ await new Promise((resolve) => setTimeout(resolve, 1000));
331
+ if (typeof globalThis.gc === 'function') {
332
+ globalThis.gc();
333
+ }
334
+ }
335
+ catch (error) {
336
+ Logger.warning(`⚠️ Erro no cleanup final: ${String(error)}`);
337
+ }
338
+ MobileConnection.forceCleanupExecuted = true;
339
+ }
340
+ /**
341
+ * ✅ SIMPLE CONNECTION CREATION - Baseado na versão que funcionava
342
+ */
343
+ static async createSimpleConnection(capabilities, useProxy) {
344
+ // ✅ PREPARAR CAPABILITIES BÁSICAS
345
+ const fullCapabilities = {
346
+ 'appium:apiKey': MobileConnection.apiKey,
347
+ 'appium:deviceId': capabilities.deviceId || capabilities.deviceName,
348
+ 'appium:automationName': capabilities.platformName === 'Android' ? 'UiAutomator2' : 'XCUITest',
349
+ 'appium:platformName': capabilities.platformName,
350
+ 'appium:noReset': true,
351
+ 'appium:newCommandTimeout': 300,
352
+ 'appium:autoGrantPermissions': true,
353
+ 'appium:realDevice': true,
354
+ // Android específico
355
+ ...(capabilities.platformName === 'Android' && {
356
+ 'appium:appPackage': capabilities.appPackage,
357
+ 'appium:appActivity': capabilities.appActivity,
358
+ }),
359
+ // iOS específico
360
+ ...(capabilities.platformName === 'iOS' && {
361
+ 'appium:bundleId': capabilities.bundleId,
362
+ }),
363
+ };
364
+ // ✅ PREPARAR CONFIGURAÇÕES WEBDRIVER
365
+ const agent = useProxy
366
+ ? await MobileConnection.setupProxy()
367
+ : await MobileConnection.setupSSLAgent();
368
+ const webdriverOptions = {
369
+ protocol: 'https',
370
+ hostname: MobileConnection.remoteHost,
371
+ port: MobileConnection.remotePort,
372
+ path: MobileConnection.remotePath,
373
+ capabilities: {
374
+ alwaysMatch: fullCapabilities,
375
+ firstMatch: [{}],
376
+ },
377
+ logLevel: 'silent',
378
+ connectionRetryCount: 2,
379
+ connectionRetryTimeout: 60_000,
380
+ requestTimeout: 120_000,
381
+ agent,
382
+ headers: {
383
+ 'User-Agent': 'AutoCore-Mobile/2.0',
384
+ Accept: 'application/json',
385
+ 'Content-Type': 'application/json',
386
+ },
387
+ };
388
+ Logger.info('🔌 Criando sessão WebDriverIO...');
389
+ // ✅ CRIAR DRIVER COM TIMEOUT
390
+ const driver = await Promise.race([
391
+ remote(webdriverOptions),
392
+ new Promise((_, reject) => setTimeout(() => reject(new Error('❌ Timeout na criação de sessão (120s)')), 120_000)),
393
+ ]);
394
+ if (!driver?.sessionId) {
395
+ throw new Error('❌ Driver criado mas sessionId não encontrado');
396
+ }
397
+ Logger.success(`Sessão criada: ${driver.sessionId}`);
398
+ return driver;
399
+ }
400
+ /**
401
+ * ✅ CONNECTIVITY CHECK WITH FALLBACK STRATEGIES - Simplificado
402
+ */
403
+ static async checkDeviceFarmConnectivityWithFallback() {
404
+ // Estratégia 1: Proxy
405
+ try {
406
+ const withProxy = await MobileConnection.checkConnectivity(true);
407
+ if (withProxy) {
408
+ return { success: true, method: 'proxy corporativo', useProxy: true };
409
+ }
410
+ }
411
+ catch (error) {
412
+ Logger.warning(`Conectividade com proxy falhou: ${String(error)}`);
413
+ }
414
+ // Estratégia 2: Direto
415
+ try {
416
+ Logger.info('📡 Tentativa 2: Conectividade direta (sem proxy)...');
417
+ const direct = await MobileConnection.checkConnectivity(false);
418
+ if (direct) {
419
+ return { success: true, method: 'conexão direta', useProxy: false };
420
+ }
421
+ }
422
+ catch (error) {
423
+ Logger.warning(`⚠️ ⚠️ Conectividade direta falhou: ${String(error)}`);
424
+ }
425
+ // Estratégia 3: SSL relaxado
426
+ try {
427
+ Logger.info('ℹ️ 📡 Tentativa 3: Conectividade com SSL relaxado...');
428
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
429
+ const sslRelaxed = await MobileConnection.checkConnectivity(false);
430
+ if (sslRelaxed) {
431
+ return { success: true, method: 'SSL relaxado', useProxy: false };
432
+ }
433
+ }
434
+ catch (error) {
435
+ Logger.warning(`⚠️ ⚠️ Conectividade direta falhou: ${String(error)}`);
436
+ }
437
+ // Estratégia 4: Múltiplas tentativas
438
+ Logger.info('ℹ️ 📡 Tentativa 4: Múltiplas tentativas com timeout otimizado...');
439
+ for (let attempt = 1; attempt <= 3; attempt++) {
440
+ try {
441
+ Logger.info(`ℹ️ 🔄 Tentativa ${attempt}/3 com timeout otimizado...`);
442
+ const result = await MobileConnection.testBasicEndpoint();
443
+ if (result) {
444
+ return {
445
+ success: true,
446
+ method: `tentativa otimizada ${attempt}`,
447
+ useProxy: false,
448
+ };
449
+ }
450
+ }
451
+ catch (error) {
452
+ Logger.error(`❌ Erro inesperado: ${String(error)}...`);
453
+ if (attempt < 3) {
454
+ Logger.info('⏱️ Aguardando 3s antes da próxima tentativa...');
455
+ await new Promise((resolve) => setTimeout(resolve, 3000));
456
+ }
457
+ }
458
+ }
459
+ return { success: false, method: 'nenhum', useProxy: false };
460
+ }
461
+ /**
462
+ * ✅ BASIC CONNECTIVITY CHECK - Simplificado
463
+ */
464
+ static async checkConnectivity(useProxy) {
465
+ try {
466
+ const url = `https://${MobileConnection.remoteHost}:${MobileConnection.remotePort}/api/health`;
467
+ const options = {
468
+ method: 'GET',
469
+ headers: {
470
+ 'User-Agent': 'AutoCore-Mobile-Test/2.0',
471
+ Accept: 'application/json',
472
+ },
473
+ };
474
+ if (useProxy && MobileConnection.proxyUrl) {
475
+ options.agent = new HttpsProxyAgent(MobileConnection.proxyUrl);
476
+ }
477
+ const controller = new AbortController();
478
+ const timeoutId = setTimeout(() => controller.abort(), 15_000);
479
+ options.signal = controller.signal;
480
+ const response = await fetch(url, options);
481
+ clearTimeout(timeoutId);
482
+ return response.status < 500;
483
+ }
484
+ catch (error) {
485
+ throw new Error(`Conectividade falhou: ${String(error)}`);
486
+ }
487
+ }
488
+ /**
489
+ * ✅ TEST BASIC ENDPOINT - Simplificado
490
+ */
491
+ static async testBasicEndpoint() {
492
+ try {
493
+ Logger.info('🎯 Testando endpoint DeviceFarm com configurações otimizadas...');
494
+ const url = `https://${MobileConnection.remoteHost}:${MobileConnection.remotePort}/api/mobile/status`;
495
+ const controller = new AbortController();
496
+ const timeoutId = setTimeout(() => controller.abort(), 10_000);
497
+ const response = await fetch(url, {
498
+ method: 'GET',
499
+ headers: {
500
+ 'User-Agent': 'AutoCore-Mobile-Test/2.0',
501
+ Accept: 'application/json',
502
+ Connection: 'close',
503
+ },
504
+ signal: controller.signal,
505
+ });
506
+ clearTimeout(timeoutId);
507
+ return response.status < 500;
508
+ }
509
+ catch (error) {
510
+ throw new Error(`Test endpoint falhou: ${String(error)}`);
511
+ }
512
+ }
513
+ /**
514
+ * 🎬 SETUP AUTOMATIC VISUALIZATION - COM 1 SEGUNDO POLLING
515
+ */
516
+ static async setupAutomaticVisualization(capabilities) {
517
+ try {
518
+ if (!MobileConnection.driver?.sessionId) {
519
+ Logger.warning('⚠️ Sem sessão ativa para configurar visualização');
520
+ return;
521
+ }
522
+ const deviceId = capabilities.deviceId || capabilities.deviceName || 'unknown';
523
+ Logger.info('🎬 Configurando visualização automática...');
524
+ // ✅ INICIAR DEVICEFARM VIEWER COM 1 SEGUNDO DE POLLING
525
+ const htmlPath = await DeviceFarmViewer.start(deviceId);
526
+ if (htmlPath) {
527
+ Logger.info('📱 VISUALIZADOR MOBILE ATIVO (1s refresh)!');
528
+ Logger.info(`📄 Arquivo HTML: ${htmlPath}`);
529
+ // Capturar screenshot inicial
530
+ const screenshot = await MobileConnection.captureScreenshot('Conexão estabelecida');
531
+ if (screenshot) {
532
+ Logger.info('📸 Screenshot inicial capturado');
533
+ }
534
+ }
535
+ }
536
+ catch (error) {
537
+ Logger.warning(`Erro na configuração de visualização: ${String(error)}`);
538
+ }
539
+ }
540
+ /**
541
+ * ✅ SETUP PROXY CONFIGURATION
542
+ */
543
+ static async setupProxy() {
544
+ if (!MobileConnection.proxyUrl) {
545
+ return null;
546
+ }
547
+ try {
548
+ const agent = new HttpsProxyAgent(MobileConnection.proxyUrl, {
549
+ rejectUnauthorized: false,
550
+ requestCert: false,
551
+ });
552
+ Logger.info(`🔄 Proxy configurado: ${MobileConnection.proxyUrl}`);
553
+ return agent;
554
+ }
555
+ catch (error) {
556
+ Logger.warning(`⚠️ Erro ao configurar proxy: ${String(error)}`);
557
+ return null;
558
+ }
559
+ }
560
+ /**
561
+ * ✅ SETUP SSL AGENT - Simples mas efetivo
562
+ */
563
+ static async setupSSLAgent() {
564
+ try {
565
+ return new https.Agent({
566
+ rejectUnauthorized: false,
567
+ requestCert: false,
568
+ checkServerIdentity: () => undefined,
569
+ keepAlive: true,
570
+ maxSockets: 50,
571
+ });
572
+ }
573
+ catch (error) {
574
+ Logger.warning(`⚠️ Erro ao configurar SSL Agent: ${String(error)}`);
575
+ return null;
576
+ }
577
+ }
578
+ /**
579
+ * ✅ INITIALIZE GLOBAL SSL KILLER - Simples mas efetivo
580
+ */
581
+ static async initializeGlobalSSLKiller() {
582
+ try {
583
+ // ✅ NÍVEL 1: Environment variables
584
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
585
+ process.env.HTTPS_PROXY_REJECT_UNAUTHORIZED = '0';
586
+ process.env.SSL_VERIFY = '0';
587
+ // ✅ NÍVEL 2: Global fetch override
588
+ if (typeof globalThis.fetch !== 'undefined') {
589
+ const originalFetch = globalThis.fetch;
590
+ globalThis.fetch = async function (input, init = {}) {
591
+ // Aplicar SSL bypass para DeviceFarm
592
+ const url = typeof input === 'string' ? input : input?.url || '';
593
+ if ((url.includes('devicefarm') || url.includes('.com.br')) &&
594
+ !init.agent) {
595
+ try {
596
+ init.agent = new https.Agent({
597
+ rejectUnauthorized: false,
598
+ checkServerIdentity: () => undefined,
599
+ });
600
+ }
601
+ catch {
602
+ // Fallback se não conseguir criar agent
603
+ }
604
+ }
605
+ return originalFetch.call(this, input, init);
606
+ };
607
+ }
608
+ // ✅ NÍVEL 3: Undici configuration
609
+ try {
610
+ setGlobalDispatcher(new Agent({
611
+ connect: {
612
+ rejectUnauthorized: false,
613
+ checkServerIdentity: () => undefined,
614
+ },
615
+ }));
616
+ }
617
+ catch {
618
+ // Undici pode não estar disponível
619
+ }
620
+ }
621
+ catch (error) {
622
+ Logger.warning(`⚠️ Erro ao configurar SSL Killer: ${String(error)}`);
623
+ // Fallback básico
624
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
625
+ }
626
+ }
627
+ /**
628
+ * ✅ ENHANCED SCREENSHOT CAPTURE WITH EVIDENCE INTEGRATION
629
+ */
630
+ static async captureScreenshot(description = 'Mobile Screenshot') {
631
+ try {
632
+ if (!MobileConnection.driver) {
633
+ Logger.warning('Sem driver ativo para screenshot');
634
+ return null;
635
+ }
636
+ const screenshot = await MobileConnection.driver.takeScreenshot();
637
+ if (!screenshot)
638
+ return null;
639
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
640
+ const fileName = `mobile-${timestamp}-${description.replace(/[^a-zA-Z0-9]/g, '_')}.png`;
641
+ const screenshotDir = path.resolve('./test-results/mobile-screenshots');
642
+ if (!fs.existsSync(screenshotDir)) {
643
+ fs.mkdirSync(screenshotDir, { recursive: true });
644
+ }
645
+ const screenshotPath = path.join(screenshotDir, fileName);
646
+ fs.writeFileSync(screenshotPath, screenshot, 'base64');
647
+ // ✅ ANEXAR AO PLAYWRIGHT
648
+ const testInfo = TestContext.getSafeTestInfo();
649
+ if (testInfo) {
650
+ await testInfo.attach(`mobile-${description}`, {
651
+ body: Buffer.from(screenshot, 'base64'),
652
+ contentType: 'image/png',
653
+ });
654
+ }
655
+ // ✅ ADICIONAR AO VIEWER COM 1 SEGUNDO POLLING
656
+ try {
657
+ DeviceFarmViewer.addScreenshot(fileName, description);
658
+ }
659
+ catch (error) {
660
+ // Silencioso se viewer não estiver disponível
661
+ }
662
+ Logger.info(`📸 Screenshot salvo: ${fileName}`);
663
+ return screenshotPath;
664
+ }
665
+ catch (error) {
666
+ Logger.error(`Erro ao capturar screenshot: ${String(error)}`);
667
+ return null;
668
+ }
669
+ }
670
+ /**
671
+ * ✅ VALIDATE CAPABILITIES
672
+ */
673
+ static validateCapabilities(capabilities) {
674
+ if (!(capabilities.deviceId || capabilities.deviceName)) {
675
+ throw new Error('Device ID é obrigatório');
676
+ }
677
+ if (capabilities.platformName === 'Android' && !capabilities.appPackage) {
678
+ throw new Error('App Package é obrigatório para Android');
679
+ }
680
+ if (capabilities.platformName === 'iOS' && !capabilities.bundleId) {
681
+ throw new Error('Bundle ID é obrigatório para iOS');
682
+ }
683
+ }
684
+ /**
685
+ * ✅ GET DRIVER INSTANCE
686
+ */
687
+ static getDriver() {
688
+ return MobileConnection.driver;
689
+ }
690
+ /**
691
+ * ✅ GET CURRENT DEVICE ID
692
+ */
693
+ static getCurrentDeviceId() {
694
+ return (MobileConnection._currentCapabilities?.deviceId ||
695
+ MobileConnection._currentCapabilities?.deviceName ||
696
+ 'unknown-device');
697
+ }
698
+ /**
699
+ * ✅ GET CURRENT PLATFORM
700
+ */
701
+ static getCurrentPlatform() {
702
+ return MobileConnection._currentCapabilities?.platformName || 'Android';
703
+ }
704
+ /**
705
+ * ✅ CAPTURE EVIDENCE (ALIAS FOR SCREENSHOT)
706
+ */
707
+ static async captureEvidence(description = 'Evidence') {
708
+ return await MobileConnection.captureScreenshot(description);
709
+ }
710
+ /**
711
+ * ✅ IS CONNECTED CHECK
712
+ */
713
+ static isConnected() {
714
+ return (MobileConnection._isConnected &&
715
+ MobileConnection.driver !== null &&
716
+ !!MobileConnection.driver?.sessionId);
717
+ }
718
+ /**
719
+ * ✅ VERIFY DEVICEFARM VISUAL CONNECTION
720
+ */
721
+ static async verifyDeviceFarmVisualConnection() {
722
+ try {
723
+ const screenshot = await MobileConnection.captureScreenshot('Test connectivity');
724
+ return !!screenshot;
725
+ }
726
+ catch {
727
+ return false;
728
+ }
729
+ }
730
+ /**
731
+ * ✅ TAKE SCREENSHOT (ALIAS)
732
+ */
733
+ static async takeScreenshot() {
734
+ return await MobileConnection.captureScreenshot();
735
+ }
736
+ /**
737
+ * ✅ CAPTURE SCREENSHOT AS BUFFER
738
+ */
739
+ static async captureScreenshotBuffer(description = 'Mobile Screenshot') {
740
+ try {
741
+ if (!MobileConnection.driver)
742
+ return null;
743
+ const screenshot = await MobileConnection.driver.takeScreenshot();
744
+ if (!screenshot)
745
+ return null;
746
+ return Buffer.from(screenshot, 'base64');
747
+ }
748
+ catch {
749
+ return null;
750
+ }
751
+ }
752
+ /**
753
+ * ✅ CREATE SESSION (ALIAS FOR CONNECT)
754
+ */
755
+ static async createSession(capabilities) {
756
+ return await MobileConnection.connect(capabilities);
757
+ }
758
+ /**
759
+ * ✅ TROUBLESHOOTING INFO
760
+ */
761
+ static logTroubleshootingInfo() {
762
+ Logger.info('🔧 === TROUBLESHOOTING MOBILE ===');
763
+ Logger.info('💡 Se a conexão mobile falhar:');
764
+ Logger.info('ℹ️ 1. ✅ Verificar se Device Farm está online');
765
+ Logger.info('ℹ️ 2. ✅ API key é automática (DEVICEFARM_API_KEY opcional)');
766
+ Logger.info('ℹ️ 3. ✅ Verificar se device está disponível');
767
+ Logger.info('ℹ️ 4. ✅ Testar conectividade de rede');
768
+ Logger.info('ℹ️ 5. ✅ Verificar proxy se necessário');
769
+ Logger.info(`ℹ️ 6. ✅ Host: ${MobileConnection.remoteHost}:${MobileConnection.remotePort}`);
770
+ Logger.info('ℹ️ 7. ✅ Tentativas: proxy → direto → SSL relaxado');
771
+ }
772
+ }