@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,1034 @@
|
|
|
1
|
+
export function HTMLTemplate(data) {
|
|
2
|
+
const { testes, titulo, subtitulo, totalTestes, testesPassaram, testesFalharam, estatisticasPorTipo, coresDosTipos, chartLabels, chartData, chartColors, barLabels, barData, pieLabels, pieData, getIconePorTipo, projectName, environment, executionDate, autocoreVersion, globalTotalCTs = 0, globalPassedCTs = 0, globalFailedCTs = 0, globalSkippedCTs = 0, } = data;
|
|
3
|
+
// 🔗 Obter dados do StatementTracker se disponível (via data.ctData passado externamente)
|
|
4
|
+
const ctData = data.ctData || null;
|
|
5
|
+
let allCNsData = data.allCNsData || new Map(); // 🆕 Mapa hierárquico CN → CTs → Statements → Actions
|
|
6
|
+
// 🔧 CORREÇÃO: Converter Map para objeto plano se necessário (JSON serialization)
|
|
7
|
+
if (allCNsData && typeof allCNsData === 'object' && !allCNsData.size) {
|
|
8
|
+
allCNsData = new Map(Object.entries(allCNsData));
|
|
9
|
+
}
|
|
10
|
+
const escapeHtml = (value) => typeof value === 'string'
|
|
11
|
+
? value
|
|
12
|
+
.replace(/&/g, '&')
|
|
13
|
+
.replace(/</g, '<')
|
|
14
|
+
.replace(/>/g, '>')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/'/g, ''')
|
|
17
|
+
: '';
|
|
18
|
+
return `
|
|
19
|
+
<!DOCTYPE html>
|
|
20
|
+
<html lang="pt-BR">
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="UTF-8" />
|
|
23
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
24
|
+
<title>${titulo}</title>
|
|
25
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
26
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
27
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
28
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
29
|
+
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
|
|
30
|
+
<style>
|
|
31
|
+
body { font-family: 'Inter', sans-serif; background-color: #0f172a; color: #f1f5f9; min-height: 100vh; }
|
|
32
|
+
.light-mode { background-color: #f9fafb !important; color: #222 !important; }
|
|
33
|
+
.tipo-badge { display: inline-flex; align-items: center; padding: 4px 12px; border-radius: 9999px; font-size: 13px; font-weight: 600; color: white; }
|
|
34
|
+
.card { background: #1e293b; border-radius: 1rem; padding: 1.5rem; box-shadow: 0 2px 8px #0002; }
|
|
35
|
+
.light-mode .card { background: #fff; color: #222; }
|
|
36
|
+
.btn { background: #334155; color: #fff; border: none; border-radius: 8px; padding: 0.5rem 1.2rem; font-weight: 600; cursor: pointer; margin-bottom: 0.25rem; transition: background 0.2s; }
|
|
37
|
+
.btn:hover { background: #475569; }
|
|
38
|
+
.light-mode .btn { background: #e2e8f0; color: #222; }
|
|
39
|
+
.table-container { overflow-x: auto; }
|
|
40
|
+
table { border-collapse: collapse; width: 100%; }
|
|
41
|
+
th, td { padding: 0.75rem 1rem; text-align: left; }
|
|
42
|
+
th { background: #1e293b; color: #fbbf24; font-size: 1rem; }
|
|
43
|
+
.light-mode th { background: #f1f5f9; color: #b45309; }
|
|
44
|
+
tr:nth-child(even) { background: #1e293b44; }
|
|
45
|
+
.light-mode tr:nth-child(even) { background: #f1f5f9; }
|
|
46
|
+
.chart-card { background: #1e293b; border-radius: 1rem; padding: 1rem; margin-bottom: 1.5rem; }
|
|
47
|
+
.light-mode .chart-card { background: #fff; }
|
|
48
|
+
.status-pass { color: #22c55e; font-weight: 700; }
|
|
49
|
+
.status-fail { color: #ef4444; font-weight: 700; }
|
|
50
|
+
.status-skip { color: #fbbf24; font-weight: 700; }
|
|
51
|
+
.header-bar { background: #1e293b; padding: 1rem 2rem; border-radius: 1rem 1rem 0 0; margin-bottom: 1.5rem; display: flex; align-items: center; justify-content: space-between; }
|
|
52
|
+
.header-bar .header-title { font-size: 2rem; font-weight: 700; color: #fbbf24; }
|
|
53
|
+
.header-bar .header-meta { font-size: 1rem; color: #f1f5f9; }
|
|
54
|
+
.light-mode .header-bar { background: #f1f5f9; color: #222; }
|
|
55
|
+
.light-mode .header-title { color: #b45309; }
|
|
56
|
+
.light-mode .header-meta { color: #222 !important; }
|
|
57
|
+
.footer-bar { background: #1e293b; color: #fbbf24; padding: 1rem 2rem; border-radius: 0 0 1rem 1rem; margin-top: 2rem; text-align: center; font-size: 1rem; }
|
|
58
|
+
.light-mode .footer-bar { background: #f1f5f9; color: #b45309; }
|
|
59
|
+
.footer-bar a { color: #fbbf24; text-decoration: underline; }
|
|
60
|
+
.light-mode .footer-bar a { color: #b45309; }
|
|
61
|
+
@media (max-width: 900px) {
|
|
62
|
+
.grid-cols-2, .grid-cols-3, .grid-cols-4 { grid-template-columns: 1fr !important; }
|
|
63
|
+
}
|
|
64
|
+
@media print {
|
|
65
|
+
.chart-card canvas {
|
|
66
|
+
width: 300px !important;
|
|
67
|
+
height: 150px !important;
|
|
68
|
+
max-height: 150px !important;
|
|
69
|
+
transform: scale(0.85) !important;
|
|
70
|
+
transform-origin: top left !important;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
.chart-card canvas {
|
|
74
|
+
height: 320px !important;
|
|
75
|
+
max-height: 320px !important;
|
|
76
|
+
width: 100% !important;
|
|
77
|
+
}
|
|
78
|
+
.chart-card-full { width: 100%; }
|
|
79
|
+
#chart-duracao {
|
|
80
|
+
width: 100% !important;
|
|
81
|
+
display: block !important;
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body id="body-root">
|
|
86
|
+
<div class="header-bar">
|
|
87
|
+
<div class="header-title">Relatório Unificado de Testes</div>
|
|
88
|
+
<div class="header-meta">
|
|
89
|
+
<span>Projeto: <strong>${projectName || 'TestHUB'}</strong></span> |
|
|
90
|
+
<span>Ambiente: <strong>${environment || 'N/A'}</strong></span> |
|
|
91
|
+
<span>Data: <strong>${executionDate || new Date().toLocaleString('pt-BR')}</strong></span> |
|
|
92
|
+
<span>Test Hub: <strong>${autocoreVersion || 'v1.1.x'}</strong></span>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="flex gap-2 mb-6 justify-end mr-6">
|
|
96
|
+
<button id="toggle-theme" class="btn" type="button" title="Alternar tema">🌙 Tema</button>
|
|
97
|
+
<button id="export-pdf" class="btn" type="button" title="Exportar PDF">📄 PDF</button>
|
|
98
|
+
<button id="export-csv" class="btn" type="button" title="Exportar CSV">📑 CSV</button>
|
|
99
|
+
<button id="export-json" class="btn" type="button" title="Exportar JSON">🗒️ JSON</button>
|
|
100
|
+
<button id="export-xlsx" class="btn" type="button" title="Exportar XLSX">📊 XLSX</button>
|
|
101
|
+
</div>
|
|
102
|
+
<div id="report-root" class="max-w-7xl mx-auto p-6" style="background:inherit;">
|
|
103
|
+
<h1 class="text-4xl font-bold mb-2">${titulo}</h1>
|
|
104
|
+
<p class="text-slate-400 mb-6">${subtitulo}</p>
|
|
105
|
+
|
|
106
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
|
|
107
|
+
<div class="card flex flex-col items-center">
|
|
108
|
+
<span class="text-2xl font-bold">${totalTestes}</span>
|
|
109
|
+
<span class="text-slate-400">Total</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="card flex flex-col items-center">
|
|
112
|
+
<span class="text-2xl font-bold text-green-400">${testesPassaram}</span>
|
|
113
|
+
<span class="text-green-400">Passou</span>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="card flex flex-col items-center">
|
|
116
|
+
<span class="text-2xl font-bold text-red-400">${testesFalharam}</span>
|
|
117
|
+
<span class="text-red-400">Falhou</span>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
${globalTotalCTs > 0
|
|
122
|
+
? `
|
|
123
|
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
|
|
124
|
+
<div class="card flex flex-col items-center">
|
|
125
|
+
<span class="text-2xl font-bold">${globalTotalCTs}</span>
|
|
126
|
+
<span class="text-slate-400">Total de CTs</span>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="card flex flex-col items-center">
|
|
129
|
+
<span class="text-2xl font-bold text-green-400">${globalPassedCTs}</span>
|
|
130
|
+
<span class="text-green-400">CTs Passaram</span>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="card flex flex-col items-center">
|
|
133
|
+
<span class="text-2xl font-bold text-red-400">${globalFailedCTs}</span>
|
|
134
|
+
<span class="text-red-400">CTs Falharam</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="card flex flex-col items-center">
|
|
137
|
+
<span class="text-2xl font-bold text-yellow-400">${globalSkippedCTs}</span>
|
|
138
|
+
<span class="text-yellow-400">CTs Pulados</span>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
`
|
|
142
|
+
: ''}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
<!-- Gráficos superiores -->
|
|
146
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
|
147
|
+
<div class="chart-card"><canvas id="chart-tipos" height="180"></canvas></div>
|
|
148
|
+
<div class="chart-card"><canvas id="chart-passfail" height="180"></canvas></div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<!-- Gráfico inferior ocupando toda a largura -->
|
|
152
|
+
<div class="chart-card w-full mb-8">
|
|
153
|
+
<canvas id="chart-duracao" height="320" style="width: 100%; display: block;"></canvas>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<!-- 🆕 NOVA SEÇÃO: Hierarquia Completa de CNs → CTs → Statements → Actions -->
|
|
157
|
+
${allCNsData && allCNsData.size > 0
|
|
158
|
+
? `
|
|
159
|
+
<div class="mb-8">
|
|
160
|
+
<h2 class="text-2xl font-bold mb-6 text-center text-cyan-400">
|
|
161
|
+
🧪 Hierarquia Completa: Casos de Negócio (CNs) e Cenários de Teste (CTs)
|
|
162
|
+
</h2>
|
|
163
|
+
|
|
164
|
+
<div class="card">
|
|
165
|
+
<div class="mb-4 flex items-center justify-between">
|
|
166
|
+
<div class="text-gray-300">
|
|
167
|
+
<span class="bg-cyan-600 px-3 py-1 rounded-full text-sm font-medium mr-2">
|
|
168
|
+
${allCNsData.size} CN${allCNsData.size > 1 ? 's' : ''}
|
|
169
|
+
</span>
|
|
170
|
+
<span class="bg-blue-600 px-3 py-1 rounded-full text-sm font-medium">
|
|
171
|
+
${Array.from(allCNsData.values()).reduce((total, cn) => total + (cn.cts?.length || 0), 0)} CT${Array.from(allCNsData.values()).reduce((total, cn) => total + (cn.cts?.length || 0), 0) !== 1 ? 's' : ''}
|
|
172
|
+
</span>
|
|
173
|
+
</div>
|
|
174
|
+
<button onclick="expandAllCNs()" class="btn text-xs px-3 py-1">🔽 Expandir Todos</button>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div class="space-y-4">
|
|
178
|
+
${Array.from(allCNsData.entries())
|
|
179
|
+
.map((entry, cnIndex) => {
|
|
180
|
+
const [cnName, cnData] = entry;
|
|
181
|
+
const cts = cnData.cts || [];
|
|
182
|
+
const totalCTs = cts.length;
|
|
183
|
+
const passedCTs = cts.filter((ct) => ct.status === 'passed').length;
|
|
184
|
+
// ✅ CORREÇÃO: CTs "running" devem ser contados como "failed"
|
|
185
|
+
const failedCTs = cts.filter((ct) => ct.status === 'failed' || ct.status === 'running').length;
|
|
186
|
+
const totalDuration = cts.reduce((sum, ct) => sum + (ct.duration || 0), 0);
|
|
187
|
+
const totalStatements = cts.reduce((sum, ct) => sum + (ct.statements?.length || 0), 0);
|
|
188
|
+
const totalActions = cts.reduce((sum, ct) => sum + (ct.executedActions?.length || 0), 0);
|
|
189
|
+
return `
|
|
190
|
+
<div class="bg-slate-800 rounded-lg overflow-hidden border-l-4 ${failedCTs > 0 ? 'border-red-500' : passedCTs === totalCTs ? 'border-green-500' : 'border-yellow-500'}">
|
|
191
|
+
<!-- Cabeçalho do CN -->
|
|
192
|
+
<button onclick="toggleCN('cn-${cnIndex}')" class="w-full text-left p-4 hover:bg-slate-700 transition-colors flex items-center justify-between">
|
|
193
|
+
<div class="flex items-center gap-3 flex-1">
|
|
194
|
+
<span class="text-2xl">🧪</span>
|
|
195
|
+
<div class="flex-1">
|
|
196
|
+
<h3 class="text-lg font-bold text-white">${cnName}</h3>
|
|
197
|
+
<div class="flex items-center gap-3 mt-1 text-sm text-gray-400">
|
|
198
|
+
<span>📋 ${totalCTs} CT${totalCTs !== 1 ? 's' : ''}</span>
|
|
199
|
+
<span>⏱️ ${(totalDuration / 1000).toFixed(2)}s</span>
|
|
200
|
+
<span>📝 ${totalStatements} Statement${totalStatements !== 1 ? 's' : ''}</span>
|
|
201
|
+
<span>🎬 ${totalActions} Action${totalActions !== 1 ? 's' : ''}</span>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
<div class="flex items-center gap-2">
|
|
205
|
+
<span class="status-pass text-sm">✅ ${passedCTs}</span>
|
|
206
|
+
<span class="status-fail text-sm">❌ ${failedCTs}</span>
|
|
207
|
+
<span class="text-2xl transform transition-transform" id="arrow-cn-${cnIndex}">▶</span>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</button>
|
|
211
|
+
|
|
212
|
+
<!-- Corpo expandível do CN -->
|
|
213
|
+
<div id="cn-${cnIndex}" style="display: none;" class="bg-slate-900 p-4">
|
|
214
|
+
<div class="space-y-3">
|
|
215
|
+
${cts
|
|
216
|
+
.map((ct, ctIndex) => `
|
|
217
|
+
<div class="bg-slate-800 rounded-lg p-3 border-l-4 ${ct.status === 'passed'
|
|
218
|
+
? 'border-green-500'
|
|
219
|
+
: ct.status === 'skipped'
|
|
220
|
+
? 'border-yellow-500'
|
|
221
|
+
: 'border-red-500'}">
|
|
222
|
+
<!-- Cabeçalho do CT -->
|
|
223
|
+
<button onclick="toggleCT('ct-${cnIndex}-${ctIndex}')" class="w-full text-left flex items-start justify-between hover:opacity-80 transition-opacity">
|
|
224
|
+
<div class="flex-1">
|
|
225
|
+
<div class="flex items-center gap-2 mb-1">
|
|
226
|
+
<span class="inline-flex items-center justify-center w-6 h-6 bg-blue-600 text-white text-xs rounded-full">
|
|
227
|
+
${ctIndex + 1}
|
|
228
|
+
</span>
|
|
229
|
+
<code class="text-xs text-cyan-300 bg-gray-900 px-2 py-1 rounded">${ct.id || `CT${(ctIndex + 1).toString().padStart(3, '0')}`}</code>
|
|
230
|
+
<span class="font-medium text-white">${ct.name || 'Unknown CT'}</span>
|
|
231
|
+
<span class="text-xs transform transition-transform inline-block" id="arrow-ct-${cnIndex}-${ctIndex}">▶</span>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="flex items-center gap-3 text-xs text-gray-400 ml-8">
|
|
234
|
+
<span class="font-mono ${(ct.duration / 1000) > 5
|
|
235
|
+
? 'text-red-400'
|
|
236
|
+
: ct.duration / 1000 > 2
|
|
237
|
+
? 'text-yellow-400'
|
|
238
|
+
: 'text-green-400'}">⏱️ ${((ct.duration || 0) / 1000).toFixed(3)}s</span>
|
|
239
|
+
${ct.statements && ct.statements.length > 0 ? `<span>📝 ${ct.statements.length} Statements</span>` : ''}
|
|
240
|
+
${ct.executedActions && ct.executedActions.length > 0 ? `<span>🎬 ${ct.executedActions.length} Actions</span>` : ''}
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${ct.status === 'passed'
|
|
244
|
+
? 'bg-green-600 text-white'
|
|
245
|
+
: ct.status === 'skipped'
|
|
246
|
+
? 'bg-yellow-600 text-black'
|
|
247
|
+
: 'bg-red-600 text-white'}">
|
|
248
|
+
${ct.status === 'passed'
|
|
249
|
+
? '✅ PASSED'
|
|
250
|
+
: ct.status === 'skipped'
|
|
251
|
+
? '⏭️ SKIPPED'
|
|
252
|
+
: '❌ FAILED'}
|
|
253
|
+
</span>
|
|
254
|
+
</button>
|
|
255
|
+
|
|
256
|
+
<!-- Corpo expandível do CT -->
|
|
257
|
+
<div id="ct-${cnIndex}-${ctIndex}" style="display: none;" class="mt-3 ml-8 space-y-3">
|
|
258
|
+
<!-- Classe e Método -->
|
|
259
|
+
<div class="bg-slate-700 rounded p-2 text-xs">
|
|
260
|
+
<div class="text-yellow-300 font-mono">📦 ${ct.className || 'Unknown'}</div>
|
|
261
|
+
<div class="text-green-300 font-mono">.${ct.methodName || 'unknownMethod'}()</div>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
${ct.error
|
|
265
|
+
? `
|
|
266
|
+
<div class="bg-red-900/30 border border-red-600 rounded p-3">
|
|
267
|
+
<div class="flex items-start gap-2">
|
|
268
|
+
<span class="text-red-400 text-lg">⚠️</span>
|
|
269
|
+
<div>
|
|
270
|
+
<div class="text-sm font-medium text-red-400 mb-1">Erro:</div>
|
|
271
|
+
<pre class="text-xs text-red-200 overflow-x-auto">${ct.error}</pre>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
`
|
|
276
|
+
: ''}
|
|
277
|
+
|
|
278
|
+
<!-- Statements -->
|
|
279
|
+
${ct.statements && ct.statements.length > 0
|
|
280
|
+
? `
|
|
281
|
+
<div class="bg-slate-700 rounded-lg p-3">
|
|
282
|
+
<div class="flex items-center gap-2 mb-2">
|
|
283
|
+
<span class="text-lg">📝</span>
|
|
284
|
+
<h5 class="text-sm font-bold text-cyan-400">Statements (${ct.statements.length})</h5>
|
|
285
|
+
</div>
|
|
286
|
+
<div class="space-y-1">
|
|
287
|
+
${ct.statements
|
|
288
|
+
.map((stmt, stmtIdx) => `
|
|
289
|
+
<div class="bg-slate-800 rounded p-2 flex items-start justify-between gap-2">
|
|
290
|
+
<div class="flex items-start gap-2 flex-1 min-w-0">
|
|
291
|
+
<span class="text-slate-400 font-mono text-xs flex-shrink-0">#${stmtIdx + 1}</span>
|
|
292
|
+
<span class="${stmt.status === 'passed'
|
|
293
|
+
? 'text-green-400'
|
|
294
|
+
: stmt.status === 'failed'
|
|
295
|
+
? 'text-red-400'
|
|
296
|
+
: stmt.status === 'skipped'
|
|
297
|
+
? 'text-yellow-400'
|
|
298
|
+
: 'text-blue-400'}">
|
|
299
|
+
${stmt.status === 'passed' ? '✅' : stmt.status === 'failed' ? '❌' : stmt.status === 'skipped' ? '⚠️' : '🔄'}
|
|
300
|
+
</span>
|
|
301
|
+
<div class="flex-1 min-w-0">
|
|
302
|
+
<div class="text-xs truncate">
|
|
303
|
+
<code class="text-yellow-300">${stmt.className || 'Statement'}</code>
|
|
304
|
+
<span class="text-gray-400">.</span>
|
|
305
|
+
<code class="text-green-300">${stmt.methodName || 'method'}()</code>
|
|
306
|
+
</div>
|
|
307
|
+
${stmt.error
|
|
308
|
+
? `
|
|
309
|
+
<div class="text-xs text-red-300 mt-1 bg-red-900/20 p-1 rounded">
|
|
310
|
+
${stmt.error}
|
|
311
|
+
</div>
|
|
312
|
+
`
|
|
313
|
+
: ''}
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
<div class="text-right flex-shrink-0">
|
|
317
|
+
<div class="text-xs font-mono ${stmt.duration > 5000
|
|
318
|
+
? 'text-red-400'
|
|
319
|
+
: stmt.duration > 2000
|
|
320
|
+
? 'text-yellow-400'
|
|
321
|
+
: 'text-green-400'}">
|
|
322
|
+
${stmt.duration || 0}ms
|
|
323
|
+
</div>
|
|
324
|
+
<div class="text-xs text-slate-400 capitalize">
|
|
325
|
+
${stmt.status || 'running'}
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
`)
|
|
330
|
+
.join('')}
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
`
|
|
334
|
+
: ''}
|
|
335
|
+
|
|
336
|
+
<!-- Actions -->
|
|
337
|
+
${ct.executedActions && ct.executedActions.length > 0
|
|
338
|
+
? `
|
|
339
|
+
<div class="bg-slate-700 rounded-lg p-3">
|
|
340
|
+
<div class="flex items-center gap-2 mb-2">
|
|
341
|
+
<span class="text-lg">🎬</span>
|
|
342
|
+
<h5 class="text-sm font-bold text-purple-400">Actions (${ct.executedActions.length})</h5>
|
|
343
|
+
</div>
|
|
344
|
+
<div class="grid gap-2 md:grid-cols-2">
|
|
345
|
+
${ct.executedActions
|
|
346
|
+
.map((action, actIdx) => `
|
|
347
|
+
<div class="bg-slate-800 rounded p-2 flex items-start gap-2">
|
|
348
|
+
<span class="text-slate-400 font-mono text-xs flex-shrink-0">#${actIdx + 1}</span>
|
|
349
|
+
<div class="flex-1 min-w-0">
|
|
350
|
+
<div class="flex items-center gap-2 flex-wrap mb-1">
|
|
351
|
+
<span class="${action.type === 'API'
|
|
352
|
+
? 'bg-green-600'
|
|
353
|
+
: action.type === 'WEB'
|
|
354
|
+
? 'bg-blue-600'
|
|
355
|
+
: action.type === 'MOBILE'
|
|
356
|
+
? 'bg-purple-600'
|
|
357
|
+
: action.type === 'SSH'
|
|
358
|
+
? 'bg-orange-600'
|
|
359
|
+
: action.type === 'DATABASE'
|
|
360
|
+
? 'bg-yellow-600'
|
|
361
|
+
: 'bg-gray-600'} text-white text-xs px-2 py-0.5 rounded font-bold flex-shrink-0">
|
|
362
|
+
${action.type === 'API'
|
|
363
|
+
? '📡 API'
|
|
364
|
+
: action.type === 'WEB'
|
|
365
|
+
? '🌐 WEB'
|
|
366
|
+
: action.type === 'MOBILE'
|
|
367
|
+
? '📱 MOBILE'
|
|
368
|
+
: action.type === 'SSH'
|
|
369
|
+
? '🖥️ SSH'
|
|
370
|
+
: action.type === 'DATABASE'
|
|
371
|
+
? '🗄️ DB'
|
|
372
|
+
: '⚙️ ' + action.type}
|
|
373
|
+
</span>
|
|
374
|
+
<span class="${action.success ? 'text-green-400' : 'text-red-400'} text-sm">
|
|
375
|
+
${action.success ? '✅' : '❌'}
|
|
376
|
+
</span>
|
|
377
|
+
<span class="text-xs font-mono ${action.duration > 1000
|
|
378
|
+
? 'text-red-400'
|
|
379
|
+
: action.duration > 500
|
|
380
|
+
? 'text-yellow-400'
|
|
381
|
+
: 'text-green-400'}">
|
|
382
|
+
${action.duration || 0}ms
|
|
383
|
+
</span>
|
|
384
|
+
</div>
|
|
385
|
+
<div class="text-xs text-slate-300 truncate" title="${action.description || action.method || action.url || 'Ação executada'}">
|
|
386
|
+
${action.description || action.method || action.url || 'Ação executada'}
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
`)
|
|
391
|
+
.join('')}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
`
|
|
395
|
+
: ''}
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
`)
|
|
399
|
+
.join('')}
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
`;
|
|
404
|
+
})
|
|
405
|
+
.join('')}
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
`
|
|
410
|
+
: ''}
|
|
411
|
+
|
|
412
|
+
<!-- Seção de CTs Detectados Automaticamente -->
|
|
413
|
+
${ctData && ctData.length > 0
|
|
414
|
+
? `
|
|
415
|
+
<div class="mb-8">
|
|
416
|
+
<h2 class="text-2xl font-bold mb-6 text-center">🎯 CTs Detectados Automaticamente</h2>
|
|
417
|
+
<div class="card">
|
|
418
|
+
<div class="mb-4 text-center text-gray-300">
|
|
419
|
+
<span class="bg-blue-600 px-3 py-1 rounded-full text-sm font-medium">
|
|
420
|
+
${ctData.length} CT${ctData.length > 1 ? 's' : ''} detectado${ctData.length > 1 ? 's' : ''}
|
|
421
|
+
</span>
|
|
422
|
+
</div>
|
|
423
|
+
|
|
424
|
+
<div class="overflow-x-auto">
|
|
425
|
+
<table class="w-full text-sm">
|
|
426
|
+
<thead>
|
|
427
|
+
<tr class="bg-gray-700">
|
|
428
|
+
<th class="p-3 text-left">CT#</th>
|
|
429
|
+
<th class="p-3 text-left">Nome do CT</th>
|
|
430
|
+
<th class="p-3 text-center">Duração</th>
|
|
431
|
+
<th class="p-3 text-center">Ações Executadas</th>
|
|
432
|
+
<th class="p-3 text-left">Detalhes</th>
|
|
433
|
+
</tr>
|
|
434
|
+
</thead>
|
|
435
|
+
<tbody>
|
|
436
|
+
${ctData
|
|
437
|
+
.map((ct, index) => `
|
|
438
|
+
<tr class="border-b border-gray-600">
|
|
439
|
+
<td class="p-3 font-mono text-blue-400">CT${ct.id}</td>
|
|
440
|
+
<td class="p-3 font-medium">${ct.name}</td>
|
|
441
|
+
<td class="p-3 text-center font-mono ${ct.duration > 5000
|
|
442
|
+
? 'text-red-400'
|
|
443
|
+
: ct.duration > 2000
|
|
444
|
+
? 'text-yellow-400'
|
|
445
|
+
: 'text-green-400'}">
|
|
446
|
+
${(ct.duration / 1000).toFixed(3)}s
|
|
447
|
+
</td>
|
|
448
|
+
<td class="p-3 text-center">
|
|
449
|
+
<div class="flex justify-center gap-1 flex-wrap">
|
|
450
|
+
${ct.executedActions && ct.executedActions.length > 0
|
|
451
|
+
? ct.executedActions
|
|
452
|
+
.map((action) => `
|
|
453
|
+
<span class="px-2 py-1 rounded text-xs font-medium ${action.type === 'API'
|
|
454
|
+
? 'bg-green-600 text-white'
|
|
455
|
+
: action.type === 'SSH'
|
|
456
|
+
? 'bg-purple-600 text-white'
|
|
457
|
+
: action.type === 'DB'
|
|
458
|
+
? 'bg-blue-600 text-white'
|
|
459
|
+
: action.type === 'UI'
|
|
460
|
+
? 'bg-orange-600 text-white'
|
|
461
|
+
: action.type === 'MOBILE'
|
|
462
|
+
? 'bg-pink-600 text-white'
|
|
463
|
+
: 'bg-gray-600 text-white'}" title="${action.description}">
|
|
464
|
+
${action.type}
|
|
465
|
+
</span>
|
|
466
|
+
`)
|
|
467
|
+
.join('')
|
|
468
|
+
: '<span class="text-gray-400 text-xs">Nenhuma ação detectada</span>'}
|
|
469
|
+
</div>
|
|
470
|
+
</td>
|
|
471
|
+
<td class="p-3 text-xs text-gray-400">
|
|
472
|
+
<div>Iniciado: ${new Date(ct.startTime).toLocaleTimeString()}</div>
|
|
473
|
+
<div>Finalizado: ${new Date(ct.endTime).toLocaleTimeString()}</div>
|
|
474
|
+
</td>
|
|
475
|
+
</tr>
|
|
476
|
+
`)
|
|
477
|
+
.join('')}
|
|
478
|
+
</tbody>
|
|
479
|
+
</table>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
`
|
|
484
|
+
: ''}
|
|
485
|
+
|
|
486
|
+
<!-- 📋 NOVO: Logs do Terminal -->
|
|
487
|
+
${(() => {
|
|
488
|
+
// Tentar obter logs do TerminalLogCapture via data
|
|
489
|
+
const terminalLogs = data.terminalLogs;
|
|
490
|
+
if (!terminalLogs ||
|
|
491
|
+
!terminalLogs.byTest ||
|
|
492
|
+
Object.keys(terminalLogs.byTest).length === 0) {
|
|
493
|
+
return ''; // Não mostrar seção se não houver logs
|
|
494
|
+
}
|
|
495
|
+
return `
|
|
496
|
+
<div class="card mb-8">
|
|
497
|
+
<h2 class="text-2xl font-bold mb-6 text-center">📋 Logs do Terminal</h2>
|
|
498
|
+
|
|
499
|
+
<div class="mb-4 flex gap-4 justify-center text-sm">
|
|
500
|
+
<div class="px-4 py-2 bg-blue-900/30 rounded-lg border border-blue-700/50">
|
|
501
|
+
<span class="text-gray-400">Total:</span>
|
|
502
|
+
<span class="font-bold text-blue-400">${terminalLogs.totalLogs || 0}</span>
|
|
503
|
+
</div>
|
|
504
|
+
<div class="px-4 py-2 bg-gray-900/30 rounded-lg border border-gray-700/50">
|
|
505
|
+
<span class="text-gray-400">Log:</span>
|
|
506
|
+
<span class="font-bold text-gray-300">${terminalLogs.byLevel?.log || 0}</span>
|
|
507
|
+
</div>
|
|
508
|
+
<div class="px-4 py-2 bg-cyan-900/30 rounded-lg border border-cyan-700/50">
|
|
509
|
+
<span class="text-gray-400">Info:</span>
|
|
510
|
+
<span class="font-bold text-cyan-400">${terminalLogs.byLevel?.info || 0}</span>
|
|
511
|
+
</div>
|
|
512
|
+
<div class="px-4 py-2 bg-yellow-900/30 rounded-lg border border-yellow-700/50">
|
|
513
|
+
<span class="text-gray-400">Warn:</span>
|
|
514
|
+
<span class="font-bold text-yellow-400">${terminalLogs.byLevel?.warn || 0}</span>
|
|
515
|
+
</div>
|
|
516
|
+
<div class="px-4 py-2 bg-red-900/30 rounded-lg border border-red-700/50">
|
|
517
|
+
<span class="text-gray-400">Error:</span>
|
|
518
|
+
<span class="font-bold text-red-400">${terminalLogs.byLevel?.error || 0}</span>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
${Object.entries(terminalLogs.byTest)
|
|
523
|
+
.map(([testName, logs]) => {
|
|
524
|
+
if (!logs || logs.length === 0)
|
|
525
|
+
return '';
|
|
526
|
+
const cleanName = testName.replace(/[^a-zA-Z0-9]/g, '_');
|
|
527
|
+
return `
|
|
528
|
+
<div class="mb-4 border border-gray-700 rounded-lg overflow-hidden">
|
|
529
|
+
<button
|
|
530
|
+
onclick="toggleTerminalLogs('${cleanName}')"
|
|
531
|
+
class="w-full text-left px-4 py-3 bg-gray-800/50 hover:bg-gray-700/50 transition-colors flex items-center justify-between">
|
|
532
|
+
<div class="flex items-center gap-2">
|
|
533
|
+
<span class="text-yellow-400">📋</span>
|
|
534
|
+
<span class="font-medium">${testName}</span>
|
|
535
|
+
<span class="text-xs px-2 py-1 bg-blue-900/50 rounded-full text-blue-300">${logs.length} logs</span>
|
|
536
|
+
</div>
|
|
537
|
+
<span id="terminal-btn-${cleanName}" class="text-xs text-gray-400">▼ Expandir</span>
|
|
538
|
+
</button>
|
|
539
|
+
<div id="terminal-logs-${cleanName}" style="display: none;" class="max-h-96 overflow-y-auto bg-gray-900/50">
|
|
540
|
+
<div class="p-4 font-mono text-xs space-y-1">
|
|
541
|
+
${logs
|
|
542
|
+
.map((log) => {
|
|
543
|
+
const levelColors = {
|
|
544
|
+
log: 'text-gray-300',
|
|
545
|
+
info: 'text-cyan-400',
|
|
546
|
+
warn: 'text-yellow-400',
|
|
547
|
+
error: 'text-red-400',
|
|
548
|
+
debug: 'text-purple-400',
|
|
549
|
+
};
|
|
550
|
+
const color = levelColors[log.level] || 'text-gray-300';
|
|
551
|
+
const icon = log.level === 'error'
|
|
552
|
+
? '❌'
|
|
553
|
+
: log.level === 'warn'
|
|
554
|
+
? '⚠️'
|
|
555
|
+
: log.level === 'info'
|
|
556
|
+
? 'ℹ️'
|
|
557
|
+
: '📝';
|
|
558
|
+
return `
|
|
559
|
+
<div class="py-1 px-2 hover:bg-gray-800/30 rounded">
|
|
560
|
+
<span class="text-gray-500">[${new Date(log.timestamp).toLocaleTimeString('pt-BR')}]</span>
|
|
561
|
+
<span class="${color}">[${icon} ${log.level.toUpperCase()}]</span>
|
|
562
|
+
<span class="text-gray-200">${log.message.replace(/</g, '<').replace(/>/g, '>')}</span>
|
|
563
|
+
</div>
|
|
564
|
+
`;
|
|
565
|
+
})
|
|
566
|
+
.join('')}
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
</div>
|
|
570
|
+
`;
|
|
571
|
+
})
|
|
572
|
+
.join('')}
|
|
573
|
+
</div>
|
|
574
|
+
`;
|
|
575
|
+
})()}
|
|
576
|
+
|
|
577
|
+
<div class="footer-bar">
|
|
578
|
+
Desenvolvido por <strong>TestHUB</strong> — Plataforma Unificada de Automação de Testes.<br>
|
|
579
|
+
<span>Relatório gerado automaticamente. Para dúvidas, acesse a <a href="http://brtlvlty0559pl:3002/" target="_blank">website HUB</a>.</span>
|
|
580
|
+
</div>
|
|
581
|
+
|
|
582
|
+
<script>
|
|
583
|
+
document.getElementById('toggle-theme').onclick = () => {
|
|
584
|
+
document.getElementById('body-root').classList.toggle('light-mode')
|
|
585
|
+
document.querySelector('.header-bar').classList.toggle('light-mode')
|
|
586
|
+
document.querySelector('.footer-bar').classList.toggle('light-mode')
|
|
587
|
+
const meta = document.querySelector('.header-meta')
|
|
588
|
+
if (document.getElementById('body-root').classList.contains('light-mode')) {
|
|
589
|
+
meta && (meta.style.color = '#222')
|
|
590
|
+
} else {
|
|
591
|
+
meta && (meta.style.color = '#f1f5f9')
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// 🆕 Função para expandir/colapsar CTs
|
|
596
|
+
function toggleCTs(testName) {
|
|
597
|
+
const cleanName = testName.replace(/[^a-zA-Z0-9]/g, '_')
|
|
598
|
+
const ctsRow = document.getElementById('cts-' + cleanName)
|
|
599
|
+
const btn = document.getElementById('btn-' + cleanName)
|
|
600
|
+
|
|
601
|
+
if (ctsRow && btn) {
|
|
602
|
+
if (ctsRow.style.display === 'none') {
|
|
603
|
+
ctsRow.style.display = 'table-row'
|
|
604
|
+
btn.innerHTML = '📋 CTs ▲'
|
|
605
|
+
} else {
|
|
606
|
+
ctsRow.style.display = 'none'
|
|
607
|
+
btn.innerHTML = '📋 CTs'
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// 🆕 Função para expandir/colapsar Logs
|
|
613
|
+
function toggleLogs(testName) {
|
|
614
|
+
const cleanName = testName.replace(/[^a-zA-Z0-9]/g, '_')
|
|
615
|
+
const logsRow = document.getElementById('logs-' + cleanName)
|
|
616
|
+
const btn = document.getElementById('log-btn-' + cleanName)
|
|
617
|
+
|
|
618
|
+
if (logsRow && btn) {
|
|
619
|
+
if (logsRow.style.display === 'none') {
|
|
620
|
+
logsRow.style.display = 'table-row'
|
|
621
|
+
btn.innerHTML = '📜 Logs ▲'
|
|
622
|
+
} else {
|
|
623
|
+
logsRow.style.display = 'none'
|
|
624
|
+
btn.innerHTML = '📜 Logs'
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// 📋 Função para expandir/colapsar Logs do Terminal
|
|
630
|
+
function toggleTerminalLogs(testName) {
|
|
631
|
+
const logsDiv = document.getElementById('terminal-logs-' + testName)
|
|
632
|
+
const btn = document.getElementById('terminal-btn-' + testName)
|
|
633
|
+
|
|
634
|
+
if (logsDiv && btn) {
|
|
635
|
+
if (logsDiv.style.display === 'none') {
|
|
636
|
+
logsDiv.style.display = 'block'
|
|
637
|
+
btn.innerHTML = '▲ Colapsar'
|
|
638
|
+
} else {
|
|
639
|
+
logsDiv.style.display = 'none'
|
|
640
|
+
btn.innerHTML = '▼ Expandir'
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// 🆕 Funções para expandir/colapsar CNs e CTs
|
|
646
|
+
function toggleCN(cnId) {
|
|
647
|
+
const cnBody = document.getElementById(cnId)
|
|
648
|
+
const arrow = document.getElementById('arrow-' + cnId)
|
|
649
|
+
|
|
650
|
+
if (cnBody.style.display === 'none') {
|
|
651
|
+
cnBody.style.display = 'block'
|
|
652
|
+
arrow.style.transform = 'rotate(90deg)'
|
|
653
|
+
} else {
|
|
654
|
+
cnBody.style.display = 'none'
|
|
655
|
+
arrow.style.transform = 'rotate(0deg)'
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function toggleCT(ctId) {
|
|
660
|
+
const ctBody = document.getElementById(ctId)
|
|
661
|
+
const arrow = document.getElementById('arrow-' + ctId)
|
|
662
|
+
|
|
663
|
+
if (ctBody.style.display === 'none') {
|
|
664
|
+
ctBody.style.display = 'block'
|
|
665
|
+
arrow.style.transform = 'rotate(90deg)'
|
|
666
|
+
} else {
|
|
667
|
+
ctBody.style.display = 'none'
|
|
668
|
+
arrow.style.transform = 'rotate(0deg)'
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function expandAllCNs() {
|
|
673
|
+
const allCNs = document.querySelectorAll('[id^="cn-"]')
|
|
674
|
+
const allArrows = document.querySelectorAll('[id^="arrow-cn-"]')
|
|
675
|
+
const isAnyExpanded = Array.from(allCNs).some(cn => cn.style.display !== 'none')
|
|
676
|
+
|
|
677
|
+
allCNs.forEach((cn, index) => {
|
|
678
|
+
if (isAnyExpanded) {
|
|
679
|
+
cn.style.display = 'none'
|
|
680
|
+
allArrows[index].style.transform = 'rotate(0deg)'
|
|
681
|
+
} else {
|
|
682
|
+
cn.style.display = 'block'
|
|
683
|
+
allArrows[index].style.transform = 'rotate(90deg)'
|
|
684
|
+
}
|
|
685
|
+
})
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function getTestData() {
|
|
689
|
+
return Array.from(document.querySelectorAll('table tbody tr.test-row')).map(row => {
|
|
690
|
+
const cells = row.querySelectorAll('td')
|
|
691
|
+
return {
|
|
692
|
+
nome: cells[0].innerText,
|
|
693
|
+
tipo: cells[1].innerText,
|
|
694
|
+
resultado: cells[2].innerText,
|
|
695
|
+
duracao: cells[3].innerText,
|
|
696
|
+
cts: cells[4].innerText,
|
|
697
|
+
timestamp: cells[5].innerText
|
|
698
|
+
}
|
|
699
|
+
})
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
document.getElementById('export-pdf').onclick = async () => {
|
|
703
|
+
console.log('🔵 [PDF] Botão clicado - Iniciando geração do PDF unificado...');
|
|
704
|
+
|
|
705
|
+
const element = document.getElementById('report-root');
|
|
706
|
+
if (!element) {
|
|
707
|
+
console.error('❌ [PDF] Elemento report-root não encontrado!');
|
|
708
|
+
alert('❌ Erro: Elemento do relatório não encontrado!');
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Verificar se jsPDF está carregado
|
|
713
|
+
if (typeof jspdf === 'undefined') {
|
|
714
|
+
console.error('❌ [PDF] jsPDF não está carregado!');
|
|
715
|
+
alert('❌ Erro: Biblioteca jsPDF não carregada. Recarregue a página.');
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
console.log('✅ [PDF] jsPDF carregado com sucesso');
|
|
719
|
+
|
|
720
|
+
// 🆕 EXPANDIR TODAS AS SEÇÕES CN, CT, CTs e Logs antes de gerar PDF
|
|
721
|
+
const originalStates = {
|
|
722
|
+
cns: [],
|
|
723
|
+
cts: [],
|
|
724
|
+
ctsRows: [],
|
|
725
|
+
logsRows: []
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
// Expandir todos os CNs
|
|
729
|
+
const allCNs = document.querySelectorAll('[id^="cn-"]');
|
|
730
|
+
const allCNArrows = document.querySelectorAll('[id^="arrow-cn-"]');
|
|
731
|
+
allCNs.forEach((cn, index) => {
|
|
732
|
+
originalStates.cns.push(cn.style.display);
|
|
733
|
+
cn.style.display = 'block';
|
|
734
|
+
if (allCNArrows[index]) {
|
|
735
|
+
allCNArrows[index].style.transform = 'rotate(90deg)';
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// Expandir todos os CTs dentro dos CNs
|
|
740
|
+
const allCTs = document.querySelectorAll('[id^="ct-"]');
|
|
741
|
+
const allCTArrows = document.querySelectorAll('[id^="arrow-ct-"]');
|
|
742
|
+
allCTs.forEach((ct, index) => {
|
|
743
|
+
originalStates.cts.push(ct.style.display);
|
|
744
|
+
ct.style.display = 'block';
|
|
745
|
+
if (allCTArrows[index]) {
|
|
746
|
+
allCTArrows[index].style.transform = 'rotate(90deg)';
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
// Expandir todas as linhas de CTs nos testes
|
|
751
|
+
const allCTsRows = document.querySelectorAll('[id^="cts-"]');
|
|
752
|
+
allCTsRows.forEach((ctsRow) => {
|
|
753
|
+
originalStates.ctsRows.push(ctsRow.style.display);
|
|
754
|
+
ctsRow.style.display = 'table-row';
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// Expandir todas as linhas de Logs
|
|
758
|
+
const allLogsRows = document.querySelectorAll('[id^="logs-"]');
|
|
759
|
+
allLogsRows.forEach((logsRow) => {
|
|
760
|
+
originalStates.logsRows.push(logsRow.style.display);
|
|
761
|
+
logsRow.style.display = 'table-row';
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
// Aguardar imagens carregarem
|
|
765
|
+
const images = element.querySelectorAll('img');
|
|
766
|
+
console.log('📸 Total de imagens encontradas:', images.length);
|
|
767
|
+
|
|
768
|
+
await Promise.all(Array.from(images).map(img => {
|
|
769
|
+
if (img.complete) return Promise.resolve();
|
|
770
|
+
return new Promise(resolve => {
|
|
771
|
+
img.onload = resolve;
|
|
772
|
+
img.onerror = resolve;
|
|
773
|
+
setTimeout(resolve, 3000);
|
|
774
|
+
});
|
|
775
|
+
}));
|
|
776
|
+
|
|
777
|
+
console.log('✅ Imagens aguardadas');
|
|
778
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
779
|
+
|
|
780
|
+
// Preparar elemento para PDF
|
|
781
|
+
const originalBg = element.style.background;
|
|
782
|
+
const originalColor = element.style.color;
|
|
783
|
+
element.style.background = '#fff';
|
|
784
|
+
element.style.color = '#222';
|
|
785
|
+
|
|
786
|
+
// Reduzir e alinhar gráficos no PDF
|
|
787
|
+
document.querySelectorAll('.chart-card').forEach((card) => {
|
|
788
|
+
card.style.width = '100%';
|
|
789
|
+
card.style.display = 'block';
|
|
790
|
+
card.style.padding = '0.5rem';
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
document.querySelectorAll('.chart-card canvas').forEach((canvas) => {
|
|
794
|
+
canvas.style.width = '300px';
|
|
795
|
+
canvas.style.height = '150px';
|
|
796
|
+
canvas.style.maxHeight = '150px';
|
|
797
|
+
canvas.style.display = 'block';
|
|
798
|
+
canvas.style.margin = '0 auto';
|
|
799
|
+
canvas.style.transform = 'scale(0.85)';
|
|
800
|
+
canvas.style.transformOrigin = 'top left';
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
console.log('📄 [PDF] Iniciando geração do PDF...');
|
|
804
|
+
|
|
805
|
+
try {
|
|
806
|
+
// Usar html2canvas para capturar o conteúdo como imagem
|
|
807
|
+
const canvas = await html2canvas(element, {
|
|
808
|
+
scale: 2,
|
|
809
|
+
useCORS: false,
|
|
810
|
+
allowTaint: true,
|
|
811
|
+
backgroundColor: '#fff',
|
|
812
|
+
scrollY: 0,
|
|
813
|
+
logging: false,
|
|
814
|
+
imageTimeout: 0
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
// Criar PDF com jsPDF
|
|
818
|
+
const { jsPDF } = jspdf;
|
|
819
|
+
const pdf = new jsPDF({
|
|
820
|
+
orientation: 'portrait',
|
|
821
|
+
unit: 'mm',
|
|
822
|
+
format: 'a4'
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
const imgData = canvas.toDataURL('image/jpeg', 0.98);
|
|
826
|
+
const imgWidth = 210; // A4 width in mm
|
|
827
|
+
const pageHeight = 297; // A4 height in mm
|
|
828
|
+
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
|
829
|
+
let heightLeft = imgHeight;
|
|
830
|
+
let position = 0;
|
|
831
|
+
|
|
832
|
+
// Adicionar primeira página
|
|
833
|
+
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight);
|
|
834
|
+
heightLeft -= pageHeight;
|
|
835
|
+
|
|
836
|
+
// Adicionar páginas extras se necessário
|
|
837
|
+
while (heightLeft > 0) {
|
|
838
|
+
position = heightLeft - imgHeight;
|
|
839
|
+
pdf.addPage();
|
|
840
|
+
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight);
|
|
841
|
+
heightLeft -= pageHeight;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Salvar PDF
|
|
845
|
+
pdf.save('relatorio.pdf');
|
|
846
|
+
|
|
847
|
+
console.log('✅ PDF gerado com sucesso!');
|
|
848
|
+
alert('✅ PDF gerado com sucesso! Verifique sua pasta de Downloads.');
|
|
849
|
+
} catch (error) {
|
|
850
|
+
console.error('❌ Erro ao gerar PDF:', error);
|
|
851
|
+
alert('❌ Erro ao gerar PDF: ' + (error.message || error));
|
|
852
|
+
} finally {
|
|
853
|
+
// Restaurar estilos originais
|
|
854
|
+
element.style.background = originalBg;
|
|
855
|
+
element.style.color = originalColor;
|
|
856
|
+
|
|
857
|
+
document.querySelectorAll('.chart-card').forEach((card) => {
|
|
858
|
+
card.style.width = '';
|
|
859
|
+
card.style.display = '';
|
|
860
|
+
card.style.padding = '';
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
document.querySelectorAll('.chart-card canvas').forEach((canvas) => {
|
|
864
|
+
canvas.style.width = '';
|
|
865
|
+
canvas.style.height = '';
|
|
866
|
+
canvas.style.maxHeight = '';
|
|
867
|
+
canvas.style.display = '';
|
|
868
|
+
canvas.style.margin = '';
|
|
869
|
+
canvas.style.transform = '';
|
|
870
|
+
canvas.style.transformOrigin = '';
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
// Restaurar estados originais das seções
|
|
874
|
+
allCNs.forEach((cn, index) => {
|
|
875
|
+
cn.style.display = originalStates.cns[index] || 'none';
|
|
876
|
+
if (allCNArrows[index] && originalStates.cns[index] === 'none') {
|
|
877
|
+
allCNArrows[index].style.transform = 'rotate(0deg)';
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
allCTs.forEach((ct, index) => {
|
|
882
|
+
ct.style.display = originalStates.cts[index] || 'none';
|
|
883
|
+
if (allCTArrows[index] && originalStates.cts[index] === 'none') {
|
|
884
|
+
allCTArrows[index].style.transform = 'rotate(0deg)';
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
allCTsRows.forEach((ctsRow, index) => {
|
|
889
|
+
ctsRow.style.display = originalStates.ctsRows[index] || 'none';
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
allLogsRows.forEach((logsRow, index) => {
|
|
893
|
+
logsRow.style.display = originalStates.logsRows[index] || 'none';
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
document.getElementById('export-csv').onclick = () => {
|
|
899
|
+
const data = getTestData()
|
|
900
|
+
const csv = [
|
|
901
|
+
['Nome', 'Tipo', 'Resultado', 'Duração', 'Timestamp'],
|
|
902
|
+
...data.map(d => [d.nome, d.tipo, d.resultado, d.duracao, d.timestamp])
|
|
903
|
+
].map(e => e.join(';')).join('\\n')
|
|
904
|
+
const blob = new Blob([csv], { type: 'text/csv' })
|
|
905
|
+
const a = document.createElement('a')
|
|
906
|
+
a.href = URL.createObjectURL(blob)
|
|
907
|
+
a.download = 'relatorio.csv'
|
|
908
|
+
a.click()
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
document.getElementById('export-json').onclick = () => {
|
|
912
|
+
const blob = new Blob([JSON.stringify(getTestData(), null, 2)], { type: 'application/json' })
|
|
913
|
+
const a = document.createElement('a')
|
|
914
|
+
a.href = URL.createObjectURL(blob)
|
|
915
|
+
a.download = 'relatorio.json'
|
|
916
|
+
a.click()
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
document.getElementById('export-xlsx').onclick = () => {
|
|
920
|
+
const ws = XLSX.utils.json_to_sheet(getTestData())
|
|
921
|
+
const wb = XLSX.utils.book_new()
|
|
922
|
+
XLSX.utils.book_append_sheet(wb, ws, 'Relatorio')
|
|
923
|
+
XLSX.writeFile(wb, 'relatorio.xlsx')
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Gráfico de Rosca - Testes por Tipo
|
|
927
|
+
new Chart(document.getElementById('chart-tipos'), {
|
|
928
|
+
type: 'doughnut',
|
|
929
|
+
data: {
|
|
930
|
+
labels: ${JSON.stringify(chartLabels)},
|
|
931
|
+
datasets: [{
|
|
932
|
+
data: ${JSON.stringify(chartData)},
|
|
933
|
+
backgroundColor: ${JSON.stringify(chartColors)}
|
|
934
|
+
}]
|
|
935
|
+
},
|
|
936
|
+
options: {
|
|
937
|
+
plugins: {
|
|
938
|
+
legend: {
|
|
939
|
+
display: true,
|
|
940
|
+
position: 'bottom',
|
|
941
|
+
labels: {
|
|
942
|
+
font: { size: 10 }
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
title: {
|
|
946
|
+
display: true,
|
|
947
|
+
text: 'Testes por Tipo',
|
|
948
|
+
font: { size: 14 }
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
layout: {
|
|
952
|
+
padding: 0
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
// Gráfico de Barras - Duração dos Testes
|
|
958
|
+
new Chart(document.getElementById('chart-duracao'), {
|
|
959
|
+
type: 'bar',
|
|
960
|
+
data: {
|
|
961
|
+
labels: ${JSON.stringify(barLabels)},
|
|
962
|
+
datasets: [{
|
|
963
|
+
label: 'Duração (s)',
|
|
964
|
+
data: ${JSON.stringify(barData)},
|
|
965
|
+
backgroundColor: '#8b5cf6'
|
|
966
|
+
}]
|
|
967
|
+
},
|
|
968
|
+
options: {
|
|
969
|
+
plugins: {
|
|
970
|
+
legend: {
|
|
971
|
+
display: false
|
|
972
|
+
},
|
|
973
|
+
title: {
|
|
974
|
+
display: true,
|
|
975
|
+
text: 'Duração dos Testes',
|
|
976
|
+
font: { size: 14 }
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
layout: {
|
|
980
|
+
padding: 0
|
|
981
|
+
},
|
|
982
|
+
scales: {
|
|
983
|
+
x: {
|
|
984
|
+
ticks: {
|
|
985
|
+
font: { size: 9 },
|
|
986
|
+
maxRotation: 45,
|
|
987
|
+
minRotation: 45
|
|
988
|
+
}
|
|
989
|
+
},
|
|
990
|
+
y: {
|
|
991
|
+
ticks: {
|
|
992
|
+
font: { size: 9 }
|
|
993
|
+
},
|
|
994
|
+
beginAtZero: true
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
// Gráfico de Pizza - Passou x Falhou
|
|
1001
|
+
new Chart(document.getElementById('chart-passfail'), {
|
|
1002
|
+
type: 'pie',
|
|
1003
|
+
data: {
|
|
1004
|
+
labels: ${JSON.stringify(pieLabels)},
|
|
1005
|
+
datasets: [{
|
|
1006
|
+
data: ${JSON.stringify(pieData)},
|
|
1007
|
+
backgroundColor: ['#10b981', '#ef4444']
|
|
1008
|
+
}]
|
|
1009
|
+
},
|
|
1010
|
+
options: {
|
|
1011
|
+
plugins: {
|
|
1012
|
+
legend: {
|
|
1013
|
+
display: true,
|
|
1014
|
+
position: 'bottom',
|
|
1015
|
+
labels: {
|
|
1016
|
+
font: { size: 10 }
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
title: {
|
|
1020
|
+
display: true,
|
|
1021
|
+
text: 'Passou x Falhou',
|
|
1022
|
+
font: { size: 14 }
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
layout: {
|
|
1026
|
+
padding: 0
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
</script>
|
|
1031
|
+
</body>
|
|
1032
|
+
</html>
|
|
1033
|
+
`;
|
|
1034
|
+
}
|