api-tests-coverage 1.0.6 → 1.0.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/dist/src/index.js +49 -24
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -1427,10 +1427,34 @@ program
|
|
|
1427
1427
|
// ── 4. Full coverage analysis → coverage-summary.json ─────────────────
|
|
1428
1428
|
const allCoverageResults = [];
|
|
1429
1429
|
const fsMod = require('fs');
|
|
1430
|
+
// When test files are explicitly discovered, use them directly.
|
|
1431
|
+
// Otherwise fall back to a test-file-pattern glob (avoids scanning node_modules
|
|
1432
|
+
// or the entire project tree, which can hang on large repositories).
|
|
1430
1433
|
const testsGlob = artifacts.testFiles.length > 0
|
|
1431
1434
|
? '{' + artifacts.testFiles.join(',') + '}'
|
|
1432
|
-
: path.join(rootDir, '**', '
|
|
1435
|
+
: path.join(rootDir, '**', '*.{test,spec}.{js,ts,jsx,tsx,mjs,cjs,py,rb}');
|
|
1433
1436
|
const detectedLanguages = artifacts.languages;
|
|
1437
|
+
// Pre-compute test entries once from the discovered test files.
|
|
1438
|
+
// These are reused for endpoint, error, and business-rule coverage matching
|
|
1439
|
+
// (avoids multiple glob expansions which can hang on large projects).
|
|
1440
|
+
const TEST_DECL_RE = /\b(?:test|it)\s*\(\s*(['"`])([\s\S]*?)\1/g;
|
|
1441
|
+
const testEntries = artifacts.testFiles.flatMap((tf) => {
|
|
1442
|
+
let content = '';
|
|
1443
|
+
try {
|
|
1444
|
+
content = fsMod.readFileSync(tf, 'utf-8');
|
|
1445
|
+
}
|
|
1446
|
+
catch {
|
|
1447
|
+
return [];
|
|
1448
|
+
}
|
|
1449
|
+
const descriptions = [];
|
|
1450
|
+
const contentLower = content.toLowerCase();
|
|
1451
|
+
let m;
|
|
1452
|
+
TEST_DECL_RE.lastIndex = 0;
|
|
1453
|
+
while ((m = TEST_DECL_RE.exec(content)) !== null) {
|
|
1454
|
+
descriptions.push(m[2].toLowerCase());
|
|
1455
|
+
}
|
|
1456
|
+
return [{ file: tf, contentLower, descriptions }];
|
|
1457
|
+
});
|
|
1434
1458
|
if (artifacts.specs.length > 0) {
|
|
1435
1459
|
for (const specPath of artifacts.specs) {
|
|
1436
1460
|
// ── 4a. Endpoint coverage ───────────────────────────────────────────
|
|
@@ -1514,27 +1538,6 @@ program
|
|
|
1514
1538
|
console.log(` Routes detected in service code: ${routeResult.routes.length}`);
|
|
1515
1539
|
console.log(` Written to: ${routesPath}`);
|
|
1516
1540
|
console.log(`\nAnalyzing endpoint coverage (from inferred routes)...`);
|
|
1517
|
-
// Read test file contents for matching
|
|
1518
|
-
const testContents = artifacts.testFiles.map((tf) => {
|
|
1519
|
-
try {
|
|
1520
|
-
return { file: tf, content: fsMod.readFileSync(tf, 'utf-8') };
|
|
1521
|
-
}
|
|
1522
|
-
catch {
|
|
1523
|
-
return { file: tf, content: '' };
|
|
1524
|
-
}
|
|
1525
|
-
});
|
|
1526
|
-
// Extract test descriptions for fine-grained matching
|
|
1527
|
-
const TEST_DECL_PATTERN = /\b(?:test|it)\s*\(\s*(['"`])([\s\S]*?)\1/g;
|
|
1528
|
-
const testEntries = testContents.map(({ file, content }) => {
|
|
1529
|
-
const descriptions = [];
|
|
1530
|
-
const contentLower = content.toLowerCase();
|
|
1531
|
-
let m;
|
|
1532
|
-
TEST_DECL_PATTERN.lastIndex = 0;
|
|
1533
|
-
while ((m = TEST_DECL_PATTERN.exec(content)) !== null) {
|
|
1534
|
-
descriptions.push(m[2].toLowerCase());
|
|
1535
|
-
}
|
|
1536
|
-
return { file, contentLower, descriptions };
|
|
1537
|
-
});
|
|
1538
1541
|
const endpointItems = routeResult.routes.map((route) => {
|
|
1539
1542
|
var _a;
|
|
1540
1543
|
const pathSegments = route.path.split('/').filter((s) => s.length > 1 && !s.startsWith(':'));
|
|
@@ -1684,7 +1687,9 @@ program
|
|
|
1684
1687
|
}
|
|
1685
1688
|
}
|
|
1686
1689
|
else if (inferredRulesResult && inferredRulesResult.rules.length > 0) {
|
|
1687
|
-
// Auto-inferred: use specificKeywords from rule for accurate test matching
|
|
1690
|
+
// Auto-inferred: use specificKeywords from rule for accurate test matching.
|
|
1691
|
+
// Reuse the testEntries already computed for endpoint coverage — avoids
|
|
1692
|
+
// a second glob expansion (which can be slow/hang on large projects).
|
|
1688
1693
|
try {
|
|
1689
1694
|
console.log(`\nAnalyzing business rules coverage (from inferred rules)...`);
|
|
1690
1695
|
const syntheticRules = inferredRulesResult.rules.map((r) => {
|
|
@@ -1715,7 +1720,27 @@ program
|
|
|
1715
1720
|
scenarios: [],
|
|
1716
1721
|
};
|
|
1717
1722
|
});
|
|
1718
|
-
|
|
1723
|
+
// Match rules against the testEntries already built for endpoint coverage.
|
|
1724
|
+
// This avoids a second glob expansion and is safe when there are no test files.
|
|
1725
|
+
const bizCoverages = syntheticRules.map((rule) => {
|
|
1726
|
+
const kwsLower = rule.keywords.map((k) => k.toLowerCase());
|
|
1727
|
+
const matchedDescs = [];
|
|
1728
|
+
const matchedFileSet = new Set();
|
|
1729
|
+
for (const { file, descriptions } of testEntries) {
|
|
1730
|
+
const hitting = descriptions.filter((desc) => kwsLower.length > 0 && kwsLower.some((kw) => desc.includes(kw)));
|
|
1731
|
+
if (hitting.length > 0) {
|
|
1732
|
+
matchedDescs.push(...hitting);
|
|
1733
|
+
matchedFileSet.add(file);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return {
|
|
1737
|
+
rule,
|
|
1738
|
+
covered: matchedDescs.length > 0,
|
|
1739
|
+
testFiles: [...matchedFileSet],
|
|
1740
|
+
matchedTests: matchedDescs,
|
|
1741
|
+
scenarios: [],
|
|
1742
|
+
};
|
|
1743
|
+
});
|
|
1719
1744
|
const bizReport = (0, businessCoverage_1.buildBusinessCoverageReport)(bizCoverages);
|
|
1720
1745
|
const bizResult = {
|
|
1721
1746
|
type: 'business',
|
package/package.json
CHANGED