qa360 1.4.5 ā 2.0.1
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/README.md +1 -1
- package/dist/commands/ai.d.ts +41 -0
- package/dist/commands/ai.js +499 -0
- package/dist/commands/ask.js +12 -12
- package/dist/commands/coverage.d.ts +8 -0
- package/dist/commands/coverage.js +252 -0
- package/dist/commands/explain.d.ts +27 -0
- package/dist/commands/explain.js +630 -0
- package/dist/commands/flakiness.d.ts +73 -0
- package/dist/commands/flakiness.js +435 -0
- package/dist/commands/generate.d.ts +66 -0
- package/dist/commands/generate.js +438 -0
- package/dist/commands/init.d.ts +56 -9
- package/dist/commands/init.js +217 -10
- package/dist/commands/monitor.d.ts +27 -0
- package/dist/commands/monitor.js +225 -0
- package/dist/commands/ollama.d.ts +40 -0
- package/dist/commands/ollama.js +301 -0
- package/dist/commands/pack.d.ts +37 -9
- package/dist/commands/pack.js +240 -141
- package/dist/commands/regression.d.ts +8 -0
- package/dist/commands/regression.js +340 -0
- package/dist/commands/repair.d.ts +26 -0
- package/dist/commands/repair.js +307 -0
- package/dist/commands/retry.d.ts +43 -0
- package/dist/commands/retry.js +275 -0
- package/dist/commands/run.d.ts +8 -3
- package/dist/commands/run.js +45 -31
- package/dist/commands/slo.d.ts +8 -0
- package/dist/commands/slo.js +327 -0
- package/dist/core/adapters/playwright-native-api.d.ts +183 -0
- package/dist/core/adapters/playwright-native-api.js +461 -0
- package/dist/core/adapters/playwright-ui.d.ts +7 -0
- package/dist/core/adapters/playwright-ui.js +29 -1
- package/dist/core/ai/anthropic-provider.d.ts +50 -0
- package/dist/core/ai/anthropic-provider.js +211 -0
- package/dist/core/ai/deepseek-provider.d.ts +81 -0
- package/dist/core/ai/deepseek-provider.js +254 -0
- package/dist/core/ai/index.d.ts +60 -0
- package/dist/core/ai/index.js +18 -0
- package/dist/core/ai/llm-client.d.ts +45 -0
- package/dist/core/ai/llm-client.js +7 -0
- package/dist/core/ai/mock-provider.d.ts +49 -0
- package/dist/core/ai/mock-provider.js +121 -0
- package/dist/core/ai/ollama-provider.d.ts +78 -0
- package/dist/core/ai/ollama-provider.js +192 -0
- package/dist/core/ai/openai-provider.d.ts +48 -0
- package/dist/core/ai/openai-provider.js +188 -0
- package/dist/core/ai/provider-factory.d.ts +160 -0
- package/dist/core/ai/provider-factory.js +269 -0
- package/dist/core/auth/api-key-provider.d.ts +16 -0
- package/dist/core/auth/api-key-provider.js +63 -0
- package/dist/core/auth/aws-iam-provider.d.ts +35 -0
- package/dist/core/auth/aws-iam-provider.js +177 -0
- package/dist/core/auth/azure-ad-provider.d.ts +15 -0
- package/dist/core/auth/azure-ad-provider.js +99 -0
- package/dist/core/auth/basic-auth-provider.d.ts +26 -0
- package/dist/core/auth/basic-auth-provider.js +111 -0
- package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
- package/dist/core/auth/gcp-adc-provider.js +126 -0
- package/dist/core/auth/index.d.ts +238 -0
- package/dist/core/auth/index.js +82 -0
- package/dist/core/auth/jwt-provider.d.ts +19 -0
- package/dist/core/auth/jwt-provider.js +160 -0
- package/dist/core/auth/manager.d.ts +84 -0
- package/dist/core/auth/manager.js +230 -0
- package/dist/core/auth/oauth2-provider.d.ts +17 -0
- package/dist/core/auth/oauth2-provider.js +114 -0
- package/dist/core/auth/totp-provider.d.ts +31 -0
- package/dist/core/auth/totp-provider.js +134 -0
- package/dist/core/auth/ui-login-provider.d.ts +26 -0
- package/dist/core/auth/ui-login-provider.js +198 -0
- package/dist/core/cache/index.d.ts +7 -0
- package/dist/core/cache/index.js +6 -0
- package/dist/core/cache/lru-cache.d.ts +203 -0
- package/dist/core/cache/lru-cache.js +397 -0
- package/dist/core/coverage/analyzer.d.ts +101 -0
- package/dist/core/coverage/analyzer.js +415 -0
- package/dist/core/coverage/collector.d.ts +74 -0
- package/dist/core/coverage/collector.js +459 -0
- package/dist/core/coverage/config.d.ts +37 -0
- package/dist/core/coverage/config.js +156 -0
- package/dist/core/coverage/index.d.ts +11 -0
- package/dist/core/coverage/index.js +15 -0
- package/dist/core/coverage/types.d.ts +267 -0
- package/dist/core/coverage/types.js +6 -0
- package/dist/core/coverage/vault.d.ts +95 -0
- package/dist/core/coverage/vault.js +405 -0
- package/dist/core/dashboard/assets.d.ts +6 -0
- package/dist/core/dashboard/assets.js +690 -0
- package/dist/core/dashboard/index.d.ts +6 -0
- package/dist/core/dashboard/index.js +5 -0
- package/dist/core/dashboard/server.d.ts +72 -0
- package/dist/core/dashboard/server.js +354 -0
- package/dist/core/dashboard/types.d.ts +70 -0
- package/dist/core/dashboard/types.js +5 -0
- package/dist/core/discoverer/index.d.ts +115 -0
- package/dist/core/discoverer/index.js +250 -0
- package/dist/core/flakiness/index.d.ts +228 -0
- package/dist/core/flakiness/index.js +384 -0
- package/dist/core/generation/code-formatter.d.ts +111 -0
- package/dist/core/generation/code-formatter.js +307 -0
- package/dist/core/generation/code-generator.d.ts +144 -0
- package/dist/core/generation/code-generator.js +293 -0
- package/dist/core/generation/generator.d.ts +40 -0
- package/dist/core/generation/generator.js +76 -0
- package/dist/core/generation/index.d.ts +30 -0
- package/dist/core/generation/index.js +28 -0
- package/dist/core/generation/pack-generator.d.ts +107 -0
- package/dist/core/generation/pack-generator.js +416 -0
- package/dist/core/generation/prompt-builder.d.ts +132 -0
- package/dist/core/generation/prompt-builder.js +672 -0
- package/dist/core/generation/source-analyzer.d.ts +213 -0
- package/dist/core/generation/source-analyzer.js +657 -0
- package/dist/core/generation/test-optimizer.d.ts +117 -0
- package/dist/core/generation/test-optimizer.js +328 -0
- package/dist/core/generation/types.d.ts +214 -0
- package/dist/core/generation/types.js +4 -0
- package/dist/core/index.d.ts +23 -1
- package/dist/core/index.js +39 -0
- package/dist/core/pack/validator.js +31 -1
- package/dist/core/pack-v2/index.d.ts +9 -0
- package/dist/core/pack-v2/index.js +8 -0
- package/dist/core/pack-v2/loader.d.ts +62 -0
- package/dist/core/pack-v2/loader.js +231 -0
- package/dist/core/pack-v2/migrator.d.ts +56 -0
- package/dist/core/pack-v2/migrator.js +455 -0
- package/dist/core/pack-v2/validator.d.ts +61 -0
- package/dist/core/pack-v2/validator.js +577 -0
- package/dist/core/regression/detector.d.ts +107 -0
- package/dist/core/regression/detector.js +497 -0
- package/dist/core/regression/index.d.ts +9 -0
- package/dist/core/regression/index.js +11 -0
- package/dist/core/regression/trend-analyzer.d.ts +102 -0
- package/dist/core/regression/trend-analyzer.js +345 -0
- package/dist/core/regression/types.d.ts +222 -0
- package/dist/core/regression/types.js +7 -0
- package/dist/core/regression/vault.d.ts +87 -0
- package/dist/core/regression/vault.js +289 -0
- package/dist/core/repair/engine/fixer.d.ts +24 -0
- package/dist/core/repair/engine/fixer.js +226 -0
- package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
- package/dist/core/repair/engine/suggestion-engine.js +187 -0
- package/dist/core/repair/index.d.ts +10 -0
- package/dist/core/repair/index.js +13 -0
- package/dist/core/repair/repairer.d.ts +90 -0
- package/dist/core/repair/repairer.js +284 -0
- package/dist/core/repair/types.d.ts +91 -0
- package/dist/core/repair/types.js +6 -0
- package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
- package/dist/core/repair/utils/error-analyzer.js +264 -0
- package/dist/core/retry/flakiness-integration.d.ts +60 -0
- package/dist/core/retry/flakiness-integration.js +228 -0
- package/dist/core/retry/index.d.ts +14 -0
- package/dist/core/retry/index.js +16 -0
- package/dist/core/retry/retry-engine.d.ts +80 -0
- package/dist/core/retry/retry-engine.js +296 -0
- package/dist/core/retry/types.d.ts +178 -0
- package/dist/core/retry/types.js +52 -0
- package/dist/core/retry/vault.d.ts +77 -0
- package/dist/core/retry/vault.js +304 -0
- package/dist/core/runner/e2e-helpers.d.ts +102 -0
- package/dist/core/runner/e2e-helpers.js +153 -0
- package/dist/core/runner/phase3-runner.d.ts +101 -2
- package/dist/core/runner/phase3-runner.js +559 -24
- package/dist/core/self-healing/assertion-healer.d.ts +97 -0
- package/dist/core/self-healing/assertion-healer.js +371 -0
- package/dist/core/self-healing/engine.d.ts +122 -0
- package/dist/core/self-healing/engine.js +538 -0
- package/dist/core/self-healing/index.d.ts +10 -0
- package/dist/core/self-healing/index.js +11 -0
- package/dist/core/self-healing/selector-healer.d.ts +103 -0
- package/dist/core/self-healing/selector-healer.js +372 -0
- package/dist/core/self-healing/types.d.ts +152 -0
- package/dist/core/self-healing/types.js +6 -0
- package/dist/core/slo/config.d.ts +107 -0
- package/dist/core/slo/config.js +360 -0
- package/dist/core/slo/index.d.ts +11 -0
- package/dist/core/slo/index.js +15 -0
- package/dist/core/slo/sli-calculator.d.ts +92 -0
- package/dist/core/slo/sli-calculator.js +364 -0
- package/dist/core/slo/slo-tracker.d.ts +148 -0
- package/dist/core/slo/slo-tracker.js +379 -0
- package/dist/core/slo/types.d.ts +281 -0
- package/dist/core/slo/types.js +7 -0
- package/dist/core/slo/vault.d.ts +102 -0
- package/dist/core/slo/vault.js +427 -0
- package/dist/core/tui/index.d.ts +7 -0
- package/dist/core/tui/index.js +6 -0
- package/dist/core/tui/monitor.d.ts +92 -0
- package/dist/core/tui/monitor.js +271 -0
- package/dist/core/tui/renderer.d.ts +33 -0
- package/dist/core/tui/renderer.js +218 -0
- package/dist/core/tui/types.d.ts +63 -0
- package/dist/core/tui/types.js +5 -0
- package/dist/core/types/pack-v2.d.ts +425 -0
- package/dist/core/types/pack-v2.js +8 -0
- package/dist/core/vault/index.d.ts +116 -0
- package/dist/core/vault/index.js +400 -5
- package/dist/core/watch/index.d.ts +7 -0
- package/dist/core/watch/index.js +6 -0
- package/dist/core/watch/watch-mode.d.ts +213 -0
- package/dist/core/watch/watch-mode.js +389 -0
- package/dist/index.js +68 -68
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +136 -0
- package/package.json +5 -1
- package/dist/core/adapters/playwright-api.d.ts +0 -82
- package/dist/core/adapters/playwright-api.js +0 -264
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Coverage Command
|
|
3
|
+
*
|
|
4
|
+
* CLI command for coverage analytics and reporting.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { CoverageCollector, CoverageAnalyzer, parseCoverageThreshold, formatCoverageThreshold } from '../core/index.js';
|
|
9
|
+
export const coverageCommand = new Command('coverage');
|
|
10
|
+
coverageCommand.description('Coverage analytics and reporting');
|
|
11
|
+
// Show coverage for a specific file or run
|
|
12
|
+
coverageCommand
|
|
13
|
+
.command('show')
|
|
14
|
+
.description('Show coverage metrics')
|
|
15
|
+
.option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
|
|
16
|
+
.option('-r, --run <id>', 'Run ID to fetch from vault')
|
|
17
|
+
.option('--json', 'Output as JSON')
|
|
18
|
+
.option('--verbose', 'Show detailed file-by-file coverage')
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
if (!options.file && !options.run) {
|
|
21
|
+
console.error('Error: Please specify --file or --run');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const collector = new CoverageCollector();
|
|
25
|
+
const analyzer = new CoverageAnalyzer();
|
|
26
|
+
let result;
|
|
27
|
+
if (options.file) {
|
|
28
|
+
if (!existsSync(options.file)) {
|
|
29
|
+
console.error(`Error: File not found: ${options.file}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
result = await collector.collectFromFile(options.file);
|
|
33
|
+
if (!result) {
|
|
34
|
+
console.error('Error: Could not parse coverage file');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (options.run) {
|
|
39
|
+
// TODO: Fetch from vault when vault integration is complete
|
|
40
|
+
console.error('Error: Vault fetch not yet implemented');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
if (!result)
|
|
44
|
+
return;
|
|
45
|
+
if (options.json) {
|
|
46
|
+
console.log(JSON.stringify(result, null, 2));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Print summary
|
|
50
|
+
console.log('\nš Coverage Report\n');
|
|
51
|
+
console.log(`Line Coverage: ${analyzer.formatCoverage(result.metrics.lineCoverage)}`);
|
|
52
|
+
console.log(`Branch Coverage: ${analyzer.formatCoverage(result.metrics.branchCoverage)}`);
|
|
53
|
+
console.log(`Function Coverage: ${analyzer.formatCoverage(result.metrics.functionCoverage)}`);
|
|
54
|
+
console.log(`Statement Coverage: ${analyzer.formatCoverage(result.metrics.statementCoverage)}`);
|
|
55
|
+
console.log(`\nFiles: ${result.metrics.filesWithCoverage}/${result.metrics.totalFiles}`);
|
|
56
|
+
if (options.verbose) {
|
|
57
|
+
console.log('\nš File Coverage:\n');
|
|
58
|
+
const files = Object.entries(result.files)
|
|
59
|
+
.sort((a, b) => a[1].lineCoverage - b[1].lineCoverage);
|
|
60
|
+
for (const [path, file] of files) {
|
|
61
|
+
const status = file.lineCoverage >= 80 ? 'ā' : file.lineCoverage >= 60 ? 'ā ' : 'ā';
|
|
62
|
+
console.log(` ${status} ${path}`);
|
|
63
|
+
console.log(` Lines: ${file.coveredLines}/${file.totalLines} (${file.lineCoverage.toFixed(1)}%)`);
|
|
64
|
+
console.log(` Branches: ${file.coveredBranches}/${file.totalBranches} (${file.branchCoverage.toFixed(1)}%)`);
|
|
65
|
+
console.log(` Functions: ${file.coveredFunctions}/${file.totalFunctions} (${file.functionCoverage.toFixed(1)}%)`);
|
|
66
|
+
if (file.uncoveredLines.length > 0 && file.uncoveredLines.length <= 10) {
|
|
67
|
+
console.log(` Uncovered: ${file.uncoveredLines.join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
else if (file.uncoveredLines.length > 10) {
|
|
70
|
+
console.log(` Uncovered: ${file.uncoveredLines.slice(0, 10).join(', ')} ... (${file.uncoveredLines.length} total)`);
|
|
71
|
+
}
|
|
72
|
+
console.log('');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// Analyze coverage and find gaps
|
|
77
|
+
coverageCommand
|
|
78
|
+
.command('analyze')
|
|
79
|
+
.description('Analyze coverage and find gaps')
|
|
80
|
+
.option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
|
|
81
|
+
.option('-t, --threshold <value>', 'Coverage threshold (default: 80)', '80')
|
|
82
|
+
.option('--json', 'Output as JSON')
|
|
83
|
+
.action(async (options) => {
|
|
84
|
+
if (!options.file) {
|
|
85
|
+
console.error('Error: Please specify --file');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
if (!existsSync(options.file)) {
|
|
89
|
+
console.error(`Error: File not found: ${options.file}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const collector = new CoverageCollector();
|
|
93
|
+
const analyzer = new CoverageAnalyzer();
|
|
94
|
+
const result = await collector.collectFromFile(options.file);
|
|
95
|
+
if (!result) {
|
|
96
|
+
console.error('Error: Could not parse coverage file');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
const threshold = parseCoverageThreshold(options.threshold);
|
|
100
|
+
const report = analyzer.analyze(result, threshold);
|
|
101
|
+
if (options.json) {
|
|
102
|
+
console.log(JSON.stringify(report, null, 2));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.log('\nš Coverage Analysis\n');
|
|
106
|
+
console.log(`Overall Coverage: ${report.metrics.lineCoverage.toFixed(1)}%`);
|
|
107
|
+
console.log(`Thresholds Met: ${report.thresholdsMet ? 'ā Yes' : 'ā No'}`);
|
|
108
|
+
console.log(`Files Meeting Threshold: ${report.metrics.filesMeetingThreshold}/${report.metrics.totalFiles}`);
|
|
109
|
+
if (report.gaps.length > 0) {
|
|
110
|
+
console.log('\nš“ Coverage Gaps (files below threshold):\n');
|
|
111
|
+
for (const gap of report.gaps) {
|
|
112
|
+
const icon = gap.priority === 'high' ? 'š“' : gap.priority === 'medium' ? 'š”' : 'š¢';
|
|
113
|
+
console.log(` ${icon} ${gap.path}`);
|
|
114
|
+
console.log(` Current: ${gap.currentCoverage.toFixed(1)}% | Target: ${gap.targetCoverage}% | Gap: ${gap.gap.toFixed(1)}%`);
|
|
115
|
+
console.log(` Effort: ${gap.effort} | Uncovered: ${gap.uncoveredCount} lines`);
|
|
116
|
+
if (gap.suggestions.length > 0) {
|
|
117
|
+
console.log(` Suggestions:`);
|
|
118
|
+
for (const suggestion of gap.suggestions) {
|
|
119
|
+
console.log(` - ${suggestion}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
console.log('');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log('\nā All files meet the coverage threshold!\n');
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// Compare two coverage files
|
|
130
|
+
coverageCommand
|
|
131
|
+
.command('diff')
|
|
132
|
+
.description('Compare two coverage files')
|
|
133
|
+
.option('-b, --base <path>', 'Base coverage file')
|
|
134
|
+
.option('-c, --compare <path>', 'Comparison coverage file')
|
|
135
|
+
.option('--json', 'Output as JSON')
|
|
136
|
+
.action(async (options) => {
|
|
137
|
+
if (!options.base || !options.compare) {
|
|
138
|
+
console.error('Error: Please specify both --base and --compare');
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
if (!existsSync(options.base)) {
|
|
142
|
+
console.error(`Error: Base file not found: ${options.base}`);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
if (!existsSync(options.compare)) {
|
|
146
|
+
console.error(`Error: Compare file not found: ${options.compare}`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const collector = new CoverageCollector();
|
|
150
|
+
const analyzer = new CoverageAnalyzer();
|
|
151
|
+
const baseResult = await collector.collectFromFile(options.base);
|
|
152
|
+
const compareResult = await collector.collectFromFile(options.compare);
|
|
153
|
+
if (!baseResult || !compareResult) {
|
|
154
|
+
console.error('Error: Could not parse coverage files');
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
const comparison = analyzer.compare(baseResult, compareResult);
|
|
158
|
+
if (options.json) {
|
|
159
|
+
console.log(JSON.stringify(comparison, null, 2));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
console.log('\nš Coverage Comparison\n');
|
|
163
|
+
console.log(`Overall Change: ${comparison.overallChange >= 0 ? '+' : ''}${comparison.overallChange.toFixed(1)}%`);
|
|
164
|
+
if (comparison.improved.length > 0) {
|
|
165
|
+
console.log('\nā
Improved Files:\n');
|
|
166
|
+
for (const file of comparison.improved.slice(0, 10)) {
|
|
167
|
+
console.log(` ${file.path}`);
|
|
168
|
+
console.log(` ${file.before.toFixed(1)}% ā ${file.after.toFixed(1)}% (+${file.delta.toFixed(1)}%)`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (comparison.regressed.length > 0) {
|
|
172
|
+
console.log('\nā ļø Regressed Files:\n');
|
|
173
|
+
for (const file of comparison.regressed.slice(0, 10)) {
|
|
174
|
+
console.log(` ${file.path}`);
|
|
175
|
+
console.log(` ${file.before.toFixed(1)}% ā ${file.after.toFixed(1)}% (${file.delta.toFixed(1)}%)`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (comparison.newFiles.length > 0) {
|
|
179
|
+
console.log('\nš New Files:\n');
|
|
180
|
+
for (const file of comparison.newFiles.slice(0, 10)) {
|
|
181
|
+
console.log(` ${file}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (comparison.removedFiles.length > 0) {
|
|
185
|
+
console.log('\nšļø Removed Files:\n');
|
|
186
|
+
for (const file of comparison.removedFiles.slice(0, 10)) {
|
|
187
|
+
console.log(` ${file}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
console.log('');
|
|
191
|
+
});
|
|
192
|
+
// List coverage files in project
|
|
193
|
+
coverageCommand
|
|
194
|
+
.command('list')
|
|
195
|
+
.description('List available coverage files in the project')
|
|
196
|
+
.action(() => {
|
|
197
|
+
const coveragePaths = [
|
|
198
|
+
'coverage/coverage-final.json',
|
|
199
|
+
'coverage/lcov.info',
|
|
200
|
+
'coverage/lcov-report/index.html',
|
|
201
|
+
'.nyc_output/out.json',
|
|
202
|
+
'coverage/istanbul.json'
|
|
203
|
+
];
|
|
204
|
+
console.log('\nš Coverage Files:\n');
|
|
205
|
+
for (const path of coveragePaths) {
|
|
206
|
+
const exists = existsSync(path);
|
|
207
|
+
const status = exists ? 'ā' : 'ā';
|
|
208
|
+
console.log(` ${status} ${path}`);
|
|
209
|
+
}
|
|
210
|
+
console.log('');
|
|
211
|
+
});
|
|
212
|
+
// Validate coverage against thresholds
|
|
213
|
+
coverageCommand
|
|
214
|
+
.command('check')
|
|
215
|
+
.description('Check if coverage meets thresholds')
|
|
216
|
+
.option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
|
|
217
|
+
.option('-t, --threshold <value>', 'Coverage threshold (default: line:80,branch:70)', 'line:80,branch:70')
|
|
218
|
+
.option('--fail', 'Exit with error code if thresholds not met')
|
|
219
|
+
.action(async (options) => {
|
|
220
|
+
if (!options.file) {
|
|
221
|
+
console.error('Error: Please specify --file');
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
if (!existsSync(options.file)) {
|
|
225
|
+
console.error(`Error: File not found: ${options.file}`);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
const collector = new CoverageCollector();
|
|
229
|
+
const analyzer = new CoverageAnalyzer();
|
|
230
|
+
const result = await collector.collectFromFile(options.file);
|
|
231
|
+
if (!result) {
|
|
232
|
+
console.error('Error: Could not parse coverage file');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
const threshold = parseCoverageThreshold(options.threshold);
|
|
236
|
+
const passed = analyzer.checkThresholds(result.metrics, threshold);
|
|
237
|
+
console.log('\nš Coverage Check\n');
|
|
238
|
+
console.log(`Threshold: ${formatCoverageThreshold(threshold)}`);
|
|
239
|
+
console.log(`Line Coverage: ${result.metrics.lineCoverage.toFixed(1)}% ${result.metrics.lineCoverage >= (threshold.line || 0) ? 'ā' : 'ā'}`);
|
|
240
|
+
console.log(`Branch Coverage: ${result.metrics.branchCoverage.toFixed(1)}% ${result.metrics.branchCoverage >= (threshold.branch || 0) ? 'ā' : 'ā'}`);
|
|
241
|
+
console.log(`Function Coverage: ${result.metrics.functionCoverage.toFixed(1)}% ${result.metrics.functionCoverage >= (threshold.function || 0) ? 'ā' : 'ā'}`);
|
|
242
|
+
if (passed) {
|
|
243
|
+
console.log('\nā
All thresholds met!\n');
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.log('\nā Some thresholds not met!\n');
|
|
247
|
+
if (options.fail) {
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
export default coverageCommand;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Explain Command
|
|
3
|
+
*
|
|
4
|
+
* Advanced error and failure explanations with:
|
|
5
|
+
* - Static error code database
|
|
6
|
+
* - AI-powered explanations
|
|
7
|
+
* - Vault-based historical context
|
|
8
|
+
* - Flakiness insights
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* qa360 explain QX001 # Static error code
|
|
12
|
+
* qa360 explain --ai "my test failed" # AI explanation
|
|
13
|
+
* qa360 explain --run run-xxx # Explain run results
|
|
14
|
+
* qa360 explain --gate api_smoke # Explain gate failure
|
|
15
|
+
*/
|
|
16
|
+
export interface ExplainOptions {
|
|
17
|
+
ai?: boolean;
|
|
18
|
+
provider?: string;
|
|
19
|
+
run?: string;
|
|
20
|
+
gate?: string;
|
|
21
|
+
json?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Main explain command
|
|
25
|
+
*/
|
|
26
|
+
export declare function explainCommand(input: string | undefined, options?: ExplainOptions): Promise<void>;
|
|
27
|
+
export default explainCommand;
|