api-tests-coverage 1.0.21 → 1.0.22
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/dashboard/dist/assets/_basePickBy-BKGHUeDJ.js +1 -0
- package/dist/dashboard/dist/assets/_baseUniq-CtA-DQF7.js +1 -0
- package/dist/dashboard/dist/assets/arc-CbXP3Mc9.js +1 -0
- package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-n7QxasMM.js +36 -0
- package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-MXnGwKRn.js +122 -0
- package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-B3yZ5P9k.js +10 -0
- package/dist/dashboard/dist/assets/channel-C7QwX7U8.js +1 -0
- package/dist/dashboard/dist/assets/chunk-4BX2VUAB-Dw3El5KF.js +1 -0
- package/dist/dashboard/dist/assets/chunk-55IACEB6-T8Jf00IL.js +1 -0
- package/dist/dashboard/dist/assets/chunk-B4BG7PRW-DAJalKYJ.js +165 -0
- package/dist/dashboard/dist/assets/chunk-DI55MBZ5-p7o_KuDF.js +220 -0
- package/dist/dashboard/dist/assets/chunk-FMBD7UC4-B0wUAfQR.js +15 -0
- package/dist/dashboard/dist/assets/chunk-QN33PNHL-BTFwTEw8.js +1 -0
- package/dist/dashboard/dist/assets/chunk-QZHKN3VN-CNXHnjkC.js +1 -0
- package/dist/dashboard/dist/assets/chunk-TZMSLE5B-BIVywBYp.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-Dkb-G0UK.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-Dkb-G0UK.js +1 -0
- package/dist/dashboard/dist/assets/clone-BSdXhKmH.js +1 -0
- package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-DuALhY5a.js +1 -0
- package/dist/dashboard/dist/assets/cytoscape.esm-CyJtwmzi.js +331 -0
- package/dist/dashboard/dist/assets/dagre-6UL2VRFP-w6endfy9.js +4 -0
- package/dist/dashboard/dist/assets/diagram-PSM6KHXK-BDnUwPQC.js +24 -0
- package/dist/dashboard/dist/assets/diagram-QEK2KX5R-Cbb7ctAo.js +43 -0
- package/dist/dashboard/dist/assets/diagram-S2PKOQOG-76ascveh.js +24 -0
- package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-BQQnVF0J.js +60 -0
- package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-dKukiSxD.js +162 -0
- package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-BqnazZuZ.js +267 -0
- package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-BUFcnXCj.js +65 -0
- package/dist/dashboard/dist/assets/graph-CGQIvL3r.js +1 -0
- package/dist/dashboard/dist/assets/index-CadOHtae.css +1 -0
- package/dist/dashboard/dist/assets/index-DwqfA4mc.js +777 -0
- package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-BdylFPLI.js +2 -0
- package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-BzJTBkhp.js +139 -0
- package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-StKomgio.js +89 -0
- package/dist/dashboard/dist/assets/katex-O9d3_IXG.js +261 -0
- package/dist/dashboard/dist/assets/layout-BnsX73QS.js +1 -0
- package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-HqFRhVFX.js +68 -0
- package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-2I2tFH0C.js +30 -0
- package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-PlELkdBW.js +7 -0
- package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-_9eLQNcZ.js +64 -0
- package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-DHl1Ss7O.js +10 -0
- package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-B9p0m3Uf.js +145 -0
- package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC--rpDODjT.js +1 -0
- package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-Ca9uGk46.js +1 -0
- package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-BCHaGBHB.js +61 -0
- package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CgiqDY8M.js +162 -0
- package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-BMvBBbeV.js +7 -0
- package/dist/dashboard/dist/index.html +14 -0
- package/dist/dashboard/dist/reports/business-coverage.json +201 -0
- package/dist/dashboard/dist/reports/coverage-intelligence.json +728 -0
- package/dist/dashboard/dist/reports/coverage-summary.json +995 -0
- package/dist/dashboard/dist/reports/endpoint-coverage.json +336 -0
- package/dist/dashboard/dist/reports/error-coverage.json +367 -0
- package/dist/dashboard/dist/reports/missing-tests-recommendations.json +285 -0
- package/dist/dashboard/dist/reports/risk-prioritization.json +312 -0
- package/dist/dashboard/dist/reports/security-coverage.json +299 -0
- package/dist/dashboard/dist/vite.svg +1 -0
- package/dist/src/generation/context-builder.d.ts +6 -0
- package/dist/src/generation/context-builder.d.ts.map +1 -0
- package/dist/src/generation/context-builder.js +202 -0
- package/dist/src/generation/engine.d.ts +40 -0
- package/dist/src/generation/engine.d.ts.map +1 -0
- package/dist/src/generation/engine.js +378 -0
- package/dist/src/generation/file-router.d.ts +7 -0
- package/dist/src/generation/file-router.d.ts.map +1 -0
- package/dist/src/generation/file-router.js +79 -0
- package/dist/src/generation/gap-extractor.d.ts +12 -0
- package/dist/src/generation/gap-extractor.d.ts.map +1 -0
- package/dist/src/generation/gap-extractor.js +281 -0
- package/dist/src/generation/template-renderer.d.ts +10 -0
- package/dist/src/generation/template-renderer.d.ts.map +1 -0
- package/dist/src/generation/template-renderer.js +526 -0
- package/dist/src/generation/types.d.ts +73 -0
- package/dist/src/generation/types.d.ts.map +1 -0
- package/dist/src/generation/types.js +2 -0
- package/dist/src/index.js +154 -0
- package/dist/src/pipeline/detectors/expressMiddlewareDetector.d.ts +21 -0
- package/dist/src/pipeline/detectors/expressMiddlewareDetector.d.ts.map +1 -0
- package/dist/src/pipeline/detectors/expressMiddlewareDetector.js +201 -0
- package/dist/src/pipeline/detectors/flaskBlueprintDetector.d.ts +23 -0
- package/dist/src/pipeline/detectors/flaskBlueprintDetector.d.ts.map +1 -0
- package/dist/src/pipeline/detectors/flaskBlueprintDetector.js +263 -0
- package/dist/src/pipeline/detectors/springDddDetector.d.ts +23 -0
- package/dist/src/pipeline/detectors/springDddDetector.d.ts.map +1 -0
- package/dist/src/pipeline/detectors/springDddDetector.js +237 -0
- package/dist/src/pipeline/detectors/types.d.ts +97 -0
- package/dist/src/pipeline/detectors/types.d.ts.map +1 -0
- package/dist/src/pipeline/detectors/types.js +15 -0
- package/dist/src/reporting.d.ts.map +1 -1
- package/dist/src/reporting.js +2 -1
- package/dist/src/streaming/detectors/eventBridgeDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/eventBridgeDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/eventBridgeDetector.js +82 -0
- package/dist/src/streaming/detectors/kafkaDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/kafkaDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/kafkaDetector.js +97 -0
- package/dist/src/streaming/detectors/natsDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/natsDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/natsDetector.js +96 -0
- package/dist/src/streaming/detectors/pubsubDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/pubsubDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/pubsubDetector.js +82 -0
- package/dist/src/streaming/detectors/rabbitmqDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/rabbitmqDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/rabbitmqDetector.js +103 -0
- package/dist/src/streaming/detectors/redisPubsubDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/redisPubsubDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/redisPubsubDetector.js +81 -0
- package/dist/src/streaming/detectors/snsDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/snsDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/snsDetector.js +81 -0
- package/dist/src/streaming/detectors/sqsDetector.d.ts +5 -0
- package/dist/src/streaming/detectors/sqsDetector.d.ts.map +1 -0
- package/dist/src/streaming/detectors/sqsDetector.js +81 -0
- package/dist/src/streaming/eventCoverage.d.ts +46 -0
- package/dist/src/streaming/eventCoverage.d.ts.map +1 -0
- package/dist/src/streaming/eventCoverage.js +270 -0
- package/dist/src/streaming/types.d.ts +34 -0
- package/dist/src/streaming/types.d.ts.map +1 -0
- package/dist/src/streaming/types.js +2 -0
- package/dist/src/summary/markdownRenderer.d.ts.map +1 -1
- package/dist/src/summary/markdownRenderer.js +1 -0
- package/dist/src/summary/summaryTypes.d.ts.map +1 -1
- package/dist/src/summary/summaryTypes.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OWASP_INJECTION_STRINGS = void 0;
|
|
4
|
+
exports.renderFileHeader = renderFileHeader;
|
|
5
|
+
exports.renderTemplate = renderTemplate;
|
|
6
|
+
exports.getTemplateName = getTemplateName;
|
|
7
|
+
/** Common OWASP injection strings for security tests */
|
|
8
|
+
exports.OWASP_INJECTION_STRINGS = [
|
|
9
|
+
"' OR '1'='1",
|
|
10
|
+
"'; DROP TABLE users; --",
|
|
11
|
+
'<script>alert("xss")</script>',
|
|
12
|
+
'../../../etc/passwd',
|
|
13
|
+
'${7*7}',
|
|
14
|
+
'{{7*7}}',
|
|
15
|
+
'; ls -la',
|
|
16
|
+
'\\x00',
|
|
17
|
+
'%00',
|
|
18
|
+
'<img src=x onerror=alert(1)>',
|
|
19
|
+
];
|
|
20
|
+
/** Standard file header injected into every generated test file */
|
|
21
|
+
function renderFileHeader(gapId, gapType) {
|
|
22
|
+
return [
|
|
23
|
+
'// AUTO-GENERATED by api-test-coverage-analyzer',
|
|
24
|
+
`// Gap ID: ${gapId} | Type: ${gapType}`,
|
|
25
|
+
'// DO NOT EDIT — regenerate with: node dist/src/index.js generate-tests',
|
|
26
|
+
'// TODO: Review and adjust before committing',
|
|
27
|
+
'',
|
|
28
|
+
].join('\n');
|
|
29
|
+
}
|
|
30
|
+
/** Simple string interpolation — replaces {{key}} tokens with values */
|
|
31
|
+
function interpolate(template, vars) {
|
|
32
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => { var _a; return (_a = vars[key]) !== null && _a !== void 0 ? _a : `{{${key}}}`; });
|
|
33
|
+
}
|
|
34
|
+
// ─── TypeScript / Jest templates ─────────────────────────────────────────────
|
|
35
|
+
function renderEndpointMissing(gap, ctx) {
|
|
36
|
+
var _a, _b, _c, _d;
|
|
37
|
+
const method = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : 'GET';
|
|
38
|
+
const endpointPath = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : '/unknown';
|
|
39
|
+
const methodLower = method.toLowerCase();
|
|
40
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
41
|
+
const body = `
|
|
42
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
43
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
44
|
+
|
|
45
|
+
describe('${method} ${endpointPath}', () => {
|
|
46
|
+
it('should return 200 with valid response', async () => {
|
|
47
|
+
const response = await request(app)
|
|
48
|
+
.${methodLower}('${endpointPath}')
|
|
49
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'); // TODO: add valid token
|
|
50
|
+
|
|
51
|
+
expect(response.status).toBe(200);
|
|
52
|
+
expect(response.body).toMatchObject({}); // TODO: add expected shape
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should return 401 when not authenticated', async () => {
|
|
56
|
+
const response = await request(app).${methodLower}('${endpointPath}');
|
|
57
|
+
expect(response.status).toBe(401);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
`;
|
|
61
|
+
return header + body.trimStart();
|
|
62
|
+
}
|
|
63
|
+
function renderParameterMissing(gap, ctx) {
|
|
64
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
65
|
+
const paramName = (_b = (_a = gap.parameter) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'param';
|
|
66
|
+
const paramIn = (_d = (_c = gap.parameter) === null || _c === void 0 ? void 0 : _c.in) !== null && _d !== void 0 ? _d : 'query';
|
|
67
|
+
const required = (_f = (_e = gap.parameter) === null || _e === void 0 ? void 0 : _e.required) !== null && _f !== void 0 ? _f : false;
|
|
68
|
+
const endpointPath = (_h = (_g = gap.endpoint) === null || _g === void 0 ? void 0 : _g.path) !== null && _h !== void 0 ? _h : '/api/endpoint';
|
|
69
|
+
const method = (_k = (_j = gap.endpoint) === null || _j === void 0 ? void 0 : _j.method) !== null && _k !== void 0 ? _k : 'GET';
|
|
70
|
+
const methodLower = method.toLowerCase();
|
|
71
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
72
|
+
const body = `
|
|
73
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
74
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
75
|
+
|
|
76
|
+
describe('${method} ${endpointPath} — parameter: ${paramName}', () => {
|
|
77
|
+
it('should accept a valid ${paramName} ${paramIn} parameter', async () => {
|
|
78
|
+
const response = await request(app)
|
|
79
|
+
.${methodLower}('${endpointPath}')
|
|
80
|
+
${paramIn === 'query' ? `.query({ ${paramName}: 'valid-value' }) // TODO: provide valid value` : `.send({ ${paramName}: 'valid-value' }) // TODO: provide valid value`}
|
|
81
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'); // TODO: add valid token
|
|
82
|
+
|
|
83
|
+
expect(response.status).toBe(200);
|
|
84
|
+
expect(response.body).toMatchObject({}); // TODO: add expected shape
|
|
85
|
+
});
|
|
86
|
+
${required
|
|
87
|
+
? `
|
|
88
|
+
it('should return 400 when ${paramName} is missing', async () => {
|
|
89
|
+
const response = await request(app)
|
|
90
|
+
.${methodLower}('${endpointPath}')
|
|
91
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'); // TODO: add valid token
|
|
92
|
+
|
|
93
|
+
expect(response.status).toBe(400);
|
|
94
|
+
});
|
|
95
|
+
`
|
|
96
|
+
: ''}
|
|
97
|
+
it('should return 400 when ${paramName} is invalid', async () => {
|
|
98
|
+
const response = await request(app)
|
|
99
|
+
.${methodLower}('${endpointPath}')
|
|
100
|
+
${paramIn === 'query' ? `.query({ ${paramName}: 'INVALID_VALUE' }) // TODO: provide invalid value` : `.send({ ${paramName}: 'INVALID_VALUE' }) // TODO: provide invalid value`}
|
|
101
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'); // TODO: add valid token
|
|
102
|
+
|
|
103
|
+
expect(response.status).toBe(400);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
`;
|
|
107
|
+
return header + body.trimStart();
|
|
108
|
+
}
|
|
109
|
+
function renderParameterNotValidated(gap, ctx) {
|
|
110
|
+
var _a, _b, _c, _d, _e, _f;
|
|
111
|
+
const paramName = (_b = (_a = gap.parameter) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'param';
|
|
112
|
+
const endpointPath = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : '/api/endpoint';
|
|
113
|
+
const method = (_f = (_e = gap.endpoint) === null || _e === void 0 ? void 0 : _e.method) !== null && _f !== void 0 ? _f : 'GET';
|
|
114
|
+
const methodLower = method.toLowerCase();
|
|
115
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
116
|
+
const body = `
|
|
117
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
118
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
119
|
+
|
|
120
|
+
describe('${method} ${endpointPath} — validation: ${paramName}', () => {
|
|
121
|
+
it('should reject empty ${paramName}', async () => {
|
|
122
|
+
const response = await request(app)
|
|
123
|
+
.${methodLower}('${endpointPath}')
|
|
124
|
+
.send({ ${paramName}: '' }) // TODO: adjust payload location
|
|
125
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
126
|
+
|
|
127
|
+
expect(response.status).toBe(400);
|
|
128
|
+
expect(response.body).toMatchObject({ error: expect.any(String) }); // TODO: match actual error shape
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should reject ${paramName} exceeding max length', async () => {
|
|
132
|
+
const response = await request(app)
|
|
133
|
+
.${methodLower}('${endpointPath}')
|
|
134
|
+
.send({ ${paramName}: 'x'.repeat(1000) }) // TODO: adjust max length
|
|
135
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
136
|
+
|
|
137
|
+
expect(response.status).toBe(400);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
`;
|
|
141
|
+
return header + body.trimStart();
|
|
142
|
+
}
|
|
143
|
+
function renderBusinessMissing(gap, ctx) {
|
|
144
|
+
var _a, _b, _c, _d;
|
|
145
|
+
const ruleId = (_b = (_a = gap.businessRule) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'BR-XXX';
|
|
146
|
+
const description = (_d = (_c = gap.businessRule) === null || _c === void 0 ? void 0 : _c.description) !== null && _d !== void 0 ? _d : 'Business rule';
|
|
147
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
148
|
+
const body = `
|
|
149
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
150
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
151
|
+
|
|
152
|
+
// Business Rule: ${ruleId} — ${description}
|
|
153
|
+
describe('Business Rule ${ruleId}: ${description}', () => {
|
|
154
|
+
it('should enforce rule when conditions are met', async () => {
|
|
155
|
+
// TODO: set up test data that triggers the business rule
|
|
156
|
+
const response = await request(app)
|
|
157
|
+
.post('/api/TODO_ENDPOINT') // TODO: replace with actual endpoint
|
|
158
|
+
.send({
|
|
159
|
+
// TODO: add request body that triggers the rule
|
|
160
|
+
})
|
|
161
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
162
|
+
|
|
163
|
+
expect(response.status).toBe(422); // TODO: adjust expected status
|
|
164
|
+
expect(response.body).toMatchObject({
|
|
165
|
+
error: expect.any(String), // TODO: match actual error shape
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should allow the operation when the rule is satisfied', async () => {
|
|
170
|
+
const response = await request(app)
|
|
171
|
+
.post('/api/TODO_ENDPOINT') // TODO: replace with actual endpoint
|
|
172
|
+
.send({
|
|
173
|
+
// TODO: add request body that satisfies the rule
|
|
174
|
+
})
|
|
175
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
176
|
+
|
|
177
|
+
expect(response.status).toBe(200); // TODO: adjust expected status
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
`;
|
|
181
|
+
return header + body.trimStart();
|
|
182
|
+
}
|
|
183
|
+
function renderIntegrationMissingStep(gap, ctx) {
|
|
184
|
+
var _a, _b, _c, _d, _e, _f;
|
|
185
|
+
const flowId = (_b = (_a = gap.integrationFlow) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'flow-001';
|
|
186
|
+
const flowName = (_d = (_c = gap.integrationFlow) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : 'Integration Flow';
|
|
187
|
+
const missingStep = (_f = (_e = gap.integrationFlow) === null || _e === void 0 ? void 0 : _e.missingStep) !== null && _f !== void 0 ? _f : 'step';
|
|
188
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
189
|
+
const body = `
|
|
190
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
191
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
192
|
+
|
|
193
|
+
// Integration Flow: ${flowId} — ${flowName}
|
|
194
|
+
describe('Integration Flow ${flowId}: ${flowName}', () => {
|
|
195
|
+
it('should complete the full flow including: ${missingStep}', async () => {
|
|
196
|
+
// Step 1: TODO — describe step 1
|
|
197
|
+
const step1 = await request(app)
|
|
198
|
+
.post('/api/TODO_STEP_1') // TODO: replace with actual endpoint
|
|
199
|
+
.send({}) // TODO: add step 1 body
|
|
200
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
201
|
+
expect(step1.status).toBe(200);
|
|
202
|
+
|
|
203
|
+
// Step 2: ${missingStep} (this was the missing step)
|
|
204
|
+
const step2 = await request(app)
|
|
205
|
+
.post('/api/TODO_STEP_2') // TODO: replace with actual endpoint
|
|
206
|
+
.send({}) // TODO: add step 2 body
|
|
207
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
208
|
+
expect(step2.status).toBe(200);
|
|
209
|
+
expect(step2.body).toMatchObject({}); // TODO: verify step 2 result
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
`;
|
|
213
|
+
return header + body.trimStart();
|
|
214
|
+
}
|
|
215
|
+
function renderErrorMissingStatus(gap, ctx) {
|
|
216
|
+
var _a, _b, _c, _d;
|
|
217
|
+
const endpointPath = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/api/endpoint';
|
|
218
|
+
const method = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.method) !== null && _d !== void 0 ? _d : 'GET';
|
|
219
|
+
const methodLower = method.toLowerCase();
|
|
220
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
221
|
+
const body = `
|
|
222
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
223
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
224
|
+
|
|
225
|
+
describe('${method} ${endpointPath} — error handling', () => {
|
|
226
|
+
it('should return 400 for invalid request body', async () => {
|
|
227
|
+
const response = await request(app)
|
|
228
|
+
.${methodLower}('${endpointPath}')
|
|
229
|
+
.send({ invalidField: 'bad-value' }) // TODO: craft invalid payload
|
|
230
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
231
|
+
|
|
232
|
+
expect(response.status).toBe(400);
|
|
233
|
+
expect(response.body).toMatchObject({ error: expect.any(String) }); // TODO: match error shape
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should return 401 when unauthenticated', async () => {
|
|
237
|
+
const response = await request(app).${methodLower}('${endpointPath}');
|
|
238
|
+
expect(response.status).toBe(401);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should return 404 for non-existent resource', async () => {
|
|
242
|
+
const response = await request(app)
|
|
243
|
+
.${methodLower}('${endpointPath.replace('{id}', 'nonexistent-99999')}')
|
|
244
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
245
|
+
expect(response.status).toBe(404);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should return 500 when the service fails', async () => {
|
|
249
|
+
// TODO: mock the service to throw an error
|
|
250
|
+
// Example with jest.spyOn:
|
|
251
|
+
// jest.spyOn(someService, 'someMethod').mockRejectedValueOnce(new Error('Service error'));
|
|
252
|
+
const response = await request(app)
|
|
253
|
+
.${methodLower}('${endpointPath}')
|
|
254
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
255
|
+
// TODO: trigger 500 condition
|
|
256
|
+
expect(response.status).toBeGreaterThanOrEqual(500);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
`;
|
|
260
|
+
return header + body.trimStart();
|
|
261
|
+
}
|
|
262
|
+
function renderSecurityMissingAuth(gap, ctx) {
|
|
263
|
+
var _a, _b, _c, _d;
|
|
264
|
+
const endpointPath = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/api/endpoint';
|
|
265
|
+
const method = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.method) !== null && _d !== void 0 ? _d : 'GET';
|
|
266
|
+
const methodLower = method.toLowerCase();
|
|
267
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
268
|
+
const body = `
|
|
269
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
270
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
271
|
+
|
|
272
|
+
describe('${method} ${endpointPath} — authentication', () => {
|
|
273
|
+
it('should return 401 when no token is provided', async () => {
|
|
274
|
+
const response = await request(app).${methodLower}('${endpointPath}');
|
|
275
|
+
expect(response.status).toBe(401);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should return 401 when an invalid token is provided', async () => {
|
|
279
|
+
const response = await request(app)
|
|
280
|
+
.${methodLower}('${endpointPath}')
|
|
281
|
+
.set('Authorization', 'Bearer invalid-token-here');
|
|
282
|
+
expect(response.status).toBe(401);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should return 403 when the user lacks required permissions', async () => {
|
|
286
|
+
const response = await request(app)
|
|
287
|
+
.${methodLower}('${endpointPath}')
|
|
288
|
+
.set('Authorization', 'Bearer TODO_LOW_PRIVILEGE_TOKEN'); // TODO: provide a low-privilege token
|
|
289
|
+
expect(response.status).toBe(403);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should succeed when a valid authorized token is provided', async () => {
|
|
293
|
+
const response = await request(app)
|
|
294
|
+
.${methodLower}('${endpointPath}')
|
|
295
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'); // TODO: provide valid token
|
|
296
|
+
expect(response.status).toBe(200);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
`;
|
|
300
|
+
return header + body.trimStart();
|
|
301
|
+
}
|
|
302
|
+
function renderSecurityInjection(gap, ctx) {
|
|
303
|
+
var _a, _b, _c, _d;
|
|
304
|
+
const endpointPath = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/api/endpoint';
|
|
305
|
+
const method = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.method) !== null && _d !== void 0 ? _d : 'POST';
|
|
306
|
+
const methodLower = method.toLowerCase();
|
|
307
|
+
const injectionCases = exports.OWASP_INJECTION_STRINGS.slice(0, 4)
|
|
308
|
+
.map((s) => ` { input: ${JSON.stringify(s)}, label: 'injection: ${s.slice(0, 20)}...' },`)
|
|
309
|
+
.join('\n');
|
|
310
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
311
|
+
const body = `
|
|
312
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
313
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
314
|
+
|
|
315
|
+
describe('${method} ${endpointPath} — injection security', () => {
|
|
316
|
+
const injectionPayloads = [
|
|
317
|
+
${injectionCases}
|
|
318
|
+
];
|
|
319
|
+
|
|
320
|
+
it.each(injectionPayloads)('should reject $label', async ({ input }) => {
|
|
321
|
+
const response = await request(app)
|
|
322
|
+
.${methodLower}('${endpointPath}')
|
|
323
|
+
.send({ field: input }) // TODO: replace 'field' with actual vulnerable field name
|
|
324
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
325
|
+
|
|
326
|
+
expect(response.status).toBe(400); // TODO: adjust — may be 422 or 200 with sanitised output
|
|
327
|
+
expect(response.body).not.toMatchObject({ data: input }); // TODO: verify injection is blocked
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
`;
|
|
331
|
+
return header + body.trimStart();
|
|
332
|
+
}
|
|
333
|
+
function renderPerformanceMissingSla(gap, ctx) {
|
|
334
|
+
var _a, _b, _c, _d;
|
|
335
|
+
const endpointPath = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/api/endpoint';
|
|
336
|
+
const method = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.method) !== null && _d !== void 0 ? _d : 'GET';
|
|
337
|
+
const methodLower = method.toLowerCase();
|
|
338
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
339
|
+
const body = `
|
|
340
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
341
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
342
|
+
|
|
343
|
+
const SLA_RESPONSE_MS = 500; // TODO: adjust SLA threshold
|
|
344
|
+
|
|
345
|
+
describe('${method} ${endpointPath} — performance SLA', () => {
|
|
346
|
+
it('should respond within SLA threshold', async () => {
|
|
347
|
+
const start = Date.now();
|
|
348
|
+
const response = await request(app)
|
|
349
|
+
.${methodLower}('${endpointPath}')
|
|
350
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
351
|
+
const elapsed = Date.now() - start;
|
|
352
|
+
|
|
353
|
+
expect(response.status).toBe(200);
|
|
354
|
+
expect(elapsed).toBeLessThan(SLA_RESPONSE_MS);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should handle concurrent requests within SLA', async () => {
|
|
358
|
+
const concurrency = 5; // TODO: adjust concurrency level
|
|
359
|
+
const start = Date.now();
|
|
360
|
+
const responses = await Promise.all(
|
|
361
|
+
Array.from({ length: concurrency }, () =>
|
|
362
|
+
request(app)
|
|
363
|
+
.${methodLower}('${endpointPath}')
|
|
364
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN'),
|
|
365
|
+
),
|
|
366
|
+
);
|
|
367
|
+
const elapsed = Date.now() - start;
|
|
368
|
+
|
|
369
|
+
for (const response of responses) {
|
|
370
|
+
expect(response.status).toBe(200);
|
|
371
|
+
}
|
|
372
|
+
expect(elapsed / concurrency).toBeLessThan(SLA_RESPONSE_MS);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
`;
|
|
376
|
+
return header + body.trimStart();
|
|
377
|
+
}
|
|
378
|
+
function renderResilienceMissingRetry(gap, ctx) {
|
|
379
|
+
var _a, _b, _c, _d;
|
|
380
|
+
const endpointPath = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/api/endpoint';
|
|
381
|
+
const method = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.method) !== null && _d !== void 0 ? _d : 'GET';
|
|
382
|
+
const methodLower = method.toLowerCase();
|
|
383
|
+
const header = renderFileHeader(gap.id, gap.type);
|
|
384
|
+
const body = `
|
|
385
|
+
import request from 'supertest'; // TODO: adjust import path
|
|
386
|
+
import app from '../../../src/app'; // TODO: adjust import path
|
|
387
|
+
|
|
388
|
+
describe('${method} ${endpointPath} — resilience / retry', () => {
|
|
389
|
+
it('should return 503 or retry-after header when service is unavailable', async () => {
|
|
390
|
+
// TODO: mock downstream dependency to simulate failure
|
|
391
|
+
// jest.spyOn(downstreamService, 'call').mockRejectedValueOnce(new Error('Downstream unavailable'));
|
|
392
|
+
const response = await request(app)
|
|
393
|
+
.${methodLower}('${endpointPath}')
|
|
394
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
395
|
+
|
|
396
|
+
// Either the service retries successfully (200) or signals unavailability (503)
|
|
397
|
+
expect([200, 503]).toContain(response.status);
|
|
398
|
+
if (response.status === 503) {
|
|
399
|
+
expect(response.headers).toHaveProperty('retry-after'); // TODO: check actual header name
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('should handle circuit-breaker open state gracefully', async () => {
|
|
404
|
+
// TODO: trigger circuit breaker open state
|
|
405
|
+
const response = await request(app)
|
|
406
|
+
.${methodLower}('${endpointPath}')
|
|
407
|
+
.set('Authorization', 'Bearer TODO_VALID_TOKEN');
|
|
408
|
+
|
|
409
|
+
expect(response.status).toBe(503); // TODO: adjust expected status
|
|
410
|
+
expect(response.body).toMatchObject({ error: expect.any(String) });
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
`;
|
|
414
|
+
return header + body.trimStart();
|
|
415
|
+
}
|
|
416
|
+
// ─── Python / pytest templates ────────────────────────────────────────────────
|
|
417
|
+
function renderPythonEndpoint(gap, ctx) {
|
|
418
|
+
var _a, _b, _c, _d;
|
|
419
|
+
const method = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : 'GET';
|
|
420
|
+
const endpointPath = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : '/api/endpoint';
|
|
421
|
+
const methodLower = method.toLowerCase();
|
|
422
|
+
const header = renderFileHeader(gap.id, gap.type).replace(/\/\//g, '#');
|
|
423
|
+
const body = `
|
|
424
|
+
import pytest
|
|
425
|
+
import requests # TODO: adjust import path
|
|
426
|
+
|
|
427
|
+
BASE_URL = "${ctx.baseUrl}" # TODO: adjust base URL
|
|
428
|
+
AUTH_TOKEN = "TODO_VALID_TOKEN" # TODO: add valid token
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class Test${method.charAt(0) + method.slice(1).toLowerCase()}${endpointPath.replace(/[^a-zA-Z0-9]/g, '_')}:
|
|
432
|
+
def test_returns_200_with_valid_request(self):
|
|
433
|
+
response = requests.${methodLower}(
|
|
434
|
+
f"{BASE_URL}${endpointPath}",
|
|
435
|
+
headers={"Authorization": f"Bearer {AUTH_TOKEN}"},
|
|
436
|
+
)
|
|
437
|
+
assert response.status_code == 200
|
|
438
|
+
assert response.json() is not None # TODO: replace with specific assertion
|
|
439
|
+
|
|
440
|
+
def test_returns_401_when_unauthenticated(self):
|
|
441
|
+
response = requests.${methodLower}(f"{BASE_URL}${endpointPath}")
|
|
442
|
+
assert response.status_code == 401
|
|
443
|
+
`;
|
|
444
|
+
return header + body.trimStart();
|
|
445
|
+
}
|
|
446
|
+
// ─── Java / JUnit5 templates ──────────────────────────────────────────────────
|
|
447
|
+
function renderJavaEndpoint(gap, ctx) {
|
|
448
|
+
var _a, _b, _c, _d;
|
|
449
|
+
const method = (_b = (_a = gap.endpoint) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : 'GET';
|
|
450
|
+
const endpointPath = (_d = (_c = gap.endpoint) === null || _c === void 0 ? void 0 : _c.path) !== null && _d !== void 0 ? _d : '/api/endpoint';
|
|
451
|
+
const className = `Test${gap.id.split('-').map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join('')}`;
|
|
452
|
+
const header = renderFileHeader(gap.id, gap.type).replace(/\/\//g, '//');
|
|
453
|
+
const body = `
|
|
454
|
+
package generated;
|
|
455
|
+
|
|
456
|
+
import org.junit.jupiter.api.Test;
|
|
457
|
+
import org.springframework.boot.test.context.SpringBootTest;
|
|
458
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
459
|
+
import org.springframework.test.web.servlet.MockMvc;
|
|
460
|
+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
461
|
+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
462
|
+
|
|
463
|
+
// TODO: Add @SpringBootTest or @WebMvcTest and adjust imports
|
|
464
|
+
@SpringBootTest
|
|
465
|
+
class ${className} {
|
|
466
|
+
|
|
467
|
+
@Autowired
|
|
468
|
+
private MockMvc mockMvc; // TODO: inject MockMvc
|
|
469
|
+
|
|
470
|
+
@Test
|
|
471
|
+
void shouldReturn200WithValidRequest() throws Exception {
|
|
472
|
+
mockMvc.perform(${method.toLowerCase()}("${endpointPath}")
|
|
473
|
+
.header("Authorization", "Bearer TODO_VALID_TOKEN")) // TODO: add valid token
|
|
474
|
+
.andExpect(status().isOk())
|
|
475
|
+
.andExpect(jsonPath("$").isNotEmpty()); // TODO: replace with specific assertion
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
@Test
|
|
479
|
+
void shouldReturn401WhenUnauthenticated() throws Exception {
|
|
480
|
+
mockMvc.perform(${method.toLowerCase()}("${endpointPath}"))
|
|
481
|
+
.andExpect(status().isUnauthorized());
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
`;
|
|
485
|
+
return header + body.trimStart();
|
|
486
|
+
}
|
|
487
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
488
|
+
/** Render test file content for a given gap and context */
|
|
489
|
+
function renderTemplate(gap, ctx) {
|
|
490
|
+
const { language } = ctx;
|
|
491
|
+
if (language === 'python') {
|
|
492
|
+
return renderPythonEndpoint(gap, ctx);
|
|
493
|
+
}
|
|
494
|
+
if (language === 'java' || language === 'kotlin') {
|
|
495
|
+
return renderJavaEndpoint(gap, ctx);
|
|
496
|
+
}
|
|
497
|
+
// TypeScript / JavaScript (Jest, Cypress, Playwright)
|
|
498
|
+
switch (gap.type) {
|
|
499
|
+
case 'endpoint:missing':
|
|
500
|
+
return renderEndpointMissing(gap, ctx);
|
|
501
|
+
case 'parameter:missing':
|
|
502
|
+
return renderParameterMissing(gap, ctx);
|
|
503
|
+
case 'parameter:not-validated':
|
|
504
|
+
return renderParameterNotValidated(gap, ctx);
|
|
505
|
+
case 'business:missing':
|
|
506
|
+
return renderBusinessMissing(gap, ctx);
|
|
507
|
+
case 'integration:missing-step':
|
|
508
|
+
return renderIntegrationMissingStep(gap, ctx);
|
|
509
|
+
case 'error:missing-status':
|
|
510
|
+
return renderErrorMissingStatus(gap, ctx);
|
|
511
|
+
case 'security:missing-auth':
|
|
512
|
+
return renderSecurityMissingAuth(gap, ctx);
|
|
513
|
+
case 'security:injection':
|
|
514
|
+
return renderSecurityInjection(gap, ctx);
|
|
515
|
+
case 'performance:missing-sla':
|
|
516
|
+
return renderPerformanceMissingSla(gap, ctx);
|
|
517
|
+
case 'resilience:missing-retry':
|
|
518
|
+
return renderResilienceMissingRetry(gap, ctx);
|
|
519
|
+
default:
|
|
520
|
+
return renderEndpointMissing(gap, ctx);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/** Returns the template name used for a given gap type */
|
|
524
|
+
function getTemplateName(gap, ctx) {
|
|
525
|
+
return `${ctx.language}/${ctx.framework}/${gap.type}`;
|
|
526
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export type GapType = 'endpoint:missing' | 'parameter:missing' | 'parameter:not-validated' | 'business:missing' | 'integration:missing-step' | 'error:missing-status' | 'security:missing-auth' | 'security:injection' | 'performance:missing-sla' | 'resilience:missing-retry';
|
|
2
|
+
export type Language = 'typescript' | 'javascript' | 'python' | 'java' | 'kotlin';
|
|
3
|
+
export type Framework = 'jest' | 'pytest' | 'junit5' | 'cypress' | 'playwright';
|
|
4
|
+
export interface DetectedGap {
|
|
5
|
+
id: string;
|
|
6
|
+
type: GapType;
|
|
7
|
+
endpoint?: {
|
|
8
|
+
method: string;
|
|
9
|
+
path: string;
|
|
10
|
+
};
|
|
11
|
+
parameter?: {
|
|
12
|
+
name: string;
|
|
13
|
+
in: 'query' | 'path' | 'header' | 'body';
|
|
14
|
+
required: boolean;
|
|
15
|
+
};
|
|
16
|
+
businessRule?: {
|
|
17
|
+
id: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
integrationFlow?: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
missingStep: string;
|
|
24
|
+
};
|
|
25
|
+
riskScore: number;
|
|
26
|
+
sourceFile?: string;
|
|
27
|
+
existingSimilarTests: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface GenerationContext {
|
|
30
|
+
projectRoot: string;
|
|
31
|
+
language: Language;
|
|
32
|
+
framework: Framework;
|
|
33
|
+
testFramework: 'jest' | 'pytest' | 'junit5';
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
authHeader?: string;
|
|
36
|
+
gaps: DetectedGap[];
|
|
37
|
+
}
|
|
38
|
+
export interface GeneratedFile {
|
|
39
|
+
outputPath: string;
|
|
40
|
+
content: string;
|
|
41
|
+
gapId: string;
|
|
42
|
+
templateUsed: string;
|
|
43
|
+
qualityScore?: number;
|
|
44
|
+
}
|
|
45
|
+
export interface TestQualityReport {
|
|
46
|
+
file: string;
|
|
47
|
+
overallScore: number;
|
|
48
|
+
dimensions: {
|
|
49
|
+
hasStatusAssertion: boolean;
|
|
50
|
+
hasBodyAssertion: boolean;
|
|
51
|
+
hasErrorPath: boolean;
|
|
52
|
+
hasNoGenericMatchers: boolean;
|
|
53
|
+
hasDescriptiveName: boolean;
|
|
54
|
+
};
|
|
55
|
+
violations: string[];
|
|
56
|
+
}
|
|
57
|
+
export interface AiReadyFlow {
|
|
58
|
+
id: string;
|
|
59
|
+
gapId: string;
|
|
60
|
+
gapType: GapType;
|
|
61
|
+
suggestedOutputPath: string;
|
|
62
|
+
copilotPrompt: string;
|
|
63
|
+
existingSimilarTests: string[];
|
|
64
|
+
estimatedComplexity: 'low' | 'medium' | 'high';
|
|
65
|
+
riskScore: number;
|
|
66
|
+
}
|
|
67
|
+
export interface AiReadyFlowsManifest {
|
|
68
|
+
generatedAt: string;
|
|
69
|
+
totalFlows: number;
|
|
70
|
+
byType: Record<GapType, number>;
|
|
71
|
+
flows: AiReadyFlow[];
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/generation/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GACf,kBAAkB,GAClB,mBAAmB,GACnB,yBAAyB,GACzB,kBAAkB,GAClB,0BAA0B,GAC1B,sBAAsB,GACtB,uBAAuB,GACvB,oBAAoB,GACpB,yBAAyB,GACzB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAEhF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1F,YAAY,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,eAAe,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,kBAAkB,EAAE,OAAO,CAAC;QAC5B,gBAAgB,EAAE,OAAO,CAAC;QAC1B,YAAY,EAAE,OAAO,CAAC;QACtB,oBAAoB,EAAE,OAAO,CAAC;QAC9B,kBAAkB,EAAE,OAAO,CAAC;KAC7B,CAAC;IACF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,mBAAmB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB"}
|