@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.
- package/.github/copilot-instructions.md +520 -0
- package/biome.json +37 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +169 -0
- package/dist/scripts/consumer-postinstall.d.ts +15 -0
- package/dist/scripts/consumer-postinstall.js +785 -0
- package/dist/scripts/generate-docs.d.ts +16 -0
- package/dist/scripts/generate-docs.js +1363 -0
- package/dist/scripts/generate-index.d.ts +2 -0
- package/dist/scripts/generate-index.js +314 -0
- package/dist/scripts/init-api.d.ts +2 -0
- package/dist/scripts/init-api.js +525 -0
- package/dist/scripts/init-banco.d.ts +2 -0
- package/dist/scripts/init-banco.js +347 -0
- package/dist/scripts/init-frontend.d.ts +2 -0
- package/dist/scripts/init-frontend.js +627 -0
- package/dist/scripts/init-mobile.d.ts +2 -0
- package/dist/scripts/init-mobile.js +481 -0
- package/dist/scripts/init-scenarios.d.ts +2 -0
- package/dist/scripts/init-scenarios.js +846 -0
- package/dist/scripts/init-ssh.d.ts +2 -0
- package/dist/scripts/init-ssh.js +639 -0
- package/dist/scripts/package-versions.d.ts +57 -0
- package/dist/scripts/package-versions.js +768 -0
- package/dist/scripts/postinstall.d.ts +1 -0
- package/dist/scripts/postinstall.js +527 -0
- package/dist/scripts/robust-build.d.ts +7 -0
- package/dist/scripts/robust-build.js +88 -0
- package/dist/scripts/setup-local-packages.d.ts +31 -0
- package/dist/scripts/setup-local-packages.js +237 -0
- package/dist/scripts/smart-override.d.ts +2 -0
- package/dist/scripts/smart-override.js +1360 -0
- package/dist/scripts/sync-configs.d.ts +27 -0
- package/dist/scripts/sync-configs.js +248 -0
- package/dist/scripts/test-biome-parse.d.ts +5 -0
- package/dist/scripts/test-biome-parse.js +84 -0
- package/dist/scripts/ultracite-setup.d.ts +4 -0
- package/dist/scripts/ultracite-setup.js +310 -0
- package/dist/scripts/update-all-init-scripts.d.ts +2 -0
- package/dist/scripts/update-all-init-scripts.js +52 -0
- package/dist/scripts/update-biome-schema.d.ts +15 -0
- package/dist/scripts/update-biome-schema.js +124 -0
- package/dist/src/AutoCoreFacade.d.ts +145 -0
- package/dist/src/AutoCoreFacade.js +217 -0
- package/dist/src/api/ApiActions.d.ts +297 -0
- package/dist/src/api/ApiActions.js +1905 -0
- package/dist/src/api/Certificate.d.ts +60 -0
- package/dist/src/api/Certificate.js +79 -0
- package/dist/src/api/JsonResponse.d.ts +116 -0
- package/dist/src/api/JsonResponse.js +206 -0
- package/dist/src/appium/DeviceFarmViewer.d.ts +79 -0
- package/dist/src/appium/DeviceFarmViewer.js +1083 -0
- package/dist/src/appium/MobileActions.d.ts +347 -0
- package/dist/src/appium/MobileActions.js +1632 -0
- package/dist/src/appium/MobileConnection.d.ts +160 -0
- package/dist/src/appium/MobileConnection.js +772 -0
- package/dist/src/config/envLoader.d.ts +123 -0
- package/dist/src/config/envLoader.js +361 -0
- package/dist/src/config/jest-safe-setup.d.ts +19 -0
- package/dist/src/config/jest-safe-setup.js +369 -0
- package/dist/src/config/timeouts.d.ts +32 -0
- package/dist/src/config/timeouts.js +38 -0
- package/dist/src/desktop/DesktopActions.d.ts +46 -0
- package/dist/src/desktop/DesktopActions.js +398 -0
- package/dist/src/desktop/DesktopConnection.d.ts +32 -0
- package/dist/src/desktop/DesktopConnection.js +84 -0
- package/dist/src/domain/entities/TestExecution.d.ts +117 -0
- package/dist/src/domain/entities/TestExecution.js +150 -0
- package/dist/src/domain/entities/TestReport.d.ts +114 -0
- package/dist/src/domain/entities/TestReport.js +179 -0
- package/dist/src/domain/repositories/ITestRepository.d.ts +196 -0
- package/dist/src/domain/repositories/ITestRepository.js +14 -0
- package/dist/src/domain/schemas/ValidationSchemas.d.ts +159 -0
- package/dist/src/domain/schemas/ValidationSchemas.js +181 -0
- package/dist/src/functions/errors/BaseError.d.ts +78 -0
- package/dist/src/functions/errors/BaseError.js +245 -0
- package/dist/src/functions/errors/ConfigurationError.d.ts +16 -0
- package/dist/src/functions/errors/ConfigurationError.js +48 -0
- package/dist/src/functions/errors/ErrorCatalog.d.ts +148 -0
- package/dist/src/functions/errors/ErrorCatalog.js +157 -0
- package/dist/src/functions/errors/GlobalErrorHandler.d.ts +101 -0
- package/dist/src/functions/errors/GlobalErrorHandler.js +281 -0
- package/dist/src/functions/errors/IntegrationError.d.ts +17 -0
- package/dist/src/functions/errors/IntegrationError.js +51 -0
- package/dist/src/functions/errors/SecurityError.d.ts +14 -0
- package/dist/src/functions/errors/SecurityError.js +42 -0
- package/dist/src/functions/errors/SystemError.d.ts +12 -0
- package/dist/src/functions/errors/SystemError.js +36 -0
- package/dist/src/functions/errors/ValidationError.d.ts +14 -0
- package/dist/src/functions/errors/ValidationError.js +61 -0
- package/dist/src/functions/errors/index.d.ts +12 -0
- package/dist/src/functions/errors/index.js +13 -0
- package/dist/src/global-setup.d.ts +1 -0
- package/dist/src/global-setup.js +1037 -0
- package/dist/src/helpers/BancoActions.d.ts +188 -0
- package/dist/src/helpers/BancoActions.js +581 -0
- package/dist/src/helpers/EnviromentHelper.d.ts +17 -0
- package/dist/src/helpers/EnviromentHelper.js +66 -0
- package/dist/src/helpers/ParallelExecutionHelper.d.ts +183 -0
- package/dist/src/helpers/ParallelExecutionHelper.js +375 -0
- package/dist/src/helpers/SyncSignal.d.ts +15 -0
- package/dist/src/helpers/SyncSignal.js +44 -0
- package/dist/src/hubdocs/CategoryDetector.d.ts +83 -0
- package/dist/src/hubdocs/CategoryDetector.js +401 -0
- package/dist/src/hubdocs/DirectStatementInterceptor.d.ts +54 -0
- package/dist/src/hubdocs/DirectStatementInterceptor.js +243 -0
- package/dist/src/hubdocs/ExecutionTracker.d.ts +107 -0
- package/dist/src/hubdocs/ExecutionTracker.js +702 -0
- package/dist/src/hubdocs/HubDocs.d.ts +395 -0
- package/dist/src/hubdocs/HubDocs.js +3586 -0
- package/dist/src/hubdocs/StatementMethodFilter.d.ts +71 -0
- package/dist/src/hubdocs/StatementMethodFilter.js +618 -0
- package/dist/src/hubdocs/StatementTracker.d.ts +417 -0
- package/dist/src/hubdocs/StatementTracker.js +2419 -0
- package/dist/src/hubdocs/SwaggerGenerator.d.ts +59 -0
- package/dist/src/hubdocs/SwaggerGenerator.js +405 -0
- package/dist/src/hubdocs/index.d.ts +9 -0
- package/dist/src/hubdocs/index.js +9 -0
- package/dist/src/hubdocs/types.d.ts +114 -0
- package/dist/src/hubdocs/types.js +5 -0
- package/dist/src/infrastructure/DependencyContainer.d.ts +142 -0
- package/dist/src/infrastructure/DependencyContainer.js +250 -0
- package/dist/src/infrastructure/adapters/AppiumAdapter.d.ts +168 -0
- package/dist/src/infrastructure/adapters/AppiumAdapter.js +468 -0
- package/dist/src/infrastructure/adapters/OracleAdapter.d.ts +150 -0
- package/dist/src/infrastructure/adapters/OracleAdapter.js +388 -0
- package/dist/src/infrastructure/adapters/PlaywrightAdapter.d.ts +192 -0
- package/dist/src/infrastructure/adapters/PlaywrightAdapter.js +382 -0
- package/dist/src/infrastructure/adapters/SSHAdapter.d.ts +141 -0
- package/dist/src/infrastructure/adapters/SSHAdapter.js +428 -0
- package/dist/src/interfaces.d.ts +501 -0
- package/dist/src/interfaces.js +25 -0
- package/dist/src/internal/fakes/__fake-actions__.d.ts +17 -0
- package/dist/src/internal/fakes/__fake-actions__.js +21 -0
- package/dist/src/internal/fakes/__forbidden__.d.ts +10 -0
- package/dist/src/internal/fakes/__forbidden__.js +18 -0
- package/dist/src/internal/fakes/__honeypot__.d.ts +15 -0
- package/dist/src/internal/fakes/__honeypot__.js +24 -0
- package/dist/src/octane/OctaneReporter.d.ts +13 -0
- package/dist/src/octane/OctaneReporter.js +61 -0
- package/dist/src/playwright/CryptoActions.d.ts +20 -0
- package/dist/src/playwright/CryptoActions.js +75 -0
- package/dist/src/playwright/EnhancedWebActions.d.ts +7 -0
- package/dist/src/playwright/EnhancedWebActions.js +65 -0
- package/dist/src/playwright/WebActions.d.ts +1599 -0
- package/dist/src/playwright/WebActions.js +11788 -0
- package/dist/src/playwright/actions/ActionTimeline.d.ts +36 -0
- package/dist/src/playwright/actions/ActionTimeline.js +101 -0
- package/dist/src/playwright/actions/RecoveryQueue.d.ts +82 -0
- package/dist/src/playwright/actions/RecoveryQueue.js +130 -0
- package/dist/src/playwright/actions/SelectorCache.d.ts +53 -0
- package/dist/src/playwright/actions/SelectorCache.js +96 -0
- package/dist/src/playwright/actions/index.d.ts +13 -0
- package/dist/src/playwright/actions/index.js +14 -0
- package/dist/src/playwright/actions/types.d.ts +147 -0
- package/dist/src/playwright/actions/types.js +5 -0
- package/dist/src/playwright/fixtures.d.ts +112 -0
- package/dist/src/playwright/fixtures.js +718 -0
- package/dist/src/playwright/network-logs-reporter.d.ts +7 -0
- package/dist/src/playwright/network-logs-reporter.js +66 -0
- package/dist/src/playwright/registerRecoveryWrappers.d.ts +1 -0
- package/dist/src/playwright/registerRecoveryWrappers.js +54 -0
- package/dist/src/security/BuildSecurity.d.ts +12 -0
- package/dist/src/security/BuildSecurity.js +138 -0
- package/dist/src/security/EulaProtection.d.ts +70 -0
- package/dist/src/security/EulaProtection.js +155 -0
- package/dist/src/security/HoneypotManager.d.ts +46 -0
- package/dist/src/security/HoneypotManager.js +234 -0
- package/dist/src/security/KeysManager.d.ts +36 -0
- package/dist/src/security/KeysManager.js +158 -0
- package/dist/src/security/ProofOfWorkIntegration.d.ts +64 -0
- package/dist/src/security/ProofOfWorkIntegration.js +206 -0
- package/dist/src/security/SecurityValidation.d.ts +21 -0
- package/dist/src/security/SecurityValidation.js +163 -0
- package/dist/src/security/SourceMapProtection.d.ts +55 -0
- package/dist/src/security/SourceMapProtection.js +220 -0
- package/dist/src/security/protector.d.ts +1 -0
- package/dist/src/security/protector.js +97 -0
- package/dist/src/ssh/SSHActions.d.ts +262 -0
- package/dist/src/ssh/SSHActions.js +790 -0
- package/dist/src/ssh/SSHClient.d.ts +99 -0
- package/dist/src/ssh/SSHClient.js +409 -0
- package/dist/src/statements/BaseStatement.d.ts +38 -0
- package/dist/src/statements/BaseStatement.js +78 -0
- package/dist/src/testContext/AuthStateManager.d.ts +93 -0
- package/dist/src/testContext/AuthStateManager.js +256 -0
- package/dist/src/testContext/CoverageManager.d.ts +198 -0
- package/dist/src/testContext/CoverageManager.js +917 -0
- package/dist/src/testContext/TestAnnotations.d.ts +476 -0
- package/dist/src/testContext/TestAnnotations.js +2647 -0
- package/dist/src/testContext/TestContext.d.ts +138 -0
- package/dist/src/testContext/TestContext.js +369 -0
- package/dist/src/testContext/UnifiedHtmlGenerator.d.ts +7 -0
- package/dist/src/testContext/UnifiedHtmlGenerator.js +264 -0
- package/dist/src/testContext/UnifiedReportManager.d.ts +211 -0
- package/dist/src/testContext/UnifiedReportManager.js +1206 -0
- package/dist/src/testhub/DynamicConfigManager.d.ts +121 -0
- package/dist/src/testhub/DynamicConfigManager.js +320 -0
- package/dist/src/testhub/SystemsManager.d.ts +119 -0
- package/dist/src/testhub/SystemsManager.js +365 -0
- package/dist/src/testhub/TestHubClient.d.ts +335 -0
- package/dist/src/testhub/TestHubClient.js +1215 -0
- package/dist/src/testhub/TestHubReporter.d.ts +62 -0
- package/dist/src/testhub/TestHubReporter.js +576 -0
- package/dist/src/testhub/TestHubVars.d.ts +116 -0
- package/dist/src/testhub/TestHubVars.js +273 -0
- package/dist/src/utils/ActionInterceptor.d.ts +59 -0
- package/dist/src/utils/ActionInterceptor.js +741 -0
- package/dist/src/utils/ArtifactsCompressor.d.ts +43 -0
- package/dist/src/utils/ArtifactsCompressor.js +181 -0
- package/dist/src/utils/AutoLogsFinal.d.ts +47 -0
- package/dist/src/utils/AutoLogsFinal.js +148 -0
- package/dist/src/utils/CodeGenSession.d.ts +114 -0
- package/dist/src/utils/CodeGenSession.js +264 -0
- package/dist/src/utils/ConfigLogger.d.ts +133 -0
- package/dist/src/utils/ConfigLogger.js +611 -0
- package/dist/src/utils/CustomReporter.d.ts +22 -0
- package/dist/src/utils/CustomReporter.js +352 -0
- package/dist/src/utils/DataStore.d.ts +171 -0
- package/dist/src/utils/DataStore.js +484 -0
- package/dist/src/utils/DatabaseInterceptor.d.ts +19 -0
- package/dist/src/utils/DatabaseInterceptor.js +295 -0
- package/dist/src/utils/DateHelper.d.ts +16 -0
- package/dist/src/utils/DateHelper.js +120 -0
- package/dist/src/utils/DateValidator.d.ts +4 -0
- package/dist/src/utils/DateValidator.js +51 -0
- package/dist/src/utils/DocumentGenerator.d.ts +35 -0
- package/dist/src/utils/DocumentGenerator.js +129 -0
- package/dist/src/utils/EvidenceCapture.d.ts +90 -0
- package/dist/src/utils/EvidenceCapture.js +600 -0
- package/dist/src/utils/EvidenceReportGenerator.d.ts +70 -0
- package/dist/src/utils/EvidenceReportGenerator.js +799 -0
- package/dist/src/utils/FrameManagementUtil.d.ts +42 -0
- package/dist/src/utils/FrameManagementUtil.js +75 -0
- package/dist/src/utils/GlobalStatementsInterceptor.d.ts +1 -0
- package/dist/src/utils/GlobalStatementsInterceptor.js +1 -0
- package/dist/src/utils/HTMLTemplate.d.ts +1 -0
- package/dist/src/utils/HTMLTemplate.js +1034 -0
- package/dist/src/utils/InterceptacaoMagica.d.ts +23 -0
- package/dist/src/utils/InterceptacaoMagica.js +365 -0
- package/dist/src/utils/LogSanitizer.d.ts +35 -0
- package/dist/src/utils/LogSanitizer.js +110 -0
- package/dist/src/utils/Logger.d.ts +65 -0
- package/dist/src/utils/Logger.js +284 -0
- package/dist/src/utils/McpLocalClient.d.ts +141 -0
- package/dist/src/utils/McpLocalClient.js +871 -0
- package/dist/src/utils/PDFEvidenceGenerator.d.ts +20 -0
- package/dist/src/utils/PDFEvidenceGenerator.js +156 -0
- package/dist/src/utils/SpecFileAnalyzer.d.ts +35 -0
- package/dist/src/utils/SpecFileAnalyzer.js +209 -0
- package/dist/src/utils/StatementInterceptor.d.ts +18 -0
- package/dist/src/utils/StatementInterceptor.js +87 -0
- package/dist/src/utils/StatementLogger.d.ts +33 -0
- package/dist/src/utils/StatementLogger.js +113 -0
- package/dist/src/utils/StatementsInterceptor.d.ts +1 -0
- package/dist/src/utils/StatementsInterceptor.js +1 -0
- package/dist/src/utils/TeamsFlushHook.d.ts +17 -0
- package/dist/src/utils/TeamsFlushHook.js +168 -0
- package/dist/src/utils/TerminalLogCapture.d.ts +158 -0
- package/dist/src/utils/TerminalLogCapture.js +531 -0
- package/dist/src/utils/TestMethodLogger.d.ts +70 -0
- package/dist/src/utils/TestMethodLogger.js +95 -0
- package/dist/src/utils/UnifiedTeardown.d.ts +4 -0
- package/dist/src/utils/UnifiedTeardown.js +400 -0
- package/dist/src/utils/XPathCatalog.d.ts +152 -0
- package/dist/src/utils/XPathCatalog.js +350 -0
- package/dist/src/utils/generators.d.ts +90 -0
- package/dist/src/utils/generators.js +167 -0
- package/dist/src/utils/testRecovery/ResilientPlaywright.d.ts +152 -0
- package/dist/src/utils/testRecovery/ResilientPlaywright.js +715 -0
- package/dist/src/utils/testRecovery/TestRecoveryClient.d.ts +801 -0
- package/dist/src/utils/testRecovery/TestRecoveryClient.js +1415 -0
- package/dist/src/utils/testRecovery/autoFixCode.d.ts +65 -0
- package/dist/src/utils/testRecovery/autoFixCode.js +32 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +59 -0
- package/dist/wdio.conf.d.ts +1 -0
- package/dist/wdio.conf.js +420 -0
- package/package.json +137 -0
- package/protect-loader.mjs +643 -0
- package/scripts/consumer-postinstall.ts +975 -0
- package/scripts/generate-index.ts +343 -0
- package/scripts/init-api.ts +613 -0
- package/scripts/init-banco.ts +437 -0
- package/scripts/init-frontend.ts +727 -0
- package/scripts/init-mobile.ts +558 -0
- package/scripts/init-scenarios.ts +925 -0
- package/scripts/init-ssh.ts +734 -0
- package/scripts/package-versions.ts +978 -0
- package/scripts/postinstall.ts +605 -0
- package/scripts/smart-override.ts +1675 -0
- package/scripts/sync-configs.ts +302 -0
- package/scripts/ultracite-setup.ts +370 -0
- package/src/types/globals.d.ts +48 -0
- package/tsconfig.json +29 -0
- 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
|
+
}
|