api-tests-coverage 1.0.17 → 1.0.19
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 +7 -3
- package/dist/dashboard/dist/assets/_basePickBy-CYB1KXah.js +1 -0
- package/dist/dashboard/dist/assets/_basePickBy-DUQHbXda.js +1 -0
- package/dist/dashboard/dist/assets/_baseUniq-Bwm426M6.js +1 -0
- package/dist/dashboard/dist/assets/_baseUniq-Ct8XEXnH.js +1 -0
- package/dist/dashboard/dist/assets/arc-B7p8x22e.js +1 -0
- package/dist/dashboard/dist/assets/arc-CjFGY63A.js +1 -0
- package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-Boahc5dR.js +36 -0
- package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-wVr1_uNB.js +36 -0
- package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-BBXc88fn.js +122 -0
- package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-CavSRNuP.js +122 -0
- package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-BsgzPfQ3.js +10 -0
- package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-w18S5AEN.js +10 -0
- package/dist/dashboard/dist/assets/channel-BgeGdqQG.js +1 -0
- package/dist/dashboard/dist/assets/channel-psxgcQ_j.js +1 -0
- package/dist/dashboard/dist/assets/chunk-4BX2VUAB-BF8loPLD.js +1 -0
- package/dist/dashboard/dist/assets/chunk-4BX2VUAB-IN53WLTx.js +1 -0
- package/dist/dashboard/dist/assets/chunk-55IACEB6-C3HNF-UF.js +1 -0
- package/dist/dashboard/dist/assets/chunk-55IACEB6-kJkjQYxk.js +1 -0
- package/dist/dashboard/dist/assets/chunk-B4BG7PRW-B7YfMggR.js +165 -0
- package/dist/dashboard/dist/assets/chunk-B4BG7PRW-wQ6TCEMq.js +165 -0
- package/dist/dashboard/dist/assets/chunk-DI55MBZ5-B7xHuqZu.js +220 -0
- package/dist/dashboard/dist/assets/chunk-DI55MBZ5-DfslhtXS.js +220 -0
- package/dist/dashboard/dist/assets/chunk-FMBD7UC4-BBMfQbw1.js +15 -0
- package/dist/dashboard/dist/assets/chunk-FMBD7UC4-K3PC79JF.js +15 -0
- package/dist/dashboard/dist/assets/chunk-QN33PNHL-CmeZ1h1Z.js +1 -0
- package/dist/dashboard/dist/assets/chunk-QN33PNHL-DFgUs0T8.js +1 -0
- package/dist/dashboard/dist/assets/chunk-QZHKN3VN-Cyg7Km90.js +1 -0
- package/dist/dashboard/dist/assets/chunk-QZHKN3VN-DKgOcPif.js +1 -0
- package/dist/dashboard/dist/assets/chunk-TZMSLE5B-BoJFBewj.js +1 -0
- package/dist/dashboard/dist/assets/chunk-TZMSLE5B-C8KNXDi7.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-AMwn99HP.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-CM6Qs-Qs.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-AMwn99HP.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-CM6Qs-Qs.js +1 -0
- package/dist/dashboard/dist/assets/clone-DEYRVSAn.js +1 -0
- package/dist/dashboard/dist/assets/clone-KEkbvJY9.js +1 -0
- package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-DMGRGhwB.js +1 -0
- package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-YL9kFxCl.js +1 -0
- package/dist/dashboard/dist/assets/dagre-6UL2VRFP-CJT7lofP.js +4 -0
- package/dist/dashboard/dist/assets/dagre-6UL2VRFP-NZWnQN_Y.js +4 -0
- package/dist/dashboard/dist/assets/diagram-PSM6KHXK-DGtyS7lD.js +24 -0
- package/dist/dashboard/dist/assets/diagram-PSM6KHXK-DtE0cTIs.js +24 -0
- package/dist/dashboard/dist/assets/diagram-QEK2KX5R-BHyZd544.js +43 -0
- package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CSCGZUfr.js +43 -0
- package/dist/dashboard/dist/assets/diagram-S2PKOQOG-DdqZVGN1.js +24 -0
- package/dist/dashboard/dist/assets/diagram-S2PKOQOG-qvXlTDud.js +24 -0
- package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-D0MbudeO.js +60 -0
- package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-Dhb_VQMS.js +60 -0
- package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-DRAD4OG7.js +162 -0
- package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-gKUH-GJ2.js +162 -0
- package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-DK_45K6s.js +267 -0
- package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-Dm_lLo9y.js +267 -0
- package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DM9AW1aP.js +65 -0
- package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DYrdM8tK.js +65 -0
- package/dist/dashboard/dist/assets/graph-CD7-npU0.js +1 -0
- package/dist/dashboard/dist/assets/graph-Clj85F2M.js +1 -0
- package/dist/dashboard/dist/assets/index-CqEIqNus.js +781 -0
- package/dist/dashboard/dist/assets/index-DbUdNJca.js +781 -0
- package/dist/dashboard/dist/assets/index-xecKLQ58.css +1 -0
- package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-BMp4C5wf.js +2 -0
- package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-DyT5Fs8R.js +2 -0
- package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-BC0GSZ7W.js +139 -0
- package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-nYZBlgTD.js +139 -0
- package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-COTfX74l.js +89 -0
- package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-D6aRd_q1.js +89 -0
- package/dist/dashboard/dist/assets/layout-6njVG9Ld.js +1 -0
- package/dist/dashboard/dist/assets/layout-BbJNDkTr.js +1 -0
- package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-B93XW27v.js +68 -0
- package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-CkyYtMaD.js +68 -0
- package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-9G1tEuaq.js +30 -0
- package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-uWFQFMEe.js +30 -0
- package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-i3-JTN3e.js +7 -0
- package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-jDtdB4Ws.js +7 -0
- package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-Dw260IiT.js +64 -0
- package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-WIJ0qiJG.js +64 -0
- package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-Cb4WB9UB.js +10 -0
- package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-LR8T4Hv0.js +10 -0
- package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-BqGJWVUS.js +145 -0
- package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-DBqchhlr.js +145 -0
- package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-0Wd-KmOv.js +1 -0
- package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-Bl16d4W5.js +1 -0
- package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-B05ygO34.js +1 -0
- package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-BlwaoFEG.js +1 -0
- package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-CAmQOjBu.js +61 -0
- package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-D6JNee_P.js +61 -0
- package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CCvvSJBX.js +162 -0
- package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CRP-WvE-.js +162 -0
- package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-5DoR2_q5.js +7 -0
- package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-B72UwDAP.js +7 -0
- package/dist/dashboard/dist/index.html +2 -2
- package/dist/src/config/defaultConfig.d.ts.map +1 -1
- package/dist/src/config/defaultConfig.js +37 -0
- package/dist/src/config/types.d.ts +42 -0
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/config/validateConfig.d.ts.map +1 -1
- package/dist/src/config/validateConfig.js +3 -0
- package/dist/src/generation/ai-flow-exporter.d.ts +7 -0
- package/dist/src/generation/ai-flow-exporter.d.ts.map +1 -0
- package/dist/src/generation/ai-flow-exporter.js +260 -0
- package/dist/src/generation/context-builder.d.ts +16 -0
- package/dist/src/generation/context-builder.d.ts.map +1 -0
- package/dist/src/generation/context-builder.js +170 -0
- package/dist/src/generation/engine.d.ts +19 -0
- package/dist/src/generation/engine.d.ts.map +1 -0
- package/dist/src/generation/engine.js +204 -0
- package/dist/src/generation/file-router.d.ts +8 -0
- package/dist/src/generation/file-router.d.ts.map +1 -0
- package/dist/src/generation/file-router.js +98 -0
- package/dist/src/generation/gap-extractor.d.ts +7 -0
- package/dist/src/generation/gap-extractor.d.ts.map +1 -0
- package/dist/src/generation/gap-extractor.js +291 -0
- package/dist/src/generation/index.d.ts +9 -0
- package/dist/src/generation/index.d.ts.map +1 -0
- package/dist/src/generation/index.js +15 -0
- package/dist/src/generation/quality-scorer.d.ts +15 -0
- package/dist/src/generation/quality-scorer.d.ts.map +1 -0
- package/dist/src/generation/quality-scorer.js +273 -0
- package/dist/src/generation/template-renderer.d.ts +12 -0
- package/dist/src/generation/template-renderer.d.ts.map +1 -0
- package/dist/src/generation/template-renderer.js +546 -0
- package/dist/src/generation/types.d.ts +269 -0
- package/dist/src/generation/types.d.ts.map +1 -0
- package/dist/src/generation/types.js +6 -0
- package/dist/src/index.js +113 -0
- package/dist/src/inference/routeInference.d.ts.map +1 -1
- package/dist/src/inference/routeInference.js +54 -8
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature 28 — FileRouter
|
|
3
|
+
* Determines output file paths for generated test files.
|
|
4
|
+
*/
|
|
5
|
+
import type { DetectedGap, TestType, FileNamingConvention } from './types';
|
|
6
|
+
export declare function routeOutputFile(gap: DetectedGap, testType: TestType, outDir: string, language: string, convention?: FileNamingConvention): string;
|
|
7
|
+
export declare function sortGapsByPriority(gaps: DetectedGap[]): DetectedGap[];
|
|
8
|
+
//# sourceMappingURL=file-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-router.d.ts","sourceRoot":"","sources":["../../../src/generation/file-router.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAyC3E,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,oBAA8B,GACzC,MAAM,CAoBR;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAErE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feature 28 — FileRouter
|
|
4
|
+
* Determines output file paths for generated test files.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.routeOutputFile = routeOutputFile;
|
|
41
|
+
exports.sortGapsByPriority = sortGapsByPriority;
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const PRIORITY_ORDER = { P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5 };
|
|
44
|
+
function toKebab(s) {
|
|
45
|
+
return s
|
|
46
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
47
|
+
.replace(/[^a-zA-Z0-9]+/g, '-')
|
|
48
|
+
.replace(/^-+|-+$/g, '')
|
|
49
|
+
.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
function toCamel(s) {
|
|
52
|
+
return toKebab(s)
|
|
53
|
+
.split('-')
|
|
54
|
+
.map((w, i) => (i === 0 ? w : w.charAt(0).toUpperCase() + w.slice(1)))
|
|
55
|
+
.join('');
|
|
56
|
+
}
|
|
57
|
+
function toSnake(s) {
|
|
58
|
+
return toKebab(s).replace(/-/g, '_');
|
|
59
|
+
}
|
|
60
|
+
function applyNaming(name, convention) {
|
|
61
|
+
switch (convention) {
|
|
62
|
+
case 'camelCase': return toCamel(name);
|
|
63
|
+
case 'snake_case': return toSnake(name);
|
|
64
|
+
case 'kebab':
|
|
65
|
+
default: return toKebab(name);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function pathToFileName(method, apiPath, convention) {
|
|
69
|
+
const parts = apiPath
|
|
70
|
+
.split('/')
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.map(p => p.replace(/[{}]/g, '').replace(/[^a-zA-Z0-9]/g, '-'));
|
|
73
|
+
const base = [...parts, method.toLowerCase()].join('-');
|
|
74
|
+
return applyNaming(base, convention);
|
|
75
|
+
}
|
|
76
|
+
function routeOutputFile(gap, testType, outDir, language, convention = 'kebab') {
|
|
77
|
+
const method = gap.endpoint.method.toLowerCase();
|
|
78
|
+
const apiPath = gap.endpoint.path;
|
|
79
|
+
const baseName = pathToFileName(method, apiPath, convention);
|
|
80
|
+
switch (testType) {
|
|
81
|
+
case 'security':
|
|
82
|
+
return path.join(outDir, 'security', `${baseName}.security.test.ts`);
|
|
83
|
+
case 'cypress':
|
|
84
|
+
return path.join('cypress', 'e2e', 'generated', `${baseName}.cy.js`);
|
|
85
|
+
case 'integration':
|
|
86
|
+
if (gap.flow) {
|
|
87
|
+
const flowName = applyNaming(gap.flow.name, convention);
|
|
88
|
+
return path.join(outDir, 'flows', `${flowName}.flow.test.ts`);
|
|
89
|
+
}
|
|
90
|
+
return path.join(outDir, `${baseName}.integration.test.ts`);
|
|
91
|
+
case 'unit':
|
|
92
|
+
default:
|
|
93
|
+
return path.join(outDir, `${baseName}.test.ts`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function sortGapsByPriority(gaps) {
|
|
97
|
+
return [...gaps].sort((a, b) => { var _a, _b; return ((_a = PRIORITY_ORDER[a.priority]) !== null && _a !== void 0 ? _a : 99) - ((_b = PRIORITY_ORDER[b.priority]) !== null && _b !== void 0 ? _b : 99); });
|
|
98
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature 28 — GapExtractor
|
|
3
|
+
* Reads coverage-summary.json (or coverage reports) and extracts DetectedGap objects.
|
|
4
|
+
*/
|
|
5
|
+
import type { DetectedGap } from './types';
|
|
6
|
+
export declare function extractGapsFromReports(reportsDir: string): DetectedGap[];
|
|
7
|
+
//# sourceMappingURL=gap-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gap-extractor.d.ts","sourceRoot":"","sources":["../../../src/generation/gap-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,SAAS,CAAC;AA4D7E,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAmLxE"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feature 28 — GapExtractor
|
|
4
|
+
* Reads coverage-summary.json (or coverage reports) and extracts DetectedGap objects.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.extractGapsFromReports = extractGapsFromReports;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
// ─── Priority logic ───────────────────────────────────────────────────────────
|
|
44
|
+
function computePriority(type, authRequired, riskScore) {
|
|
45
|
+
if (type === 'security' || (type === 'auth' && authRequired))
|
|
46
|
+
return 'P0';
|
|
47
|
+
if (type === 'endpoint')
|
|
48
|
+
return 'P1';
|
|
49
|
+
if (type === 'error')
|
|
50
|
+
return 'P2';
|
|
51
|
+
if (type === 'business')
|
|
52
|
+
return 'P3';
|
|
53
|
+
if (type === 'parameter')
|
|
54
|
+
return 'P4';
|
|
55
|
+
if (type === 'integration')
|
|
56
|
+
return 'P5';
|
|
57
|
+
return 'P3';
|
|
58
|
+
}
|
|
59
|
+
function buildGapId(type, method, apiPath, condition) {
|
|
60
|
+
return `${type}:${method.toUpperCase()}:${apiPath}:${condition}`;
|
|
61
|
+
}
|
|
62
|
+
// ─── Summary JSON reader ──────────────────────────────────────────────────────
|
|
63
|
+
function readJson(filePath) {
|
|
64
|
+
if (!fs.existsSync(filePath))
|
|
65
|
+
return null;
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
74
|
+
function extractGapsFromReports(reportsDir) {
|
|
75
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24;
|
|
76
|
+
const gaps = [];
|
|
77
|
+
// Try coverage-summary.json first
|
|
78
|
+
const summaryPath = path.join(reportsDir, 'coverage-summary.json');
|
|
79
|
+
const summary = readJson(summaryPath);
|
|
80
|
+
if (!summary) {
|
|
81
|
+
// Return synthetic sample gaps for smoke-test / dry-run mode
|
|
82
|
+
return buildSampleGaps();
|
|
83
|
+
}
|
|
84
|
+
// ── Endpoint gaps ─────────────────────────────────────────────────────────
|
|
85
|
+
const endpointItems = (_c = (_b = (_a = summary.details) === null || _a === void 0 ? void 0 : _a.endpoint) === null || _b === void 0 ? void 0 : _b.items) !== null && _c !== void 0 ? _c : [];
|
|
86
|
+
for (const item of endpointItems) {
|
|
87
|
+
if (item.covered)
|
|
88
|
+
continue;
|
|
89
|
+
const method = ((_d = item.method) !== null && _d !== void 0 ? _d : 'GET').toUpperCase();
|
|
90
|
+
const apiPath = (_e = item.path) !== null && _e !== void 0 ? _e : '/unknown';
|
|
91
|
+
const authRequired = (_f = item.authRequired) !== null && _f !== void 0 ? _f : false;
|
|
92
|
+
const authOptional = (_g = item.authOptional) !== null && _g !== void 0 ? _g : false;
|
|
93
|
+
const riskScore = authRequired ? 85 : 60;
|
|
94
|
+
gaps.push({
|
|
95
|
+
id: buildGapId('endpoint', method, apiPath, 'uncovered'),
|
|
96
|
+
type: 'endpoint',
|
|
97
|
+
priority: computePriority('endpoint', authRequired, riskScore),
|
|
98
|
+
riskScore,
|
|
99
|
+
endpoint: {
|
|
100
|
+
method,
|
|
101
|
+
path: apiPath,
|
|
102
|
+
operationId: item.operationId,
|
|
103
|
+
tags: item.tags,
|
|
104
|
+
auth: {
|
|
105
|
+
required: authRequired,
|
|
106
|
+
optional: authOptional,
|
|
107
|
+
type: authRequired ? 'jwt' : undefined,
|
|
108
|
+
headerName: authRequired ? 'Authorization' : undefined,
|
|
109
|
+
scheme: authRequired ? 'Bearer' : undefined,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
responses: [
|
|
113
|
+
{ statusCode: 200, description: 'Success' },
|
|
114
|
+
...(authRequired ? [{ statusCode: 401, description: 'Unauthorized' }] : []),
|
|
115
|
+
{ statusCode: 422, description: 'Unprocessable Entity' },
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// ── Security gaps ─────────────────────────────────────────────────────────
|
|
120
|
+
const securityItems = (_k = (_j = (_h = summary.details) === null || _h === void 0 ? void 0 : _h.security) === null || _j === void 0 ? void 0 : _j.items) !== null && _k !== void 0 ? _k : [];
|
|
121
|
+
for (const item of securityItems) {
|
|
122
|
+
if (item.covered)
|
|
123
|
+
continue;
|
|
124
|
+
const parts = ((_l = item.endpoint) !== null && _l !== void 0 ? _l : 'GET /unknown').split(' ');
|
|
125
|
+
const method = ((_m = parts[0]) !== null && _m !== void 0 ? _m : 'GET').toUpperCase();
|
|
126
|
+
const apiPath = (_o = parts[1]) !== null && _o !== void 0 ? _o : '/unknown';
|
|
127
|
+
gaps.push({
|
|
128
|
+
id: buildGapId('security', method, apiPath, (_p = item.controlType) !== null && _p !== void 0 ? _p : 'auth-bypass'),
|
|
129
|
+
type: 'security',
|
|
130
|
+
priority: 'P0',
|
|
131
|
+
riskScore: 95,
|
|
132
|
+
endpoint: {
|
|
133
|
+
method,
|
|
134
|
+
path: apiPath,
|
|
135
|
+
auth: { required: true, optional: false, type: 'jwt', headerName: 'Authorization', scheme: 'Bearer' },
|
|
136
|
+
},
|
|
137
|
+
securityControl: {
|
|
138
|
+
type: (_q = item.controlType) !== null && _q !== void 0 ? _q : 'auth-bypass',
|
|
139
|
+
description: `Security control not tested for ${item.endpoint}`,
|
|
140
|
+
attackVector: 'Missing auth validation test',
|
|
141
|
+
expectedStatusCode: 401,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// ── Error gaps ────────────────────────────────────────────────────────────
|
|
146
|
+
const errorItems = (_t = (_s = (_r = summary.details) === null || _r === void 0 ? void 0 : _r.error) === null || _s === void 0 ? void 0 : _s.items) !== null && _t !== void 0 ? _t : [];
|
|
147
|
+
for (const item of errorItems) {
|
|
148
|
+
if (item.covered)
|
|
149
|
+
continue;
|
|
150
|
+
const parts = ((_u = item.endpoint) !== null && _u !== void 0 ? _u : 'GET /unknown').split(' ');
|
|
151
|
+
const method = ((_v = parts[0]) !== null && _v !== void 0 ? _v : 'GET').toUpperCase();
|
|
152
|
+
const apiPath = (_w = parts[1]) !== null && _w !== void 0 ? _w : '/unknown';
|
|
153
|
+
const statusCode = (_x = item.statusCode) !== null && _x !== void 0 ? _x : 500;
|
|
154
|
+
gaps.push({
|
|
155
|
+
id: buildGapId('error', method, apiPath, String(statusCode)),
|
|
156
|
+
type: 'error',
|
|
157
|
+
priority: 'P2',
|
|
158
|
+
riskScore: 65,
|
|
159
|
+
endpoint: {
|
|
160
|
+
method,
|
|
161
|
+
path: apiPath,
|
|
162
|
+
auth: { required: false, optional: false },
|
|
163
|
+
},
|
|
164
|
+
responses: [{ statusCode, description: `Error ${statusCode} not tested` }],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// ── Business rule gaps ────────────────────────────────────────────────────
|
|
168
|
+
const businessItems = (_0 = (_z = (_y = summary.details) === null || _y === void 0 ? void 0 : _y.business) === null || _z === void 0 ? void 0 : _z.items) !== null && _0 !== void 0 ? _0 : [];
|
|
169
|
+
for (const item of businessItems) {
|
|
170
|
+
if (item.covered)
|
|
171
|
+
continue;
|
|
172
|
+
const parts = ((_1 = item.endpoint) !== null && _1 !== void 0 ? _1 : 'GET /unknown').split(' ');
|
|
173
|
+
const method = ((_2 = parts[0]) !== null && _2 !== void 0 ? _2 : 'GET').toUpperCase();
|
|
174
|
+
const apiPath = (_3 = parts[1]) !== null && _3 !== void 0 ? _3 : '/unknown';
|
|
175
|
+
gaps.push({
|
|
176
|
+
id: buildGapId('business', method, apiPath, (_4 = item.ruleId) !== null && _4 !== void 0 ? _4 : 'business-rule'),
|
|
177
|
+
type: 'business',
|
|
178
|
+
priority: 'P3',
|
|
179
|
+
riskScore: 55,
|
|
180
|
+
endpoint: {
|
|
181
|
+
method,
|
|
182
|
+
path: apiPath,
|
|
183
|
+
auth: { required: false, optional: false },
|
|
184
|
+
},
|
|
185
|
+
businessRule: {
|
|
186
|
+
id: (_5 = item.ruleId) !== null && _5 !== void 0 ? _5 : 'rule-1',
|
|
187
|
+
description: (_6 = item.description) !== null && _6 !== void 0 ? _6 : 'Business rule not covered',
|
|
188
|
+
condition: 'When condition is met',
|
|
189
|
+
acceptanceCriteria: ['Expected behavior is verified'],
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
// ── Integration flow gaps ─────────────────────────────────────────────────
|
|
194
|
+
const integrationItems = (_9 = (_8 = (_7 = summary.details) === null || _7 === void 0 ? void 0 : _7.integration) === null || _8 === void 0 ? void 0 : _8.items) !== null && _9 !== void 0 ? _9 : [];
|
|
195
|
+
for (const item of integrationItems) {
|
|
196
|
+
if (item.covered)
|
|
197
|
+
continue;
|
|
198
|
+
gaps.push({
|
|
199
|
+
id: `integration:${(_10 = item.flowId) !== null && _10 !== void 0 ? _10 : 'flow'}:step-${(_11 = item.missingStepIndex) !== null && _11 !== void 0 ? _11 : 0}-missing`,
|
|
200
|
+
type: 'integration',
|
|
201
|
+
priority: 'P5',
|
|
202
|
+
riskScore: 45,
|
|
203
|
+
endpoint: {
|
|
204
|
+
method: 'GET',
|
|
205
|
+
path: '/unknown',
|
|
206
|
+
auth: { required: false, optional: false },
|
|
207
|
+
},
|
|
208
|
+
flow: {
|
|
209
|
+
id: (_12 = item.flowId) !== null && _12 !== void 0 ? _12 : 'flow-1',
|
|
210
|
+
name: (_13 = item.name) !== null && _13 !== void 0 ? _13 : 'Integration Flow',
|
|
211
|
+
steps: (_14 = item.steps) !== null && _14 !== void 0 ? _14 : [],
|
|
212
|
+
missingStepIndex: (_15 = item.missingStepIndex) !== null && _15 !== void 0 ? _15 : 0,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// ── Parameter gaps ────────────────────────────────────────────────────────
|
|
217
|
+
const parameterItems = (_18 = (_17 = (_16 = summary.details) === null || _16 === void 0 ? void 0 : _16.parameter) === null || _17 === void 0 ? void 0 : _17.items) !== null && _18 !== void 0 ? _18 : [];
|
|
218
|
+
for (const item of parameterItems) {
|
|
219
|
+
const parts = ((_19 = item.endpoint) !== null && _19 !== void 0 ? _19 : 'GET /unknown').split(' ');
|
|
220
|
+
const method = ((_20 = parts[0]) !== null && _20 !== void 0 ? _20 : 'GET').toUpperCase();
|
|
221
|
+
const apiPath = (_21 = parts[1]) !== null && _21 !== void 0 ? _21 : '/unknown';
|
|
222
|
+
const paramName = (_22 = item.parameter) !== null && _22 !== void 0 ? _22 : 'param';
|
|
223
|
+
const missingCases = ((_23 = item.missingCases) !== null && _23 !== void 0 ? _23 : ['boundary-min']);
|
|
224
|
+
const condition = (_24 = missingCases[0]) !== null && _24 !== void 0 ? _24 : 'boundary';
|
|
225
|
+
gaps.push({
|
|
226
|
+
id: buildGapId('parameter', method, apiPath, `${paramName}:${condition}`),
|
|
227
|
+
type: 'parameter',
|
|
228
|
+
priority: 'P4',
|
|
229
|
+
riskScore: 40,
|
|
230
|
+
endpoint: {
|
|
231
|
+
method,
|
|
232
|
+
path: apiPath,
|
|
233
|
+
auth: { required: false, optional: false },
|
|
234
|
+
},
|
|
235
|
+
parameters: [{
|
|
236
|
+
name: paramName,
|
|
237
|
+
in: 'query',
|
|
238
|
+
required: false,
|
|
239
|
+
schema: { type: 'string' },
|
|
240
|
+
missingCases,
|
|
241
|
+
}],
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return gaps;
|
|
245
|
+
}
|
|
246
|
+
/** Build a minimal set of synthetic gaps for smoke-test / dry-run mode */
|
|
247
|
+
function buildSampleGaps() {
|
|
248
|
+
return [
|
|
249
|
+
{
|
|
250
|
+
id: 'endpoint:POST:/api/articles:uncovered',
|
|
251
|
+
type: 'endpoint',
|
|
252
|
+
priority: 'P1',
|
|
253
|
+
riskScore: 85,
|
|
254
|
+
endpoint: {
|
|
255
|
+
method: 'POST',
|
|
256
|
+
path: '/api/articles',
|
|
257
|
+
operationId: 'createArticle',
|
|
258
|
+
summary: 'Create Article',
|
|
259
|
+
auth: { required: true, optional: false, type: 'jwt', headerName: 'Authorization', scheme: 'Bearer' },
|
|
260
|
+
},
|
|
261
|
+
parameters: [
|
|
262
|
+
{
|
|
263
|
+
name: 'title',
|
|
264
|
+
in: 'body',
|
|
265
|
+
required: true,
|
|
266
|
+
schema: { type: 'string', minLength: 1 },
|
|
267
|
+
missingCases: ['missing-required'],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'body',
|
|
271
|
+
in: 'body',
|
|
272
|
+
required: true,
|
|
273
|
+
schema: { type: 'string' },
|
|
274
|
+
missingCases: ['missing-required'],
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'description',
|
|
278
|
+
in: 'body',
|
|
279
|
+
required: true,
|
|
280
|
+
schema: { type: 'string' },
|
|
281
|
+
missingCases: ['missing-required'],
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
responses: [
|
|
285
|
+
{ statusCode: 201, description: 'Created' },
|
|
286
|
+
{ statusCode: 401, description: 'Unauthorized' },
|
|
287
|
+
{ statusCode: 422, description: 'Unprocessable Entity' },
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature 28 — Test Generation & Quality Intelligence Engine
|
|
3
|
+
* Public API exports
|
|
4
|
+
*/
|
|
5
|
+
export { TestGenerationEngine, generateTests } from './engine';
|
|
6
|
+
export { scoreTests, scoreFile } from './quality-scorer';
|
|
7
|
+
export { exportAiFlows } from './ai-flow-exporter';
|
|
8
|
+
export type { DetectedGap, GeneratedFile, GenerationResult, GenerationOptions, TestQualityReport, FileQualityScore, AiReadyFlows, AiFlowGap, AiFlowExporterOptions, GenerationConfig, TestQualityConfig, AiFlowsConfig, } from './types';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GACd,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feature 28 — Test Generation & Quality Intelligence Engine
|
|
4
|
+
* Public API exports
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.exportAiFlows = exports.scoreFile = exports.scoreTests = exports.generateTests = exports.TestGenerationEngine = void 0;
|
|
8
|
+
var engine_1 = require("./engine");
|
|
9
|
+
Object.defineProperty(exports, "TestGenerationEngine", { enumerable: true, get: function () { return engine_1.TestGenerationEngine; } });
|
|
10
|
+
Object.defineProperty(exports, "generateTests", { enumerable: true, get: function () { return engine_1.generateTests; } });
|
|
11
|
+
var quality_scorer_1 = require("./quality-scorer");
|
|
12
|
+
Object.defineProperty(exports, "scoreTests", { enumerable: true, get: function () { return quality_scorer_1.scoreTests; } });
|
|
13
|
+
Object.defineProperty(exports, "scoreFile", { enumerable: true, get: function () { return quality_scorer_1.scoreFile; } });
|
|
14
|
+
var ai_flow_exporter_1 = require("./ai-flow-exporter");
|
|
15
|
+
Object.defineProperty(exports, "exportAiFlows", { enumerable: true, get: function () { return ai_flow_exporter_1.exportAiFlows; } });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature 28 — QualityScorer
|
|
3
|
+
* Scores existing test files on 5 dimensions (0–100 total).
|
|
4
|
+
*
|
|
5
|
+
* Dimensions (20 pts each):
|
|
6
|
+
* 1. Assertion Depth
|
|
7
|
+
* 2. Negative Path Coverage
|
|
8
|
+
* 3. Auth Coverage
|
|
9
|
+
* 4. Boundary Coverage
|
|
10
|
+
* 5. Test Independence
|
|
11
|
+
*/
|
|
12
|
+
import type { FileQualityScore, TestQualityReport, QualityScorerOptions } from './types';
|
|
13
|
+
export declare function scoreFile(filePath: string): FileQualityScore;
|
|
14
|
+
export declare function scoreTests(opts: QualityScorerOptions): Promise<TestQualityReport>;
|
|
15
|
+
//# sourceMappingURL=quality-scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-scorer.d.ts","sourceRoot":"","sources":["../../../src/generation/quality-scorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,gBAAgB,EAEhB,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,SAAS,CAAC;AA8JjB,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAoB5D;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAsEvF"}
|