erosolar-cli 2.1.249 → 2.1.252
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/agents/general.rules.json +10 -133
- package/agents/general.rules.json.bak +278 -0
- package/agents/general.rules.json.bak2 +306 -0
- package/dist/bin/erosolar.js +9 -5
- package/dist/bin/erosolar.js.map +1 -1
- package/dist/capabilities/bidirectionalAuditCapability.d.ts +26 -0
- package/dist/capabilities/bidirectionalAuditCapability.d.ts.map +1 -0
- package/dist/capabilities/bidirectionalAuditCapability.js +44 -0
- package/dist/capabilities/bidirectionalAuditCapability.js.map +1 -0
- package/dist/capabilities/globCapability.d.ts +3 -6
- package/dist/capabilities/globCapability.d.ts.map +1 -1
- package/dist/capabilities/globCapability.js +6 -10
- package/dist/capabilities/globCapability.js.map +1 -1
- package/dist/capabilities/index.d.ts +1 -18
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +1 -18
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/orchestrationCapability.d.ts +2 -0
- package/dist/capabilities/orchestrationCapability.d.ts.map +1 -1
- package/dist/capabilities/orchestrationCapability.js +980 -2
- package/dist/capabilities/orchestrationCapability.js.map +1 -1
- package/dist/capabilities/searchCapability.d.ts +8 -2
- package/dist/capabilities/searchCapability.d.ts.map +1 -1
- package/dist/capabilities/searchCapability.js +11 -6
- package/dist/capabilities/searchCapability.js.map +1 -1
- package/dist/contracts/tools.schema.json +9 -133
- package/dist/core/aiErrorFixer.d.ts +1 -14
- package/dist/core/aiErrorFixer.d.ts.map +1 -1
- package/dist/core/aiErrorFixer.js +51 -239
- package/dist/core/aiErrorFixer.js.map +1 -1
- package/dist/core/alphaZeroEngine.d.ts +16 -256
- package/dist/core/alphaZeroEngine.d.ts.map +1 -1
- package/dist/core/alphaZeroEngine.js +22 -513
- package/dist/core/alphaZeroEngine.js.map +1 -1
- package/dist/core/completeAttackOrchestrator.d.ts +102 -0
- package/dist/core/completeAttackOrchestrator.d.ts.map +1 -0
- package/dist/core/completeAttackOrchestrator.js +293 -0
- package/dist/core/completeAttackOrchestrator.js.map +1 -0
- package/dist/core/defensiveSecurityToolkit.d.ts +373 -0
- package/dist/core/defensiveSecurityToolkit.d.ts.map +1 -0
- package/dist/core/defensiveSecurityToolkit.js +1304 -0
- package/dist/core/defensiveSecurityToolkit.js.map +1 -0
- package/dist/core/errors/errorTypes.d.ts +30 -57
- package/dist/core/errors/errorTypes.d.ts.map +1 -1
- package/dist/core/errors/errorTypes.js +51 -228
- package/dist/core/errors/errorTypes.js.map +1 -1
- package/dist/core/errors/safetyValidator.d.ts +19 -3
- package/dist/core/errors/safetyValidator.d.ts.map +1 -1
- package/dist/core/errors/safetyValidator.js +33 -71
- package/dist/core/errors/safetyValidator.js.map +1 -1
- package/dist/core/failureRecovery.d.ts +4 -100
- package/dist/core/failureRecovery.d.ts.map +1 -1
- package/dist/core/failureRecovery.js +16 -440
- package/dist/core/failureRecovery.js.map +1 -1
- package/dist/core/intelligentTargetResearcher.d.ts +142 -0
- package/dist/core/intelligentTargetResearcher.d.ts.map +1 -0
- package/dist/core/intelligentTargetResearcher.js +367 -0
- package/dist/core/intelligentTargetResearcher.js.map +1 -0
- package/dist/core/intelligentTestFlows.d.ts +26 -107
- package/dist/core/intelligentTestFlows.d.ts.map +1 -1
- package/dist/core/intelligentTestFlows.js +15 -659
- package/dist/core/intelligentTestFlows.js.map +1 -1
- package/dist/core/learningPersistence.d.ts +45 -132
- package/dist/core/learningPersistence.d.ts.map +1 -1
- package/dist/core/learningPersistence.js +32 -463
- package/dist/core/learningPersistence.js.map +1 -1
- package/dist/core/metricsTracker.d.ts +22 -139
- package/dist/core/metricsTracker.d.ts.map +1 -1
- package/dist/core/metricsTracker.js +51 -241
- package/dist/core/metricsTracker.js.map +1 -1
- package/dist/core/performanceMonitor.d.ts +15 -109
- package/dist/core/performanceMonitor.d.ts.map +1 -1
- package/dist/core/performanceMonitor.js +27 -184
- package/dist/core/performanceMonitor.js.map +1 -1
- package/dist/core/resultVerification.d.ts +6 -100
- package/dist/core/resultVerification.d.ts.map +1 -1
- package/dist/core/resultVerification.js +31 -400
- package/dist/core/resultVerification.js.map +1 -1
- package/dist/core/selfEvolution.d.ts +32 -126
- package/dist/core/selfEvolution.d.ts.map +1 -1
- package/dist/core/selfEvolution.js +24 -967
- package/dist/core/selfEvolution.js.map +1 -1
- package/dist/core/selfImprovement.d.ts +50 -109
- package/dist/core/selfImprovement.d.ts.map +1 -1
- package/dist/core/selfImprovement.js +14 -689
- package/dist/core/selfImprovement.js.map +1 -1
- package/dist/core/sourceCodeManager.d.ts +89 -0
- package/dist/core/sourceCodeManager.d.ts.map +1 -0
- package/dist/core/sourceCodeManager.js +332 -0
- package/dist/core/sourceCodeManager.js.map +1 -0
- package/dist/core/unifiedOrchestrator.d.ts +88 -0
- package/dist/core/unifiedOrchestrator.d.ts.map +1 -0
- package/dist/core/unifiedOrchestrator.js +284 -0
- package/dist/core/unifiedOrchestrator.js.map +1 -0
- package/dist/core/userDefenseOrchestrator.d.ts +202 -0
- package/dist/core/userDefenseOrchestrator.d.ts.map +1 -0
- package/dist/core/userDefenseOrchestrator.js +1006 -0
- package/dist/core/userDefenseOrchestrator.js.map +1 -0
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +36 -26
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.d.ts +8 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.js +17 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.js.map +1 -0
- package/dist/plugins/tools/nodeDefaults.d.ts +14 -0
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +17 -54
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts +9 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js +18 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +97 -2
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +1001 -6
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/tools/appleExposureTools.d.ts +108 -0
- package/dist/tools/appleExposureTools.d.ts.map +1 -0
- package/dist/tools/appleExposureTools.js +850 -0
- package/dist/tools/appleExposureTools.js.map +1 -0
- package/dist/tools/bidirectionalAuditTools.d.ts +104 -0
- package/dist/tools/bidirectionalAuditTools.d.ts.map +1 -0
- package/dist/tools/bidirectionalAuditTools.js +1280 -0
- package/dist/tools/bidirectionalAuditTools.js.map +1 -0
- package/dist/tools/defensiveSecurityTools.d.ts +152 -0
- package/dist/tools/defensiveSecurityTools.d.ts.map +1 -0
- package/dist/tools/defensiveSecurityTools.js +576 -0
- package/dist/tools/defensiveSecurityTools.js.map +1 -0
- package/dist/tools/forwardAttackChainTracer.d.ts +73 -0
- package/dist/tools/forwardAttackChainTracer.d.ts.map +1 -0
- package/dist/tools/forwardAttackChainTracer.js +604 -0
- package/dist/tools/forwardAttackChainTracer.js.map +1 -0
- package/dist/tools/localExplore.d.ts +12 -199
- package/dist/tools/localExplore.d.ts.map +1 -1
- package/dist/tools/localExplore.js +18 -1352
- package/dist/tools/localExplore.js.map +1 -1
- package/dist/tools/offensiveTransparencyTools.d.ts +188 -0
- package/dist/tools/offensiveTransparencyTools.d.ts.map +1 -0
- package/dist/tools/offensiveTransparencyTools.js +890 -0
- package/dist/tools/offensiveTransparencyTools.js.map +1 -0
- package/dist/tools/planningTools.d.ts +8 -17
- package/dist/tools/planningTools.d.ts.map +1 -1
- package/dist/tools/planningTools.js +31 -141
- package/dist/tools/planningTools.js.map +1 -1
- package/dist/tools/searchTools.d.ts +9 -0
- package/dist/tools/searchTools.d.ts.map +1 -1
- package/dist/tools/searchTools.js +305 -189
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/skillTools.d.ts +7 -5
- package/dist/tools/skillTools.d.ts.map +1 -1
- package/dist/tools/skillTools.js +13 -155
- package/dist/tools/skillTools.js.map +1 -1
- package/dist/tools/threatIntelligenceTools.d.ts +128 -0
- package/dist/tools/threatIntelligenceTools.d.ts.map +1 -0
- package/dist/tools/threatIntelligenceTools.js +712 -0
- package/dist/tools/threatIntelligenceTools.js.map +1 -0
- package/dist/ui/PromptController.d.ts +4 -0
- package/dist/ui/PromptController.d.ts.map +1 -1
- package/dist/ui/PromptController.js +32 -11
- package/dist/ui/PromptController.js.map +1 -1
- package/dist/ui/UnifiedUIRenderer.d.ts +20 -0
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
- package/dist/ui/UnifiedUIRenderer.js +235 -28
- package/dist/ui/UnifiedUIRenderer.js.map +1 -1
- package/dist/ui/animatedStatus.d.ts +2 -0
- package/dist/ui/animatedStatus.d.ts.map +1 -1
- package/dist/ui/animatedStatus.js +36 -2
- package/dist/ui/animatedStatus.js.map +1 -1
- package/dist/ui/orchestration/StatusOrchestrator.d.ts +10 -0
- package/dist/ui/orchestration/StatusOrchestrator.d.ts.map +1 -1
- package/dist/ui/orchestration/StatusOrchestrator.js +36 -4
- package/dist/ui/orchestration/StatusOrchestrator.js.map +1 -1
- package/package.json +1 -1
- package/dist/capabilities/advancedTestGenerationCapability.d.ts +0 -17
- package/dist/capabilities/advancedTestGenerationCapability.d.ts.map +0 -1
- package/dist/capabilities/advancedTestGenerationCapability.js +0 -28
- package/dist/capabilities/advancedTestGenerationCapability.js.map +0 -1
- package/dist/capabilities/browserAutomationCapability.d.ts +0 -37
- package/dist/capabilities/browserAutomationCapability.d.ts.map +0 -1
- package/dist/capabilities/browserAutomationCapability.js +0 -49
- package/dist/capabilities/browserAutomationCapability.js.map +0 -1
- package/dist/capabilities/buildCapability.d.ts +0 -24
- package/dist/capabilities/buildCapability.d.ts.map +0 -1
- package/dist/capabilities/buildCapability.js +0 -25
- package/dist/capabilities/buildCapability.js.map +0 -1
- package/dist/capabilities/cloudCapability.d.ts +0 -13
- package/dist/capabilities/cloudCapability.d.ts.map +0 -1
- package/dist/capabilities/cloudCapability.js +0 -38
- package/dist/capabilities/cloudCapability.js.map +0 -1
- package/dist/capabilities/codeAnalysisCapability.d.ts +0 -13
- package/dist/capabilities/codeAnalysisCapability.d.ts.map +0 -1
- package/dist/capabilities/codeAnalysisCapability.js +0 -24
- package/dist/capabilities/codeAnalysisCapability.js.map +0 -1
- package/dist/capabilities/codeQualityCapability.d.ts +0 -13
- package/dist/capabilities/codeQualityCapability.d.ts.map +0 -1
- package/dist/capabilities/codeQualityCapability.js +0 -25
- package/dist/capabilities/codeQualityCapability.js.map +0 -1
- package/dist/capabilities/dependencySecurityCapability.d.ts +0 -13
- package/dist/capabilities/dependencySecurityCapability.d.ts.map +0 -1
- package/dist/capabilities/dependencySecurityCapability.js +0 -24
- package/dist/capabilities/dependencySecurityCapability.js.map +0 -1
- package/dist/capabilities/devCapability.d.ts +0 -13
- package/dist/capabilities/devCapability.d.ts.map +0 -1
- package/dist/capabilities/devCapability.js +0 -24
- package/dist/capabilities/devCapability.js.map +0 -1
- package/dist/capabilities/emailCapability.d.ts +0 -12
- package/dist/capabilities/emailCapability.d.ts.map +0 -1
- package/dist/capabilities/emailCapability.js +0 -22
- package/dist/capabilities/emailCapability.js.map +0 -1
- package/dist/capabilities/enhancedAnalysisCapability.d.ts +0 -13
- package/dist/capabilities/enhancedAnalysisCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedAnalysisCapability.js +0 -20
- package/dist/capabilities/enhancedAnalysisCapability.js.map +0 -1
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts +0 -17
- package/dist/capabilities/enhancedCodeIntelligenceCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js +0 -28
- package/dist/capabilities/enhancedCodeIntelligenceCapability.js.map +0 -1
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts +0 -17
- package/dist/capabilities/enhancedDevWorkflowCapability.d.ts.map +0 -1
- package/dist/capabilities/enhancedDevWorkflowCapability.js +0 -28
- package/dist/capabilities/enhancedDevWorkflowCapability.js.map +0 -1
- package/dist/capabilities/frontendTestingCapability.d.ts +0 -13
- package/dist/capabilities/frontendTestingCapability.d.ts.map +0 -1
- package/dist/capabilities/frontendTestingCapability.js +0 -28
- package/dist/capabilities/frontendTestingCapability.js.map +0 -1
- package/dist/capabilities/interactionCapability.d.ts +0 -12
- package/dist/capabilities/interactionCapability.d.ts.map +0 -1
- package/dist/capabilities/interactionCapability.js +0 -22
- package/dist/capabilities/interactionCapability.js.map +0 -1
- package/dist/capabilities/learnCapability.d.ts +0 -22
- package/dist/capabilities/learnCapability.d.ts.map +0 -1
- package/dist/capabilities/learnCapability.js +0 -37
- package/dist/capabilities/learnCapability.js.map +0 -1
- package/dist/capabilities/notebookCapability.d.ts +0 -17
- package/dist/capabilities/notebookCapability.d.ts.map +0 -1
- package/dist/capabilities/notebookCapability.js +0 -27
- package/dist/capabilities/notebookCapability.js.map +0 -1
- package/dist/capabilities/planningCapability.d.ts +0 -16
- package/dist/capabilities/planningCapability.d.ts.map +0 -1
- package/dist/capabilities/planningCapability.js +0 -26
- package/dist/capabilities/planningCapability.js.map +0 -1
- package/dist/capabilities/refactoringCapability.d.ts +0 -13
- package/dist/capabilities/refactoringCapability.d.ts.map +0 -1
- package/dist/capabilities/refactoringCapability.js +0 -25
- package/dist/capabilities/refactoringCapability.js.map +0 -1
- package/dist/capabilities/repoChecksCapability.d.ts +0 -10
- package/dist/capabilities/repoChecksCapability.d.ts.map +0 -1
- package/dist/capabilities/repoChecksCapability.js +0 -24
- package/dist/capabilities/repoChecksCapability.js.map +0 -1
- package/dist/capabilities/taskManagementCapability.d.ts +0 -12
- package/dist/capabilities/taskManagementCapability.d.ts.map +0 -1
- package/dist/capabilities/taskManagementCapability.js +0 -22
- package/dist/capabilities/taskManagementCapability.js.map +0 -1
- package/dist/capabilities/testingCapability.d.ts +0 -13
- package/dist/capabilities/testingCapability.d.ts.map +0 -1
- package/dist/capabilities/testingCapability.js +0 -25
- package/dist/capabilities/testingCapability.js.map +0 -1
- package/dist/capabilities/validationCapability.d.ts +0 -13
- package/dist/capabilities/validationCapability.d.ts.map +0 -1
- package/dist/capabilities/validationCapability.js +0 -24
- package/dist/capabilities/validationCapability.js.map +0 -1
- package/dist/capabilities/webCapability.d.ts +0 -12
- package/dist/capabilities/webCapability.d.ts.map +0 -1
- package/dist/capabilities/webCapability.js +0 -22
- package/dist/capabilities/webCapability.js.map +0 -1
- package/dist/core/deepBugAnalyzer.d.ts +0 -128
- package/dist/core/deepBugAnalyzer.d.ts.map +0 -1
- package/dist/core/deepBugAnalyzer.js +0 -406
- package/dist/core/deepBugAnalyzer.js.map +0 -1
- package/dist/core/hypothesisEngine.d.ts +0 -113
- package/dist/core/hypothesisEngine.d.ts.map +0 -1
- package/dist/core/hypothesisEngine.js +0 -264
- package/dist/core/hypothesisEngine.js.map +0 -1
- package/dist/core/productTestHarness.d.ts +0 -113
- package/dist/core/productTestHarness.d.ts.map +0 -1
- package/dist/core/productTestHarness.js +0 -351
- package/dist/core/productTestHarness.js.map +0 -1
- package/dist/core/validationRunner.d.ts +0 -106
- package/dist/core/validationRunner.d.ts.map +0 -1
- package/dist/core/validationRunner.js +0 -892
- package/dist/core/validationRunner.js.map +0 -1
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts +0 -14
- package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/browser/browserAutomationPlugin.js +0 -26
- package/dist/plugins/tools/browser/browserAutomationPlugin.js.map +0 -1
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts +0 -3
- package/dist/plugins/tools/checks/localRepoChecksPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js +0 -14
- package/dist/plugins/tools/checks/localRepoChecksPlugin.js.map +0 -1
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts +0 -3
- package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/cloud/cloudPlugin.js +0 -14
- package/dist/plugins/tools/cloud/cloudPlugin.js.map +0 -1
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts +0 -3
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +0 -14
- package/dist/plugins/tools/codeAnalysis/codeAnalysisPlugin.js.map +0 -1
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts +0 -3
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js +0 -14
- package/dist/plugins/tools/codeQuality/codeQualityPlugin.js.map +0 -1
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts +0 -3
- package/dist/plugins/tools/dependency/dependencyPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/dependency/dependencyPlugin.js +0 -12
- package/dist/plugins/tools/dependency/dependencyPlugin.js.map +0 -1
- package/dist/plugins/tools/development/devPlugin.d.ts +0 -3
- package/dist/plugins/tools/development/devPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/development/devPlugin.js +0 -14
- package/dist/plugins/tools/development/devPlugin.js.map +0 -1
- package/dist/plugins/tools/email/emailPlugin.d.ts +0 -3
- package/dist/plugins/tools/email/emailPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/email/emailPlugin.js +0 -12
- package/dist/plugins/tools/email/emailPlugin.js.map +0 -1
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.d.ts +0 -3
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.js +0 -14
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.js.map +0 -1
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.d.ts +0 -3
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.d.ts.map +0 -1
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.js +0 -12
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.js.map +0 -1
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.d.ts +0 -3
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.js +0 -12
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.js.map +0 -1
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts +0 -3
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js +0 -14
- package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js.map +0 -1
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts +0 -3
- package/dist/plugins/tools/interaction/interactionPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/interaction/interactionPlugin.js +0 -12
- package/dist/plugins/tools/interaction/interactionPlugin.js.map +0 -1
- package/dist/plugins/tools/learn/learnPlugin.d.ts +0 -3
- package/dist/plugins/tools/learn/learnPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/learn/learnPlugin.js +0 -14
- package/dist/plugins/tools/learn/learnPlugin.js.map +0 -1
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts +0 -9
- package/dist/plugins/tools/notebook/notebookPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/notebook/notebookPlugin.js +0 -15
- package/dist/plugins/tools/notebook/notebookPlugin.js.map +0 -1
- package/dist/plugins/tools/planning/planningPlugin.d.ts +0 -9
- package/dist/plugins/tools/planning/planningPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/planning/planningPlugin.js +0 -15
- package/dist/plugins/tools/planning/planningPlugin.js.map +0 -1
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts +0 -3
- package/dist/plugins/tools/refactoring/refactoringPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/refactoring/refactoringPlugin.js +0 -12
- package/dist/plugins/tools/refactoring/refactoringPlugin.js.map +0 -1
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts +0 -3
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js +0 -12
- package/dist/plugins/tools/taskManagement/taskManagementPlugin.js.map +0 -1
- package/dist/plugins/tools/testing/testingPlugin.d.ts +0 -3
- package/dist/plugins/tools/testing/testingPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/testing/testingPlugin.js +0 -12
- package/dist/plugins/tools/testing/testingPlugin.js.map +0 -1
- package/dist/plugins/tools/validation/validationPlugin.d.ts +0 -3
- package/dist/plugins/tools/validation/validationPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/validation/validationPlugin.js +0 -14
- package/dist/plugins/tools/validation/validationPlugin.js.map +0 -1
- package/dist/plugins/tools/web/webPlugin.d.ts +0 -3
- package/dist/plugins/tools/web/webPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/web/webPlugin.js +0 -12
- package/dist/plugins/tools/web/webPlugin.js.map +0 -1
- package/dist/tools/advancedTestGenerationTools.d.ts +0 -21
- package/dist/tools/advancedTestGenerationTools.d.ts.map +0 -1
- package/dist/tools/advancedTestGenerationTools.js +0 -304
- package/dist/tools/advancedTestGenerationTools.js.map +0 -1
- package/dist/tools/browserAutomationTools.d.ts +0 -23
- package/dist/tools/browserAutomationTools.d.ts.map +0 -1
- package/dist/tools/browserAutomationTools.js +0 -916
- package/dist/tools/browserAutomationTools.js.map +0 -1
- package/dist/tools/buildTools.d.ts +0 -9
- package/dist/tools/buildTools.d.ts.map +0 -1
- package/dist/tools/buildTools.js +0 -346
- package/dist/tools/buildTools.js.map +0 -1
- package/dist/tools/cloudTools.d.ts +0 -49
- package/dist/tools/cloudTools.d.ts.map +0 -1
- package/dist/tools/cloudTools.js +0 -1258
- package/dist/tools/cloudTools.js.map +0 -1
- package/dist/tools/codeAnalysisTools.d.ts +0 -74
- package/dist/tools/codeAnalysisTools.d.ts.map +0 -1
- package/dist/tools/codeAnalysisTools.js +0 -664
- package/dist/tools/codeAnalysisTools.js.map +0 -1
- package/dist/tools/codeGenerationTools.d.ts +0 -3
- package/dist/tools/codeGenerationTools.d.ts.map +0 -1
- package/dist/tools/codeGenerationTools.js +0 -439
- package/dist/tools/codeGenerationTools.js.map +0 -1
- package/dist/tools/codeQualityTools.d.ts +0 -3
- package/dist/tools/codeQualityTools.d.ts.map +0 -1
- package/dist/tools/codeQualityTools.js +0 -297
- package/dist/tools/codeQualityTools.js.map +0 -1
- package/dist/tools/dependencyTools.d.ts +0 -3
- package/dist/tools/dependencyTools.d.ts.map +0 -1
- package/dist/tools/dependencyTools.js +0 -284
- package/dist/tools/dependencyTools.js.map +0 -1
- package/dist/tools/devTools.d.ts +0 -10
- package/dist/tools/devTools.d.ts.map +0 -1
- package/dist/tools/devTools.js +0 -2126
- package/dist/tools/devTools.js.map +0 -1
- package/dist/tools/emailTools.d.ts +0 -21
- package/dist/tools/emailTools.d.ts.map +0 -1
- package/dist/tools/emailTools.js +0 -449
- package/dist/tools/emailTools.js.map +0 -1
- package/dist/tools/enhancedAnalysisTools.d.ts +0 -9
- package/dist/tools/enhancedAnalysisTools.d.ts.map +0 -1
- package/dist/tools/enhancedAnalysisTools.js +0 -370
- package/dist/tools/enhancedAnalysisTools.js.map +0 -1
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts +0 -7
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts.map +0 -1
- package/dist/tools/enhancedCodeIntelligenceTools.js +0 -540
- package/dist/tools/enhancedCodeIntelligenceTools.js.map +0 -1
- package/dist/tools/enhancedDevWorkflowTools.d.ts +0 -7
- package/dist/tools/enhancedDevWorkflowTools.d.ts.map +0 -1
- package/dist/tools/enhancedDevWorkflowTools.js +0 -432
- package/dist/tools/enhancedDevWorkflowTools.js.map +0 -1
- package/dist/tools/frontendTestingTools.d.ts +0 -35
- package/dist/tools/frontendTestingTools.d.ts.map +0 -1
- package/dist/tools/frontendTestingTools.js +0 -1258
- package/dist/tools/frontendTestingTools.js.map +0 -1
- package/dist/tools/globTools.d.ts +0 -15
- package/dist/tools/globTools.d.ts.map +0 -1
- package/dist/tools/globTools.js +0 -174
- package/dist/tools/globTools.js.map +0 -1
- package/dist/tools/grepTools.d.ts +0 -19
- package/dist/tools/grepTools.d.ts.map +0 -1
- package/dist/tools/grepTools.js +0 -411
- package/dist/tools/grepTools.js.map +0 -1
- package/dist/tools/interactionTools.d.ts +0 -6
- package/dist/tools/interactionTools.d.ts.map +0 -1
- package/dist/tools/interactionTools.js +0 -209
- package/dist/tools/interactionTools.js.map +0 -1
- package/dist/tools/learnTools.d.ts +0 -164
- package/dist/tools/learnTools.d.ts.map +0 -1
- package/dist/tools/learnTools.js +0 -2098
- package/dist/tools/learnTools.js.map +0 -1
- package/dist/tools/notebookEditTools.d.ts +0 -15
- package/dist/tools/notebookEditTools.d.ts.map +0 -1
- package/dist/tools/notebookEditTools.js +0 -197
- package/dist/tools/notebookEditTools.js.map +0 -1
- package/dist/tools/refactoringTools.d.ts +0 -3
- package/dist/tools/refactoringTools.d.ts.map +0 -1
- package/dist/tools/refactoringTools.js +0 -294
- package/dist/tools/refactoringTools.js.map +0 -1
- package/dist/tools/repoChecksTools.d.ts +0 -3
- package/dist/tools/repoChecksTools.d.ts.map +0 -1
- package/dist/tools/repoChecksTools.js +0 -276
- package/dist/tools/repoChecksTools.js.map +0 -1
- package/dist/tools/taskManagementTools.d.ts +0 -10
- package/dist/tools/taskManagementTools.d.ts.map +0 -1
- package/dist/tools/taskManagementTools.js +0 -133
- package/dist/tools/taskManagementTools.js.map +0 -1
- package/dist/tools/testingTools.d.ts +0 -3
- package/dist/tools/testingTools.d.ts.map +0 -1
- package/dist/tools/testingTools.js +0 -237
- package/dist/tools/testingTools.js.map +0 -1
- package/dist/tools/validationTools.d.ts +0 -7
- package/dist/tools/validationTools.d.ts.map +0 -1
- package/dist/tools/validationTools.js +0 -344
- package/dist/tools/validationTools.js.map +0 -1
- package/dist/tools/webTools.d.ts +0 -3
- package/dist/tools/webTools.d.ts.map +0 -1
- package/dist/tools/webTools.js +0 -502
- package/dist/tools/webTools.js.map +0 -1
|
@@ -1,1258 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frontend Testing Tools - Comprehensive frontend testing and verification capabilities
|
|
3
|
-
*
|
|
4
|
-
* Provides tools for:
|
|
5
|
-
* - E2E Testing (Cypress, Playwright, Selenium)
|
|
6
|
-
* - Build Verification (bundle analysis, build output validation)
|
|
7
|
-
* - Deployment Verification (URL health checks, asset verification, smoke tests)
|
|
8
|
-
* - Accessibility Testing (axe-core, pa11y integration)
|
|
9
|
-
* - Performance Testing (Lighthouse, Web Vitals)
|
|
10
|
-
* - Visual Regression Testing (screenshot comparison)
|
|
11
|
-
*
|
|
12
|
-
* @license MIT
|
|
13
|
-
* @author Bo Shang
|
|
14
|
-
*/
|
|
15
|
-
import { spawn } from 'child_process';
|
|
16
|
-
import * as fs from 'fs';
|
|
17
|
-
import * as path from 'path';
|
|
18
|
-
const E2E_FRAMEWORKS = {
|
|
19
|
-
cypress: {
|
|
20
|
-
id: 'cypress',
|
|
21
|
-
name: 'Cypress',
|
|
22
|
-
cliCommand: 'cypress',
|
|
23
|
-
installCommand: 'npm install -D cypress',
|
|
24
|
-
configFile: 'cypress.config.js',
|
|
25
|
-
runCommand: 'npx cypress run',
|
|
26
|
-
headlessFlag: '--headless',
|
|
27
|
-
},
|
|
28
|
-
playwright: {
|
|
29
|
-
id: 'playwright',
|
|
30
|
-
name: 'Playwright',
|
|
31
|
-
cliCommand: 'playwright',
|
|
32
|
-
installCommand: 'npm install -D @playwright/test && npx playwright install',
|
|
33
|
-
configFile: 'playwright.config.ts',
|
|
34
|
-
runCommand: 'npx playwright test',
|
|
35
|
-
headlessFlag: '--headed=false',
|
|
36
|
-
},
|
|
37
|
-
puppeteer: {
|
|
38
|
-
id: 'puppeteer',
|
|
39
|
-
name: 'Puppeteer',
|
|
40
|
-
cliCommand: 'puppeteer',
|
|
41
|
-
installCommand: 'npm install -D puppeteer',
|
|
42
|
-
configFile: 'puppeteer.config.js',
|
|
43
|
-
runCommand: 'npx jest --config=jest-puppeteer.config.js',
|
|
44
|
-
headlessFlag: '',
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
const BUILD_CONFIGS = {
|
|
48
|
-
react: {
|
|
49
|
-
framework: 'React',
|
|
50
|
-
outputDir: 'build',
|
|
51
|
-
indexFile: 'index.html',
|
|
52
|
-
expectedAssets: ['static/js', 'static/css'],
|
|
53
|
-
},
|
|
54
|
-
nextjs: {
|
|
55
|
-
framework: 'Next.js',
|
|
56
|
-
outputDir: '.next',
|
|
57
|
-
indexFile: '',
|
|
58
|
-
expectedAssets: ['static', 'server'],
|
|
59
|
-
},
|
|
60
|
-
angular: {
|
|
61
|
-
framework: 'Angular',
|
|
62
|
-
outputDir: 'dist',
|
|
63
|
-
indexFile: 'index.html',
|
|
64
|
-
expectedAssets: ['main.js', 'polyfills.js', 'styles.css'],
|
|
65
|
-
},
|
|
66
|
-
vue: {
|
|
67
|
-
framework: 'Vue',
|
|
68
|
-
outputDir: 'dist',
|
|
69
|
-
indexFile: 'index.html',
|
|
70
|
-
expectedAssets: ['js', 'css'],
|
|
71
|
-
},
|
|
72
|
-
svelte: {
|
|
73
|
-
framework: 'Svelte',
|
|
74
|
-
outputDir: 'build',
|
|
75
|
-
indexFile: 'index.html',
|
|
76
|
-
expectedAssets: ['_app'],
|
|
77
|
-
},
|
|
78
|
-
vite: {
|
|
79
|
-
framework: 'Vite',
|
|
80
|
-
outputDir: 'dist',
|
|
81
|
-
indexFile: 'index.html',
|
|
82
|
-
expectedAssets: ['assets'],
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
async function runCommand(command, cwd, timeout = 300000) {
|
|
86
|
-
return new Promise((resolve) => {
|
|
87
|
-
let killed = false;
|
|
88
|
-
let stdout = '';
|
|
89
|
-
let stderr = '';
|
|
90
|
-
const child = spawn('sh', ['-c', command], {
|
|
91
|
-
cwd,
|
|
92
|
-
env: { ...process.env },
|
|
93
|
-
});
|
|
94
|
-
// Set up timeout with proper cleanup
|
|
95
|
-
const timeoutId = setTimeout(() => {
|
|
96
|
-
killed = true;
|
|
97
|
-
child.kill('SIGTERM');
|
|
98
|
-
// Force kill if not terminated after 5 seconds
|
|
99
|
-
setTimeout(() => {
|
|
100
|
-
if (!child.killed) {
|
|
101
|
-
child.kill('SIGKILL');
|
|
102
|
-
}
|
|
103
|
-
}, 5000);
|
|
104
|
-
}, timeout);
|
|
105
|
-
child.stdout?.on('data', (data) => {
|
|
106
|
-
stdout += data.toString();
|
|
107
|
-
});
|
|
108
|
-
child.stderr?.on('data', (data) => {
|
|
109
|
-
stderr += data.toString();
|
|
110
|
-
});
|
|
111
|
-
child.on('close', (code) => {
|
|
112
|
-
clearTimeout(timeoutId);
|
|
113
|
-
if (killed) {
|
|
114
|
-
resolve({
|
|
115
|
-
stdout: stdout.trim(),
|
|
116
|
-
stderr: `${stderr.trim()}\n[Process timed out and was terminated]`,
|
|
117
|
-
exitCode: code ?? 1,
|
|
118
|
-
timedOut: true,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
resolve({ stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code ?? 1 });
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
child.on('error', (err) => {
|
|
126
|
-
clearTimeout(timeoutId);
|
|
127
|
-
resolve({ stdout: '', stderr: err.message, exitCode: 1 });
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Safely parse JSON with helpful error messages
|
|
133
|
-
*/
|
|
134
|
-
function safeJsonParse(content, source) {
|
|
135
|
-
try {
|
|
136
|
-
return { data: JSON.parse(content), error: null };
|
|
137
|
-
}
|
|
138
|
-
catch (e) {
|
|
139
|
-
const preview = content.slice(0, 100).replace(/\n/g, '\\n');
|
|
140
|
-
return {
|
|
141
|
-
data: null,
|
|
142
|
-
error: `Failed to parse ${source}: ${e instanceof Error ? e.message : 'Invalid JSON'}. Content preview: "${preview}..."`,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Validate URL format and protocol
|
|
148
|
-
*/
|
|
149
|
-
function validateUrl(url) {
|
|
150
|
-
if (!url || typeof url !== 'string') {
|
|
151
|
-
return { valid: false, error: 'URL is required and must be a string' };
|
|
152
|
-
}
|
|
153
|
-
try {
|
|
154
|
-
const parsed = new URL(url);
|
|
155
|
-
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
156
|
-
return { valid: false, error: `Invalid protocol "${parsed.protocol}". Only http: and https: are supported` };
|
|
157
|
-
}
|
|
158
|
-
return { valid: true, normalized: parsed.toString() };
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
return { valid: false, error: `Invalid URL format: "${url}"` };
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Validate file path for path traversal attacks
|
|
166
|
-
*/
|
|
167
|
-
function validateFilePath(filePath, baseDir) {
|
|
168
|
-
if (!filePath || typeof filePath !== 'string') {
|
|
169
|
-
return { valid: false, error: 'File path is required and must be a string' };
|
|
170
|
-
}
|
|
171
|
-
const resolved = path.resolve(baseDir, filePath);
|
|
172
|
-
const normalizedBase = path.resolve(baseDir);
|
|
173
|
-
if (!resolved.startsWith(normalizedBase)) {
|
|
174
|
-
return { valid: false, error: 'Path traversal not allowed - path must be within working directory' };
|
|
175
|
-
}
|
|
176
|
-
return { valid: true, resolved };
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Format output with truncation warning
|
|
180
|
-
*/
|
|
181
|
-
function truncateOutput(output, maxLength, label) {
|
|
182
|
-
if (output.length <= maxLength) {
|
|
183
|
-
return output;
|
|
184
|
-
}
|
|
185
|
-
return `${output.slice(0, maxLength)}\n\n[${label} truncated - ${output.length - maxLength} more characters not shown]`;
|
|
186
|
-
}
|
|
187
|
-
function detectFramework(workingDir) {
|
|
188
|
-
const packageJsonPath = path.join(workingDir, 'package.json');
|
|
189
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
190
|
-
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
191
|
-
const { data: pkg } = safeJsonParse(content, 'package.json');
|
|
192
|
-
if (pkg) {
|
|
193
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
194
|
-
if (deps['next'])
|
|
195
|
-
return 'nextjs';
|
|
196
|
-
if (deps['@angular/core'])
|
|
197
|
-
return 'angular';
|
|
198
|
-
if (deps['vue'])
|
|
199
|
-
return 'vue';
|
|
200
|
-
if (deps['svelte'])
|
|
201
|
-
return 'svelte';
|
|
202
|
-
if (deps['vite'])
|
|
203
|
-
return 'vite';
|
|
204
|
-
if (deps['react'])
|
|
205
|
-
return 'react';
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return 'unknown';
|
|
209
|
-
}
|
|
210
|
-
function detectE2EFramework(workingDir) {
|
|
211
|
-
const packageJsonPath = path.join(workingDir, 'package.json');
|
|
212
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
213
|
-
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
214
|
-
const { data: pkg } = safeJsonParse(content, 'package.json');
|
|
215
|
-
if (pkg) {
|
|
216
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
217
|
-
if (deps['cypress'])
|
|
218
|
-
return 'cypress';
|
|
219
|
-
if (deps['@playwright/test'] || deps['playwright'])
|
|
220
|
-
return 'playwright';
|
|
221
|
-
if (deps['puppeteer'])
|
|
222
|
-
return 'puppeteer';
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// Check for config files
|
|
226
|
-
if (fs.existsSync(path.join(workingDir, 'cypress.config.js')) ||
|
|
227
|
-
fs.existsSync(path.join(workingDir, 'cypress.config.ts'))) {
|
|
228
|
-
return 'cypress';
|
|
229
|
-
}
|
|
230
|
-
if (fs.existsSync(path.join(workingDir, 'playwright.config.ts')) ||
|
|
231
|
-
fs.existsSync(path.join(workingDir, 'playwright.config.js'))) {
|
|
232
|
-
return 'playwright';
|
|
233
|
-
}
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
async function fetchUrl(url, timeout = 10000) {
|
|
237
|
-
try {
|
|
238
|
-
const controller = new AbortController();
|
|
239
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
240
|
-
const response = await fetch(url, {
|
|
241
|
-
signal: controller.signal,
|
|
242
|
-
headers: { 'User-Agent': 'erosolar-cli/frontend-testing' },
|
|
243
|
-
});
|
|
244
|
-
clearTimeout(timeoutId);
|
|
245
|
-
const body = await response.text();
|
|
246
|
-
return { status: response.status, body: body.slice(0, 5000) };
|
|
247
|
-
}
|
|
248
|
-
catch (error) {
|
|
249
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
250
|
-
let errorType = 'UNKNOWN';
|
|
251
|
-
let userFriendlyError = errorMessage;
|
|
252
|
-
// Categorize common network errors
|
|
253
|
-
if (errorMessage.includes('ENOTFOUND') || errorMessage.includes('getaddrinfo')) {
|
|
254
|
-
errorType = 'DNS_FAILURE';
|
|
255
|
-
userFriendlyError = 'DNS lookup failed - check if the domain exists and your internet connection';
|
|
256
|
-
}
|
|
257
|
-
else if (errorMessage.includes('ECONNREFUSED')) {
|
|
258
|
-
errorType = 'CONNECTION_REFUSED';
|
|
259
|
-
userFriendlyError = 'Connection refused - is the server running?';
|
|
260
|
-
}
|
|
261
|
-
else if (errorMessage.includes('ETIMEDOUT') || errorMessage.includes('timeout') || errorMessage.includes('aborted')) {
|
|
262
|
-
errorType = 'TIMEOUT';
|
|
263
|
-
userFriendlyError = `Request timed out after ${timeout}ms - server may be slow or unreachable`;
|
|
264
|
-
}
|
|
265
|
-
else if (errorMessage.includes('EHOSTUNREACH')) {
|
|
266
|
-
errorType = 'HOST_UNREACHABLE';
|
|
267
|
-
userFriendlyError = 'Host unreachable - check your network connection';
|
|
268
|
-
}
|
|
269
|
-
else if (errorMessage.includes('certificate') || errorMessage.includes('SSL') || errorMessage.includes('TLS')) {
|
|
270
|
-
errorType = 'SSL_ERROR';
|
|
271
|
-
userFriendlyError = 'SSL/TLS certificate error - the site may have an invalid certificate';
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
status: 0,
|
|
275
|
-
body: '',
|
|
276
|
-
error: userFriendlyError,
|
|
277
|
-
errorType,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
function analyzeBundle(dir) {
|
|
282
|
-
const result = {
|
|
283
|
-
totalSize: 0,
|
|
284
|
-
jsSize: 0,
|
|
285
|
-
cssSize: 0,
|
|
286
|
-
imageSize: 0,
|
|
287
|
-
files: [],
|
|
288
|
-
};
|
|
289
|
-
function walk(currentDir) {
|
|
290
|
-
if (!fs.existsSync(currentDir))
|
|
291
|
-
return;
|
|
292
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
293
|
-
for (const entry of entries) {
|
|
294
|
-
const fullPath = path.join(currentDir, entry.name);
|
|
295
|
-
if (entry.isDirectory()) {
|
|
296
|
-
walk(fullPath);
|
|
297
|
-
}
|
|
298
|
-
else if (entry.isFile()) {
|
|
299
|
-
const stats = fs.statSync(fullPath);
|
|
300
|
-
const size = stats.size;
|
|
301
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
302
|
-
result.totalSize += size;
|
|
303
|
-
result.files.push({ name: path.relative(dir, fullPath), size });
|
|
304
|
-
if (['.js', '.mjs', '.cjs'].includes(ext)) {
|
|
305
|
-
result.jsSize += size;
|
|
306
|
-
}
|
|
307
|
-
else if (['.css', '.scss', '.sass', '.less'].includes(ext)) {
|
|
308
|
-
result.cssSize += size;
|
|
309
|
-
}
|
|
310
|
-
else if (['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.avif'].includes(ext)) {
|
|
311
|
-
result.imageSize += size;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
walk(dir);
|
|
317
|
-
// Sort by size descending
|
|
318
|
-
result.files.sort((a, b) => b.size - a.size);
|
|
319
|
-
return result;
|
|
320
|
-
}
|
|
321
|
-
function formatBytes(bytes) {
|
|
322
|
-
if (bytes === 0)
|
|
323
|
-
return '0 B';
|
|
324
|
-
const k = 1024;
|
|
325
|
-
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
326
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
327
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
328
|
-
}
|
|
329
|
-
export function createFrontendTestingTools(workingDir = process.cwd()) {
|
|
330
|
-
return [
|
|
331
|
-
{
|
|
332
|
-
name: 'run_e2e_tests',
|
|
333
|
-
description: `Run end-to-end tests using Cypress, Playwright, or Puppeteer.
|
|
334
|
-
|
|
335
|
-
Automatically detects the E2E framework from your project and runs tests.
|
|
336
|
-
Supports:
|
|
337
|
-
- Cypress (cypress run)
|
|
338
|
-
- Playwright (npx playwright test)
|
|
339
|
-
- Puppeteer (jest with puppeteer)
|
|
340
|
-
|
|
341
|
-
Features:
|
|
342
|
-
- Headless mode for CI/CD
|
|
343
|
-
- Spec/test file filtering
|
|
344
|
-
- Browser selection
|
|
345
|
-
- Screenshot capture on failure
|
|
346
|
-
- Video recording (Cypress/Playwright)`,
|
|
347
|
-
parameters: {
|
|
348
|
-
type: 'object',
|
|
349
|
-
properties: {
|
|
350
|
-
framework: {
|
|
351
|
-
type: 'string',
|
|
352
|
-
enum: ['cypress', 'playwright', 'puppeteer', 'auto'],
|
|
353
|
-
description: 'E2E framework to use (default: auto-detect)',
|
|
354
|
-
},
|
|
355
|
-
spec: {
|
|
356
|
-
type: 'string',
|
|
357
|
-
description: 'Specific test file or pattern to run',
|
|
358
|
-
},
|
|
359
|
-
browser: {
|
|
360
|
-
type: 'string',
|
|
361
|
-
enum: ['chrome', 'chromium', 'firefox', 'webkit', 'electron'],
|
|
362
|
-
description: 'Browser to use for testing',
|
|
363
|
-
},
|
|
364
|
-
headed: {
|
|
365
|
-
type: 'boolean',
|
|
366
|
-
description: 'Run in headed mode (show browser window)',
|
|
367
|
-
},
|
|
368
|
-
baseUrl: {
|
|
369
|
-
type: 'string',
|
|
370
|
-
description: 'Base URL for the application under test',
|
|
371
|
-
},
|
|
372
|
-
timeout: {
|
|
373
|
-
type: 'number',
|
|
374
|
-
description: 'Timeout in milliseconds (default: 300000)',
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
},
|
|
378
|
-
handler: async (args) => {
|
|
379
|
-
let frameworkId = args['framework'] || 'auto';
|
|
380
|
-
const spec = args['spec'];
|
|
381
|
-
const browser = args['browser'];
|
|
382
|
-
const headed = args['headed'] === true;
|
|
383
|
-
const baseUrl = args['baseUrl'];
|
|
384
|
-
const timeout = args['timeout'] || 300000;
|
|
385
|
-
// Auto-detect framework
|
|
386
|
-
if (frameworkId === 'auto') {
|
|
387
|
-
const detected = detectE2EFramework(workingDir);
|
|
388
|
-
if (!detected) {
|
|
389
|
-
return `No E2E testing framework detected in ${workingDir}
|
|
390
|
-
|
|
391
|
-
To get started, install one of the supported frameworks:
|
|
392
|
-
- Cypress: npm install -D cypress && npx cypress open
|
|
393
|
-
- Playwright: npm install -D @playwright/test && npx playwright install
|
|
394
|
-
|
|
395
|
-
Then run this tool again.`;
|
|
396
|
-
}
|
|
397
|
-
frameworkId = detected;
|
|
398
|
-
}
|
|
399
|
-
const framework = E2E_FRAMEWORKS[frameworkId];
|
|
400
|
-
if (!framework) {
|
|
401
|
-
return `Unknown E2E framework: ${frameworkId}\n\nSupported: cypress, playwright, puppeteer`;
|
|
402
|
-
}
|
|
403
|
-
// Build command
|
|
404
|
-
let command = framework.runCommand;
|
|
405
|
-
if (spec) {
|
|
406
|
-
if (frameworkId === 'cypress') {
|
|
407
|
-
command += ` --spec "${spec}"`;
|
|
408
|
-
}
|
|
409
|
-
else if (frameworkId === 'playwright') {
|
|
410
|
-
command += ` "${spec}"`;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
if (browser) {
|
|
414
|
-
if (frameworkId === 'cypress') {
|
|
415
|
-
command += ` --browser ${browser}`;
|
|
416
|
-
}
|
|
417
|
-
else if (frameworkId === 'playwright') {
|
|
418
|
-
command += ` --project=${browser}`;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
if (!headed && framework.headlessFlag) {
|
|
422
|
-
command += ` ${framework.headlessFlag}`;
|
|
423
|
-
}
|
|
424
|
-
else if (headed && frameworkId === 'playwright') {
|
|
425
|
-
command += ' --headed';
|
|
426
|
-
}
|
|
427
|
-
if (baseUrl && frameworkId === 'cypress') {
|
|
428
|
-
command += ` --config baseUrl=${baseUrl}`;
|
|
429
|
-
}
|
|
430
|
-
const results = [`🧪 Running ${framework.name} E2E Tests\n`];
|
|
431
|
-
results.push(`Command: ${command}\n`);
|
|
432
|
-
const result = await runCommand(command, workingDir, timeout);
|
|
433
|
-
if (result.exitCode === 0) {
|
|
434
|
-
results.push(`✅ All E2E tests passed!\n`);
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
results.push(`❌ E2E tests failed (exit code: ${result.exitCode})\n`);
|
|
438
|
-
}
|
|
439
|
-
if (result.stdout) {
|
|
440
|
-
results.push(`Output:\n${truncateOutput(result.stdout, 10000, 'output')}\n`);
|
|
441
|
-
}
|
|
442
|
-
if (result.stderr) {
|
|
443
|
-
results.push(`Errors:\n${truncateOutput(result.stderr, 5000, 'errors')}\n`);
|
|
444
|
-
}
|
|
445
|
-
return results.join('\n');
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
name: 'verify_build_output',
|
|
450
|
-
description: `Verify frontend build output and analyze bundle.
|
|
451
|
-
|
|
452
|
-
Checks:
|
|
453
|
-
- Build directory exists and contains expected files
|
|
454
|
-
- Bundle size analysis (JS, CSS, images)
|
|
455
|
-
- Source map presence
|
|
456
|
-
- Index.html integrity
|
|
457
|
-
- Large file detection
|
|
458
|
-
- Missing asset detection
|
|
459
|
-
|
|
460
|
-
Works with: React, Next.js, Angular, Vue, Svelte, Vite`,
|
|
461
|
-
parameters: {
|
|
462
|
-
type: 'object',
|
|
463
|
-
properties: {
|
|
464
|
-
buildDir: {
|
|
465
|
-
type: 'string',
|
|
466
|
-
description: 'Build output directory (auto-detected if not specified)',
|
|
467
|
-
},
|
|
468
|
-
framework: {
|
|
469
|
-
type: 'string',
|
|
470
|
-
enum: ['react', 'nextjs', 'angular', 'vue', 'svelte', 'vite', 'auto'],
|
|
471
|
-
description: 'Frontend framework (default: auto-detect)',
|
|
472
|
-
},
|
|
473
|
-
maxBundleSize: {
|
|
474
|
-
type: 'number',
|
|
475
|
-
description: 'Maximum total bundle size in bytes (default: 5MB)',
|
|
476
|
-
},
|
|
477
|
-
warnLargeFiles: {
|
|
478
|
-
type: 'number',
|
|
479
|
-
description: 'Warn about files larger than this (bytes, default: 500KB)',
|
|
480
|
-
},
|
|
481
|
-
},
|
|
482
|
-
},
|
|
483
|
-
handler: async (args) => {
|
|
484
|
-
let frameworkId = args['framework'] || 'auto';
|
|
485
|
-
const maxBundleSize = args['maxBundleSize'] || 5 * 1024 * 1024; // 5MB
|
|
486
|
-
const warnLargeFiles = args['warnLargeFiles'] || 500 * 1024; // 500KB
|
|
487
|
-
// Auto-detect framework
|
|
488
|
-
if (frameworkId === 'auto') {
|
|
489
|
-
frameworkId = detectFramework(workingDir);
|
|
490
|
-
}
|
|
491
|
-
const config = BUILD_CONFIGS[frameworkId] ?? BUILD_CONFIGS['react'];
|
|
492
|
-
const buildDir = args['buildDir'] || path.join(workingDir, config.outputDir);
|
|
493
|
-
const results = [`📦 Build Output Verification\n`];
|
|
494
|
-
results.push(`Framework: ${config.framework}`);
|
|
495
|
-
results.push(`Build directory: ${buildDir}\n`);
|
|
496
|
-
// Check if build directory exists
|
|
497
|
-
if (!fs.existsSync(buildDir)) {
|
|
498
|
-
return `❌ Build directory not found: ${buildDir}
|
|
499
|
-
|
|
500
|
-
Run your build command first:
|
|
501
|
-
- React: npm run build
|
|
502
|
-
- Next.js: npm run build
|
|
503
|
-
- Angular: ng build
|
|
504
|
-
- Vue: npm run build
|
|
505
|
-
- Vite: npm run build`;
|
|
506
|
-
}
|
|
507
|
-
results.push(`✅ Build directory exists\n`);
|
|
508
|
-
// Check for index.html (if applicable)
|
|
509
|
-
if (config.indexFile) {
|
|
510
|
-
const indexPath = path.join(buildDir, config.indexFile);
|
|
511
|
-
if (fs.existsSync(indexPath)) {
|
|
512
|
-
results.push(`✅ ${config.indexFile} found`);
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
results.push(`⚠️ ${config.indexFile} not found`);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
// Check for expected assets
|
|
519
|
-
const missingAssets = [];
|
|
520
|
-
for (const asset of config.expectedAssets) {
|
|
521
|
-
const assetPath = path.join(buildDir, asset);
|
|
522
|
-
if (!fs.existsSync(assetPath)) {
|
|
523
|
-
missingAssets.push(asset);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
if (missingAssets.length > 0) {
|
|
527
|
-
results.push(`⚠️ Missing expected assets: ${missingAssets.join(', ')}`);
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
results.push(`✅ All expected assets present`);
|
|
531
|
-
}
|
|
532
|
-
// Analyze bundle
|
|
533
|
-
const analysis = analyzeBundle(buildDir);
|
|
534
|
-
results.push(`\n📊 Bundle Analysis:`);
|
|
535
|
-
results.push(`Total size: ${formatBytes(analysis.totalSize)}`);
|
|
536
|
-
results.push(`JavaScript: ${formatBytes(analysis.jsSize)}`);
|
|
537
|
-
results.push(`CSS: ${formatBytes(analysis.cssSize)}`);
|
|
538
|
-
results.push(`Images: ${formatBytes(analysis.imageSize)}`);
|
|
539
|
-
// Check bundle size limit
|
|
540
|
-
if (analysis.totalSize > maxBundleSize) {
|
|
541
|
-
results.push(`\n❌ Bundle exceeds size limit (${formatBytes(maxBundleSize)})`);
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
544
|
-
results.push(`\n✅ Bundle within size limit`);
|
|
545
|
-
}
|
|
546
|
-
// Large files warning
|
|
547
|
-
const largeFiles = analysis.files.filter((f) => f.size > warnLargeFiles);
|
|
548
|
-
if (largeFiles.length > 0) {
|
|
549
|
-
results.push(`\n⚠️ Large files detected (>${formatBytes(warnLargeFiles)}):`);
|
|
550
|
-
largeFiles.slice(0, 10).forEach((f) => {
|
|
551
|
-
results.push(` - ${f.name}: ${formatBytes(f.size)}`);
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
// Top 10 largest files
|
|
555
|
-
results.push(`\n📁 Largest files:`);
|
|
556
|
-
analysis.files.slice(0, 10).forEach((f, i) => {
|
|
557
|
-
results.push(` ${i + 1}. ${f.name}: ${formatBytes(f.size)}`);
|
|
558
|
-
});
|
|
559
|
-
return results.join('\n');
|
|
560
|
-
},
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
name: 'verify_deployment',
|
|
564
|
-
description: `Verify a frontend deployment by checking the deployed URL.
|
|
565
|
-
|
|
566
|
-
Performs:
|
|
567
|
-
- URL health check (HTTP status)
|
|
568
|
-
- HTML content validation
|
|
569
|
-
- Asset loading verification
|
|
570
|
-
- Response time measurement
|
|
571
|
-
- Basic smoke tests
|
|
572
|
-
- SSL certificate check
|
|
573
|
-
|
|
574
|
-
Use this after deploying to verify the deployment was successful.`,
|
|
575
|
-
parameters: {
|
|
576
|
-
type: 'object',
|
|
577
|
-
properties: {
|
|
578
|
-
url: {
|
|
579
|
-
type: 'string',
|
|
580
|
-
description: 'URL of the deployed frontend (required)',
|
|
581
|
-
},
|
|
582
|
-
checkAssets: {
|
|
583
|
-
type: 'boolean',
|
|
584
|
-
description: 'Check if CSS/JS assets are accessible (default: true)',
|
|
585
|
-
},
|
|
586
|
-
expectedContent: {
|
|
587
|
-
type: 'string',
|
|
588
|
-
description: 'String that should be present in the HTML',
|
|
589
|
-
},
|
|
590
|
-
expectedTitle: {
|
|
591
|
-
type: 'string',
|
|
592
|
-
description: 'Expected page title',
|
|
593
|
-
},
|
|
594
|
-
timeout: {
|
|
595
|
-
type: 'number',
|
|
596
|
-
description: 'Request timeout in milliseconds (default: 10000)',
|
|
597
|
-
},
|
|
598
|
-
},
|
|
599
|
-
required: ['url'],
|
|
600
|
-
},
|
|
601
|
-
handler: async (args) => {
|
|
602
|
-
const rawUrl = args['url'];
|
|
603
|
-
const checkAssets = args['checkAssets'] !== false;
|
|
604
|
-
const expectedContent = args['expectedContent'];
|
|
605
|
-
const expectedTitle = args['expectedTitle'];
|
|
606
|
-
const timeout = args['timeout'] || 10000;
|
|
607
|
-
// Validate URL
|
|
608
|
-
const urlValidation = validateUrl(rawUrl);
|
|
609
|
-
if (!urlValidation.valid) {
|
|
610
|
-
return `❌ Invalid URL: ${urlValidation.error}`;
|
|
611
|
-
}
|
|
612
|
-
const url = urlValidation.normalized;
|
|
613
|
-
const results = [`🌐 Deployment Verification\n`];
|
|
614
|
-
results.push(`URL: ${url}\n`);
|
|
615
|
-
const startTime = Date.now();
|
|
616
|
-
const response = await fetchUrl(url, timeout);
|
|
617
|
-
const responseTime = Date.now() - startTime;
|
|
618
|
-
results.push(`⏱️ Response time: ${responseTime}ms`);
|
|
619
|
-
if (response.error) {
|
|
620
|
-
results.push(`\n❌ Failed to reach URL: ${response.error}`);
|
|
621
|
-
if (response.errorType) {
|
|
622
|
-
results.push(`Error type: ${response.errorType}`);
|
|
623
|
-
}
|
|
624
|
-
return results.join('\n');
|
|
625
|
-
}
|
|
626
|
-
// HTTP status check with helpful context
|
|
627
|
-
if (response.status >= 200 && response.status < 300) {
|
|
628
|
-
results.push(`✅ HTTP Status: ${response.status}`);
|
|
629
|
-
}
|
|
630
|
-
else {
|
|
631
|
-
let statusContext = '';
|
|
632
|
-
if (response.status === 404)
|
|
633
|
-
statusContext = ' (page not found - check URL path)';
|
|
634
|
-
else if (response.status === 403)
|
|
635
|
-
statusContext = ' (forbidden - authentication may be required)';
|
|
636
|
-
else if (response.status === 500)
|
|
637
|
-
statusContext = ' (server error - check server logs)';
|
|
638
|
-
else if (response.status === 502)
|
|
639
|
-
statusContext = ' (bad gateway - upstream server issue)';
|
|
640
|
-
else if (response.status === 503)
|
|
641
|
-
statusContext = ' (service unavailable - server may be overloaded)';
|
|
642
|
-
results.push(`❌ HTTP Status: ${response.status}${statusContext}`);
|
|
643
|
-
}
|
|
644
|
-
// SSL check
|
|
645
|
-
if (url.startsWith('https://')) {
|
|
646
|
-
results.push(`✅ HTTPS enabled`);
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
results.push(`⚠️ Not using HTTPS`);
|
|
650
|
-
}
|
|
651
|
-
// Content checks
|
|
652
|
-
const body = response.body;
|
|
653
|
-
// Check for HTML doctype
|
|
654
|
-
if (body.toLowerCase().includes('<!doctype html')) {
|
|
655
|
-
results.push(`✅ Valid HTML document`);
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
results.push(`⚠️ HTML doctype not found`);
|
|
659
|
-
}
|
|
660
|
-
// Check for expected content
|
|
661
|
-
if (expectedContent) {
|
|
662
|
-
if (body.includes(expectedContent)) {
|
|
663
|
-
results.push(`✅ Expected content found: "${expectedContent.slice(0, 50)}..."`);
|
|
664
|
-
}
|
|
665
|
-
else {
|
|
666
|
-
results.push(`❌ Expected content not found: "${expectedContent.slice(0, 50)}..."`);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
// Check title
|
|
670
|
-
const titleMatch = body.match(/<title>([^<]*)<\/title>/i);
|
|
671
|
-
const actualTitle = titleMatch?.[1] || '';
|
|
672
|
-
if (expectedTitle) {
|
|
673
|
-
if (actualTitle.includes(expectedTitle)) {
|
|
674
|
-
results.push(`✅ Title matches: "${actualTitle}"`);
|
|
675
|
-
}
|
|
676
|
-
else {
|
|
677
|
-
results.push(`❌ Title mismatch. Expected: "${expectedTitle}", Got: "${actualTitle}"`);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
else if (actualTitle) {
|
|
681
|
-
results.push(`📄 Page title: "${actualTitle}"`);
|
|
682
|
-
}
|
|
683
|
-
// Check for common SPA indicators
|
|
684
|
-
if (body.includes('id="root"') || body.includes('id="app"') || body.includes('id="__next"')) {
|
|
685
|
-
results.push(`✅ SPA mount point detected`);
|
|
686
|
-
}
|
|
687
|
-
// Extract and check assets
|
|
688
|
-
if (checkAssets) {
|
|
689
|
-
results.push(`\n🔍 Asset Verification:`);
|
|
690
|
-
// Find JS files
|
|
691
|
-
const jsMatches = body.match(/src="([^"]+\.js[^"]*)"/g) || [];
|
|
692
|
-
const jsFiles = jsMatches.map((m) => m.match(/src="([^"]+)"/)?.[1]).filter(Boolean);
|
|
693
|
-
// Find CSS files
|
|
694
|
-
const cssMatches = body.match(/href="([^"]+\.css[^"]*)"/g) || [];
|
|
695
|
-
const cssFiles = cssMatches.map((m) => m.match(/href="([^"]+)"/)?.[1]).filter(Boolean);
|
|
696
|
-
results.push(`Found ${jsFiles.length} JavaScript file(s)`);
|
|
697
|
-
results.push(`Found ${cssFiles.length} CSS file(s)`);
|
|
698
|
-
// Check first few assets in parallel for faster feedback
|
|
699
|
-
const assetsToCheck = [...jsFiles.slice(0, 2), ...cssFiles.slice(0, 2)];
|
|
700
|
-
const assetPromises = assetsToCheck
|
|
701
|
-
.filter((assetPath) => typeof assetPath === 'string' && assetPath.length > 0)
|
|
702
|
-
.map(async (assetPath) => {
|
|
703
|
-
const assetUrl = assetPath.startsWith('http') ? assetPath : new URL(assetPath, url).toString();
|
|
704
|
-
const response = await fetchUrl(assetUrl, 5000);
|
|
705
|
-
return { assetPath, response };
|
|
706
|
-
});
|
|
707
|
-
const assetResponses = await Promise.all(assetPromises);
|
|
708
|
-
for (const { assetPath, response } of assetResponses) {
|
|
709
|
-
if (response.status === 200) {
|
|
710
|
-
results.push(` ✅ ${assetPath.slice(0, 50)}...`);
|
|
711
|
-
}
|
|
712
|
-
else {
|
|
713
|
-
results.push(` ❌ ${assetPath.slice(0, 50)}... (${response.status || response.error})`);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
// Summary
|
|
718
|
-
results.push(`\n📋 Summary:`);
|
|
719
|
-
if (response.status >= 200 && response.status < 300 && responseTime < 3000) {
|
|
720
|
-
results.push(`✅ Deployment appears healthy`);
|
|
721
|
-
}
|
|
722
|
-
else if (response.status >= 200 && response.status < 300) {
|
|
723
|
-
results.push(`⚠️ Deployment working but slow (${responseTime}ms)`);
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
results.push(`❌ Deployment issues detected`);
|
|
727
|
-
}
|
|
728
|
-
return results.join('\n');
|
|
729
|
-
},
|
|
730
|
-
},
|
|
731
|
-
{
|
|
732
|
-
name: 'run_accessibility_tests',
|
|
733
|
-
description: `Run accessibility tests on a URL or HTML file using axe-core.
|
|
734
|
-
|
|
735
|
-
Checks for:
|
|
736
|
-
- WCAG 2.1 Level A and AA compliance
|
|
737
|
-
- Color contrast issues
|
|
738
|
-
- Missing alt text
|
|
739
|
-
- Form label issues
|
|
740
|
-
- Keyboard navigation problems
|
|
741
|
-
- ARIA attribute errors
|
|
742
|
-
|
|
743
|
-
Requires: axe-core (will offer to install if not found)`,
|
|
744
|
-
parameters: {
|
|
745
|
-
type: 'object',
|
|
746
|
-
properties: {
|
|
747
|
-
url: {
|
|
748
|
-
type: 'string',
|
|
749
|
-
description: 'URL to test (can be local dev server)',
|
|
750
|
-
},
|
|
751
|
-
htmlFile: {
|
|
752
|
-
type: 'string',
|
|
753
|
-
description: 'Path to HTML file to test (alternative to URL)',
|
|
754
|
-
},
|
|
755
|
-
rules: {
|
|
756
|
-
type: 'string',
|
|
757
|
-
enum: ['wcag2a', 'wcag2aa', 'wcag2aaa', 'best-practice', 'all'],
|
|
758
|
-
description: 'Accessibility rules to check (default: wcag2aa)',
|
|
759
|
-
},
|
|
760
|
-
timeout: {
|
|
761
|
-
type: 'number',
|
|
762
|
-
description: 'Timeout in milliseconds (default: 60000)',
|
|
763
|
-
},
|
|
764
|
-
},
|
|
765
|
-
},
|
|
766
|
-
handler: async (args) => {
|
|
767
|
-
const rawUrl = args['url'];
|
|
768
|
-
const rawHtmlFile = args['htmlFile'];
|
|
769
|
-
const rules = args['rules'] || 'wcag2aa';
|
|
770
|
-
const timeout = args['timeout'] || 60000;
|
|
771
|
-
if (!rawUrl && !rawHtmlFile) {
|
|
772
|
-
return `Please provide either a URL or HTML file path to test.
|
|
773
|
-
|
|
774
|
-
Examples:
|
|
775
|
-
- URL: http://localhost:3000
|
|
776
|
-
- HTML file: ./build/index.html`;
|
|
777
|
-
}
|
|
778
|
-
// Validate URL if provided
|
|
779
|
-
let validatedUrl;
|
|
780
|
-
if (rawUrl) {
|
|
781
|
-
const urlValidation = validateUrl(rawUrl);
|
|
782
|
-
if (!urlValidation.valid) {
|
|
783
|
-
return `❌ Invalid URL: ${urlValidation.error}`;
|
|
784
|
-
}
|
|
785
|
-
validatedUrl = urlValidation.normalized;
|
|
786
|
-
}
|
|
787
|
-
// Validate file path if provided (with path traversal protection)
|
|
788
|
-
let validatedHtmlFile;
|
|
789
|
-
if (rawHtmlFile) {
|
|
790
|
-
const fileValidation = validateFilePath(rawHtmlFile, workingDir);
|
|
791
|
-
if (!fileValidation.valid) {
|
|
792
|
-
return `❌ Invalid file path: ${fileValidation.error}`;
|
|
793
|
-
}
|
|
794
|
-
validatedHtmlFile = fileValidation.resolved;
|
|
795
|
-
}
|
|
796
|
-
// Check for axe-core in project
|
|
797
|
-
const packageJsonPath = path.join(workingDir, 'package.json');
|
|
798
|
-
let hasAxe = false;
|
|
799
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
800
|
-
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
801
|
-
const { data: pkg } = safeJsonParse(content, 'package.json');
|
|
802
|
-
if (pkg) {
|
|
803
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
804
|
-
hasAxe = !!(deps['axe-core'] || deps['@axe-core/puppeteer'] || deps['@axe-core/playwright']);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
// Try to use pa11y or axe-cli if available
|
|
808
|
-
const result = await runCommand('which pa11y || which axe', workingDir, 5000);
|
|
809
|
-
const hasCli = result.exitCode === 0;
|
|
810
|
-
if (!hasAxe && !hasCli) {
|
|
811
|
-
return `Accessibility testing tools not found.
|
|
812
|
-
|
|
813
|
-
Install one of the following:
|
|
814
|
-
|
|
815
|
-
Option 1 - pa11y (recommended for CLI):
|
|
816
|
-
npm install -g pa11y
|
|
817
|
-
|
|
818
|
-
Option 2 - axe-cli:
|
|
819
|
-
npm install -g @axe-core/cli
|
|
820
|
-
|
|
821
|
-
Option 3 - Add to project:
|
|
822
|
-
npm install -D axe-core @axe-core/playwright
|
|
823
|
-
|
|
824
|
-
After installation, run this tool again.`;
|
|
825
|
-
}
|
|
826
|
-
const target = validatedUrl || validatedHtmlFile;
|
|
827
|
-
const results = [`♿ Accessibility Testing\n`];
|
|
828
|
-
results.push(`Target: ${target}`);
|
|
829
|
-
results.push(`Rules: ${rules}\n`);
|
|
830
|
-
// Try pa11y first
|
|
831
|
-
if (hasCli) {
|
|
832
|
-
let command = `pa11y "${target}" --standard ${rules.toUpperCase().replace('WCAG2', 'WCAG2').replace('aa', 'AA').replace('a', 'A')} --reporter json 2>&1`;
|
|
833
|
-
if (validatedUrl) {
|
|
834
|
-
command = `pa11y "${validatedUrl}" --reporter cli --standard WCAG2AA 2>&1`;
|
|
835
|
-
}
|
|
836
|
-
const testResult = await runCommand(command, workingDir, timeout);
|
|
837
|
-
if (testResult.exitCode === 0 && !testResult.stdout.includes('Error:')) {
|
|
838
|
-
results.push(`✅ No accessibility violations found!\n`);
|
|
839
|
-
}
|
|
840
|
-
else if (testResult.stdout.includes('Error:')) {
|
|
841
|
-
results.push(`⚠️ Could not run pa11y: ${truncateOutput(testResult.stdout, 500, 'output')}`);
|
|
842
|
-
}
|
|
843
|
-
else {
|
|
844
|
-
results.push(`❌ Accessibility issues found:\n`);
|
|
845
|
-
results.push(truncateOutput(testResult.stdout, 8000, 'output'));
|
|
846
|
-
}
|
|
847
|
-
if (testResult.stderr && !testResult.stderr.includes('Deprecation')) {
|
|
848
|
-
results.push(`\nWarnings:\n${truncateOutput(testResult.stderr, 2000, 'warnings')}`);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
else {
|
|
852
|
-
// Fallback to basic HTML analysis
|
|
853
|
-
results.push(`Using basic HTML analysis (install pa11y for comprehensive testing)\n`);
|
|
854
|
-
if (validatedHtmlFile && fs.existsSync(validatedHtmlFile)) {
|
|
855
|
-
const html = fs.readFileSync(validatedHtmlFile, 'utf-8');
|
|
856
|
-
// Basic checks
|
|
857
|
-
const issues = [];
|
|
858
|
-
// Check for images without alt
|
|
859
|
-
const imgWithoutAlt = html.match(/<img(?![^>]*\balt=)[^>]*>/gi);
|
|
860
|
-
if (imgWithoutAlt?.length) {
|
|
861
|
-
issues.push(`- ${imgWithoutAlt.length} image(s) missing alt attribute`);
|
|
862
|
-
}
|
|
863
|
-
// Check for inputs without labels
|
|
864
|
-
const inputsWithoutId = html.match(/<input(?![^>]*\bid=)[^>]*>/gi);
|
|
865
|
-
if (inputsWithoutId?.length) {
|
|
866
|
-
issues.push(`- ${inputsWithoutId.length} input(s) may be missing associated labels`);
|
|
867
|
-
}
|
|
868
|
-
// Check for lang attribute
|
|
869
|
-
if (!html.includes('lang=')) {
|
|
870
|
-
issues.push(`- Missing lang attribute on <html> element`);
|
|
871
|
-
}
|
|
872
|
-
// Check for viewport
|
|
873
|
-
if (!html.includes('viewport')) {
|
|
874
|
-
issues.push(`- Missing viewport meta tag`);
|
|
875
|
-
}
|
|
876
|
-
if (issues.length > 0) {
|
|
877
|
-
results.push(`Found ${issues.length} potential issue(s):\n${issues.join('\n')}`);
|
|
878
|
-
}
|
|
879
|
-
else {
|
|
880
|
-
results.push(`✅ No basic accessibility issues detected`);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
else if (validatedUrl) {
|
|
884
|
-
const response = await fetchUrl(validatedUrl);
|
|
885
|
-
if (response.status === 200) {
|
|
886
|
-
// Basic analysis of fetched HTML
|
|
887
|
-
const html = response.body;
|
|
888
|
-
const issues = [];
|
|
889
|
-
if (!html.includes('lang=')) {
|
|
890
|
-
issues.push(`- Missing lang attribute`);
|
|
891
|
-
}
|
|
892
|
-
const imgWithoutAlt = html.match(/<img(?![^>]*\balt=)[^>]*>/gi);
|
|
893
|
-
if (imgWithoutAlt?.length) {
|
|
894
|
-
issues.push(`- ${imgWithoutAlt.length} image(s) missing alt attribute`);
|
|
895
|
-
}
|
|
896
|
-
if (issues.length > 0) {
|
|
897
|
-
results.push(`Found ${issues.length} potential issue(s):\n${issues.join('\n')}`);
|
|
898
|
-
}
|
|
899
|
-
else {
|
|
900
|
-
results.push(`✅ No basic accessibility issues detected`);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
return results.join('\n');
|
|
906
|
-
},
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
name: 'run_lighthouse',
|
|
910
|
-
description: `Run Lighthouse performance audit on a URL.
|
|
911
|
-
|
|
912
|
-
Generates reports for:
|
|
913
|
-
- Performance (LCP, FID, CLS, etc.)
|
|
914
|
-
- Accessibility
|
|
915
|
-
- Best Practices
|
|
916
|
-
- SEO
|
|
917
|
-
- PWA (optional)
|
|
918
|
-
|
|
919
|
-
Requires: lighthouse CLI or Chrome browser`,
|
|
920
|
-
parameters: {
|
|
921
|
-
type: 'object',
|
|
922
|
-
properties: {
|
|
923
|
-
url: {
|
|
924
|
-
type: 'string',
|
|
925
|
-
description: 'URL to audit (required)',
|
|
926
|
-
},
|
|
927
|
-
categories: {
|
|
928
|
-
type: 'array',
|
|
929
|
-
items: { type: 'string' },
|
|
930
|
-
description: 'Categories to audit: performance, accessibility, best-practices, seo, pwa',
|
|
931
|
-
},
|
|
932
|
-
output: {
|
|
933
|
-
type: 'string',
|
|
934
|
-
enum: ['json', 'html', 'csv'],
|
|
935
|
-
description: 'Output format (default: json)',
|
|
936
|
-
},
|
|
937
|
-
outputPath: {
|
|
938
|
-
type: 'string',
|
|
939
|
-
description: 'Path to save report (optional)',
|
|
940
|
-
},
|
|
941
|
-
device: {
|
|
942
|
-
type: 'string',
|
|
943
|
-
enum: ['mobile', 'desktop'],
|
|
944
|
-
description: 'Device emulation (default: mobile)',
|
|
945
|
-
},
|
|
946
|
-
timeout: {
|
|
947
|
-
type: 'number',
|
|
948
|
-
description: 'Timeout in milliseconds (default: 120000)',
|
|
949
|
-
},
|
|
950
|
-
},
|
|
951
|
-
required: ['url'],
|
|
952
|
-
},
|
|
953
|
-
handler: async (args) => {
|
|
954
|
-
const rawUrl = args['url'];
|
|
955
|
-
const categories = args['categories'] || ['performance', 'accessibility', 'best-practices', 'seo'];
|
|
956
|
-
const output = args['output'] || 'json';
|
|
957
|
-
const rawOutputPath = args['outputPath'];
|
|
958
|
-
const device = args['device'] || 'mobile';
|
|
959
|
-
const timeout = args['timeout'] || 120000;
|
|
960
|
-
// Validate URL
|
|
961
|
-
const urlValidation = validateUrl(rawUrl);
|
|
962
|
-
if (!urlValidation.valid) {
|
|
963
|
-
return `❌ Invalid URL: ${urlValidation.error}`;
|
|
964
|
-
}
|
|
965
|
-
const url = urlValidation.normalized;
|
|
966
|
-
// Validate output path if provided (with path traversal protection)
|
|
967
|
-
let outputPath;
|
|
968
|
-
if (rawOutputPath) {
|
|
969
|
-
const pathValidation = validateFilePath(rawOutputPath, workingDir);
|
|
970
|
-
if (!pathValidation.valid) {
|
|
971
|
-
return `❌ Invalid output path: ${pathValidation.error}`;
|
|
972
|
-
}
|
|
973
|
-
outputPath = pathValidation.resolved;
|
|
974
|
-
}
|
|
975
|
-
// Check for lighthouse
|
|
976
|
-
const checkResult = await runCommand('which lighthouse', workingDir, 5000);
|
|
977
|
-
if (checkResult.exitCode !== 0) {
|
|
978
|
-
return `Lighthouse CLI not found.
|
|
979
|
-
|
|
980
|
-
Install with:
|
|
981
|
-
npm install -g lighthouse
|
|
982
|
-
|
|
983
|
-
Or use Chrome DevTools Lighthouse panel for manual audits.`;
|
|
984
|
-
}
|
|
985
|
-
const results = [`🔦 Lighthouse Audit\n`];
|
|
986
|
-
results.push(`URL: ${url}`);
|
|
987
|
-
results.push(`Device: ${device}`);
|
|
988
|
-
results.push(`Categories: ${categories.join(', ')}\n`);
|
|
989
|
-
// Build command
|
|
990
|
-
let command = `lighthouse "${url}" --output=${output} --quiet`;
|
|
991
|
-
command += ` --only-categories=${categories.join(',')}`;
|
|
992
|
-
command += device === 'desktop' ? ' --preset=desktop' : '';
|
|
993
|
-
command += ' --chrome-flags="--headless --no-sandbox"';
|
|
994
|
-
if (outputPath) {
|
|
995
|
-
command += ` --output-path="${outputPath}"`;
|
|
996
|
-
}
|
|
997
|
-
const auditResult = await runCommand(command, workingDir, timeout);
|
|
998
|
-
if (auditResult.exitCode !== 0) {
|
|
999
|
-
results.push(`❌ Lighthouse audit failed:\n${truncateOutput(auditResult.stderr || auditResult.stdout, 3000, 'error output')}`);
|
|
1000
|
-
return results.join('\n');
|
|
1001
|
-
}
|
|
1002
|
-
// Parse JSON output
|
|
1003
|
-
if (output === 'json') {
|
|
1004
|
-
const { data: report, error: parseError } = safeJsonParse(auditResult.stdout, 'Lighthouse report');
|
|
1005
|
-
if (parseError || !report) {
|
|
1006
|
-
results.push(`⚠️ Could not parse Lighthouse results: ${parseError}`);
|
|
1007
|
-
results.push(`Raw output:\n${truncateOutput(auditResult.stdout, 5000, 'output')}`);
|
|
1008
|
-
return results.join('\n');
|
|
1009
|
-
}
|
|
1010
|
-
const cats = report.categories || {};
|
|
1011
|
-
results.push(`📊 Scores:\n`);
|
|
1012
|
-
for (const cat of Object.values(cats)) {
|
|
1013
|
-
const score = Math.round((cat.score || 0) * 100);
|
|
1014
|
-
const emoji = score >= 90 ? '🟢' : score >= 50 ? '🟡' : '🔴';
|
|
1015
|
-
results.push(`${emoji} ${cat.title}: ${score}/100`);
|
|
1016
|
-
}
|
|
1017
|
-
// Show key metrics if available
|
|
1018
|
-
const metrics = report.audits;
|
|
1019
|
-
if (metrics) {
|
|
1020
|
-
results.push(`\n📈 Key Metrics:`);
|
|
1021
|
-
const keyMetrics = [
|
|
1022
|
-
{ id: 'first-contentful-paint', label: 'First Contentful Paint' },
|
|
1023
|
-
{ id: 'largest-contentful-paint', label: 'Largest Contentful Paint' },
|
|
1024
|
-
{ id: 'total-blocking-time', label: 'Total Blocking Time' },
|
|
1025
|
-
{ id: 'cumulative-layout-shift', label: 'Cumulative Layout Shift' },
|
|
1026
|
-
{ id: 'speed-index', label: 'Speed Index' },
|
|
1027
|
-
];
|
|
1028
|
-
for (const metric of keyMetrics) {
|
|
1029
|
-
const audit = metrics[metric.id];
|
|
1030
|
-
if (audit) {
|
|
1031
|
-
const score = Math.round((audit.score || 0) * 100);
|
|
1032
|
-
const emoji = score >= 90 ? '✅' : score >= 50 ? '⚠️' : '❌';
|
|
1033
|
-
results.push(`${emoji} ${metric.label}: ${audit.displayValue || 'N/A'}`);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
else {
|
|
1039
|
-
results.push(`✅ Report generated`);
|
|
1040
|
-
if (outputPath) {
|
|
1041
|
-
results.push(`Saved to: ${outputPath}`);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
return results.join('\n');
|
|
1045
|
-
},
|
|
1046
|
-
},
|
|
1047
|
-
{
|
|
1048
|
-
name: 'frontend_test_workflow',
|
|
1049
|
-
description: `Run a complete frontend testing workflow.
|
|
1050
|
-
|
|
1051
|
-
Executes a series of tests in order:
|
|
1052
|
-
1. Build verification
|
|
1053
|
-
2. Unit tests (if present)
|
|
1054
|
-
3. E2E tests (if present)
|
|
1055
|
-
4. Accessibility tests
|
|
1056
|
-
5. Performance audit (optional)
|
|
1057
|
-
|
|
1058
|
-
Perfect for CI/CD pipelines or pre-deployment verification.`,
|
|
1059
|
-
parameters: {
|
|
1060
|
-
type: 'object',
|
|
1061
|
-
properties: {
|
|
1062
|
-
skipBuild: {
|
|
1063
|
-
type: 'boolean',
|
|
1064
|
-
description: 'Skip build verification (default: false)',
|
|
1065
|
-
},
|
|
1066
|
-
skipUnit: {
|
|
1067
|
-
type: 'boolean',
|
|
1068
|
-
description: 'Skip unit tests (default: false)',
|
|
1069
|
-
},
|
|
1070
|
-
skipE2e: {
|
|
1071
|
-
type: 'boolean',
|
|
1072
|
-
description: 'Skip E2E tests (default: false)',
|
|
1073
|
-
},
|
|
1074
|
-
skipA11y: {
|
|
1075
|
-
type: 'boolean',
|
|
1076
|
-
description: 'Skip accessibility tests (default: false)',
|
|
1077
|
-
},
|
|
1078
|
-
runLighthouse: {
|
|
1079
|
-
type: 'boolean',
|
|
1080
|
-
description: 'Run Lighthouse performance audit (default: false)',
|
|
1081
|
-
},
|
|
1082
|
-
baseUrl: {
|
|
1083
|
-
type: 'string',
|
|
1084
|
-
description: 'Base URL for tests (uses local server if not specified)',
|
|
1085
|
-
},
|
|
1086
|
-
timeout: {
|
|
1087
|
-
type: 'number',
|
|
1088
|
-
description: 'Timeout per step in milliseconds (default: 300000)',
|
|
1089
|
-
},
|
|
1090
|
-
},
|
|
1091
|
-
},
|
|
1092
|
-
handler: async (args) => {
|
|
1093
|
-
const skipBuild = args['skipBuild'] === true;
|
|
1094
|
-
const skipUnit = args['skipUnit'] === true;
|
|
1095
|
-
const skipE2e = args['skipE2e'] === true;
|
|
1096
|
-
const skipA11y = args['skipA11y'] === true;
|
|
1097
|
-
const runLighthouseArg = args['runLighthouse'] === true;
|
|
1098
|
-
const rawBaseUrl = args['baseUrl'];
|
|
1099
|
-
const timeout = args['timeout'] || 300000;
|
|
1100
|
-
// Validate baseUrl if provided
|
|
1101
|
-
let baseUrl;
|
|
1102
|
-
if (rawBaseUrl) {
|
|
1103
|
-
const urlValidation = validateUrl(rawBaseUrl);
|
|
1104
|
-
if (!urlValidation.valid) {
|
|
1105
|
-
return `❌ Invalid baseUrl: ${urlValidation.error}`;
|
|
1106
|
-
}
|
|
1107
|
-
baseUrl = urlValidation.normalized;
|
|
1108
|
-
}
|
|
1109
|
-
const results = [`🚀 Frontend Testing Workflow\n`];
|
|
1110
|
-
const summary = [];
|
|
1111
|
-
// Step 1: Build Verification
|
|
1112
|
-
if (!skipBuild) {
|
|
1113
|
-
results.push(`\n━━━ Step 1: Build Verification ━━━\n`);
|
|
1114
|
-
const startTime = Date.now();
|
|
1115
|
-
// Run build first
|
|
1116
|
-
const buildResult = await runCommand('npm run build', workingDir, timeout);
|
|
1117
|
-
const buildTime = Date.now() - startTime;
|
|
1118
|
-
if (buildResult.exitCode === 0) {
|
|
1119
|
-
results.push(`✅ Build succeeded (${buildTime}ms)\n`);
|
|
1120
|
-
summary.push({ step: 'Build', status: 'PASS', time: buildTime });
|
|
1121
|
-
// Verify output
|
|
1122
|
-
const detectedFramework = detectFramework(workingDir);
|
|
1123
|
-
const buildConfig = BUILD_CONFIGS[detectedFramework] ?? BUILD_CONFIGS['react'];
|
|
1124
|
-
const buildDir = path.join(workingDir, buildConfig.outputDir);
|
|
1125
|
-
if (fs.existsSync(buildDir)) {
|
|
1126
|
-
const analysis = analyzeBundle(buildDir);
|
|
1127
|
-
results.push(`Bundle size: ${formatBytes(analysis.totalSize)}`);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
else {
|
|
1131
|
-
results.push(`❌ Build failed\n${truncateOutput(buildResult.stderr || buildResult.stdout, 3000, 'build output')}`);
|
|
1132
|
-
summary.push({ step: 'Build', status: 'FAIL', time: buildTime });
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
// Step 2: Unit Tests
|
|
1136
|
-
if (!skipUnit) {
|
|
1137
|
-
results.push(`\n━━━ Step 2: Unit Tests ━━━\n`);
|
|
1138
|
-
const startTime = Date.now();
|
|
1139
|
-
const testResult = await runCommand('npm test -- --watchAll=false --passWithNoTests', workingDir, timeout);
|
|
1140
|
-
const testTime = Date.now() - startTime;
|
|
1141
|
-
if (testResult.exitCode === 0) {
|
|
1142
|
-
results.push(`✅ Unit tests passed (${testTime}ms)\n`);
|
|
1143
|
-
summary.push({ step: 'Unit Tests', status: 'PASS', time: testTime });
|
|
1144
|
-
}
|
|
1145
|
-
else {
|
|
1146
|
-
results.push(`❌ Unit tests failed\n${truncateOutput(testResult.stdout, 3000, 'test output')}`);
|
|
1147
|
-
summary.push({ step: 'Unit Tests', status: 'FAIL', time: testTime });
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
// Step 3: E2E Tests
|
|
1151
|
-
if (!skipE2e) {
|
|
1152
|
-
results.push(`\n━━━ Step 3: E2E Tests ━━━\n`);
|
|
1153
|
-
const startTime = Date.now();
|
|
1154
|
-
const e2eFramework = detectE2EFramework(workingDir);
|
|
1155
|
-
if (e2eFramework) {
|
|
1156
|
-
const e2eConfig = E2E_FRAMEWORKS[e2eFramework];
|
|
1157
|
-
let command = e2eConfig.runCommand;
|
|
1158
|
-
if (baseUrl && e2eFramework === 'cypress') {
|
|
1159
|
-
command += ` --config baseUrl=${baseUrl}`;
|
|
1160
|
-
}
|
|
1161
|
-
const e2eResult = await runCommand(command, workingDir, timeout);
|
|
1162
|
-
const e2eTime = Date.now() - startTime;
|
|
1163
|
-
if (e2eResult.exitCode === 0) {
|
|
1164
|
-
results.push(`✅ E2E tests passed (${e2eTime}ms)\n`);
|
|
1165
|
-
summary.push({ step: 'E2E Tests', status: 'PASS', time: e2eTime });
|
|
1166
|
-
}
|
|
1167
|
-
else {
|
|
1168
|
-
results.push(`❌ E2E tests failed\n${truncateOutput(e2eResult.stdout, 3000, 'E2E test output')}`);
|
|
1169
|
-
summary.push({ step: 'E2E Tests', status: 'FAIL', time: e2eTime });
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
else {
|
|
1173
|
-
results.push(`⏭️ No E2E framework detected, skipping`);
|
|
1174
|
-
summary.push({ step: 'E2E Tests', status: 'SKIP', time: 0 });
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
// Step 4: Accessibility Tests
|
|
1178
|
-
if (!skipA11y && baseUrl) {
|
|
1179
|
-
results.push(`\n━━━ Step 4: Accessibility Tests ━━━\n`);
|
|
1180
|
-
const startTime = Date.now();
|
|
1181
|
-
const a11yResult = await runCommand(`pa11y "${baseUrl}" --reporter cli 2>&1 || echo "pa11y not available"`, workingDir, 60000);
|
|
1182
|
-
const a11yTime = Date.now() - startTime;
|
|
1183
|
-
if (a11yResult.stdout.includes('pa11y not available')) {
|
|
1184
|
-
results.push(`⏭️ pa11y not installed, skipping accessibility tests`);
|
|
1185
|
-
summary.push({ step: 'Accessibility', status: 'SKIP', time: 0 });
|
|
1186
|
-
}
|
|
1187
|
-
else if (a11yResult.exitCode === 0) {
|
|
1188
|
-
results.push(`✅ No accessibility violations (${a11yTime}ms)\n`);
|
|
1189
|
-
summary.push({ step: 'Accessibility', status: 'PASS', time: a11yTime });
|
|
1190
|
-
}
|
|
1191
|
-
else {
|
|
1192
|
-
results.push(`⚠️ Accessibility issues found\n${truncateOutput(a11yResult.stdout, 2000, 'accessibility report')}`);
|
|
1193
|
-
summary.push({ step: 'Accessibility', status: 'WARN', time: a11yTime });
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
else if (!skipA11y) {
|
|
1197
|
-
results.push(`\n⏭️ Accessibility tests skipped (no baseUrl provided)`);
|
|
1198
|
-
summary.push({ step: 'Accessibility', status: 'SKIP', time: 0 });
|
|
1199
|
-
}
|
|
1200
|
-
// Step 5: Lighthouse (optional)
|
|
1201
|
-
if (runLighthouseArg && baseUrl) {
|
|
1202
|
-
results.push(`\n━━━ Step 5: Performance Audit ━━━\n`);
|
|
1203
|
-
const startTime = Date.now();
|
|
1204
|
-
const lhResult = await runCommand(`lighthouse "${baseUrl}" --output=json --quiet --chrome-flags="--headless --no-sandbox" --only-categories=performance 2>&1 || echo "lighthouse not available"`, workingDir, 120000);
|
|
1205
|
-
const lhTime = Date.now() - startTime;
|
|
1206
|
-
if (lhResult.stdout.includes('lighthouse not available')) {
|
|
1207
|
-
results.push(`⏭️ Lighthouse not installed, skipping performance audit`);
|
|
1208
|
-
summary.push({ step: 'Performance', status: 'SKIP', time: 0 });
|
|
1209
|
-
}
|
|
1210
|
-
else {
|
|
1211
|
-
const { data: report } = safeJsonParse(lhResult.stdout, 'Lighthouse report');
|
|
1212
|
-
if (report) {
|
|
1213
|
-
const perfScore = Math.round((report.categories?.performance?.score || 0) * 100);
|
|
1214
|
-
const emoji = perfScore >= 90 ? '🟢' : perfScore >= 50 ? '🟡' : '🔴';
|
|
1215
|
-
results.push(`${emoji} Performance Score: ${perfScore}/100 (${lhTime}ms)`);
|
|
1216
|
-
summary.push({
|
|
1217
|
-
step: 'Performance',
|
|
1218
|
-
status: perfScore >= 90 ? 'PASS' : perfScore >= 50 ? 'WARN' : 'FAIL',
|
|
1219
|
-
time: lhTime,
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
else {
|
|
1223
|
-
results.push(`⚠️ Could not parse Lighthouse results`);
|
|
1224
|
-
summary.push({ step: 'Performance', status: 'WARN', time: lhTime });
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
// Summary
|
|
1229
|
-
results.push(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
|
|
1230
|
-
results.push(`📋 WORKFLOW SUMMARY\n`);
|
|
1231
|
-
const passed = summary.filter((s) => s.status === 'PASS').length;
|
|
1232
|
-
const failed = summary.filter((s) => s.status === 'FAIL').length;
|
|
1233
|
-
const warned = summary.filter((s) => s.status === 'WARN').length;
|
|
1234
|
-
const skipped = summary.filter((s) => s.status === 'SKIP').length;
|
|
1235
|
-
const totalTime = summary.reduce((acc, s) => acc + s.time, 0);
|
|
1236
|
-
summary.forEach((s) => {
|
|
1237
|
-
const statusEmoji = s.status === 'PASS' ? '✅' : s.status === 'FAIL' ? '❌' : s.status === 'WARN' ? '⚠️' : '⏭️';
|
|
1238
|
-
const timeStr = s.time > 0 ? ` (${s.time}ms)` : '';
|
|
1239
|
-
results.push(`${statusEmoji} ${s.step}: ${s.status}${timeStr}`);
|
|
1240
|
-
});
|
|
1241
|
-
results.push(`\n📊 Results: ${passed} passed, ${failed} failed, ${warned} warnings, ${skipped} skipped`);
|
|
1242
|
-
results.push(`⏱️ Total time: ${totalTime}ms`);
|
|
1243
|
-
if (failed > 0) {
|
|
1244
|
-
results.push(`\n❌ WORKFLOW FAILED`);
|
|
1245
|
-
}
|
|
1246
|
-
else if (warned > 0) {
|
|
1247
|
-
results.push(`\n⚠️ WORKFLOW COMPLETED WITH WARNINGS`);
|
|
1248
|
-
}
|
|
1249
|
-
else {
|
|
1250
|
-
results.push(`\n✅ WORKFLOW PASSED`);
|
|
1251
|
-
}
|
|
1252
|
-
return results.join('\n');
|
|
1253
|
-
},
|
|
1254
|
-
},
|
|
1255
|
-
];
|
|
1256
|
-
}
|
|
1257
|
-
export { E2E_FRAMEWORKS, BUILD_CONFIGS };
|
|
1258
|
-
//# sourceMappingURL=frontendTestingTools.js.map
|