@agentic-qe/v3 3.0.0-alpha.6 → 3.0.0-alpha.7
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/assets/agents/v3/subagents/v3-qe-code-reviewer.md +339 -0
- package/assets/agents/v3/subagents/v3-qe-integration-reviewer.md +344 -0
- package/assets/agents/v3/subagents/v3-qe-performance-reviewer.md +351 -0
- package/assets/agents/v3/subagents/v3-qe-security-reviewer.md +374 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-green.md +334 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-red.md +329 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-refactor.md +361 -0
- package/assets/agents/v3/v3-qe-accessibility-auditor.md +266 -0
- package/assets/agents/v3/v3-qe-bdd-generator.md +279 -0
- package/assets/agents/v3/v3-qe-chaos-engineer.md +265 -0
- package/assets/agents/v3/v3-qe-code-complexity.md +298 -0
- package/assets/agents/v3/v3-qe-code-intelligence.md +262 -0
- package/assets/agents/v3/v3-qe-contract-validator.md +267 -0
- package/assets/agents/v3/v3-qe-coverage-specialist.md +227 -0
- package/assets/agents/v3/v3-qe-defect-predictor.md +251 -0
- package/assets/agents/v3/v3-qe-dependency-mapper.md +277 -0
- package/assets/agents/v3/v3-qe-deployment-advisor.md +275 -0
- package/assets/agents/v3/v3-qe-flaky-hunter.md +248 -0
- package/assets/agents/v3/v3-qe-fleet-commander.md +293 -0
- package/assets/agents/v3/v3-qe-gap-detector.md +260 -0
- package/assets/agents/v3/v3-qe-graphql-tester.md +308 -0
- package/assets/agents/v3/v3-qe-impact-analyzer.md +299 -0
- package/assets/agents/v3/v3-qe-integration-tester.md +238 -0
- package/assets/agents/v3/v3-qe-kg-builder.md +273 -0
- package/assets/agents/v3/v3-qe-learning-coordinator.md +226 -0
- package/assets/agents/v3/v3-qe-load-tester.md +280 -0
- package/assets/agents/v3/v3-qe-metrics-optimizer.md +300 -0
- package/assets/agents/v3/v3-qe-mutation-tester.md +301 -0
- package/assets/agents/v3/v3-qe-parallel-executor.md +240 -0
- package/assets/agents/v3/v3-qe-pattern-learner.md +271 -0
- package/assets/agents/v3/v3-qe-performance-tester.md +262 -0
- package/assets/agents/v3/v3-qe-property-tester.md +247 -0
- package/assets/agents/v3/v3-qe-quality-gate.md +218 -0
- package/assets/agents/v3/v3-qe-queen-coordinator.md +214 -0
- package/assets/agents/v3/v3-qe-qx-partner.md +313 -0
- package/assets/agents/v3/v3-qe-regression-analyzer.md +322 -0
- package/assets/agents/v3/v3-qe-requirements-validator.md +360 -0
- package/assets/agents/v3/v3-qe-responsive-tester.md +311 -0
- package/assets/agents/v3/v3-qe-retry-handler.md +256 -0
- package/assets/agents/v3/v3-qe-risk-assessor.md +273 -0
- package/assets/agents/v3/v3-qe-root-cause-analyzer.md +286 -0
- package/assets/agents/v3/v3-qe-security-auditor.md +299 -0
- package/assets/agents/v3/v3-qe-security-scanner.md +235 -0
- package/assets/agents/v3/v3-qe-tdd-specialist.md +239 -0
- package/assets/agents/v3/v3-qe-test-architect.md +233 -0
- package/assets/agents/v3/v3-qe-transfer-specialist.md +295 -0
- package/assets/agents/v3/v3-qe-visual-tester.md +232 -0
- package/assets/skills/accessibility-testing/SKILL.md +216 -0
- package/assets/skills/agentdb-advanced/SKILL.md +550 -0
- package/assets/skills/agentdb-learning/SKILL.md +545 -0
- package/assets/skills/agentdb-memory-patterns/SKILL.md +339 -0
- package/assets/skills/agentdb-optimization/SKILL.md +509 -0
- package/assets/skills/agentdb-vector-search/SKILL.md +339 -0
- package/assets/skills/agentic-jujutsu/SKILL.md +645 -0
- package/assets/skills/agentic-quality-engineering/SKILL.md +335 -0
- package/assets/skills/api-testing-patterns/SKILL.md +294 -0
- package/assets/skills/aqe-v2-v3-migration/skill.md +322 -0
- package/assets/skills/brutal-honesty-review/README.md +218 -0
- package/assets/skills/brutal-honesty-review/SKILL.md +235 -0
- package/assets/skills/brutal-honesty-review/resources/assessment-rubrics.md +295 -0
- package/assets/skills/brutal-honesty-review/resources/review-template.md +102 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-code.sh +179 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-tests.sh +223 -0
- package/assets/skills/bug-reporting-excellence/SKILL.md +225 -0
- package/assets/skills/chaos-engineering-resilience/SKILL.md +158 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/README.md +304 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/SKILL.md +315 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/microservice-pipeline.md +239 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/mobile-pipeline.md +375 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/monolith-pipeline.md +268 -0
- package/assets/skills/code-review-quality/SKILL.md +227 -0
- package/assets/skills/compatibility-testing/SKILL.md +205 -0
- package/assets/skills/compliance-testing/SKILL.md +225 -0
- package/assets/skills/consultancy-practices/SKILL.md +202 -0
- package/assets/skills/context-driven-testing/SKILL.md +196 -0
- package/assets/skills/contract-testing/SKILL.md +222 -0
- package/assets/skills/database-testing/SKILL.md +244 -0
- package/assets/skills/exploratory-testing-advanced/SKILL.md +201 -0
- package/assets/skills/flow-nexus-neural/SKILL.md +738 -0
- package/assets/skills/flow-nexus-platform/SKILL.md +1157 -0
- package/assets/skills/flow-nexus-swarm/SKILL.md +610 -0
- package/assets/skills/github-code-review/SKILL.md +1140 -0
- package/assets/skills/github-multi-repo/SKILL.md +874 -0
- package/assets/skills/github-project-management/SKILL.md +1277 -0
- package/assets/skills/github-release-management/SKILL.md +1081 -0
- package/assets/skills/github-workflow-automation/SKILL.md +1065 -0
- package/assets/skills/hive-mind-advanced/SKILL.md +712 -0
- package/assets/skills/holistic-testing-pact/SKILL.md +171 -0
- package/assets/skills/hooks-automation/SKILL.md +1201 -0
- package/assets/skills/localization-testing/SKILL.md +221 -0
- package/assets/skills/mobile-testing/SKILL.md +219 -0
- package/assets/skills/mutation-testing/SKILL.md +229 -0
- package/assets/skills/n8n-expression-testing/SKILL.md +434 -0
- package/assets/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
- package/assets/skills/n8n-security-testing/SKILL.md +599 -0
- package/assets/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
- package/assets/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
- package/assets/skills/pair-programming/SKILL.md +1202 -0
- package/assets/skills/performance-analysis/SKILL.md +563 -0
- package/assets/skills/performance-testing/SKILL.md +310 -0
- package/assets/skills/quality-metrics/SKILL.md +225 -0
- package/assets/skills/reasoningbank-agentdb/SKILL.md +446 -0
- package/assets/skills/reasoningbank-intelligence/SKILL.md +201 -0
- package/assets/skills/refactoring-patterns/SKILL.md +205 -0
- package/assets/skills/regression-testing/SKILL.md +227 -0
- package/assets/skills/risk-based-testing/SKILL.md +206 -0
- package/assets/skills/security-testing/SKILL.md +306 -0
- package/assets/skills/sherlock-review/SKILL.md +250 -0
- package/assets/skills/shift-left-testing/SKILL.md +225 -0
- package/assets/skills/shift-right-testing/SKILL.md +227 -0
- package/assets/skills/six-thinking-hats/README.md +190 -0
- package/assets/skills/six-thinking-hats/SKILL.md +280 -0
- package/assets/skills/six-thinking-hats/resources/examples/api-testing-example.md +345 -0
- package/assets/skills/six-thinking-hats/resources/templates/solo-session-template.md +167 -0
- package/assets/skills/six-thinking-hats/resources/templates/team-session-template.md +336 -0
- package/assets/skills/skill-builder/SKILL.md +910 -0
- package/assets/skills/sparc-methodology/SKILL.md +1115 -0
- package/assets/skills/stream-chain/SKILL.md +563 -0
- package/assets/skills/swarm-advanced/SKILL.md +973 -0
- package/assets/skills/swarm-orchestration/SKILL.md +179 -0
- package/assets/skills/tdd-london-chicago/SKILL.md +244 -0
- package/assets/skills/technical-writing/SKILL.md +178 -0
- package/assets/skills/test-automation-strategy/SKILL.md +230 -0
- package/assets/skills/test-data-management/SKILL.md +270 -0
- package/assets/skills/test-design-techniques/SKILL.md +244 -0
- package/assets/skills/test-environment-management/SKILL.md +243 -0
- package/assets/skills/test-reporting-analytics/SKILL.md +214 -0
- package/assets/skills/testability-scoring/README.md +71 -0
- package/assets/skills/testability-scoring/SKILL.md +346 -0
- package/assets/skills/testability-scoring/resources/templates/config.template.js +84 -0
- package/assets/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
- package/assets/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
- package/assets/skills/testability-scoring/scripts/run-assessment.sh +70 -0
- package/assets/skills/v3-qe-chaos-resilience/SKILL.md +238 -0
- package/assets/skills/v3-qe-code-intelligence/SKILL.md +209 -0
- package/assets/skills/v3-qe-contract-testing/SKILL.md +218 -0
- package/assets/skills/v3-qe-coverage-analysis/SKILL.md +187 -0
- package/assets/skills/v3-qe-defect-intelligence/SKILL.md +205 -0
- package/assets/skills/v3-qe-learning-optimization/SKILL.md +238 -0
- package/assets/skills/v3-qe-quality-assessment/SKILL.md +213 -0
- package/assets/skills/v3-qe-requirements-validation/SKILL.md +248 -0
- package/assets/skills/v3-qe-test-execution/SKILL.md +182 -0
- package/assets/skills/v3-qe-test-generation/SKILL.md +141 -0
- package/assets/skills/v3-qe-visual-accessibility/SKILL.md +242 -0
- package/assets/skills/verification-quality/SKILL.md +649 -0
- package/assets/skills/visual-testing-advanced/SKILL.md +219 -0
- package/assets/skills/xp-practices/SKILL.md +229 -0
- package/dist/cli/bundle.js +8 -8
- package/dist/init/agents-installer.js +4 -4
- package/dist/init/agents-installer.js.map +1 -1
- package/dist/init/skills-installer.js +4 -4
- package/dist/init/skills-installer.js.map +1 -1
- package/package.json +7 -1
- package/docs/analysis/V3-INIT-REQUIREMENTS-ANALYSIS.md +0 -352
- package/implementation/README.md +0 -90
- package/implementation/adrs/ADR-030-coherence-gated-quality-gates.md +0 -312
- package/implementation/adrs/ADR-031-strange-loop-self-awareness.md +0 -484
- package/implementation/adrs/ADR-032-time-crystal-scheduling.md +0 -530
- package/implementation/adrs/ADR-033-early-exit-testing.md +0 -634
- package/implementation/adrs/ADR-034-neural-topology-optimizer.md +0 -589
- package/implementation/adrs/ADR-035-causal-discovery.md +0 -610
- package/implementation/adrs/ADR-036-result-persistence.md +0 -326
- package/implementation/adrs/ADR-037-v3-qe-agent-naming.md +0 -105
- package/implementation/adrs/ADR-038-v3-qe-memory-unification.md +0 -154
- package/implementation/adrs/ADR-039-v3-qe-mcp-optimization.md +0 -179
- package/implementation/adrs/ADR-040-v3-qe-agentic-flow-integration.md +0 -240
- package/implementation/adrs/ADR-041-v3-qe-cli-enhancement.md +0 -296
- package/implementation/adrs/ADR-042-v3-qe-token-tracking-integration.md +0 -517
- package/implementation/adrs/v3-adrs.md +0 -2783
- package/implementation/planning/AQE-V3-MASTER-PLAN.md +0 -815
- package/security-scan-report-2026-01-11.md +0 -410
- package/security-verification-report-2026-01-11.md +0 -278
- package/src/benchmarks/performance-benchmarks.ts +0 -646
- package/src/benchmarks/run-benchmarks.ts +0 -324
- package/src/causal-discovery/causal-graph.ts +0 -450
- package/src/causal-discovery/discovery-engine.ts +0 -438
- package/src/causal-discovery/index.ts +0 -117
- package/src/causal-discovery/types.ts +0 -456
- package/src/causal-discovery/weight-matrix.ts +0 -453
- package/src/cli/commands/qe-tools.ts +0 -634
- package/src/cli/index.ts +0 -1976
- package/src/compatibility/agent-mapper.ts +0 -291
- package/src/compatibility/cli-adapter.ts +0 -277
- package/src/compatibility/config-migrator.ts +0 -334
- package/src/compatibility/index.ts +0 -112
- package/src/compatibility/mcp-adapter.ts +0 -248
- package/src/compatibility/types.ts +0 -156
- package/src/coordination/claims/claim-repository.ts +0 -636
- package/src/coordination/claims/claim-service.ts +0 -675
- package/src/coordination/claims/handoff-manager.ts +0 -535
- package/src/coordination/claims/index.ts +0 -276
- package/src/coordination/claims/interfaces.ts +0 -687
- package/src/coordination/claims/work-stealing.ts +0 -436
- package/src/coordination/cross-domain-router.ts +0 -492
- package/src/coordination/index.ts +0 -127
- package/src/coordination/interfaces.ts +0 -691
- package/src/coordination/protocol-executor.ts +0 -760
- package/src/coordination/protocols/code-intelligence-index.ts +0 -855
- package/src/coordination/protocols/defect-investigation.ts +0 -1184
- package/src/coordination/protocols/index.ts +0 -11
- package/src/coordination/protocols/learning-consolidation.ts +0 -1181
- package/src/coordination/protocols/morning-sync.ts +0 -1055
- package/src/coordination/protocols/quality-gate.ts +0 -1566
- package/src/coordination/protocols/security-audit.ts +0 -1587
- package/src/coordination/queen-coordinator.ts +0 -1176
- package/src/coordination/result-saver.ts +0 -780
- package/src/coordination/task-executor.ts +0 -1146
- package/src/coordination/workflow-orchestrator.ts +0 -1917
- package/src/domains/chaos-resilience/coordinator.ts +0 -1032
- package/src/domains/chaos-resilience/index.ts +0 -143
- package/src/domains/chaos-resilience/interfaces.ts +0 -659
- package/src/domains/chaos-resilience/plugin.ts +0 -691
- package/src/domains/chaos-resilience/services/chaos-engineer.ts +0 -1097
- package/src/domains/chaos-resilience/services/index.ts +0 -19
- package/src/domains/chaos-resilience/services/load-tester.ts +0 -799
- package/src/domains/chaos-resilience/services/performance-profiler.ts +0 -792
- package/src/domains/code-intelligence/coordinator.ts +0 -631
- package/src/domains/code-intelligence/index.ts +0 -86
- package/src/domains/code-intelligence/interfaces.ts +0 -162
- package/src/domains/code-intelligence/plugin.ts +0 -451
- package/src/domains/code-intelligence/services/impact-analyzer.ts +0 -567
- package/src/domains/code-intelligence/services/index.ts +0 -26
- package/src/domains/code-intelligence/services/knowledge-graph.ts +0 -1067
- package/src/domains/code-intelligence/services/semantic-analyzer.ts +0 -901
- package/src/domains/contract-testing/coordinator.ts +0 -1038
- package/src/domains/contract-testing/index.ts +0 -122
- package/src/domains/contract-testing/interfaces.ts +0 -458
- package/src/domains/contract-testing/plugin.ts +0 -746
- package/src/domains/contract-testing/services/api-compatibility.ts +0 -748
- package/src/domains/contract-testing/services/contract-validator.ts +0 -1700
- package/src/domains/contract-testing/services/index.ts +0 -19
- package/src/domains/contract-testing/services/schema-validator.ts +0 -1102
- package/src/domains/coverage-analysis/coordinator.ts +0 -485
- package/src/domains/coverage-analysis/index.ts +0 -114
- package/src/domains/coverage-analysis/interfaces.ts +0 -142
- package/src/domains/coverage-analysis/plugin.ts +0 -172
- package/src/domains/coverage-analysis/services/coverage-analyzer.ts +0 -449
- package/src/domains/coverage-analysis/services/coverage-embedder.ts +0 -733
- package/src/domains/coverage-analysis/services/coverage-parser.ts +0 -753
- package/src/domains/coverage-analysis/services/gap-detector.ts +0 -592
- package/src/domains/coverage-analysis/services/hnsw-index.ts +0 -728
- package/src/domains/coverage-analysis/services/index.ts +0 -61
- package/src/domains/coverage-analysis/services/risk-scorer.ts +0 -540
- package/src/domains/coverage-analysis/services/sublinear-analyzer.ts +0 -747
- package/src/domains/defect-intelligence/coordinator.ts +0 -635
- package/src/domains/defect-intelligence/index.ts +0 -83
- package/src/domains/defect-intelligence/interfaces.ts +0 -152
- package/src/domains/defect-intelligence/plugin.ts +0 -483
- package/src/domains/defect-intelligence/services/causal-root-cause-analyzer.ts +0 -494
- package/src/domains/defect-intelligence/services/defect-predictor.ts +0 -852
- package/src/domains/defect-intelligence/services/index.ts +0 -37
- package/src/domains/defect-intelligence/services/pattern-learner.ts +0 -738
- package/src/domains/defect-intelligence/services/root-cause-analyzer.ts +0 -637
- package/src/domains/domain-interface.ts +0 -77
- package/src/domains/index.ts +0 -23
- package/src/domains/learning-optimization/coordinator.ts +0 -1215
- package/src/domains/learning-optimization/index.ts +0 -127
- package/src/domains/learning-optimization/interfaces.ts +0 -570
- package/src/domains/learning-optimization/plugin.ts +0 -851
- package/src/domains/learning-optimization/services/index.ts +0 -29
- package/src/domains/learning-optimization/services/learning-coordinator.ts +0 -972
- package/src/domains/learning-optimization/services/metrics-optimizer.ts +0 -915
- package/src/domains/learning-optimization/services/production-intel.ts +0 -971
- package/src/domains/learning-optimization/services/transfer-specialist.ts +0 -723
- package/src/domains/quality-assessment/coherence/gate-controller.ts +0 -549
- package/src/domains/quality-assessment/coherence/index.ts +0 -211
- package/src/domains/quality-assessment/coherence/lambda-calculator.ts +0 -384
- package/src/domains/quality-assessment/coherence/partition-detector.ts +0 -469
- package/src/domains/quality-assessment/coherence/types.ts +0 -384
- package/src/domains/quality-assessment/coordinator.ts +0 -605
- package/src/domains/quality-assessment/index.ts +0 -97
- package/src/domains/quality-assessment/interfaces.ts +0 -152
- package/src/domains/quality-assessment/plugin.ts +0 -496
- package/src/domains/quality-assessment/services/coherence-gate.ts +0 -358
- package/src/domains/quality-assessment/services/deployment-advisor.ts +0 -571
- package/src/domains/quality-assessment/services/index.ts +0 -34
- package/src/domains/quality-assessment/services/quality-analyzer.ts +0 -670
- package/src/domains/quality-assessment/services/quality-gate.ts +0 -384
- package/src/domains/requirements-validation/coordinator.ts +0 -812
- package/src/domains/requirements-validation/index.ts +0 -92
- package/src/domains/requirements-validation/interfaces.ts +0 -303
- package/src/domains/requirements-validation/plugin.ts +0 -576
- package/src/domains/requirements-validation/services/bdd-scenario-writer.ts +0 -676
- package/src/domains/requirements-validation/services/index.ts +0 -20
- package/src/domains/requirements-validation/services/requirements-validator.ts +0 -559
- package/src/domains/requirements-validation/services/testability-scorer.ts +0 -639
- package/src/domains/security-compliance/coordinator.ts +0 -757
- package/src/domains/security-compliance/index.ts +0 -120
- package/src/domains/security-compliance/interfaces.ts +0 -434
- package/src/domains/security-compliance/plugin.ts +0 -509
- package/src/domains/security-compliance/services/compliance-validator.ts +0 -1226
- package/src/domains/security-compliance/services/index.ts +0 -31
- package/src/domains/security-compliance/services/security-auditor.ts +0 -2227
- package/src/domains/security-compliance/services/security-scanner.ts +0 -2354
- package/src/domains/security-compliance/services/semgrep-integration.ts +0 -289
- package/src/domains/test-execution/coordinator.ts +0 -426
- package/src/domains/test-execution/index.ts +0 -76
- package/src/domains/test-execution/interfaces.ts +0 -119
- package/src/domains/test-execution/plugin.ts +0 -208
- package/src/domains/test-execution/services/flaky-detector.ts +0 -1240
- package/src/domains/test-execution/services/index.ts +0 -8
- package/src/domains/test-execution/services/retry-handler.ts +0 -820
- package/src/domains/test-execution/services/test-executor.ts +0 -885
- package/src/domains/test-generation/coordinator.ts +0 -656
- package/src/domains/test-generation/index.ts +0 -77
- package/src/domains/test-generation/interfaces.ts +0 -118
- package/src/domains/test-generation/plugin.ts +0 -397
- package/src/domains/test-generation/services/index.ts +0 -23
- package/src/domains/test-generation/services/pattern-matcher.ts +0 -1725
- package/src/domains/test-generation/services/test-generator.ts +0 -2750
- package/src/domains/visual-accessibility/coordinator.ts +0 -860
- package/src/domains/visual-accessibility/index.ts +0 -116
- package/src/domains/visual-accessibility/interfaces.ts +0 -435
- package/src/domains/visual-accessibility/plugin.ts +0 -568
- package/src/domains/visual-accessibility/services/accessibility-tester.ts +0 -982
- package/src/domains/visual-accessibility/services/axe-core-audit.ts +0 -630
- package/src/domains/visual-accessibility/services/index.ts +0 -28
- package/src/domains/visual-accessibility/services/responsive-tester.ts +0 -934
- package/src/domains/visual-accessibility/services/visual-tester.ts +0 -458
- package/src/early-exit/early-exit-controller.ts +0 -490
- package/src/early-exit/early-exit-decision.ts +0 -391
- package/src/early-exit/index.ts +0 -115
- package/src/early-exit/quality-signal.ts +0 -389
- package/src/early-exit/speculative-executor.ts +0 -505
- package/src/early-exit/types.ts +0 -407
- package/src/feedback/coverage-learner.ts +0 -456
- package/src/feedback/feedback-loop.ts +0 -426
- package/src/feedback/index.ts +0 -72
- package/src/feedback/pattern-promotion.ts +0 -373
- package/src/feedback/quality-score-calculator.ts +0 -334
- package/src/feedback/test-outcome-tracker.ts +0 -450
- package/src/feedback/types.ts +0 -497
- package/src/index.ts +0 -224
- package/src/init/agents-installer.ts +0 -536
- package/src/init/index.ts +0 -80
- package/src/init/init-wizard.ts +0 -1061
- package/src/init/project-analyzer.ts +0 -696
- package/src/init/self-configurator.ts +0 -488
- package/src/init/skills-installer.ts +0 -467
- package/src/init/types.ts +0 -432
- package/src/integrations/ruvector/ast-complexity.ts +0 -470
- package/src/integrations/ruvector/coverage-router.ts +0 -594
- package/src/integrations/ruvector/diff-risk-classifier.ts +0 -759
- package/src/integrations/ruvector/fallback.ts +0 -942
- package/src/integrations/ruvector/graph-boundaries.ts +0 -809
- package/src/integrations/ruvector/index.ts +0 -363
- package/src/integrations/ruvector/interfaces.ts +0 -609
- package/src/integrations/ruvector/q-learning-router.ts +0 -550
- package/src/kernel/agent-coordinator.ts +0 -165
- package/src/kernel/agentdb-backend.ts +0 -504
- package/src/kernel/event-bus.ts +0 -129
- package/src/kernel/hybrid-backend.ts +0 -538
- package/src/kernel/index.ts +0 -28
- package/src/kernel/interfaces.ts +0 -257
- package/src/kernel/kernel.ts +0 -285
- package/src/kernel/memory-backend.ts +0 -169
- package/src/kernel/memory-factory.ts +0 -293
- package/src/kernel/plugin-loader.ts +0 -179
- package/src/learning/index.ts +0 -219
- package/src/learning/pattern-store.ts +0 -990
- package/src/learning/qe-guidance.ts +0 -832
- package/src/learning/qe-hooks.ts +0 -644
- package/src/learning/qe-patterns.ts +0 -449
- package/src/learning/qe-reasoning-bank.ts +0 -951
- package/src/learning/real-embeddings.ts +0 -277
- package/src/learning/real-qe-reasoning-bank.ts +0 -833
- package/src/learning/sqlite-persistence.ts +0 -554
- package/src/mcp/entry.ts +0 -59
- package/src/mcp/handlers/agent-handlers.ts +0 -285
- package/src/mcp/handlers/core-handlers.ts +0 -317
- package/src/mcp/handlers/domain-handlers.ts +0 -1444
- package/src/mcp/handlers/index.ts +0 -57
- package/src/mcp/handlers/memory-handlers.ts +0 -338
- package/src/mcp/handlers/task-handlers.ts +0 -363
- package/src/mcp/index.ts +0 -30
- package/src/mcp/metrics/index.ts +0 -14
- package/src/mcp/metrics/metrics-collector.ts +0 -503
- package/src/mcp/protocol-server.ts +0 -752
- package/src/mcp/security/cve-prevention.ts +0 -742
- package/src/mcp/security/index.ts +0 -356
- package/src/mcp/security/oauth21-provider.ts +0 -821
- package/src/mcp/security/rate-limiter.ts +0 -615
- package/src/mcp/security/sampling-server.ts +0 -662
- package/src/mcp/security/schema-validator.ts +0 -855
- package/src/mcp/server.ts +0 -657
- package/src/mcp/tool-registry.ts +0 -391
- package/src/mcp/tools/base.ts +0 -399
- package/src/mcp/tools/chaos-resilience/inject.ts +0 -699
- package/src/mcp/tools/code-intelligence/analyze.ts +0 -745
- package/src/mcp/tools/contract-testing/validate.ts +0 -708
- package/src/mcp/tools/coverage-analysis/index.ts +0 -770
- package/src/mcp/tools/defect-intelligence/predict.ts +0 -466
- package/src/mcp/tools/index.ts +0 -214
- package/src/mcp/tools/learning-optimization/optimize.ts +0 -772
- package/src/mcp/tools/quality-assessment/evaluate.ts +0 -385
- package/src/mcp/tools/registry.ts +0 -248
- package/src/mcp/tools/requirements-validation/validate.ts +0 -394
- package/src/mcp/tools/security-compliance/scan.ts +0 -365
- package/src/mcp/tools/test-execution/execute.ts +0 -291
- package/src/mcp/tools/test-generation/generate.ts +0 -544
- package/src/mcp/tools/visual-accessibility/index.ts +0 -791
- package/src/mcp/transport/index.ts +0 -31
- package/src/mcp/transport/stdio.ts +0 -318
- package/src/mcp/types.ts +0 -543
- package/src/neural-optimizer/index.ts +0 -111
- package/src/neural-optimizer/replay-buffer.ts +0 -455
- package/src/neural-optimizer/swarm-topology.ts +0 -508
- package/src/neural-optimizer/topology-optimizer.ts +0 -828
- package/src/neural-optimizer/types.ts +0 -481
- package/src/neural-optimizer/value-network.ts +0 -351
- package/src/optimization/auto-tuner.ts +0 -817
- package/src/optimization/index.ts +0 -77
- package/src/optimization/metric-collectors.ts +0 -474
- package/src/optimization/qe-workers.ts +0 -704
- package/src/optimization/tuning-algorithm.ts +0 -401
- package/src/optimization/types.ts +0 -314
- package/src/routing/index.ts +0 -51
- package/src/routing/qe-agent-registry.ts +0 -963
- package/src/routing/qe-task-router.ts +0 -564
- package/src/routing/routing-feedback.ts +0 -365
- package/src/routing/types.ts +0 -406
- package/src/shared/embeddings/embedding-cache.ts +0 -157
- package/src/shared/embeddings/index.ts +0 -50
- package/src/shared/embeddings/nomic-embedder.ts +0 -404
- package/src/shared/embeddings/ollama-client.ts +0 -195
- package/src/shared/embeddings/types.ts +0 -147
- package/src/shared/entities/agent.ts +0 -141
- package/src/shared/entities/base-entity.ts +0 -79
- package/src/shared/entities/index.ts +0 -6
- package/src/shared/events/domain-events.ts +0 -259
- package/src/shared/events/index.ts +0 -5
- package/src/shared/git/git-analyzer.ts +0 -656
- package/src/shared/git/index.ts +0 -11
- package/src/shared/http/http-client.ts +0 -420
- package/src/shared/http/index.ts +0 -13
- package/src/shared/index.ts +0 -41
- package/src/shared/io/file-reader.ts +0 -525
- package/src/shared/io/index.ts +0 -25
- package/src/shared/llm/cache.ts +0 -473
- package/src/shared/llm/circuit-breaker.ts +0 -369
- package/src/shared/llm/cost-tracker.ts +0 -460
- package/src/shared/llm/index.ts +0 -140
- package/src/shared/llm/interfaces.ts +0 -629
- package/src/shared/llm/provider-manager.ts +0 -685
- package/src/shared/llm/providers/claude.ts +0 -524
- package/src/shared/llm/providers/index.ts +0 -8
- package/src/shared/llm/providers/ollama.ts +0 -575
- package/src/shared/llm/providers/openai.ts +0 -609
- package/src/shared/metrics/code-metrics.ts +0 -520
- package/src/shared/metrics/index.ts +0 -23
- package/src/shared/metrics/system-metrics.ts +0 -353
- package/src/shared/parsers/index.ts +0 -6
- package/src/shared/parsers/typescript-parser.ts +0 -841
- package/src/shared/security/compliance-patterns.ts +0 -666
- package/src/shared/security/index.ts +0 -30
- package/src/shared/security/osv-client.ts +0 -468
- package/src/shared/types/index.ts +0 -150
- package/src/shared/value-objects/index.ts +0 -273
- package/src/strange-loop/healing-controller.ts +0 -833
- package/src/strange-loop/index.ts +0 -104
- package/src/strange-loop/self-model.ts +0 -494
- package/src/strange-loop/strange-loop.ts +0 -446
- package/src/strange-loop/swarm-observer.ts +0 -448
- package/src/strange-loop/topology-analyzer.ts +0 -565
- package/src/strange-loop/types.ts +0 -640
- package/src/time-crystal/default-phases.ts +0 -520
- package/src/time-crystal/index.ts +0 -164
- package/src/time-crystal/oscillator.ts +0 -425
- package/src/time-crystal/phase-executor.ts +0 -521
- package/src/time-crystal/scheduler.ts +0 -1025
- package/src/time-crystal/test-runner.ts +0 -787
- package/src/time-crystal/types.ts +0 -421
- package/src/workers/base-worker.ts +0 -304
- package/src/workers/daemon.ts +0 -264
- package/src/workers/index.ts +0 -119
- package/src/workers/interfaces.ts +0 -393
- package/src/workers/worker-manager.ts +0 -424
- package/src/workers/workers/compliance-checker.ts +0 -445
- package/src/workers/workers/coverage-tracker.ts +0 -344
- package/src/workers/workers/defect-predictor.ts +0 -375
- package/src/workers/workers/flaky-detector.ts +0 -390
- package/src/workers/workers/index.ts +0 -17
- package/src/workers/workers/learning-consolidation.ts +0 -442
- package/src/workers/workers/performance-baseline.ts +0 -434
- package/src/workers/workers/quality-gate.ts +0 -419
- package/src/workers/workers/regression-monitor.ts +0 -357
- package/src/workers/workers/security-scan.ts +0 -349
- package/src/workers/workers/test-health.ts +0 -359
- package/tests/integration/code-intelligence/knowledge-graph-real.test.ts +0 -540
- package/tests/integration/coordination/cross-domain-router.test.ts +0 -403
- package/tests/integration/coordination/protocol-executor.test.ts +0 -454
- package/tests/integration/coordination/workflow-orchestrator.test.ts +0 -418
- package/tests/integration/feedback/feedback-loop-integration.test.ts +0 -560
- package/tests/integration/migration/v2-to-v3-migration.test.ts +0 -471
- package/tests/integration/parsers/typescript-parser.test.ts +0 -463
- package/tests/integration/security/vulnerability-detection.test.ts +0 -628
- package/tests/integration/test-execution/coordinator.test.ts +0 -410
- package/tests/integration/test-generation/coordinator.test.ts +0 -361
- package/tests/mocks/index.ts +0 -228
- package/tests/time-crystal/default-phases.test.ts +0 -476
- package/tests/time-crystal/oscillator.test.ts +0 -541
- package/tests/time-crystal/phase-executor.test.ts +0 -653
- package/tests/time-crystal/scheduler.test.ts +0 -626
- package/tests/time-crystal/test-runner.test.ts +0 -594
- package/tests/unit/causal-discovery/causal-graph.test.ts +0 -504
- package/tests/unit/causal-discovery/causal-root-cause-analyzer.test.ts +0 -347
- package/tests/unit/causal-discovery/discovery-engine.test.ts +0 -435
- package/tests/unit/causal-discovery/weight-matrix.test.ts +0 -328
- package/tests/unit/cli/cli.test.ts +0 -341
- package/tests/unit/cli/commands.test.ts +0 -414
- package/tests/unit/cli/init-command.test.ts +0 -274
- package/tests/unit/cli/migrate-command.test.ts +0 -396
- package/tests/unit/coordination/claims/claim-service.test.ts +0 -949
- package/tests/unit/coordination/claims/handoff-manager.test.ts +0 -773
- package/tests/unit/coordination/claims/work-stealing.test.ts +0 -492
- package/tests/unit/coordination/queen-coordinator.test.ts +0 -966
- package/tests/unit/coordination/result-saver.test.ts +0 -653
- package/tests/unit/coordination/task-executor.test.ts +0 -810
- package/tests/unit/domains/chaos-resilience/chaos-engineer.test.ts +0 -484
- package/tests/unit/domains/chaos-resilience/load-tester.test.ts +0 -559
- package/tests/unit/domains/chaos-resilience/performance-profiler.test.ts +0 -490
- package/tests/unit/domains/code-intelligence/impact-analyzer.test.ts +0 -560
- package/tests/unit/domains/code-intelligence/knowledge-graph.test.ts +0 -460
- package/tests/unit/domains/code-intelligence/semantic-analyzer.test.ts +0 -584
- package/tests/unit/domains/contract-testing/api-compatibility.test.ts +0 -483
- package/tests/unit/domains/contract-testing/contract-validator.test.ts +0 -370
- package/tests/unit/domains/contract-testing/schema-validator.test.ts +0 -610
- package/tests/unit/domains/coverage-analysis/coverage-embedder.test.ts +0 -298
- package/tests/unit/domains/coverage-analysis/hnsw-index.test.ts +0 -292
- package/tests/unit/domains/coverage-analysis/sublinear-analyzer.test.ts +0 -506
- package/tests/unit/domains/defect-intelligence/defect-predictor.test.ts +0 -370
- package/tests/unit/domains/defect-intelligence/pattern-learner.test.ts +0 -546
- package/tests/unit/domains/defect-intelligence/root-cause-analyzer.test.ts +0 -534
- package/tests/unit/domains/learning-optimization/learning-coordinator.test.ts +0 -541
- package/tests/unit/domains/learning-optimization/metrics-optimizer.test.ts +0 -552
- package/tests/unit/domains/learning-optimization/production-intel.test.ts +0 -589
- package/tests/unit/domains/learning-optimization/transfer-specialist.test.ts +0 -453
- package/tests/unit/domains/quality-assessment/coherence-gate.test.ts +0 -1006
- package/tests/unit/domains/quality-assessment/deployment-advisor.test.ts +0 -515
- package/tests/unit/domains/quality-assessment/quality-analyzer.test.ts +0 -401
- package/tests/unit/domains/quality-assessment/quality-gate.test.ts +0 -324
- package/tests/unit/domains/requirements-validation/bdd-scenario-writer.test.ts +0 -479
- package/tests/unit/domains/requirements-validation/requirements-validator.test.ts +0 -452
- package/tests/unit/domains/requirements-validation/testability-scorer.test.ts +0 -505
- package/tests/unit/domains/security-compliance/compliance-validator.test.ts +0 -500
- package/tests/unit/domains/security-compliance/security-auditor.test.ts +0 -498
- package/tests/unit/domains/security-compliance/security-scanner.test.ts +0 -412
- package/tests/unit/domains/visual-accessibility/accessibility-tester.test.ts +0 -432
- package/tests/unit/domains/visual-accessibility/responsive-tester.test.ts +0 -506
- package/tests/unit/domains/visual-accessibility/visual-tester.test.ts +0 -412
- package/tests/unit/early-exit/early-exit-controller.test.ts +0 -548
- package/tests/unit/early-exit/early-exit-decision.test.ts +0 -617
- package/tests/unit/early-exit/index.test.ts +0 -254
- package/tests/unit/early-exit/quality-signal.test.ts +0 -589
- package/tests/unit/early-exit/speculative-executor.test.ts +0 -453
- package/tests/unit/feedback/coverage-learner.test.ts +0 -288
- package/tests/unit/feedback/feedback-loop.test.ts +0 -458
- package/tests/unit/feedback/pattern-promotion.test.ts +0 -390
- package/tests/unit/feedback/quality-score-calculator.test.ts +0 -364
- package/tests/unit/feedback/test-outcome-tracker.test.ts +0 -243
- package/tests/unit/init/init-wizard.test.ts +0 -881
- package/tests/unit/init/project-analyzer.test.ts +0 -807
- package/tests/unit/init/self-configurator.test.ts +0 -493
- package/tests/unit/integrations/ruvector/ast-complexity.test.ts +0 -240
- package/tests/unit/integrations/ruvector/coverage-router.test.ts +0 -366
- package/tests/unit/integrations/ruvector/diff-risk-classifier.test.ts +0 -340
- package/tests/unit/integrations/ruvector/graph-boundaries.test.ts +0 -355
- package/tests/unit/integrations/ruvector/q-learning-router.test.ts +0 -314
- package/tests/unit/kernel/agent-coordinator.test.ts +0 -220
- package/tests/unit/kernel/event-bus.test.ts +0 -197
- package/tests/unit/learning/qe-reasoning-bank.test.ts +0 -666
- package/tests/unit/learning/real-qe-reasoning-bank.benchmark.test.ts +0 -415
- package/tests/unit/mcp/mcp-server.test.ts +0 -544
- package/tests/unit/mcp/metrics/metrics-collector.test.ts +0 -340
- package/tests/unit/mcp/security/cve-prevention.test.ts +0 -512
- package/tests/unit/mcp/security/oauth21-provider.test.ts +0 -624
- package/tests/unit/mcp/security/rate-limiter.test.ts +0 -410
- package/tests/unit/mcp/security/sampling-server.test.ts +0 -420
- package/tests/unit/mcp/security/schema-validator.test.ts +0 -494
- package/tests/unit/mcp/tools/base.test.ts +0 -336
- package/tests/unit/mcp/tools/domain-tools.test.ts +0 -759
- package/tests/unit/mcp/tools/registry.test.ts +0 -240
- package/tests/unit/neural-optimizer/replay-buffer.test.ts +0 -403
- package/tests/unit/neural-optimizer/swarm-topology.test.ts +0 -473
- package/tests/unit/neural-optimizer/topology-optimizer.test.ts +0 -595
- package/tests/unit/neural-optimizer/value-network.test.ts +0 -343
- package/tests/unit/optimization/auto-tuner.test.ts +0 -506
- package/tests/unit/optimization/metric-collectors.test.ts +0 -352
- package/tests/unit/optimization/qe-workers.test.ts +0 -407
- package/tests/unit/optimization/tuning-algorithm.test.ts +0 -467
- package/tests/unit/routing/qe-agent-registry.test.ts +0 -229
- package/tests/unit/routing/qe-task-router.test.ts +0 -390
- package/tests/unit/routing/routing-feedback.test.ts +0 -339
- package/tests/unit/shared/embeddings/nomic-embedder.test.ts +0 -419
- package/tests/unit/shared/http/http-client.test.ts +0 -719
- package/tests/unit/shared/io/file-reader.test.ts +0 -511
- package/tests/unit/shared/llm/cache.test.ts +0 -391
- package/tests/unit/shared/llm/circuit-breaker.test.ts +0 -293
- package/tests/unit/shared/llm/cost-tracker.test.ts +0 -431
- package/tests/unit/shared/llm/provider-manager.test.ts +0 -550
- package/tests/unit/shared/llm/providers.test.ts +0 -532
- package/tests/unit/shared/parsers/typescript-parser.test.ts +0 -693
- package/tests/unit/shared/value-objects.test.ts +0 -184
- package/tests/unit/strange-loop/strange-loop.test.ts +0 -1170
- package/tests/unit/workers/base-worker.test.ts +0 -341
- package/tests/unit/workers/daemon.test.ts +0 -291
- package/tests/unit/workers/worker-manager.test.ts +0 -284
- package/tsconfig.json +0 -32
- package/vitest.config.ts +0 -27
|
@@ -1,1240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agentic QE v3 - Flaky Test Detector Service
|
|
3
|
-
* Identifies and analyzes flaky tests from execution history
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
7
|
-
import { spawn } from 'child_process';
|
|
8
|
-
import * as path from 'path';
|
|
9
|
-
import * as fs from 'fs';
|
|
10
|
-
import { Result, ok, err } from '../../../shared/types';
|
|
11
|
-
import {
|
|
12
|
-
FlakyDetectionRequest,
|
|
13
|
-
FlakyTestReport,
|
|
14
|
-
FlakyTest,
|
|
15
|
-
} from '../interfaces';
|
|
16
|
-
import { MemoryBackend } from '../../../kernel/interfaces';
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Configuration
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Configuration for the flaky detector service
|
|
24
|
-
*/
|
|
25
|
-
export interface FlakyDetectorConfig {
|
|
26
|
-
/**
|
|
27
|
-
* When true, simulates test execution with random outcomes (for unit testing).
|
|
28
|
-
* When false (default), actually executes tests using the configured test runner.
|
|
29
|
-
*/
|
|
30
|
-
simulateForTesting: boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Base flakiness probability (0-1) when simulateForTesting is true.
|
|
33
|
-
* Defaults to 0.3 (30% of tests are flaky in simulation).
|
|
34
|
-
*/
|
|
35
|
-
simulatedFlakinessRate: number;
|
|
36
|
-
/**
|
|
37
|
-
* Simulated pass rate for flaky tests (0-1) when simulateForTesting is true.
|
|
38
|
-
* Defaults to 0.7 (70% pass rate for flaky tests).
|
|
39
|
-
*/
|
|
40
|
-
simulatedFlakyPassRate: number;
|
|
41
|
-
/**
|
|
42
|
-
* Number of tests per file in simulation mode.
|
|
43
|
-
* Defaults to 2.
|
|
44
|
-
*/
|
|
45
|
-
simulatedTestsPerFile: number;
|
|
46
|
-
/**
|
|
47
|
-
* Test runner command to use. Defaults to 'npx vitest'.
|
|
48
|
-
* Examples: 'npx vitest', 'npm test --', 'npx jest', 'npx mocha'
|
|
49
|
-
*/
|
|
50
|
-
testRunner: string;
|
|
51
|
-
/**
|
|
52
|
-
* Additional arguments to pass to the test runner.
|
|
53
|
-
*/
|
|
54
|
-
testRunnerArgs: string[];
|
|
55
|
-
/**
|
|
56
|
-
* Working directory for test execution.
|
|
57
|
-
*/
|
|
58
|
-
cwd?: string;
|
|
59
|
-
/**
|
|
60
|
-
* Timeout in milliseconds for each test run.
|
|
61
|
-
* Defaults to 60000 (60 seconds).
|
|
62
|
-
*/
|
|
63
|
-
runTimeout: number;
|
|
64
|
-
/**
|
|
65
|
-
* Environment variables to pass to the test runner.
|
|
66
|
-
*/
|
|
67
|
-
env?: Record<string, string>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const DEFAULT_FLAKY_CONFIG: FlakyDetectorConfig = {
|
|
71
|
-
simulateForTesting: false,
|
|
72
|
-
simulatedFlakinessRate: 0.3,
|
|
73
|
-
simulatedFlakyPassRate: 0.7,
|
|
74
|
-
simulatedTestsPerFile: 2,
|
|
75
|
-
testRunner: 'npx',
|
|
76
|
-
testRunnerArgs: ['vitest', 'run', '--reporter=json'],
|
|
77
|
-
runTimeout: 60000,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// ============================================================================
|
|
81
|
-
// Interfaces
|
|
82
|
-
// ============================================================================
|
|
83
|
-
|
|
84
|
-
export interface IFlakyTestDetector {
|
|
85
|
-
/** Detect flaky tests by running multiple times */
|
|
86
|
-
detectFlaky(request: FlakyDetectionRequest): Promise<Result<FlakyTestReport, Error>>;
|
|
87
|
-
|
|
88
|
-
/** Analyze failure patterns from history */
|
|
89
|
-
analyzePattern(testId: string): Promise<Result<FlakyAnalysis, Error>>;
|
|
90
|
-
|
|
91
|
-
/** Suggest remediation for a flaky test */
|
|
92
|
-
suggestFix(testId: string): Promise<Result<FlakySuggestion, Error>>;
|
|
93
|
-
|
|
94
|
-
/** Record test execution result for analysis */
|
|
95
|
-
recordExecution(testId: string, result: TestExecutionRecord): Promise<void>;
|
|
96
|
-
|
|
97
|
-
/** Get flakiness score for a test */
|
|
98
|
-
getFlakinessScore(testId: string): Promise<number>;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface FlakyAnalysis {
|
|
102
|
-
testId: string;
|
|
103
|
-
pattern: 'timing' | 'ordering' | 'resource' | 'async' | 'unknown';
|
|
104
|
-
confidence: number;
|
|
105
|
-
factors: string[];
|
|
106
|
-
correlations: CorrelationFactor[];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface CorrelationFactor {
|
|
110
|
-
factor: string;
|
|
111
|
-
correlation: number;
|
|
112
|
-
description: string;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface FlakySuggestion {
|
|
116
|
-
testId: string;
|
|
117
|
-
pattern: string;
|
|
118
|
-
recommendations: Recommendation[];
|
|
119
|
-
priority: 'high' | 'medium' | 'low';
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export interface Recommendation {
|
|
123
|
-
action: string;
|
|
124
|
-
description: string;
|
|
125
|
-
codeSnippet?: string;
|
|
126
|
-
effort: 'low' | 'medium' | 'high';
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface TestExecutionRecord {
|
|
130
|
-
runId: string;
|
|
131
|
-
passed: boolean;
|
|
132
|
-
duration: number;
|
|
133
|
-
error?: string;
|
|
134
|
-
timestamp: Date;
|
|
135
|
-
context?: ExecutionContext;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export interface ExecutionContext {
|
|
139
|
-
workerIndex?: number;
|
|
140
|
-
parallelRuns?: number;
|
|
141
|
-
environment?: Record<string, string>;
|
|
142
|
-
precedingTests?: string[];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// ============================================================================
|
|
146
|
-
// Test Runner Output Types
|
|
147
|
-
// ============================================================================
|
|
148
|
-
|
|
149
|
-
interface VitestAssertionResult {
|
|
150
|
-
title: string;
|
|
151
|
-
fullName?: string;
|
|
152
|
-
status: 'passed' | 'failed' | 'skipped' | 'pending';
|
|
153
|
-
duration?: number;
|
|
154
|
-
failureMessages?: string[];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
interface VitestTestResult {
|
|
158
|
-
assertionResults?: VitestAssertionResult[];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
interface VitestJsonOutput {
|
|
162
|
-
testResults?: VitestTestResult[];
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
interface JestAssertionResult {
|
|
166
|
-
title: string;
|
|
167
|
-
fullName?: string;
|
|
168
|
-
status: 'passed' | 'failed' | 'skipped' | 'pending';
|
|
169
|
-
duration?: number;
|
|
170
|
-
failureMessages?: string[];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
interface JestTestFileResult {
|
|
174
|
-
assertionResults?: JestAssertionResult[];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
interface JestJsonOutput {
|
|
178
|
-
testResults?: JestTestFileResult[];
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// ============================================================================
|
|
182
|
-
// Flaky Detector Service
|
|
183
|
-
// ============================================================================
|
|
184
|
-
|
|
185
|
-
export class FlakyDetectorService implements IFlakyTestDetector {
|
|
186
|
-
private readonly testHistory = new Map<string, TestExecutionRecord[]>();
|
|
187
|
-
private readonly analysisCache = new Map<string, FlakyAnalysis>();
|
|
188
|
-
private readonly config: FlakyDetectorConfig;
|
|
189
|
-
|
|
190
|
-
constructor(
|
|
191
|
-
private readonly memory: MemoryBackend,
|
|
192
|
-
config: Partial<FlakyDetectorConfig> = {}
|
|
193
|
-
) {
|
|
194
|
-
this.config = { ...DEFAULT_FLAKY_CONFIG, ...config };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Detect flaky tests by running them multiple times
|
|
199
|
-
*/
|
|
200
|
-
async detectFlaky(request: FlakyDetectionRequest): Promise<Result<FlakyTestReport, Error>> {
|
|
201
|
-
const startTime = Date.now();
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
const { testFiles, runs, threshold } = request;
|
|
205
|
-
|
|
206
|
-
if (runs < 2) {
|
|
207
|
-
return err(new Error('Minimum 2 runs required for flaky detection'));
|
|
208
|
-
}
|
|
209
|
-
if (threshold < 0 || threshold > 1) {
|
|
210
|
-
return err(new Error('Threshold must be between 0 and 1'));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const flakyTests: FlakyTest[] = [];
|
|
214
|
-
|
|
215
|
-
for (const file of testFiles) {
|
|
216
|
-
const fileResults = await this.runMultipleTimes(file, runs);
|
|
217
|
-
const flakyInFile = this.identifyFlakyTests(fileResults, threshold);
|
|
218
|
-
flakyTests.push(...flakyInFile);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const report: FlakyTestReport = {
|
|
222
|
-
flakyTests,
|
|
223
|
-
totalRuns: runs * testFiles.length,
|
|
224
|
-
analysisTime: Date.now() - startTime,
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// Store report for future reference
|
|
228
|
-
await this.storeReport(report);
|
|
229
|
-
|
|
230
|
-
return ok(report);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Analyze failure patterns for a specific test
|
|
238
|
-
*/
|
|
239
|
-
async analyzePattern(testId: string): Promise<Result<FlakyAnalysis, Error>> {
|
|
240
|
-
try {
|
|
241
|
-
// Check cache
|
|
242
|
-
const cached = this.analysisCache.get(testId);
|
|
243
|
-
if (cached) {
|
|
244
|
-
return ok(cached);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Load history
|
|
248
|
-
const history = await this.getTestHistory(testId);
|
|
249
|
-
if (history.length < 5) {
|
|
250
|
-
return err(new Error('Insufficient history for pattern analysis (minimum 5 runs)'));
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Analyze patterns
|
|
254
|
-
const analysis = this.performPatternAnalysis(testId, history);
|
|
255
|
-
|
|
256
|
-
// Cache result
|
|
257
|
-
this.analysisCache.set(testId, analysis);
|
|
258
|
-
await this.memory.set(`flaky-analysis:${testId}`, analysis, {
|
|
259
|
-
namespace: 'test-execution',
|
|
260
|
-
ttl: 3600000, // 1 hour
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
return ok(analysis);
|
|
264
|
-
} catch (error) {
|
|
265
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Suggest fixes for a flaky test
|
|
271
|
-
*/
|
|
272
|
-
async suggestFix(testId: string): Promise<Result<FlakySuggestion, Error>> {
|
|
273
|
-
try {
|
|
274
|
-
const analysisResult = await this.analyzePattern(testId);
|
|
275
|
-
if (!analysisResult.success) {
|
|
276
|
-
return err(analysisResult.error);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const analysis = analysisResult.value;
|
|
280
|
-
const recommendations = this.generateRecommendations(analysis);
|
|
281
|
-
|
|
282
|
-
const suggestion: FlakySuggestion = {
|
|
283
|
-
testId,
|
|
284
|
-
pattern: analysis.pattern,
|
|
285
|
-
recommendations,
|
|
286
|
-
priority: this.determinePriority(analysis),
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
return ok(suggestion);
|
|
290
|
-
} catch (error) {
|
|
291
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Record a test execution for future analysis
|
|
297
|
-
*/
|
|
298
|
-
async recordExecution(testId: string, result: TestExecutionRecord): Promise<void> {
|
|
299
|
-
// Add to in-memory history
|
|
300
|
-
const history = this.testHistory.get(testId) ?? [];
|
|
301
|
-
history.push(result);
|
|
302
|
-
|
|
303
|
-
// Keep only last 100 executions
|
|
304
|
-
if (history.length > 100) {
|
|
305
|
-
history.shift();
|
|
306
|
-
}
|
|
307
|
-
this.testHistory.set(testId, history);
|
|
308
|
-
|
|
309
|
-
// Persist to storage
|
|
310
|
-
await this.memory.set(`test-history:${testId}`, history, {
|
|
311
|
-
namespace: 'test-execution',
|
|
312
|
-
persist: true,
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Invalidate analysis cache
|
|
316
|
-
this.analysisCache.delete(testId);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Calculate flakiness score (0-1, where 1 is most flaky)
|
|
321
|
-
*/
|
|
322
|
-
async getFlakinessScore(testId: string): Promise<number> {
|
|
323
|
-
const history = await this.getTestHistory(testId);
|
|
324
|
-
|
|
325
|
-
if (history.length < 2) {
|
|
326
|
-
return 0;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Count state changes
|
|
330
|
-
let stateChanges = 0;
|
|
331
|
-
for (let i = 1; i < history.length; i++) {
|
|
332
|
-
if (history[i].passed !== history[i - 1].passed) {
|
|
333
|
-
stateChanges++;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Calculate score based on state change frequency
|
|
338
|
-
const changeRate = stateChanges / (history.length - 1);
|
|
339
|
-
|
|
340
|
-
// Factor in failure rate
|
|
341
|
-
const failures = history.filter(h => !h.passed).length;
|
|
342
|
-
const failureRate = failures / history.length;
|
|
343
|
-
|
|
344
|
-
// Flakiness is high when there are many state changes and intermediate failure rate
|
|
345
|
-
// Pure passes (failureRate = 0) or pure failures (failureRate = 1) are not flaky
|
|
346
|
-
const flakinessFactor = Math.min(failureRate, 1 - failureRate) * 2;
|
|
347
|
-
|
|
348
|
-
return Math.min(1, changeRate * 0.6 + flakinessFactor * 0.4);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// ============================================================================
|
|
352
|
-
// Private Methods
|
|
353
|
-
// ============================================================================
|
|
354
|
-
|
|
355
|
-
private async runMultipleTimes(
|
|
356
|
-
file: string,
|
|
357
|
-
runs: number
|
|
358
|
-
): Promise<Map<string, TestExecutionRecord[]>> {
|
|
359
|
-
// In simulation mode (for unit testing), use random behavior
|
|
360
|
-
if (this.config.simulateForTesting) {
|
|
361
|
-
return this.simulateMultipleRuns(runs);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// In production mode, ACTUALLY execute the test file multiple times
|
|
365
|
-
// Verify the test file exists
|
|
366
|
-
const resolvedPath = this.config.cwd
|
|
367
|
-
? path.resolve(this.config.cwd, file)
|
|
368
|
-
: path.resolve(file);
|
|
369
|
-
|
|
370
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
371
|
-
throw new Error(
|
|
372
|
-
`Test file not found: ${resolvedPath}. Cannot perform flaky detection without a valid test file.`
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Execute the test file N times and collect results
|
|
377
|
-
const allResults = new Map<string, TestExecutionRecord[]>();
|
|
378
|
-
|
|
379
|
-
for (let runIndex = 0; runIndex < runs; runIndex++) {
|
|
380
|
-
const runResult = await this.executeTestFile(file, runIndex);
|
|
381
|
-
|
|
382
|
-
// Merge results from this run into allResults
|
|
383
|
-
for (const [testId, records] of runResult.entries()) {
|
|
384
|
-
const existing = allResults.get(testId) ?? [];
|
|
385
|
-
existing.push(...records);
|
|
386
|
-
allResults.set(testId, existing);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// If we got no results after N runs, that means the test runner failed
|
|
391
|
-
if (allResults.size === 0) {
|
|
392
|
-
throw new Error(
|
|
393
|
-
`Test execution produced no results for ${file}. ` +
|
|
394
|
-
`Ensure the test runner (${this.config.testRunner}) is properly configured ` +
|
|
395
|
-
`and the test file contains valid tests.`
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Record all executions for future reference
|
|
400
|
-
for (const [testId, records] of allResults.entries()) {
|
|
401
|
-
for (const record of records) {
|
|
402
|
-
await this.recordExecution(testId, record);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return allResults;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Execute a single test file and parse the results
|
|
411
|
-
*/
|
|
412
|
-
private async executeTestFile(
|
|
413
|
-
file: string,
|
|
414
|
-
runIndex: number
|
|
415
|
-
): Promise<Map<string, TestExecutionRecord[]>> {
|
|
416
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
417
|
-
const runId = uuidv4();
|
|
418
|
-
const startTime = Date.now();
|
|
419
|
-
|
|
420
|
-
return new Promise((resolve, reject) => {
|
|
421
|
-
const args = [...this.config.testRunnerArgs, file];
|
|
422
|
-
const cwd = this.config.cwd ?? process.cwd();
|
|
423
|
-
|
|
424
|
-
const child = spawn(this.config.testRunner, args, {
|
|
425
|
-
cwd,
|
|
426
|
-
env: { ...process.env, ...this.config.env },
|
|
427
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
let stdout = '';
|
|
431
|
-
let stderr = '';
|
|
432
|
-
|
|
433
|
-
child.stdout?.on('data', (data) => {
|
|
434
|
-
stdout += data.toString();
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
child.stderr?.on('data', (data) => {
|
|
438
|
-
stderr += data.toString();
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// Set timeout
|
|
442
|
-
const timeout = setTimeout(() => {
|
|
443
|
-
child.kill('SIGTERM');
|
|
444
|
-
reject(
|
|
445
|
-
new Error(
|
|
446
|
-
`Test execution timed out after ${this.config.runTimeout}ms for ${file}`
|
|
447
|
-
)
|
|
448
|
-
);
|
|
449
|
-
}, this.config.runTimeout);
|
|
450
|
-
|
|
451
|
-
child.on('error', (error) => {
|
|
452
|
-
clearTimeout(timeout);
|
|
453
|
-
reject(
|
|
454
|
-
new Error(
|
|
455
|
-
`Failed to execute test runner: ${error.message}. ` +
|
|
456
|
-
`Ensure ${this.config.testRunner} is installed and accessible.`
|
|
457
|
-
)
|
|
458
|
-
);
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
child.on('close', (code) => {
|
|
462
|
-
clearTimeout(timeout);
|
|
463
|
-
const duration = Date.now() - startTime;
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
// Parse the test results from stdout
|
|
467
|
-
const parsedResults = this.parseTestOutput(
|
|
468
|
-
stdout,
|
|
469
|
-
stderr,
|
|
470
|
-
code ?? 0,
|
|
471
|
-
file,
|
|
472
|
-
runId,
|
|
473
|
-
runIndex,
|
|
474
|
-
duration
|
|
475
|
-
);
|
|
476
|
-
|
|
477
|
-
// If parsing fails but we have an exit code, create a single result for the file
|
|
478
|
-
if (parsedResults.size === 0) {
|
|
479
|
-
const testId = this.generateTestId(file, 'main');
|
|
480
|
-
results.set(testId, [
|
|
481
|
-
{
|
|
482
|
-
runId,
|
|
483
|
-
passed: code === 0,
|
|
484
|
-
duration,
|
|
485
|
-
error: code !== 0 ? stderr || `Exit code: ${code}` : undefined,
|
|
486
|
-
timestamp: new Date(),
|
|
487
|
-
context: {
|
|
488
|
-
parallelRuns: 1,
|
|
489
|
-
workerIndex: runIndex,
|
|
490
|
-
},
|
|
491
|
-
},
|
|
492
|
-
]);
|
|
493
|
-
} else {
|
|
494
|
-
for (const [testId, records] of parsedResults.entries()) {
|
|
495
|
-
results.set(testId, records);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
resolve(results);
|
|
500
|
-
} catch (parseError) {
|
|
501
|
-
// If we can't parse output but process completed, create result from exit code
|
|
502
|
-
const testId = this.generateTestId(file, 'main');
|
|
503
|
-
results.set(testId, [
|
|
504
|
-
{
|
|
505
|
-
runId,
|
|
506
|
-
passed: code === 0,
|
|
507
|
-
duration,
|
|
508
|
-
error:
|
|
509
|
-
code !== 0
|
|
510
|
-
? stderr || `Exit code: ${code}, Parse error: ${parseError}`
|
|
511
|
-
: undefined,
|
|
512
|
-
timestamp: new Date(),
|
|
513
|
-
context: {
|
|
514
|
-
parallelRuns: 1,
|
|
515
|
-
workerIndex: runIndex,
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
]);
|
|
519
|
-
resolve(results);
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Parse test runner output to extract individual test results
|
|
527
|
-
*/
|
|
528
|
-
private parseTestOutput(
|
|
529
|
-
stdout: string,
|
|
530
|
-
stderr: string,
|
|
531
|
-
exitCode: number,
|
|
532
|
-
file: string,
|
|
533
|
-
runId: string,
|
|
534
|
-
runIndex: number,
|
|
535
|
-
totalDuration: number
|
|
536
|
-
): Map<string, TestExecutionRecord[]> {
|
|
537
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
538
|
-
|
|
539
|
-
// Try to parse as JSON (vitest with --reporter=json)
|
|
540
|
-
try {
|
|
541
|
-
const jsonOutput = this.extractJson(stdout);
|
|
542
|
-
if (jsonOutput) {
|
|
543
|
-
const parsed = JSON.parse(jsonOutput);
|
|
544
|
-
return this.parseVitestJson(parsed, file, runId, runIndex);
|
|
545
|
-
}
|
|
546
|
-
} catch {
|
|
547
|
-
// Not valid JSON, try other formats
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Try to parse Jest JSON output
|
|
551
|
-
try {
|
|
552
|
-
const jsonOutput = this.extractJson(stdout);
|
|
553
|
-
if (jsonOutput) {
|
|
554
|
-
const parsed = JSON.parse(jsonOutput);
|
|
555
|
-
if (parsed.testResults) {
|
|
556
|
-
return this.parseJestJson(parsed, file, runId, runIndex);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
} catch {
|
|
560
|
-
// Not Jest format
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Try to parse TAP format
|
|
564
|
-
if (stdout.includes('TAP version') || stdout.match(/^(ok|not ok)\s+\d+/m)) {
|
|
565
|
-
return this.parseTapOutput(stdout, file, runId, runIndex);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// Try to parse Mocha-style output
|
|
569
|
-
const mochaResults = this.parseMochaOutput(
|
|
570
|
-
stdout,
|
|
571
|
-
stderr,
|
|
572
|
-
exitCode,
|
|
573
|
-
file,
|
|
574
|
-
runId,
|
|
575
|
-
runIndex,
|
|
576
|
-
totalDuration
|
|
577
|
-
);
|
|
578
|
-
if (mochaResults.size > 0) {
|
|
579
|
-
return mochaResults;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Fallback: create a single result based on exit code
|
|
583
|
-
return results;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Extract JSON from mixed output
|
|
588
|
-
*/
|
|
589
|
-
private extractJson(output: string): string | null {
|
|
590
|
-
// Try to find JSON object or array
|
|
591
|
-
const jsonStart = output.indexOf('{');
|
|
592
|
-
const jsonArrayStart = output.indexOf('[');
|
|
593
|
-
const start =
|
|
594
|
-
jsonStart === -1
|
|
595
|
-
? jsonArrayStart
|
|
596
|
-
: jsonArrayStart === -1
|
|
597
|
-
? jsonStart
|
|
598
|
-
: Math.min(jsonStart, jsonArrayStart);
|
|
599
|
-
|
|
600
|
-
if (start === -1) return null;
|
|
601
|
-
|
|
602
|
-
let depth = 0;
|
|
603
|
-
let inString = false;
|
|
604
|
-
let escape = false;
|
|
605
|
-
|
|
606
|
-
for (let i = start; i < output.length; i++) {
|
|
607
|
-
const char = output[i];
|
|
608
|
-
|
|
609
|
-
if (escape) {
|
|
610
|
-
escape = false;
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
if (char === '\\') {
|
|
615
|
-
escape = true;
|
|
616
|
-
continue;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
if (char === '"') {
|
|
620
|
-
inString = !inString;
|
|
621
|
-
continue;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
if (inString) continue;
|
|
625
|
-
|
|
626
|
-
if (char === '{' || char === '[') depth++;
|
|
627
|
-
if (char === '}' || char === ']') depth--;
|
|
628
|
-
|
|
629
|
-
if (depth === 0) {
|
|
630
|
-
return output.substring(start, i + 1);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
return null;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* Parse Vitest JSON output
|
|
639
|
-
*/
|
|
640
|
-
private parseVitestJson(
|
|
641
|
-
json: VitestJsonOutput,
|
|
642
|
-
file: string,
|
|
643
|
-
runId: string,
|
|
644
|
-
runIndex: number
|
|
645
|
-
): Map<string, TestExecutionRecord[]> {
|
|
646
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
647
|
-
|
|
648
|
-
if (!json.testResults) return results;
|
|
649
|
-
|
|
650
|
-
for (const suite of json.testResults) {
|
|
651
|
-
for (const test of suite.assertionResults || []) {
|
|
652
|
-
const testId = this.generateTestId(file, test.fullName || test.title);
|
|
653
|
-
const record: TestExecutionRecord = {
|
|
654
|
-
runId,
|
|
655
|
-
passed: test.status === 'passed',
|
|
656
|
-
duration: test.duration || 0,
|
|
657
|
-
error:
|
|
658
|
-
test.status === 'failed'
|
|
659
|
-
? test.failureMessages?.join('\n')
|
|
660
|
-
: undefined,
|
|
661
|
-
timestamp: new Date(),
|
|
662
|
-
context: {
|
|
663
|
-
parallelRuns: 1,
|
|
664
|
-
workerIndex: runIndex,
|
|
665
|
-
},
|
|
666
|
-
};
|
|
667
|
-
results.set(testId, [record]);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
return results;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* Parse Jest JSON output
|
|
676
|
-
*/
|
|
677
|
-
private parseJestJson(
|
|
678
|
-
json: JestJsonOutput,
|
|
679
|
-
file: string,
|
|
680
|
-
runId: string,
|
|
681
|
-
runIndex: number
|
|
682
|
-
): Map<string, TestExecutionRecord[]> {
|
|
683
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
684
|
-
|
|
685
|
-
for (const testResult of json.testResults || []) {
|
|
686
|
-
for (const assertion of testResult.assertionResults || []) {
|
|
687
|
-
const testId = this.generateTestId(
|
|
688
|
-
file,
|
|
689
|
-
assertion.fullName || assertion.title
|
|
690
|
-
);
|
|
691
|
-
const record: TestExecutionRecord = {
|
|
692
|
-
runId,
|
|
693
|
-
passed: assertion.status === 'passed',
|
|
694
|
-
duration: assertion.duration || 0,
|
|
695
|
-
error:
|
|
696
|
-
assertion.status === 'failed'
|
|
697
|
-
? assertion.failureMessages?.join('\n')
|
|
698
|
-
: undefined,
|
|
699
|
-
timestamp: new Date(),
|
|
700
|
-
context: {
|
|
701
|
-
parallelRuns: 1,
|
|
702
|
-
workerIndex: runIndex,
|
|
703
|
-
},
|
|
704
|
-
};
|
|
705
|
-
results.set(testId, [record]);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
return results;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Parse TAP output format
|
|
714
|
-
*/
|
|
715
|
-
private parseTapOutput(
|
|
716
|
-
output: string,
|
|
717
|
-
file: string,
|
|
718
|
-
runId: string,
|
|
719
|
-
runIndex: number
|
|
720
|
-
): Map<string, TestExecutionRecord[]> {
|
|
721
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
722
|
-
const lines = output.split('\n');
|
|
723
|
-
|
|
724
|
-
for (const line of lines) {
|
|
725
|
-
const match = line.match(/^(ok|not ok)\s+(\d+)\s*-?\s*(.*)/);
|
|
726
|
-
if (match) {
|
|
727
|
-
const [, status, , testName] = match;
|
|
728
|
-
const testId = this.generateTestId(file, testName || `test-${match[2]}`);
|
|
729
|
-
const record: TestExecutionRecord = {
|
|
730
|
-
runId,
|
|
731
|
-
passed: status === 'ok',
|
|
732
|
-
duration: 0,
|
|
733
|
-
error: status !== 'ok' ? `Test failed: ${testName}` : undefined,
|
|
734
|
-
timestamp: new Date(),
|
|
735
|
-
context: {
|
|
736
|
-
parallelRuns: 1,
|
|
737
|
-
workerIndex: runIndex,
|
|
738
|
-
},
|
|
739
|
-
};
|
|
740
|
-
results.set(testId, [record]);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
return results;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
/**
|
|
748
|
-
* Parse Mocha-style console output
|
|
749
|
-
*/
|
|
750
|
-
private parseMochaOutput(
|
|
751
|
-
stdout: string,
|
|
752
|
-
stderr: string,
|
|
753
|
-
exitCode: number,
|
|
754
|
-
file: string,
|
|
755
|
-
runId: string,
|
|
756
|
-
runIndex: number,
|
|
757
|
-
duration: number
|
|
758
|
-
): Map<string, TestExecutionRecord[]> {
|
|
759
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
760
|
-
|
|
761
|
-
// Look for passing/failing indicators
|
|
762
|
-
const passMatch = stdout.match(/(\d+)\s+passing/);
|
|
763
|
-
const failMatch = stdout.match(/(\d+)\s+failing/);
|
|
764
|
-
|
|
765
|
-
if (passMatch || failMatch) {
|
|
766
|
-
const passing = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
767
|
-
const failing = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
768
|
-
|
|
769
|
-
// Create aggregate results
|
|
770
|
-
for (let i = 0; i < passing; i++) {
|
|
771
|
-
const testId = this.generateTestId(file, `passing-${i + 1}`);
|
|
772
|
-
results.set(testId, [
|
|
773
|
-
{
|
|
774
|
-
runId,
|
|
775
|
-
passed: true,
|
|
776
|
-
duration: duration / (passing + failing),
|
|
777
|
-
timestamp: new Date(),
|
|
778
|
-
context: { parallelRuns: 1, workerIndex: runIndex },
|
|
779
|
-
},
|
|
780
|
-
]);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
for (let i = 0; i < failing; i++) {
|
|
784
|
-
const testId = this.generateTestId(file, `failing-${i + 1}`);
|
|
785
|
-
results.set(testId, [
|
|
786
|
-
{
|
|
787
|
-
runId,
|
|
788
|
-
passed: false,
|
|
789
|
-
duration: duration / (passing + failing),
|
|
790
|
-
error: stderr || 'Test failed',
|
|
791
|
-
timestamp: new Date(),
|
|
792
|
-
context: { parallelRuns: 1, workerIndex: runIndex },
|
|
793
|
-
},
|
|
794
|
-
]);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
return results;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* Generate a deterministic test ID from file and test name
|
|
803
|
-
*/
|
|
804
|
-
private generateTestId(file: string, testName: string): string {
|
|
805
|
-
const sanitizedFile = file.replace(/[^a-zA-Z0-9]/g, '-');
|
|
806
|
-
const sanitizedName = testName.replace(/[^a-zA-Z0-9]/g, '-');
|
|
807
|
-
return `${sanitizedFile}::${sanitizedName}`;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* Get recorded execution history for tests in a file
|
|
812
|
-
*/
|
|
813
|
-
private async getHistoryForFile(file: string): Promise<Map<string, TestExecutionRecord[]>> {
|
|
814
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
815
|
-
|
|
816
|
-
// Check for any test IDs associated with this file in memory
|
|
817
|
-
for (const [testId, history] of this.testHistory.entries()) {
|
|
818
|
-
// Simple file association check (in real implementation, would use proper mapping)
|
|
819
|
-
if (testId.includes(file.replace(/[^a-zA-Z0-9]/g, '-'))) {
|
|
820
|
-
results.set(testId, history);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
return results;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* Simulate multiple test runs with random outcomes (for unit testing only)
|
|
829
|
-
*/
|
|
830
|
-
private simulateMultipleRuns(runs: number): Map<string, TestExecutionRecord[]> {
|
|
831
|
-
const results = new Map<string, TestExecutionRecord[]>();
|
|
832
|
-
const testCount = this.config.simulatedTestsPerFile;
|
|
833
|
-
const testIds = Array.from(
|
|
834
|
-
{ length: testCount },
|
|
835
|
-
() => `test-${uuidv4().slice(0, 8)}`
|
|
836
|
-
);
|
|
837
|
-
|
|
838
|
-
for (const testId of testIds) {
|
|
839
|
-
const records: TestExecutionRecord[] = [];
|
|
840
|
-
|
|
841
|
-
// Determine if this test is flaky
|
|
842
|
-
const isFlaky = Math.random() < this.config.simulatedFlakinessRate;
|
|
843
|
-
|
|
844
|
-
for (let i = 0; i < runs; i++) {
|
|
845
|
-
// If flaky, randomly pass/fail; otherwise always pass
|
|
846
|
-
const passed = isFlaky
|
|
847
|
-
? Math.random() < this.config.simulatedFlakyPassRate
|
|
848
|
-
: true;
|
|
849
|
-
|
|
850
|
-
records.push({
|
|
851
|
-
runId: uuidv4(),
|
|
852
|
-
passed,
|
|
853
|
-
duration: Math.random() * 1000 + 100,
|
|
854
|
-
error: passed ? undefined : 'Assertion failed',
|
|
855
|
-
timestamp: new Date(),
|
|
856
|
-
context: { parallelRuns: runs },
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
results.set(testId, records);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
return results;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
private identifyFlakyTests(
|
|
867
|
-
results: Map<string, TestExecutionRecord[]>,
|
|
868
|
-
threshold: number
|
|
869
|
-
): FlakyTest[] {
|
|
870
|
-
const flakyTests: FlakyTest[] = [];
|
|
871
|
-
|
|
872
|
-
for (const [testId, records] of results) {
|
|
873
|
-
const failures = records.filter(r => !r.passed).length;
|
|
874
|
-
const failureRate = failures / records.length;
|
|
875
|
-
|
|
876
|
-
// Test is flaky if it has inconsistent results above threshold
|
|
877
|
-
if (failureRate > 0 && failureRate < 1 && failureRate >= threshold) {
|
|
878
|
-
const pattern = this.detectPattern(records);
|
|
879
|
-
|
|
880
|
-
flakyTests.push({
|
|
881
|
-
testId,
|
|
882
|
-
testName: testId,
|
|
883
|
-
file: 'unknown',
|
|
884
|
-
failureRate,
|
|
885
|
-
pattern,
|
|
886
|
-
recommendation: this.getQuickRecommendation(pattern),
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
return flakyTests;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
private detectPattern(records: TestExecutionRecord[]): FlakyTest['pattern'] {
|
|
895
|
-
// Analyze records to determine the flakiness pattern
|
|
896
|
-
|
|
897
|
-
// Check for timing issues
|
|
898
|
-
const failedRecords = records.filter(r => !r.passed);
|
|
899
|
-
const passedRecords = records.filter(r => r.passed);
|
|
900
|
-
|
|
901
|
-
if (failedRecords.length > 0 && passedRecords.length > 0) {
|
|
902
|
-
const avgFailedDuration = this.average(failedRecords.map(r => r.duration));
|
|
903
|
-
const avgPassedDuration = this.average(passedRecords.map(r => r.duration));
|
|
904
|
-
|
|
905
|
-
if (Math.abs(avgFailedDuration - avgPassedDuration) / avgPassedDuration > 0.5) {
|
|
906
|
-
return 'timing';
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
// Check for async issues (errors mentioning timeout, promise, async)
|
|
911
|
-
const asyncKeywords = ['timeout', 'promise', 'async', 'await', 'callback'];
|
|
912
|
-
const hasAsyncErrors = failedRecords.some(r =>
|
|
913
|
-
r.error && asyncKeywords.some(k => r.error!.toLowerCase().includes(k))
|
|
914
|
-
);
|
|
915
|
-
if (hasAsyncErrors) {
|
|
916
|
-
return 'async';
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// Check for resource issues
|
|
920
|
-
const resourceKeywords = ['connection', 'database', 'network', 'port', 'file'];
|
|
921
|
-
const hasResourceErrors = failedRecords.some(r =>
|
|
922
|
-
r.error && resourceKeywords.some(k => r.error!.toLowerCase().includes(k))
|
|
923
|
-
);
|
|
924
|
-
if (hasResourceErrors) {
|
|
925
|
-
return 'resource';
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// Check for ordering issues (failures correlate with preceding tests)
|
|
929
|
-
const hasOrderingPattern = failedRecords.some(r =>
|
|
930
|
-
r.context?.precedingTests && r.context.precedingTests.length > 0
|
|
931
|
-
);
|
|
932
|
-
if (hasOrderingPattern) {
|
|
933
|
-
return 'ordering';
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
return 'unknown';
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
private getQuickRecommendation(pattern: FlakyTest['pattern']): string {
|
|
940
|
-
switch (pattern) {
|
|
941
|
-
case 'timing':
|
|
942
|
-
return 'Increase timeouts or use explicit waits instead of fixed delays';
|
|
943
|
-
case 'ordering':
|
|
944
|
-
return 'Ensure test isolation and independent setup/teardown';
|
|
945
|
-
case 'resource':
|
|
946
|
-
return 'Mock external dependencies or use connection pooling';
|
|
947
|
-
case 'async':
|
|
948
|
-
return 'Properly await async operations and handle promise rejections';
|
|
949
|
-
case 'unknown':
|
|
950
|
-
return 'Review test for potential race conditions or external dependencies';
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
private async getTestHistory(testId: string): Promise<TestExecutionRecord[]> {
|
|
955
|
-
// Check in-memory first
|
|
956
|
-
const cached = this.testHistory.get(testId);
|
|
957
|
-
if (cached && cached.length > 0) {
|
|
958
|
-
return cached;
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
// Load from storage
|
|
962
|
-
const stored = await this.memory.get<TestExecutionRecord[]>(`test-history:${testId}`);
|
|
963
|
-
if (stored) {
|
|
964
|
-
this.testHistory.set(testId, stored);
|
|
965
|
-
return stored;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
return [];
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
private performPatternAnalysis(
|
|
972
|
-
testId: string,
|
|
973
|
-
history: TestExecutionRecord[]
|
|
974
|
-
): FlakyAnalysis {
|
|
975
|
-
const pattern = this.detectPattern(history);
|
|
976
|
-
const factors = this.identifyFactors(history, pattern);
|
|
977
|
-
const correlations = this.calculateCorrelations(history);
|
|
978
|
-
const confidence = this.calculateConfidence(history, pattern);
|
|
979
|
-
|
|
980
|
-
return {
|
|
981
|
-
testId,
|
|
982
|
-
pattern,
|
|
983
|
-
confidence,
|
|
984
|
-
factors,
|
|
985
|
-
correlations,
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
private identifyFactors(
|
|
990
|
-
history: TestExecutionRecord[],
|
|
991
|
-
pattern: FlakyTest['pattern']
|
|
992
|
-
): string[] {
|
|
993
|
-
const factors: string[] = [];
|
|
994
|
-
|
|
995
|
-
switch (pattern) {
|
|
996
|
-
case 'timing':
|
|
997
|
-
factors.push('Variable execution duration');
|
|
998
|
-
factors.push('Possible race conditions');
|
|
999
|
-
if (this.hasDurationSpikes(history)) {
|
|
1000
|
-
factors.push('Duration spikes before failures');
|
|
1001
|
-
}
|
|
1002
|
-
break;
|
|
1003
|
-
|
|
1004
|
-
case 'async':
|
|
1005
|
-
factors.push('Unhandled async operations');
|
|
1006
|
-
factors.push('Missing await statements');
|
|
1007
|
-
break;
|
|
1008
|
-
|
|
1009
|
-
case 'resource':
|
|
1010
|
-
factors.push('External dependency instability');
|
|
1011
|
-
factors.push('Shared resource contention');
|
|
1012
|
-
break;
|
|
1013
|
-
|
|
1014
|
-
case 'ordering':
|
|
1015
|
-
factors.push('Shared state between tests');
|
|
1016
|
-
factors.push('Incomplete cleanup');
|
|
1017
|
-
break;
|
|
1018
|
-
|
|
1019
|
-
case 'unknown':
|
|
1020
|
-
factors.push('No clear pattern identified');
|
|
1021
|
-
factors.push('Manual investigation recommended');
|
|
1022
|
-
break;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
return factors;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
private calculateCorrelations(history: TestExecutionRecord[]): CorrelationFactor[] {
|
|
1029
|
-
const correlations: CorrelationFactor[] = [];
|
|
1030
|
-
|
|
1031
|
-
// Duration correlation
|
|
1032
|
-
const durationCorr = this.correlateWithFailure(
|
|
1033
|
-
history,
|
|
1034
|
-
r => r.duration
|
|
1035
|
-
);
|
|
1036
|
-
if (Math.abs(durationCorr) > 0.3) {
|
|
1037
|
-
correlations.push({
|
|
1038
|
-
factor: 'duration',
|
|
1039
|
-
correlation: durationCorr,
|
|
1040
|
-
description: durationCorr > 0
|
|
1041
|
-
? 'Failures correlate with longer duration'
|
|
1042
|
-
: 'Failures correlate with shorter duration',
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
// Time of day correlation
|
|
1047
|
-
const hourCorr = this.correlateWithFailure(
|
|
1048
|
-
history,
|
|
1049
|
-
r => new Date(r.timestamp).getHours()
|
|
1050
|
-
);
|
|
1051
|
-
if (Math.abs(hourCorr) > 0.3) {
|
|
1052
|
-
correlations.push({
|
|
1053
|
-
factor: 'time_of_day',
|
|
1054
|
-
correlation: hourCorr,
|
|
1055
|
-
description: 'Failures correlate with specific times',
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Parallel execution correlation
|
|
1060
|
-
const parallelCorr = this.correlateWithFailure(
|
|
1061
|
-
history,
|
|
1062
|
-
r => r.context?.parallelRuns ?? 1
|
|
1063
|
-
);
|
|
1064
|
-
if (Math.abs(parallelCorr) > 0.3) {
|
|
1065
|
-
correlations.push({
|
|
1066
|
-
factor: 'parallelism',
|
|
1067
|
-
correlation: parallelCorr,
|
|
1068
|
-
description: 'Failures correlate with parallel execution',
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
return correlations;
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
private correlateWithFailure(
|
|
1076
|
-
history: TestExecutionRecord[],
|
|
1077
|
-
getValue: (r: TestExecutionRecord) => number
|
|
1078
|
-
): number {
|
|
1079
|
-
if (history.length < 2) return 0;
|
|
1080
|
-
|
|
1081
|
-
const values = history.map(getValue);
|
|
1082
|
-
const failures = history.map(r => r.passed ? 0 : 1);
|
|
1083
|
-
|
|
1084
|
-
return this.pearsonCorrelation(values, failures);
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
private pearsonCorrelation(x: number[], y: number[]): number {
|
|
1088
|
-
const n = x.length;
|
|
1089
|
-
if (n === 0) return 0;
|
|
1090
|
-
|
|
1091
|
-
const sumX = x.reduce((a, b) => a + b, 0);
|
|
1092
|
-
const sumY = y.reduce((a, b) => a + b, 0);
|
|
1093
|
-
const sumXY = x.reduce((a, xi, i) => a + xi * y[i], 0);
|
|
1094
|
-
const sumX2 = x.reduce((a, xi) => a + xi * xi, 0);
|
|
1095
|
-
const sumY2 = y.reduce((a, yi) => a + yi * yi, 0);
|
|
1096
|
-
|
|
1097
|
-
const numerator = n * sumXY - sumX * sumY;
|
|
1098
|
-
const denominator = Math.sqrt(
|
|
1099
|
-
(n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY)
|
|
1100
|
-
);
|
|
1101
|
-
|
|
1102
|
-
return denominator === 0 ? 0 : numerator / denominator;
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
private calculateConfidence(
|
|
1106
|
-
history: TestExecutionRecord[],
|
|
1107
|
-
pattern: FlakyTest['pattern']
|
|
1108
|
-
): number {
|
|
1109
|
-
// Base confidence on sample size
|
|
1110
|
-
const sampleConfidence = Math.min(1, history.length / 20);
|
|
1111
|
-
|
|
1112
|
-
// Pattern-specific confidence
|
|
1113
|
-
let patternConfidence = 0.5;
|
|
1114
|
-
if (pattern !== 'unknown') {
|
|
1115
|
-
patternConfidence = 0.8;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
// Consistency of pattern
|
|
1119
|
-
const failureRate = history.filter(h => !h.passed).length / history.length;
|
|
1120
|
-
const consistencyFactor = Math.min(failureRate, 1 - failureRate) * 2;
|
|
1121
|
-
|
|
1122
|
-
return sampleConfidence * 0.4 + patternConfidence * 0.4 + consistencyFactor * 0.2;
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
private generateRecommendations(analysis: FlakyAnalysis): Recommendation[] {
|
|
1126
|
-
const recommendations: Recommendation[] = [];
|
|
1127
|
-
|
|
1128
|
-
switch (analysis.pattern) {
|
|
1129
|
-
case 'timing':
|
|
1130
|
-
recommendations.push({
|
|
1131
|
-
action: 'Use explicit waits',
|
|
1132
|
-
description: 'Replace fixed delays with condition-based waits',
|
|
1133
|
-
codeSnippet: `await waitFor(() => expect(element).toBeVisible());`,
|
|
1134
|
-
effort: 'low',
|
|
1135
|
-
});
|
|
1136
|
-
recommendations.push({
|
|
1137
|
-
action: 'Increase timeout margins',
|
|
1138
|
-
description: 'Add buffer time for slow environments',
|
|
1139
|
-
codeSnippet: `jest.setTimeout(10000);`,
|
|
1140
|
-
effort: 'low',
|
|
1141
|
-
});
|
|
1142
|
-
break;
|
|
1143
|
-
|
|
1144
|
-
case 'async':
|
|
1145
|
-
recommendations.push({
|
|
1146
|
-
action: 'Ensure proper async handling',
|
|
1147
|
-
description: 'Await all promises and use async/await consistently',
|
|
1148
|
-
codeSnippet: `const result = await asyncOperation();\nexpect(result).toBeDefined();`,
|
|
1149
|
-
effort: 'medium',
|
|
1150
|
-
});
|
|
1151
|
-
recommendations.push({
|
|
1152
|
-
action: 'Add error boundaries',
|
|
1153
|
-
description: 'Catch and handle promise rejections',
|
|
1154
|
-
codeSnippet: `try {\n await operation();\n} catch (e) {\n console.error('Operation failed:', e);\n throw e;\n}`,
|
|
1155
|
-
effort: 'medium',
|
|
1156
|
-
});
|
|
1157
|
-
break;
|
|
1158
|
-
|
|
1159
|
-
case 'resource':
|
|
1160
|
-
recommendations.push({
|
|
1161
|
-
action: 'Mock external dependencies',
|
|
1162
|
-
description: 'Use mocks for external services in unit tests',
|
|
1163
|
-
codeSnippet: `jest.mock('./externalService');`,
|
|
1164
|
-
effort: 'medium',
|
|
1165
|
-
});
|
|
1166
|
-
recommendations.push({
|
|
1167
|
-
action: 'Implement retry logic',
|
|
1168
|
-
description: 'Add retries for transient failures',
|
|
1169
|
-
codeSnippet: `const result = await retry(() => fetchData(), { retries: 3 });`,
|
|
1170
|
-
effort: 'low',
|
|
1171
|
-
});
|
|
1172
|
-
break;
|
|
1173
|
-
|
|
1174
|
-
case 'ordering':
|
|
1175
|
-
recommendations.push({
|
|
1176
|
-
action: 'Isolate test state',
|
|
1177
|
-
description: 'Reset shared state in beforeEach/afterEach',
|
|
1178
|
-
codeSnippet: `beforeEach(() => {\n resetDatabase();\n clearCache();\n});`,
|
|
1179
|
-
effort: 'medium',
|
|
1180
|
-
});
|
|
1181
|
-
recommendations.push({
|
|
1182
|
-
action: 'Remove inter-test dependencies',
|
|
1183
|
-
description: 'Each test should set up its own required state',
|
|
1184
|
-
effort: 'high',
|
|
1185
|
-
});
|
|
1186
|
-
break;
|
|
1187
|
-
|
|
1188
|
-
case 'unknown':
|
|
1189
|
-
recommendations.push({
|
|
1190
|
-
action: 'Add detailed logging',
|
|
1191
|
-
description: 'Log test state at key points to identify patterns',
|
|
1192
|
-
effort: 'low',
|
|
1193
|
-
});
|
|
1194
|
-
recommendations.push({
|
|
1195
|
-
action: 'Run in isolation',
|
|
1196
|
-
description: 'Execute test alone to determine if it is a test interaction issue',
|
|
1197
|
-
effort: 'low',
|
|
1198
|
-
});
|
|
1199
|
-
break;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
return recommendations;
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
private determinePriority(analysis: FlakyAnalysis): 'high' | 'medium' | 'low' {
|
|
1206
|
-
if (analysis.confidence > 0.8 && analysis.pattern !== 'unknown') {
|
|
1207
|
-
return 'high';
|
|
1208
|
-
}
|
|
1209
|
-
if (analysis.confidence > 0.5) {
|
|
1210
|
-
return 'medium';
|
|
1211
|
-
}
|
|
1212
|
-
return 'low';
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
private hasDurationSpikes(history: TestExecutionRecord[]): boolean {
|
|
1216
|
-
const durations = history.map(r => r.duration);
|
|
1217
|
-
const avg = this.average(durations);
|
|
1218
|
-
const stdDev = this.standardDeviation(durations);
|
|
1219
|
-
|
|
1220
|
-
return durations.some(d => d > avg + 2 * stdDev);
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
private average(values: number[]): number {
|
|
1224
|
-
return values.length === 0 ? 0 : values.reduce((a, b) => a + b, 0) / values.length;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
private standardDeviation(values: number[]): number {
|
|
1228
|
-
const avg = this.average(values);
|
|
1229
|
-
const squareDiffs = values.map(v => (v - avg) ** 2);
|
|
1230
|
-
return Math.sqrt(this.average(squareDiffs));
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
private async storeReport(report: FlakyTestReport): Promise<void> {
|
|
1234
|
-
const reportId = uuidv4();
|
|
1235
|
-
await this.memory.set(`flaky-report:${reportId}`, report, {
|
|
1236
|
-
namespace: 'test-execution',
|
|
1237
|
-
persist: true,
|
|
1238
|
-
});
|
|
1239
|
-
}
|
|
1240
|
-
}
|