@yasserkhanorg/e2e-agents 1.8.1 → 1.8.3
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/agent/plan.d.ts +29 -0
- package/dist/agent/plan.d.ts.map +1 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +15 -4
- package/dist/cli/commands/generate.js +1 -1
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +55 -18
- package/dist/cli/commands/plan_crew.d.ts +17 -0
- package/dist/cli/commands/plan_crew.d.ts.map +1 -0
- package/dist/cli/commands/plan_crew.js +273 -0
- package/dist/cli/parse_args.d.ts.map +1 -1
- package/dist/cli/parse_args.js +2 -0
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/usage.d.ts.map +1 -1
- package/dist/cli/usage.js +2 -0
- package/dist/esm/api.js +15 -4
- package/dist/esm/cli/commands/generate.js +1 -1
- package/dist/esm/cli/commands/plan.js +56 -19
- package/dist/esm/cli/commands/plan_crew.js +266 -0
- package/dist/esm/cli/parse_args.js +2 -0
- package/dist/esm/cli/usage.js +2 -0
- package/dist/esm/mcp-server.js +147 -6
- package/dist/esm/provider_factory.js +11 -0
- package/dist/mcp-server.d.ts +33 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +150 -5
- package/dist/provider_factory.d.ts +5 -0
- package/dist/provider_factory.d.ts.map +1 -1
- package/dist/provider_factory.js +11 -0
- package/package.json +4 -3
- package/schemas/plan.schema.json +158 -0
package/dist/mcp-server.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
4
|
// See LICENSE.txt for license information.
|
|
4
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
6
|
exports.E2EAgentsMCPServer = void 0;
|
|
7
|
+
exports.encodeJsonRpcMessage = encodeJsonRpcMessage;
|
|
8
|
+
exports.parseJsonRpcFrames = parseJsonRpcFrames;
|
|
9
|
+
exports.handleJsonRpcMessage = handleJsonRpcMessage;
|
|
10
|
+
exports.startStdioServer = startStdioServer;
|
|
6
11
|
/**
|
|
7
12
|
* MCP Server for E2E Agents - SECURITY HARDENED
|
|
8
13
|
* Exposes tools for Claude and Playwright agents to discover, generate, and heal tests
|
|
@@ -475,12 +480,152 @@ class E2EAgentsMCPServer {
|
|
|
475
480
|
}
|
|
476
481
|
exports.E2EAgentsMCPServer = E2EAgentsMCPServer;
|
|
477
482
|
/**
|
|
478
|
-
*
|
|
479
|
-
*
|
|
483
|
+
* Read the package version at runtime so the MCP initialize response
|
|
484
|
+
* always reflects the installed version.
|
|
480
485
|
*/
|
|
486
|
+
function getPackageVersion() {
|
|
487
|
+
try {
|
|
488
|
+
const pkgPath = (0, path_1.join)((0, path_1.dirname)(__dirname), 'package.json');
|
|
489
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
490
|
+
return pkg.version || '0.0.0';
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
return '0.0.0';
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Encode a JSON-RPC message with Content-Length framing.
|
|
498
|
+
* Exported for testability.
|
|
499
|
+
*/
|
|
500
|
+
function encodeJsonRpcMessage(message) {
|
|
501
|
+
const body = JSON.stringify(message);
|
|
502
|
+
return `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Parse Content-Length framed JSON-RPC messages from a buffer.
|
|
506
|
+
* Returns parsed messages and the remaining (unconsumed) buffer.
|
|
507
|
+
* Exported for testability.
|
|
508
|
+
*/
|
|
509
|
+
function parseJsonRpcFrames(input) {
|
|
510
|
+
const messages = [];
|
|
511
|
+
let buffer = Buffer.from(input);
|
|
512
|
+
while (true) {
|
|
513
|
+
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
514
|
+
if (headerEnd === -1)
|
|
515
|
+
break;
|
|
516
|
+
const headerText = buffer.slice(0, headerEnd).toString('utf8');
|
|
517
|
+
const match = headerText.match(/Content-Length:\s*(\d+)/i);
|
|
518
|
+
if (!match) {
|
|
519
|
+
buffer = Buffer.alloc(0);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
const contentLength = Number(match[1]);
|
|
523
|
+
const messageEnd = headerEnd + 4 + contentLength;
|
|
524
|
+
if (buffer.length < messageEnd)
|
|
525
|
+
break;
|
|
526
|
+
const body = buffer.slice(headerEnd + 4, messageEnd).toString('utf8');
|
|
527
|
+
buffer = buffer.slice(messageEnd);
|
|
528
|
+
messages.push(JSON.parse(body));
|
|
529
|
+
}
|
|
530
|
+
return { messages, remainder: buffer };
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Handle a single JSON-RPC message against the server.
|
|
534
|
+
* Returns the response message (or null for notifications).
|
|
535
|
+
* Exported for testability.
|
|
536
|
+
*/
|
|
537
|
+
async function handleJsonRpcMessage(server, message) {
|
|
538
|
+
const { id, method, params } = message;
|
|
539
|
+
const version = getPackageVersion();
|
|
540
|
+
if (method === 'initialize') {
|
|
541
|
+
return {
|
|
542
|
+
jsonrpc: '2.0',
|
|
543
|
+
id,
|
|
544
|
+
result: {
|
|
545
|
+
protocolVersion: typeof params?.protocolVersion === 'string' ? params.protocolVersion : '2024-11-05',
|
|
546
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
547
|
+
serverInfo: { name: 'e2e-agents-mcp', version },
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
if (method === 'notifications/initialized' || method === 'initialized') {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
if (method === 'tools/list') {
|
|
555
|
+
return {
|
|
556
|
+
jsonrpc: '2.0',
|
|
557
|
+
id,
|
|
558
|
+
result: {
|
|
559
|
+
tools: server.getTools().map((tool) => ({
|
|
560
|
+
name: tool.name,
|
|
561
|
+
description: tool.description,
|
|
562
|
+
inputSchema: tool.inputSchema,
|
|
563
|
+
})),
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
if (method === 'tools/call') {
|
|
568
|
+
const resultText = await server.callTool(typeof params?.name === 'string' ? params.name : '', typeof params?.arguments === 'object' && params.arguments !== null ? params.arguments : {});
|
|
569
|
+
let isError = false;
|
|
570
|
+
try {
|
|
571
|
+
const parsed = JSON.parse(resultText);
|
|
572
|
+
isError = Boolean(parsed.error);
|
|
573
|
+
}
|
|
574
|
+
catch {
|
|
575
|
+
isError = false;
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
jsonrpc: '2.0',
|
|
579
|
+
id,
|
|
580
|
+
result: { content: [{ type: 'text', text: resultText }], isError },
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
if (method === 'resources/list') {
|
|
584
|
+
return { jsonrpc: '2.0', id, result: { resources: [] } };
|
|
585
|
+
}
|
|
586
|
+
if (method === 'prompts/list') {
|
|
587
|
+
return { jsonrpc: '2.0', id, result: { prompts: [] } };
|
|
588
|
+
}
|
|
589
|
+
if (method === 'ping') {
|
|
590
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
591
|
+
}
|
|
592
|
+
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Start MCP server over stdio using Content-Length framed JSON-RPC messages.
|
|
596
|
+
*/
|
|
597
|
+
function startStdioServer(repoRoot = process.cwd()) {
|
|
598
|
+
const server = new E2EAgentsMCPServer(repoRoot);
|
|
599
|
+
let buffer = Buffer.alloc(0);
|
|
600
|
+
const sendMessage = (message) => {
|
|
601
|
+
process.stdout.write(encodeJsonRpcMessage(message));
|
|
602
|
+
};
|
|
603
|
+
const sendError = (id, code, msg) => {
|
|
604
|
+
sendMessage({ jsonrpc: '2.0', id, error: { code, message: msg } });
|
|
605
|
+
};
|
|
606
|
+
const processBuffer = () => {
|
|
607
|
+
const { messages, remainder } = parseJsonRpcFrames(buffer);
|
|
608
|
+
buffer = remainder;
|
|
609
|
+
for (const parsed of messages) {
|
|
610
|
+
void handleJsonRpcMessage(server, parsed)
|
|
611
|
+
.then((response) => {
|
|
612
|
+
if (response)
|
|
613
|
+
sendMessage(response);
|
|
614
|
+
})
|
|
615
|
+
.catch((error) => {
|
|
616
|
+
sendError(parsed.id ?? null, -32603, error instanceof Error ? error.message : String(error));
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
process.stdin.on('data', (chunk) => {
|
|
621
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
622
|
+
processBuffer();
|
|
623
|
+
});
|
|
624
|
+
process.stdin.on('end', () => {
|
|
625
|
+
process.exit(0);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
481
628
|
if (require.main === module) {
|
|
482
|
-
|
|
483
|
-
console.log('E2E Agents MCP Server started');
|
|
484
|
-
console.log('Tools:', server.getTools().map((t) => t.name).join(', '));
|
|
629
|
+
startStdioServer();
|
|
485
630
|
}
|
|
486
631
|
exports.default = E2EAgentsMCPServer;
|
|
@@ -55,6 +55,11 @@ export declare class LLMProviderFactory {
|
|
|
55
55
|
* 5. Error (no provider available)
|
|
56
56
|
*/
|
|
57
57
|
static createFromEnv(): Promise<LLMProvider>;
|
|
58
|
+
/**
|
|
59
|
+
* Create provider from an explicit preference when supplied, otherwise
|
|
60
|
+
* fall back to environment auto-detection.
|
|
61
|
+
*/
|
|
62
|
+
static createFromPreference(providerPreference?: string): Promise<LLMProvider>;
|
|
58
63
|
/**
|
|
59
64
|
* Create provider from simple string format
|
|
60
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider_factory.d.ts","sourceRoot":"","sources":["../src/provider_factory.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAKR,WAAW,EAIX,cAAc,EAEjB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kBAAkB;IAC3B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW;IAmBlD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAWtD;;;;;;;;;OASG;WACU,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC;IAyElD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;CAkC/D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,cAAc,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;CACrF;AA+ID;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC,CAsCD"}
|
|
1
|
+
{"version":3,"file":"provider_factory.d.ts","sourceRoot":"","sources":["../src/provider_factory.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAKR,WAAW,EAIX,cAAc,EAEjB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kBAAkB;IAC3B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW;IAmBlD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAWtD;;;;;;;;;OASG;WACU,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC;IAyElD;;;OAGG;WACU,oBAAoB,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IASpF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;CAkC/D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,cAAc,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;CACrF;AA+ID;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC,CAsCD"}
|
package/dist/provider_factory.js
CHANGED
|
@@ -145,6 +145,17 @@ class LLMProviderFactory {
|
|
|
145
145
|
'3. Set OPENAI_API_KEY environment variable\n' +
|
|
146
146
|
'4. Set LLM_PROVIDER environment variable');
|
|
147
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Create provider from an explicit preference when supplied, otherwise
|
|
150
|
+
* fall back to environment auto-detection.
|
|
151
|
+
*/
|
|
152
|
+
static async createFromPreference(providerPreference) {
|
|
153
|
+
const normalized = providerPreference?.trim().toLowerCase();
|
|
154
|
+
if (!normalized || normalized === 'auto') {
|
|
155
|
+
return this.createFromEnv();
|
|
156
|
+
}
|
|
157
|
+
return this.createFromString(normalized);
|
|
158
|
+
}
|
|
148
159
|
/**
|
|
149
160
|
* Create provider from simple string format
|
|
150
161
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yasserkhanorg/e2e-agents",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"description": "AI-powered E2E test impact analysis, generation, and healing. Analyzes code changes to identify affected Playwright tests, detects coverage gaps, and generates or repairs specs using pluggable LLM providers (Claude, OpenAI, Ollama). Includes MCP server, traceability, and CI/CD integration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"bin": {
|
|
30
30
|
"e2e-ai-agents": "./dist/cli.js",
|
|
31
|
-
"e2e-qa-agent": "./dist/qa-agent/cli.js"
|
|
31
|
+
"e2e-qa-agent": "./dist/qa-agent/cli.js",
|
|
32
|
+
"e2e-agents-mcp": "./dist/mcp-server.js"
|
|
32
33
|
},
|
|
33
34
|
"files": [
|
|
34
35
|
"dist",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
],
|
|
39
40
|
"scripts": {
|
|
40
41
|
"build": "npm run build:cjs && npm run build:esm",
|
|
41
|
-
"postbuild": "chmod +x dist/cli.js dist/qa-agent/cli.js",
|
|
42
|
+
"postbuild": "chmod +x dist/cli.js dist/qa-agent/cli.js dist/mcp-server.js",
|
|
42
43
|
"build:cjs": "tsc -p tsconfig.json",
|
|
43
44
|
"build:esm": "tsc -p tsconfig.esm.json && node scripts/write-esm-package.js",
|
|
44
45
|
"clean": "rm -rf dist",
|
package/schemas/plan.schema.json
CHANGED
|
@@ -280,6 +280,68 @@
|
|
|
280
280
|
},
|
|
281
281
|
"additionalProperties": false
|
|
282
282
|
},
|
|
283
|
+
"crew": {
|
|
284
|
+
"type": "object",
|
|
285
|
+
"required": [
|
|
286
|
+
"workflow",
|
|
287
|
+
"providerOverride",
|
|
288
|
+
"summary",
|
|
289
|
+
"impactedFlows",
|
|
290
|
+
"strategyEntries",
|
|
291
|
+
"testDesigns",
|
|
292
|
+
"crossImpacts",
|
|
293
|
+
"regressionRisks",
|
|
294
|
+
"findings",
|
|
295
|
+
"warnings",
|
|
296
|
+
"timings"
|
|
297
|
+
],
|
|
298
|
+
"properties": {
|
|
299
|
+
"workflow": {"type": "string"},
|
|
300
|
+
"providerOverride": {"type": "string"},
|
|
301
|
+
"summary": {
|
|
302
|
+
"type": "object",
|
|
303
|
+
"required": [
|
|
304
|
+
"impactedFlows",
|
|
305
|
+
"strategyEntries",
|
|
306
|
+
"testDesigns",
|
|
307
|
+
"crossImpacts",
|
|
308
|
+
"highRiskCrossImpacts",
|
|
309
|
+
"regressionRisks",
|
|
310
|
+
"findings",
|
|
311
|
+
"generatedSpecs",
|
|
312
|
+
"manualReviewEntries",
|
|
313
|
+
"totalCostUSD",
|
|
314
|
+
"totalTokens"
|
|
315
|
+
],
|
|
316
|
+
"properties": {
|
|
317
|
+
"impactedFlows": {"type": "number"},
|
|
318
|
+
"strategyEntries": {"type": "number"},
|
|
319
|
+
"testDesigns": {"type": "number"},
|
|
320
|
+
"crossImpacts": {"type": "number"},
|
|
321
|
+
"highRiskCrossImpacts": {"type": "number"},
|
|
322
|
+
"regressionRisks": {"type": "number"},
|
|
323
|
+
"findings": {"type": "number"},
|
|
324
|
+
"generatedSpecs": {"type": "number"},
|
|
325
|
+
"manualReviewEntries": {"type": "number"},
|
|
326
|
+
"totalCostUSD": {"type": "number"},
|
|
327
|
+
"totalTokens": {"type": "number"}
|
|
328
|
+
},
|
|
329
|
+
"additionalProperties": false
|
|
330
|
+
},
|
|
331
|
+
"impactedFlows": {"type": "array", "items": {"$ref": "#/$defs/flowDecision"}},
|
|
332
|
+
"strategyEntries": {"type": "array", "items": {"$ref": "#/$defs/strategyEntry"}},
|
|
333
|
+
"testDesigns": {"type": "array", "items": {"$ref": "#/$defs/testDesign"}},
|
|
334
|
+
"crossImpacts": {"type": "array", "items": {"$ref": "#/$defs/crossImpact"}},
|
|
335
|
+
"regressionRisks": {"type": "array", "items": {"$ref": "#/$defs/regressionRisk"}},
|
|
336
|
+
"findings": {"type": "array", "items": {"$ref": "#/$defs/finding"}},
|
|
337
|
+
"warnings": {"type": "array", "items": {"type": "string"}},
|
|
338
|
+
"timings": {
|
|
339
|
+
"type": "object",
|
|
340
|
+
"additionalProperties": {"type": "number"}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"additionalProperties": false
|
|
344
|
+
},
|
|
283
345
|
"metrics": {
|
|
284
346
|
"type": "object",
|
|
285
347
|
"required": [
|
|
@@ -327,6 +389,102 @@
|
|
|
327
389
|
"details": {"type": "string"}
|
|
328
390
|
},
|
|
329
391
|
"additionalProperties": false
|
|
392
|
+
},
|
|
393
|
+
"flowDecision": {
|
|
394
|
+
"type": "object",
|
|
395
|
+
"required": ["flowId", "flowName", "routeFamily", "changedFiles", "evidence", "evidenceSource", "confidence", "existingSpecs", "action", "priority"],
|
|
396
|
+
"properties": {
|
|
397
|
+
"flowId": {"type": "string"},
|
|
398
|
+
"flowName": {"type": "string"},
|
|
399
|
+
"routeFamily": {"type": "string"},
|
|
400
|
+
"changedFiles": {"type": "array", "items": {"type": "string"}},
|
|
401
|
+
"evidence": {"type": "string"},
|
|
402
|
+
"evidenceSource": {"enum": ["deterministic", "ai", "hybrid"]},
|
|
403
|
+
"confidence": {"type": "number"},
|
|
404
|
+
"existingSpecs": {"type": "array", "items": {"type": "string"}},
|
|
405
|
+
"action": {"enum": ["create_spec", "update_spec", "skip"]},
|
|
406
|
+
"priority": {"enum": ["P0", "P1", "P2"]},
|
|
407
|
+
"userActions": {"type": "array", "items": {"type": "string"}}
|
|
408
|
+
},
|
|
409
|
+
"additionalProperties": true
|
|
410
|
+
},
|
|
411
|
+
"strategyEntry": {
|
|
412
|
+
"type": "object",
|
|
413
|
+
"required": ["flowId", "flowName", "priority", "approach", "rationale", "testCategories", "crossImpactRisk"],
|
|
414
|
+
"properties": {
|
|
415
|
+
"flowId": {"type": "string"},
|
|
416
|
+
"flowName": {"type": "string"},
|
|
417
|
+
"priority": {"enum": ["P0", "P1", "P2"]},
|
|
418
|
+
"approach": {"enum": ["full-test", "smoke-test", "skip", "manual-review"]},
|
|
419
|
+
"rationale": {"type": "string"},
|
|
420
|
+
"testCategories": {"type": "array", "items": {"type": "string"}},
|
|
421
|
+
"crossImpactRisk": {"enum": ["high", "medium", "low", "none"]}
|
|
422
|
+
},
|
|
423
|
+
"additionalProperties": false
|
|
424
|
+
},
|
|
425
|
+
"testDesign": {
|
|
426
|
+
"type": "object",
|
|
427
|
+
"required": ["flowId", "flowName", "testCases"],
|
|
428
|
+
"properties": {
|
|
429
|
+
"flowId": {"type": "string"},
|
|
430
|
+
"flowName": {"type": "string"},
|
|
431
|
+
"testCases": {
|
|
432
|
+
"type": "array",
|
|
433
|
+
"items": {
|
|
434
|
+
"type": "object",
|
|
435
|
+
"required": ["name", "type", "preconditions", "steps", "expectedOutcome", "priority", "rationale"],
|
|
436
|
+
"properties": {
|
|
437
|
+
"name": {"type": "string"},
|
|
438
|
+
"type": {"enum": ["happy-path", "edge-case", "boundary", "negative", "state-transition", "race-condition", "permission", "accessibility", "performance"]},
|
|
439
|
+
"preconditions": {"type": "array", "items": {"type": "string"}},
|
|
440
|
+
"steps": {"type": "array", "items": {"type": "string"}},
|
|
441
|
+
"expectedOutcome": {"type": "string"},
|
|
442
|
+
"priority": {"enum": ["P0", "P1", "P2"]},
|
|
443
|
+
"rationale": {"type": "string"}
|
|
444
|
+
},
|
|
445
|
+
"additionalProperties": false
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
"additionalProperties": false
|
|
450
|
+
},
|
|
451
|
+
"crossImpact": {
|
|
452
|
+
"type": "object",
|
|
453
|
+
"required": ["sourceFamily", "affectedFamily", "sharedDependency", "riskLevel", "evidence"],
|
|
454
|
+
"properties": {
|
|
455
|
+
"sourceFamily": {"type": "string"},
|
|
456
|
+
"affectedFamily": {"type": "string"},
|
|
457
|
+
"sharedDependency": {"type": "string"},
|
|
458
|
+
"riskLevel": {"enum": ["high", "medium", "low"]},
|
|
459
|
+
"evidence": {"type": "string"}
|
|
460
|
+
},
|
|
461
|
+
"additionalProperties": false
|
|
462
|
+
},
|
|
463
|
+
"regressionRisk": {
|
|
464
|
+
"type": "object",
|
|
465
|
+
"required": ["familyId", "filePattern", "riskScore", "reason", "historicalFailures"],
|
|
466
|
+
"properties": {
|
|
467
|
+
"familyId": {"type": "string"},
|
|
468
|
+
"filePattern": {"type": "string"},
|
|
469
|
+
"riskScore": {"type": "number"},
|
|
470
|
+
"reason": {"type": "string"},
|
|
471
|
+
"historicalFailures": {"type": "number"}
|
|
472
|
+
},
|
|
473
|
+
"additionalProperties": false
|
|
474
|
+
},
|
|
475
|
+
"finding": {
|
|
476
|
+
"type": "object",
|
|
477
|
+
"required": ["id", "type", "severity", "source", "summary", "details", "relatedFlows"],
|
|
478
|
+
"properties": {
|
|
479
|
+
"id": {"type": "string"},
|
|
480
|
+
"type": {"enum": ["bug", "gap", "risk", "flaky"]},
|
|
481
|
+
"severity": {"enum": ["critical", "high", "medium", "low"]},
|
|
482
|
+
"source": {"enum": ["strategist", "test-designer", "cross-impact", "regression-advisor", "impact-analyst", "coverage-evaluator", "generator", "executor", "healer", "explorer"]},
|
|
483
|
+
"summary": {"type": "string"},
|
|
484
|
+
"details": {"type": "string"},
|
|
485
|
+
"relatedFlows": {"type": "array", "items": {"type": "string"}}
|
|
486
|
+
},
|
|
487
|
+
"additionalProperties": false
|
|
330
488
|
}
|
|
331
489
|
},
|
|
332
490
|
"additionalProperties": false
|