@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,799 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📸 Organizador de Evidências do AutoCore
|
|
3
|
+
* @description Coleta e organiza screenshots já gerados pelos projetos consumidores (Web/Mobile)
|
|
4
|
+
* @author TestHUB Team
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ IMPORTANTE: Este projeto AutoCore NÃO gera evidências
|
|
8
|
+
* Ele apenas coleta e organiza evidências dos projetos consumidores:
|
|
9
|
+
* - Web: C:\Users\{user}\PlayWright\test-simplifique-e2e\test-results\web-screenshots\
|
|
10
|
+
* - Mobile: C:\Users\{user}\PlayWright\mobile\test-results\mobile-screenshots\
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
export class EvidenceReportGenerator {
|
|
15
|
+
/**
|
|
16
|
+
* 🎯 Detectar o tipo do projeto atual baseado nas pastas de evidências
|
|
17
|
+
*
|
|
18
|
+
* ℹ️ AutoCore trabalha no projeto atual e verifica se há:
|
|
19
|
+
* - Web: test-results/web-screenshots/
|
|
20
|
+
* - Mobile: test-results/mobile-screenshots/
|
|
21
|
+
*/
|
|
22
|
+
static detectCurrentProjectType() {
|
|
23
|
+
const currentDir = process.cwd();
|
|
24
|
+
const testResultsPath = path.join(currentDir, 'test-results');
|
|
25
|
+
if (!fs.existsSync(testResultsPath)) {
|
|
26
|
+
console.log('⚠️ Pasta test-results não encontrada no projeto atual');
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// Verificar se é projeto Mobile
|
|
30
|
+
const mobileScreenshotsPath = path.join(testResultsPath, 'mobile-screenshots');
|
|
31
|
+
if (fs.existsSync(mobileScreenshotsPath)) {
|
|
32
|
+
console.log(`🎯 Projeto Mobile detectado: ${currentDir}`);
|
|
33
|
+
return {
|
|
34
|
+
path: currentDir,
|
|
35
|
+
type: 'Mobile',
|
|
36
|
+
screenshotFolder: 'mobile-screenshots',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Verificar se é projeto Web
|
|
40
|
+
const webScreenshotsPath = path.join(testResultsPath, 'web-screenshots');
|
|
41
|
+
if (fs.existsSync(webScreenshotsPath)) {
|
|
42
|
+
console.log(`🎯 Projeto Web detectado: ${currentDir}`);
|
|
43
|
+
return {
|
|
44
|
+
path: currentDir,
|
|
45
|
+
type: 'Web',
|
|
46
|
+
screenshotFolder: 'web-screenshots',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
console.log('⚠️ Nenhuma pasta de screenshots específica encontrada (web-screenshots ou mobile-screenshots)');
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 🔍 Coleta screenshots em uma pasta específica do projeto consumidor
|
|
54
|
+
*/
|
|
55
|
+
static async findScreenshotsInDirectory(directoryPath, projectType) {
|
|
56
|
+
const screenshots = [];
|
|
57
|
+
try {
|
|
58
|
+
if (!fs.existsSync(directoryPath)) {
|
|
59
|
+
return screenshots;
|
|
60
|
+
}
|
|
61
|
+
const files = fs.readdirSync(directoryPath, { withFileTypes: true });
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
const fullPath = path.join(directoryPath, file.name);
|
|
64
|
+
if (file.isDirectory()) {
|
|
65
|
+
// Busca recursiva em subpastas
|
|
66
|
+
const subScreenshots = await EvidenceReportGenerator.findScreenshotsInDirectory(fullPath, projectType);
|
|
67
|
+
screenshots.push(...subScreenshots);
|
|
68
|
+
}
|
|
69
|
+
else if (file.isFile() && /\.(png|jpg|jpeg)$/i.test(file.name)) {
|
|
70
|
+
const stats = fs.statSync(fullPath);
|
|
71
|
+
const testName = EvidenceReportGenerator.extractTestName(fullPath, projectType);
|
|
72
|
+
// 🔧 CORRIGIDO: Caminho relativo à pasta playwright-report
|
|
73
|
+
const playwrightReportDir = path.join(process.cwd(), 'playwright-report');
|
|
74
|
+
const relativePath = path
|
|
75
|
+
.relative(playwrightReportDir, fullPath)
|
|
76
|
+
.replace(/\\/g, '/');
|
|
77
|
+
const base64 = EvidenceReportGenerator.convertImageToBase64(fullPath);
|
|
78
|
+
screenshots.push({
|
|
79
|
+
fileName: file.name,
|
|
80
|
+
fullPath,
|
|
81
|
+
relativePath,
|
|
82
|
+
testName,
|
|
83
|
+
timestamp: stats.mtime,
|
|
84
|
+
size: stats.size,
|
|
85
|
+
base64,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.warn(`⚠️ Erro ao escanear pasta ${directoryPath}:`, error);
|
|
92
|
+
}
|
|
93
|
+
return screenshots;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* ✅ Gera relatório de evidências procurando screenshots nas pastas padrão
|
|
97
|
+
*/
|
|
98
|
+
static async generateEvidenceReport() {
|
|
99
|
+
try {
|
|
100
|
+
// 🎯 DETECTAR TIPO DO PROJETO ATUAL
|
|
101
|
+
const currentProject = EvidenceReportGenerator.detectCurrentProjectType();
|
|
102
|
+
if (!currentProject) {
|
|
103
|
+
await EvidenceReportGenerator.generateEmptyReport();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// 🔍 PROCURAR SCREENSHOTS NO PROJETO ATUAL
|
|
107
|
+
let allScreenshots = [];
|
|
108
|
+
console.log(`🔍 Coletando evidências de ${currentProject.type}: ${currentProject.path}`);
|
|
109
|
+
const testResultsPath = path.join(currentProject.path, 'test-results');
|
|
110
|
+
const screenshotPath = path.join(testResultsPath, currentProject.screenshotFolder);
|
|
111
|
+
console.log(`📂 Verificando: ${screenshotPath}`);
|
|
112
|
+
if (fs.existsSync(screenshotPath)) {
|
|
113
|
+
const projectScreenshots = await EvidenceReportGenerator.findScreenshotsInDirectory(screenshotPath, currentProject.type);
|
|
114
|
+
allScreenshots = allScreenshots.concat(projectScreenshots);
|
|
115
|
+
console.log(`📸 Coletados ${projectScreenshots.length} screenshot(s) de ${currentProject.type}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log(`⚠️ Pasta de evidências não encontrada: ${screenshotPath}`);
|
|
119
|
+
}
|
|
120
|
+
if (allScreenshots.length === 0) {
|
|
121
|
+
await EvidenceReportGenerator.generateEmptyReport();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Gerar relatório HTML
|
|
125
|
+
const html = EvidenceReportGenerator.generateHTML(allScreenshots);
|
|
126
|
+
// ✅ CORRIGIDO: Criar pasta playwright-report se não existir
|
|
127
|
+
const playwrightReportDir = path.join(process.cwd(), 'playwright-report');
|
|
128
|
+
if (!fs.existsSync(playwrightReportDir)) {
|
|
129
|
+
fs.mkdirSync(playwrightReportDir, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
// ✅ CORRIGIDO: Salvar relatório APENAS em playwright-report
|
|
132
|
+
const reportPath = path.join(playwrightReportDir, 'relatorio-evidencias.html');
|
|
133
|
+
fs.writeFileSync(reportPath, html, 'utf-8');
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.warn('⚠️ [EvidenceReportGenerator] Erro ao gerar relatório:', error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* ✅ Procura screenshots em diretórios específicos
|
|
141
|
+
*/
|
|
142
|
+
static async findScreenshots(directories) {
|
|
143
|
+
const screenshots = [];
|
|
144
|
+
for (const dir of directories) {
|
|
145
|
+
if (!fs.existsSync(dir))
|
|
146
|
+
continue;
|
|
147
|
+
try {
|
|
148
|
+
const files = EvidenceReportGenerator.findFilesRecursively(dir, /\.(png|jpg|jpeg)$/i);
|
|
149
|
+
for (const filePath of files) {
|
|
150
|
+
try {
|
|
151
|
+
const stats = fs.statSync(filePath);
|
|
152
|
+
const fileName = path.basename(filePath);
|
|
153
|
+
// 🔧 CORRIGIDO: Caminho relativo à pasta playwright-report
|
|
154
|
+
const playwrightReportDir = path.join(process.cwd(), 'playwright-report');
|
|
155
|
+
const relativePath = path
|
|
156
|
+
.relative(playwrightReportDir, filePath)
|
|
157
|
+
.replace(/\\/g, '/');
|
|
158
|
+
// Extrair nome do teste do caminho ou nome do arquivo
|
|
159
|
+
const testName = EvidenceReportGenerator.extractTestName(filePath, 'Legacy');
|
|
160
|
+
// 🆕 Converter imagem para base64
|
|
161
|
+
const base64 = EvidenceReportGenerator.convertImageToBase64(filePath);
|
|
162
|
+
screenshots.push({
|
|
163
|
+
fileName,
|
|
164
|
+
fullPath: filePath,
|
|
165
|
+
relativePath,
|
|
166
|
+
testName,
|
|
167
|
+
timestamp: stats.mtime,
|
|
168
|
+
size: stats.size,
|
|
169
|
+
base64, // 🆕 Incluir base64 no objeto
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (fileError) {
|
|
173
|
+
// Ignorar erros de arquivos individuais
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (dirError) {
|
|
178
|
+
// Ignorar erros de diretórios
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Ordenar por timestamp (mais recentes primeiro)
|
|
182
|
+
screenshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
183
|
+
return screenshots;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 🆕 Converte imagem para base64
|
|
187
|
+
*/
|
|
188
|
+
static convertImageToBase64(imagePath) {
|
|
189
|
+
try {
|
|
190
|
+
const imageBuffer = fs.readFileSync(imagePath);
|
|
191
|
+
const ext = path.extname(imagePath).toLowerCase();
|
|
192
|
+
let mimeType = 'image/png';
|
|
193
|
+
if (ext === '.jpg' || ext === '.jpeg') {
|
|
194
|
+
mimeType = 'image/jpeg';
|
|
195
|
+
}
|
|
196
|
+
else if (ext === '.gif') {
|
|
197
|
+
mimeType = 'image/gif';
|
|
198
|
+
}
|
|
199
|
+
else if (ext === '.webp') {
|
|
200
|
+
mimeType = 'image/webp';
|
|
201
|
+
}
|
|
202
|
+
const base64 = imageBuffer.toString('base64');
|
|
203
|
+
return `data:${mimeType};base64,${base64}`;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
console.warn(`⚠️ Erro ao converter imagem para base64: ${imagePath}`, error);
|
|
207
|
+
return ''; // Retornar string vazia em caso de erro
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* ✅ Encontra arquivos recursivamente
|
|
212
|
+
*/
|
|
213
|
+
static findFilesRecursively(dir, pattern) {
|
|
214
|
+
const files = [];
|
|
215
|
+
try {
|
|
216
|
+
const items = fs.readdirSync(dir);
|
|
217
|
+
for (const item of items) {
|
|
218
|
+
const itemPath = path.join(dir, item);
|
|
219
|
+
const stats = fs.statSync(itemPath);
|
|
220
|
+
if (stats.isDirectory()) {
|
|
221
|
+
files.push(...EvidenceReportGenerator.findFilesRecursively(itemPath, pattern));
|
|
222
|
+
}
|
|
223
|
+
else if (pattern.test(item)) {
|
|
224
|
+
files.push(itemPath);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
// Ignorar erros de acesso
|
|
230
|
+
}
|
|
231
|
+
return files;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* ✅ Extrai nome do teste do caminho ou nome do arquivo
|
|
235
|
+
*/
|
|
236
|
+
static extractTestName(fullPath, projectType) {
|
|
237
|
+
// Tentar extrair do caminho
|
|
238
|
+
const pathParts = fullPath.split(/[/\\]/);
|
|
239
|
+
const fileName = path.basename(fullPath);
|
|
240
|
+
// 🔍 Para projetos Web/Mobile, procurar padrões específicos
|
|
241
|
+
if (projectType === 'Web' || projectType === 'Mobile') {
|
|
242
|
+
// Procurar por partes que parecem nomes de teste no caminho
|
|
243
|
+
for (let i = pathParts.length - 1; i >= 0; i--) {
|
|
244
|
+
const part = pathParts[i];
|
|
245
|
+
if (part.includes('test') ||
|
|
246
|
+
part.includes('spec') ||
|
|
247
|
+
part.includes('CT') ||
|
|
248
|
+
part.includes('-chromium') ||
|
|
249
|
+
part.includes('-webkit')) {
|
|
250
|
+
return part
|
|
251
|
+
.replace(/-chromium|-webkit|-firefox/gi, '')
|
|
252
|
+
.replace(/^\d+/, '')
|
|
253
|
+
.trim();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Fallback: usar nome do arquivo sem extensão
|
|
258
|
+
return (fileName
|
|
259
|
+
.replace(/\.(png|jpg|jpeg)$/i, '')
|
|
260
|
+
.replace(/-\d+$/, '')
|
|
261
|
+
.trim() || 'Teste não identificado');
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* ✅ Gera HTML do relatório com recursos avançados (igual HTMLTemplate)
|
|
265
|
+
*/
|
|
266
|
+
static generateHTML(screenshots) {
|
|
267
|
+
const groupedByTest = EvidenceReportGenerator.groupScreenshotsByTest(screenshots);
|
|
268
|
+
const totalTests = Object.keys(groupedByTest).length;
|
|
269
|
+
const totalScreenshots = screenshots.length;
|
|
270
|
+
const totalSize = screenshots.reduce((sum, s) => sum + s.size, 0);
|
|
271
|
+
// Estatísticas por tipo de projeto
|
|
272
|
+
const projectStats = {
|
|
273
|
+
Web: screenshots.filter((s) => s.fullPath.includes('web-screenshots'))
|
|
274
|
+
.length,
|
|
275
|
+
Mobile: screenshots.filter((s) => s.fullPath.includes('mobile-screenshots')).length,
|
|
276
|
+
Other: screenshots.filter((s) => !(s.fullPath.includes('web-screenshots') ||
|
|
277
|
+
s.fullPath.includes('mobile-screenshots'))).length,
|
|
278
|
+
};
|
|
279
|
+
return `
|
|
280
|
+
<!DOCTYPE html>
|
|
281
|
+
<html lang="pt-BR">
|
|
282
|
+
<head>
|
|
283
|
+
<meta charset="UTF-8" />
|
|
284
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
285
|
+
<title>📸 Relatório de Evidências - TestHUB</title>
|
|
286
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
287
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
288
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
289
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
290
|
+
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
|
|
291
|
+
<style>
|
|
292
|
+
body { font-family: 'Inter', sans-serif; background-color: #0f172a; color: #f1f5f9; min-height: 100vh; }
|
|
293
|
+
.light-mode { background-color: #f9fafb !important; color: #222 !important; }
|
|
294
|
+
.card { background: #1e293b; border-radius: 1rem; padding: 1.5rem; box-shadow: 0 2px 8px #0002; }
|
|
295
|
+
.light-mode .card { background: #fff; color: #222; }
|
|
296
|
+
.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; }
|
|
297
|
+
.btn:hover { background: #475569; }
|
|
298
|
+
.light-mode .btn { background: #e2e8f0; color: #222; }
|
|
299
|
+
.chart-card { background: #1e293b; border-radius: 1rem; padding: 1rem; margin-bottom: 1.5rem; }
|
|
300
|
+
.light-mode .chart-card { background: #fff; }
|
|
301
|
+
.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; }
|
|
302
|
+
.header-bar .header-title { font-size: 2rem; font-weight: 700; color: #fbbf24; }
|
|
303
|
+
.header-bar .header-meta { font-size: 1rem; color: #f1f5f9; }
|
|
304
|
+
.light-mode .header-bar { background: #f1f5f9; color: #222; }
|
|
305
|
+
.light-mode .header-title { color: #b45309; }
|
|
306
|
+
.light-mode .header-meta { color: #222 !important; }
|
|
307
|
+
.footer-bar { background: #1e293b; color: #fbbf24; padding: 1rem 2rem; border-radius: 0 0 1rem 1rem; margin-top: 2rem; text-align: center; font-size: 1rem; }
|
|
308
|
+
.light-mode .footer-bar { background: #f1f5f9; color: #b45309; }
|
|
309
|
+
.footer-bar a { color: #fbbf24; text-decoration: underline; }
|
|
310
|
+
.light-mode .footer-bar a { color: #b45309; }
|
|
311
|
+
.evidence-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }
|
|
312
|
+
.evidence-item { background: #334155; border-radius: 8px; overflow: hidden; transition: transform 0.2s; }
|
|
313
|
+
.evidence-item:hover { transform: scale(1.02); }
|
|
314
|
+
.light-mode .evidence-item { background: #f1f5f9; }
|
|
315
|
+
.evidence-img { width: 100%; height: 200px; object-fit: contain; background: #475569; cursor: pointer; }
|
|
316
|
+
.light-mode .evidence-img { background: #e2e8f0; }
|
|
317
|
+
.evidence-info { padding: 1rem; }
|
|
318
|
+
.evidence-title { font-weight: 600; margin-bottom: 0.5rem; }
|
|
319
|
+
.evidence-meta { font-size: 0.875rem; color: #94a3b8; }
|
|
320
|
+
.light-mode .evidence-meta { color: #64748b; }
|
|
321
|
+
.test-section { margin-bottom: 2rem; }
|
|
322
|
+
.test-header { background: #334155; padding: 1rem; border-radius: 8px 8px 0 0; cursor: pointer; display: flex; justify-content: between; align-items: center; }
|
|
323
|
+
.light-mode .test-header { background: #e2e8f0; }
|
|
324
|
+
.test-content { background: #1e293b; padding: 1rem; border-radius: 0 0 8px 8px; }
|
|
325
|
+
.light-mode .test-content { background: #f8fafc; }
|
|
326
|
+
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.9); }
|
|
327
|
+
.modal-content { margin: auto; display: block; width: 90%; max-width: 1200px; max-height: 90%; }
|
|
328
|
+
.modal img { width: 100%; height: auto; }
|
|
329
|
+
.close { position: absolute; top: 15px; right: 35px; color: #f1f1f1; font-size: 40px; font-weight: bold; cursor: pointer; }
|
|
330
|
+
.close:hover { color: #bbb; }
|
|
331
|
+
@media (max-width: 768px) {
|
|
332
|
+
.grid-cols-2, .grid-cols-3 { grid-template-columns: 1fr !important; }
|
|
333
|
+
.header-bar { flex-direction: column; text-align: center; }
|
|
334
|
+
.header-meta { margin-top: 0.5rem; }
|
|
335
|
+
}
|
|
336
|
+
</style>
|
|
337
|
+
</head>
|
|
338
|
+
<body id="body-root">
|
|
339
|
+
<div class="header-bar">
|
|
340
|
+
<div class="header-title">📸 Relatório de Evidências</div>
|
|
341
|
+
<div class="header-meta">
|
|
342
|
+
<span>Total: <strong>${totalScreenshots}</strong></span> |
|
|
343
|
+
<span>Testes: <strong>${totalTests}</strong></span> |
|
|
344
|
+
<span>Tamanho: <strong>${EvidenceReportGenerator.formatFileSize(totalSize)}</strong></span> |
|
|
345
|
+
<span>Data: <strong>${new Date().toLocaleString('pt-BR')}</strong></span>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div class="flex gap-2 mb-6 justify-end mr-6">
|
|
350
|
+
<button id="toggle-theme" class="btn" type="button" title="Alternar tema">🌙 Tema</button>
|
|
351
|
+
<button id="export-pdf" class="btn" type="button" title="Exportar PDF">📄 PDF</button>
|
|
352
|
+
<button id="export-csv" class="btn" type="button" title="Exportar CSV">📑 CSV</button>
|
|
353
|
+
<button id="export-json" class="btn" type="button" title="Exportar JSON">🗒️ JSON</button>
|
|
354
|
+
<button id="export-xlsx" class="btn" type="button" title="Exportar XLSX">📊 XLSX</button>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<div id="report-root" class="max-w-7xl mx-auto p-6" style="background:inherit;">
|
|
358
|
+
<h1 class="text-4xl font-bold mb-2">📸 Evidências Capturadas</h1>
|
|
359
|
+
<p class="text-slate-400 mb-6">Screenshots organizados por teste executado</p>
|
|
360
|
+
|
|
361
|
+
<!-- Estatísticas -->
|
|
362
|
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
|
|
363
|
+
<div class="card flex flex-col items-center">
|
|
364
|
+
<span class="text-2xl font-bold text-blue-400">${totalTests}</span>
|
|
365
|
+
<span class="text-slate-400">Testes</span>
|
|
366
|
+
</div>
|
|
367
|
+
<div class="card flex flex-col items-center">
|
|
368
|
+
<span class="text-2xl font-bold text-green-400">${totalScreenshots}</span>
|
|
369
|
+
<span class="text-green-400">Screenshots</span>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="card flex flex-col items-center">
|
|
372
|
+
<span class="text-2xl font-bold text-purple-400">${projectStats.Web}</span>
|
|
373
|
+
<span class="text-purple-400">Web</span>
|
|
374
|
+
</div>
|
|
375
|
+
<div class="card flex flex-col items-center">
|
|
376
|
+
<span class="text-2xl font-bold text-orange-400">${projectStats.Mobile}</span>
|
|
377
|
+
<span class="text-orange-400">Mobile</span>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
<!-- Gráficos -->
|
|
382
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
|
383
|
+
<div class="chart-card">
|
|
384
|
+
<h3 class="text-lg font-bold mb-4 text-center">📊 Screenshots por Tipo</h3>
|
|
385
|
+
<canvas id="chart-tipos" height="200"></canvas>
|
|
386
|
+
</div>
|
|
387
|
+
<div class="chart-card">
|
|
388
|
+
<h3 class="text-lg font-bold mb-4 text-center">🗓️ Screenshots por Teste</h3>
|
|
389
|
+
<canvas id="chart-testes" height="200"></canvas>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<!-- Evidências por Teste -->
|
|
394
|
+
${Object.entries(groupedByTest)
|
|
395
|
+
.map(([testName, testScreenshots], index) => `
|
|
396
|
+
<div class="test-section">
|
|
397
|
+
<div class="test-header" onclick="toggleTestSection('test-${index}')">
|
|
398
|
+
<div class="flex items-center gap-3">
|
|
399
|
+
<span class="text-2xl">🧪</span>
|
|
400
|
+
<div>
|
|
401
|
+
<h3 class="text-lg font-bold">${testName}</h3>
|
|
402
|
+
<p class="text-sm text-slate-400">${testScreenshots.length} screenshot(s) • Última captura: ${testScreenshots[0].timestamp.toLocaleString('pt-BR')}</p>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
<span class="text-2xl transform transition-transform" id="arrow-test-${index}">▼</span>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="test-content" id="test-${index}">
|
|
408
|
+
<div class="evidence-grid">
|
|
409
|
+
${testScreenshots
|
|
410
|
+
.map((screenshot) => `
|
|
411
|
+
<div class="evidence-item">
|
|
412
|
+
<img src="${screenshot.base64 || screenshot.relativePath}" alt="${screenshot.fileName}" class="evidence-img" onclick="openModal('${screenshot.base64 || screenshot.relativePath}', '${screenshot.fileName}')" loading="lazy">
|
|
413
|
+
<div class="evidence-info">
|
|
414
|
+
<div class="evidence-title">${screenshot.fileName}</div>
|
|
415
|
+
<div class="evidence-meta">
|
|
416
|
+
${EvidenceReportGenerator.formatFileSize(screenshot.size)} •
|
|
417
|
+
${screenshot.timestamp.toLocaleString('pt-BR')}
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
`)
|
|
422
|
+
.join('')}
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
`)
|
|
427
|
+
.join('')}
|
|
428
|
+
</div>
|
|
429
|
+
|
|
430
|
+
<!-- Modal para visualizar imagens -->
|
|
431
|
+
<div id="imageModal" class="modal">
|
|
432
|
+
<span class="close" onclick="closeModal()">×</span>
|
|
433
|
+
<div class="modal-content">
|
|
434
|
+
<img id="modalImg" src="" alt="">
|
|
435
|
+
</div>
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
<div class="footer-bar">
|
|
439
|
+
Desenvolvido por <strong>TestHUB AutoCore</strong> — Sistema de Organização de Evidências.<br>
|
|
440
|
+
<span>Relatório gerado automaticamente • Screenshots coletados dos projetos consumidores</span>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<script>
|
|
444
|
+
// Toggle de tema
|
|
445
|
+
document.getElementById('toggle-theme').onclick = () => {
|
|
446
|
+
document.getElementById('body-root').classList.toggle('light-mode')
|
|
447
|
+
document.querySelector('.header-bar').classList.toggle('light-mode')
|
|
448
|
+
document.querySelector('.footer-bar').classList.toggle('light-mode')
|
|
449
|
+
document.querySelectorAll('.card').forEach(card => card.classList.toggle('light-mode'))
|
|
450
|
+
document.querySelectorAll('.chart-card').forEach(card => card.classList.toggle('light-mode'))
|
|
451
|
+
document.querySelectorAll('.evidence-item').forEach(item => item.classList.toggle('light-mode'))
|
|
452
|
+
document.querySelectorAll('.test-header').forEach(header => header.classList.toggle('light-mode'))
|
|
453
|
+
document.querySelectorAll('.test-content').forEach(content => content.classList.toggle('light-mode'))
|
|
454
|
+
document.querySelectorAll('.evidence-img').forEach(img => img.classList.toggle('light-mode'))
|
|
455
|
+
document.querySelectorAll('.evidence-meta').forEach(meta => meta.classList.toggle('light-mode'))
|
|
456
|
+
|
|
457
|
+
const meta = document.querySelector('.header-meta')
|
|
458
|
+
if (document.getElementById('body-root').classList.contains('light-mode')) {
|
|
459
|
+
meta && (meta.style.color = '#222')
|
|
460
|
+
} else {
|
|
461
|
+
meta && (meta.style.color = '#f1f5f9')
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Toggle de seções de teste
|
|
466
|
+
function toggleTestSection(testId) {
|
|
467
|
+
const testContent = document.getElementById(testId)
|
|
468
|
+
const arrow = document.getElementById('arrow-' + testId)
|
|
469
|
+
|
|
470
|
+
if (testContent.style.display === 'none') {
|
|
471
|
+
testContent.style.display = 'block'
|
|
472
|
+
arrow.style.transform = 'rotate(180deg)'
|
|
473
|
+
} else {
|
|
474
|
+
testContent.style.display = 'none'
|
|
475
|
+
arrow.style.transform = 'rotate(0deg)'
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Modal de imagens
|
|
480
|
+
function openModal(src, alt) {
|
|
481
|
+
document.getElementById('imageModal').style.display = 'block'
|
|
482
|
+
document.getElementById('modalImg').src = src
|
|
483
|
+
document.getElementById('modalImg').alt = alt
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function closeModal() {
|
|
487
|
+
document.getElementById('imageModal').style.display = 'none'
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Fechar modal ao clicar fora da imagem
|
|
491
|
+
window.onclick = function(event) {
|
|
492
|
+
const modal = document.getElementById('imageModal')
|
|
493
|
+
if (event.target == modal) {
|
|
494
|
+
closeModal()
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Dados para exportação
|
|
499
|
+
function getEvidenceData() {
|
|
500
|
+
const data = []
|
|
501
|
+
${Object.entries(groupedByTest)
|
|
502
|
+
.map(([testName, testScreenshots]) => `
|
|
503
|
+
${testScreenshots
|
|
504
|
+
.map((screenshot) => `
|
|
505
|
+
data.push({
|
|
506
|
+
teste: '${testName}',
|
|
507
|
+
arquivo: '${screenshot.fileName}',
|
|
508
|
+
tamanho: '${EvidenceReportGenerator.formatFileSize(screenshot.size)}',
|
|
509
|
+
timestamp: '${screenshot.timestamp.toLocaleString('pt-BR')}',
|
|
510
|
+
caminho: '${screenshot.relativePath}'
|
|
511
|
+
})
|
|
512
|
+
`)
|
|
513
|
+
.join('')}
|
|
514
|
+
`)
|
|
515
|
+
.join('')}
|
|
516
|
+
return data
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Exportação PDF
|
|
520
|
+
document.getElementById('export-pdf').onclick = async () => {
|
|
521
|
+
console.log('🔵 [PDF] Botão clicado - Iniciando geração do PDF de evidências...')
|
|
522
|
+
|
|
523
|
+
const element = document.getElementById('report-root')
|
|
524
|
+
if (!element) {
|
|
525
|
+
console.error('❌ [PDF] Elemento report-root não encontrado!')
|
|
526
|
+
alert('❌ Erro: Elemento do relatório não encontrado!')
|
|
527
|
+
return
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const hasImages = element.querySelectorAll('img').length > 0
|
|
531
|
+
if (hasImages) {
|
|
532
|
+
console.log('📸 [PDF] Imagens detectadas - usando base64 para garantir renderização offline')
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Verificar se jsPDF está carregado
|
|
536
|
+
if (typeof jspdf === 'undefined') {
|
|
537
|
+
console.error('❌ [PDF] jsPDF não está carregado!')
|
|
538
|
+
alert('❌ Erro: Biblioteca jsPDF não carregada. Recarregue a página.')
|
|
539
|
+
return
|
|
540
|
+
}
|
|
541
|
+
console.log('✅ [PDF] jsPDF carregado com sucesso')
|
|
542
|
+
|
|
543
|
+
// 🆕 EXPANDIR TODAS AS SEÇÕES antes de gerar PDF
|
|
544
|
+
const allSections = document.querySelectorAll('[id^="test-"]')
|
|
545
|
+
const allArrows = document.querySelectorAll('[id^="arrow-test-"]')
|
|
546
|
+
const originalStates = []
|
|
547
|
+
|
|
548
|
+
allSections.forEach((section, index) => {
|
|
549
|
+
originalStates.push(section.style.display)
|
|
550
|
+
section.style.display = 'block'
|
|
551
|
+
if (allArrows[index]) {
|
|
552
|
+
allArrows[index].style.transform = 'rotate(180deg)'
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
// ✅ Aguardar imagens carregarem (já estão em base64)
|
|
557
|
+
const images = element.querySelectorAll('img')
|
|
558
|
+
console.log('📸 Total de imagens encontradas:', images.length)
|
|
559
|
+
|
|
560
|
+
await Promise.all(Array.from(images).map(img => {
|
|
561
|
+
if (img.complete) return Promise.resolve()
|
|
562
|
+
return new Promise(resolve => {
|
|
563
|
+
img.onload = resolve
|
|
564
|
+
img.onerror = resolve
|
|
565
|
+
setTimeout(resolve, 2000)
|
|
566
|
+
})
|
|
567
|
+
}))
|
|
568
|
+
|
|
569
|
+
console.log('✅ Imagens carregadas (base64 embutido)')
|
|
570
|
+
await new Promise(resolve => setTimeout(resolve, 300))
|
|
571
|
+
|
|
572
|
+
// Preparar elemento para PDF
|
|
573
|
+
const originalBg = element.style.background
|
|
574
|
+
const originalColor = element.style.color
|
|
575
|
+
element.style.background = '#fff'
|
|
576
|
+
element.style.color = '#222'
|
|
577
|
+
|
|
578
|
+
// Reduzir gráficos para PDF
|
|
579
|
+
document.querySelectorAll('.chart-card canvas').forEach((canvas) => {
|
|
580
|
+
canvas.style.width = '300px'
|
|
581
|
+
canvas.style.height = '150px'
|
|
582
|
+
canvas.style.transform = 'scale(0.85)'
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
console.log('📄 [PDF] Iniciando geração do PDF...')
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
// Usar html2canvas para capturar o conteúdo como imagem
|
|
589
|
+
const canvas = await html2canvas(element, {
|
|
590
|
+
scale: 2,
|
|
591
|
+
useCORS: false,
|
|
592
|
+
allowTaint: true,
|
|
593
|
+
backgroundColor: '#fff',
|
|
594
|
+
logging: false,
|
|
595
|
+
imageTimeout: 0
|
|
596
|
+
})
|
|
597
|
+
|
|
598
|
+
// Criar PDF com jsPDF
|
|
599
|
+
const { jsPDF } = jspdf
|
|
600
|
+
const pdf = new jsPDF({
|
|
601
|
+
orientation: 'portrait',
|
|
602
|
+
unit: 'mm',
|
|
603
|
+
format: 'a4'
|
|
604
|
+
})
|
|
605
|
+
|
|
606
|
+
const imgData = canvas.toDataURL('image/jpeg', 0.98)
|
|
607
|
+
const imgWidth = 210 // A4 width in mm
|
|
608
|
+
const pageHeight = 297 // A4 height in mm
|
|
609
|
+
const imgHeight = (canvas.height * imgWidth) / canvas.width
|
|
610
|
+
let heightLeft = imgHeight
|
|
611
|
+
let position = 0
|
|
612
|
+
|
|
613
|
+
// Adicionar primeira página
|
|
614
|
+
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight)
|
|
615
|
+
heightLeft -= pageHeight
|
|
616
|
+
|
|
617
|
+
// Adicionar páginas extras se necessário
|
|
618
|
+
while (heightLeft > 0) {
|
|
619
|
+
position = heightLeft - imgHeight
|
|
620
|
+
pdf.addPage()
|
|
621
|
+
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight)
|
|
622
|
+
heightLeft -= pageHeight
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Salvar PDF
|
|
626
|
+
pdf.save('relatorio-evidencias.pdf')
|
|
627
|
+
|
|
628
|
+
console.log('✅ PDF gerado com sucesso!')
|
|
629
|
+
alert('✅ PDF gerado com sucesso! Verifique sua pasta de Downloads.')
|
|
630
|
+
} catch (error) {
|
|
631
|
+
console.error('❌ Erro ao gerar PDF:', error)
|
|
632
|
+
alert('❌ Erro ao gerar PDF: ' + (error.message || error))
|
|
633
|
+
} finally {
|
|
634
|
+
// Restaurar estilos e estados originais
|
|
635
|
+
element.style.background = originalBg
|
|
636
|
+
element.style.color = originalColor
|
|
637
|
+
|
|
638
|
+
document.querySelectorAll('.chart-card canvas').forEach((canvas) => {
|
|
639
|
+
canvas.style.width = ''
|
|
640
|
+
canvas.style.height = ''
|
|
641
|
+
canvas.style.transform = ''
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
// Restaurar estados das seções
|
|
645
|
+
allSections.forEach((section, index) => {
|
|
646
|
+
section.style.display = originalStates[index] || 'none'
|
|
647
|
+
if (allArrows[index] && originalStates[index] === 'none') {
|
|
648
|
+
allArrows[index].style.transform = 'rotate(0deg)'
|
|
649
|
+
}
|
|
650
|
+
})
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Exportação CSV
|
|
655
|
+
document.getElementById('export-csv').onclick = () => {
|
|
656
|
+
const data = getEvidenceData()
|
|
657
|
+
const csv = [
|
|
658
|
+
['Teste', 'Arquivo', 'Tamanho', 'Timestamp', 'Caminho'],
|
|
659
|
+
...data.map(d => [d.teste, d.arquivo, d.tamanho, d.timestamp, d.caminho])
|
|
660
|
+
].map(e => e.join(';')).join('\\n')
|
|
661
|
+
const blob = new Blob([csv], { type: 'text/csv' })
|
|
662
|
+
const a = document.createElement('a')
|
|
663
|
+
a.href = URL.createObjectURL(blob)
|
|
664
|
+
a.download = 'evidencias.csv'
|
|
665
|
+
a.click()
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Exportação JSON
|
|
669
|
+
document.getElementById('export-json').onclick = () => {
|
|
670
|
+
const blob = new Blob([JSON.stringify(getEvidenceData(), null, 2)], { type: 'application/json' })
|
|
671
|
+
const a = document.createElement('a')
|
|
672
|
+
a.href = URL.createObjectURL(blob)
|
|
673
|
+
a.download = 'evidencias.json'
|
|
674
|
+
a.click()
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Exportação XLSX
|
|
678
|
+
document.getElementById('export-xlsx').onclick = () => {
|
|
679
|
+
const ws = XLSX.utils.json_to_sheet(getEvidenceData())
|
|
680
|
+
const wb = XLSX.utils.book_new()
|
|
681
|
+
XLSX.utils.book_append_sheet(wb, ws, 'Evidencias')
|
|
682
|
+
XLSX.writeFile(wb, 'evidencias.xlsx')
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Gráfico de tipos
|
|
686
|
+
new Chart(document.getElementById('chart-tipos'), {
|
|
687
|
+
type: 'doughnut',
|
|
688
|
+
data: {
|
|
689
|
+
labels: ['Web', 'Mobile', 'Outros'],
|
|
690
|
+
datasets: [{
|
|
691
|
+
data: [${projectStats.Web}, ${projectStats.Mobile}, ${projectStats.Other}],
|
|
692
|
+
backgroundColor: ['#3b82f6', '#f59e0b', '#10b981'],
|
|
693
|
+
borderWidth: 2,
|
|
694
|
+
borderColor: '#1e293b'
|
|
695
|
+
}]
|
|
696
|
+
},
|
|
697
|
+
options: {
|
|
698
|
+
responsive: true,
|
|
699
|
+
plugins: {
|
|
700
|
+
legend: { position: 'bottom' }
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
})
|
|
704
|
+
|
|
705
|
+
// Gráfico de testes
|
|
706
|
+
new Chart(document.getElementById('chart-testes'), {
|
|
707
|
+
type: 'bar',
|
|
708
|
+
data: {
|
|
709
|
+
labels: [${Object.keys(groupedByTest)
|
|
710
|
+
.map((name) => `'${name.substring(0, 20)}...'`)
|
|
711
|
+
.join(', ')}],
|
|
712
|
+
datasets: [{
|
|
713
|
+
label: 'Screenshots',
|
|
714
|
+
data: [${Object.values(groupedByTest)
|
|
715
|
+
.map((screenshots) => screenshots.length)
|
|
716
|
+
.join(', ')}],
|
|
717
|
+
backgroundColor: '#3b82f6',
|
|
718
|
+
borderColor: '#1e40af',
|
|
719
|
+
borderWidth: 1
|
|
720
|
+
}]
|
|
721
|
+
},
|
|
722
|
+
options: {
|
|
723
|
+
responsive: true,
|
|
724
|
+
scales: {
|
|
725
|
+
y: { beginAtZero: true }
|
|
726
|
+
},
|
|
727
|
+
plugins: {
|
|
728
|
+
legend: { display: false }
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
})
|
|
732
|
+
</script>
|
|
733
|
+
</body>
|
|
734
|
+
</html>`;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* ✅ Agrupa screenshots por teste
|
|
738
|
+
*/
|
|
739
|
+
static groupScreenshotsByTest(screenshots) {
|
|
740
|
+
const grouped = {};
|
|
741
|
+
for (const screenshot of screenshots) {
|
|
742
|
+
if (!grouped[screenshot.testName]) {
|
|
743
|
+
grouped[screenshot.testName] = [];
|
|
744
|
+
}
|
|
745
|
+
grouped[screenshot.testName].push(screenshot);
|
|
746
|
+
}
|
|
747
|
+
return grouped;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* ✅ Formata tamanho de arquivo
|
|
751
|
+
*/
|
|
752
|
+
static formatFileSize(bytes) {
|
|
753
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
754
|
+
if (bytes === 0)
|
|
755
|
+
return '0 B';
|
|
756
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
757
|
+
return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* ✅ Gera relatório vazio quando não há evidências nos projetos consumidores
|
|
761
|
+
*/
|
|
762
|
+
static async generateEmptyReport() {
|
|
763
|
+
const html = `
|
|
764
|
+
<!DOCTYPE html>
|
|
765
|
+
<html lang="pt-BR">
|
|
766
|
+
<head>
|
|
767
|
+
<meta charset="UTF-8">
|
|
768
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
769
|
+
<title>📸 Organizador de Evidências - AutoCore</title>
|
|
770
|
+
<style>
|
|
771
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
772
|
+
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f5f7fa; color: #2d3748; }
|
|
773
|
+
.container { max-width: 800px; margin: 0 auto; padding: 20px; text-align: center; }
|
|
774
|
+
.empty-state { background: white; padding: 4rem 2rem; border-radius: 12px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
775
|
+
.empty-state h1 { font-size: 2rem; color: #667eea; margin-bottom: 1rem; }
|
|
776
|
+
.empty-state p { color: #718096; font-size: 1.1rem; margin-bottom: 0.5rem; }
|
|
777
|
+
</style>
|
|
778
|
+
</head>
|
|
779
|
+
<body>
|
|
780
|
+
<div class="container">
|
|
781
|
+
<div class="empty-state">
|
|
782
|
+
<h1>📸 Relatório de Evidências</h1>
|
|
783
|
+
<p>Nenhum screenshot foi encontrado nas pastas do projeto.</p>
|
|
784
|
+
<p>Screenshots são automaticamente capturados durante a execução dos testes.</p>
|
|
785
|
+
<p><strong>Pastas verificadas:</strong> playwright-report, test-results, reports, evidence, screenshots</p>
|
|
786
|
+
</div>
|
|
787
|
+
</div>
|
|
788
|
+
</body>
|
|
789
|
+
</html>`;
|
|
790
|
+
// ✅ CORRIGIDO: Criar pasta playwright-report se não existir
|
|
791
|
+
const playwrightReportDir = path.join(process.cwd(), 'playwright-report');
|
|
792
|
+
if (!fs.existsSync(playwrightReportDir)) {
|
|
793
|
+
fs.mkdirSync(playwrightReportDir, { recursive: true });
|
|
794
|
+
}
|
|
795
|
+
// ✅ CORRIGIDO: Salvar relatório em playwright-report
|
|
796
|
+
const reportPath = path.join(playwrightReportDir, 'relatorio-evidencias.html');
|
|
797
|
+
fs.writeFileSync(reportPath, html, 'utf-8');
|
|
798
|
+
}
|
|
799
|
+
}
|