@provartesting/provardx-cli 1.5.0-dev.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -12
- package/bin/mcp-start.js +74 -0
- package/lib/commands/provar/auth/clear.d.ts +7 -0
- package/lib/commands/provar/auth/clear.js +36 -0
- package/lib/commands/provar/auth/clear.js.map +1 -0
- package/lib/commands/provar/auth/login.d.ts +10 -0
- package/lib/commands/provar/auth/login.js +90 -0
- package/lib/commands/provar/auth/login.js.map +1 -0
- package/lib/commands/provar/auth/rotate.d.ts +7 -0
- package/lib/commands/provar/auth/rotate.js +42 -0
- package/lib/commands/provar/auth/rotate.js.map +1 -0
- package/lib/commands/provar/auth/status.d.ts +7 -0
- package/lib/commands/provar/auth/status.js +107 -0
- package/lib/commands/provar/auth/status.js.map +1 -0
- package/lib/commands/provar/mcp/start.d.ts +2 -0
- package/lib/commands/provar/mcp/start.js +14 -1
- package/lib/commands/provar/mcp/start.js.map +1 -1
- package/lib/mcp/docs/NITROX_CATALOG_SOURCE.json +6 -0
- package/lib/mcp/docs/NITROX_COMPONENT_CATALOG.md +2001 -0
- package/lib/mcp/docs/PROVAR_TEST_STEP_REFERENCE.md +1430 -0
- package/lib/mcp/docs/PROVAR_TOOL_GUIDE.md +187 -0
- package/lib/mcp/licensing/algasClient.js +14 -5
- package/lib/mcp/licensing/algasClient.js.map +1 -1
- package/lib/mcp/licensing/ideDetection.d.ts +0 -12
- package/lib/mcp/licensing/ideDetection.js +1 -73
- package/lib/mcp/licensing/ideDetection.js.map +1 -1
- package/lib/mcp/licensing/licenseCache.js +7 -1
- package/lib/mcp/licensing/licenseCache.js.map +1 -1
- package/lib/mcp/licensing/licenseValidator.d.ts +3 -3
- package/lib/mcp/licensing/licenseValidator.js +11 -4
- package/lib/mcp/licensing/licenseValidator.js.map +1 -1
- package/lib/mcp/prompts/guidePrompts.d.ts +4 -0
- package/lib/mcp/prompts/guidePrompts.js +334 -0
- package/lib/mcp/prompts/guidePrompts.js.map +1 -0
- package/lib/mcp/prompts/index.d.ts +2 -0
- package/lib/mcp/prompts/index.js +23 -0
- package/lib/mcp/prompts/index.js.map +1 -0
- package/lib/mcp/prompts/loopPrompts.d.ts +6 -0
- package/lib/mcp/prompts/loopPrompts.js +435 -0
- package/lib/mcp/prompts/loopPrompts.js.map +1 -0
- package/lib/mcp/prompts/migrationPrompts.d.ts +4 -0
- package/lib/mcp/prompts/migrationPrompts.js +207 -0
- package/lib/mcp/prompts/migrationPrompts.js.map +1 -0
- package/lib/mcp/rules/provar_best_practices_rules.json +256 -544
- package/lib/mcp/security/pathPolicy.d.ts +5 -0
- package/lib/mcp/security/pathPolicy.js +58 -3
- package/lib/mcp/security/pathPolicy.js.map +1 -1
- package/lib/mcp/server.d.ts +18 -0
- package/lib/mcp/server.js +232 -19
- package/lib/mcp/server.js.map +1 -1
- package/lib/mcp/tools/antTools.d.ts +15 -0
- package/lib/mcp/tools/antTools.js +369 -170
- package/lib/mcp/tools/antTools.js.map +1 -1
- package/lib/mcp/tools/automationTools.d.ts +18 -8
- package/lib/mcp/tools/automationTools.js +333 -176
- package/lib/mcp/tools/automationTools.js.map +1 -1
- package/lib/mcp/tools/bestPracticesEngine.js +161 -23
- package/lib/mcp/tools/bestPracticesEngine.js.map +1 -1
- package/lib/mcp/tools/connectionTools.d.ts +4 -0
- package/lib/mcp/tools/connectionTools.js +242 -0
- package/lib/mcp/tools/connectionTools.js.map +1 -0
- package/lib/mcp/tools/defectTools.d.ts +1 -1
- package/lib/mcp/tools/defectTools.js +61 -50
- package/lib/mcp/tools/defectTools.js.map +1 -1
- package/lib/mcp/tools/descHelper.d.ts +5 -0
- package/lib/mcp/tools/descHelper.js +14 -0
- package/lib/mcp/tools/descHelper.js.map +1 -0
- package/lib/mcp/tools/hierarchyValidate.d.ts +1 -1
- package/lib/mcp/tools/hierarchyValidate.js +127 -42
- package/lib/mcp/tools/hierarchyValidate.js.map +1 -1
- package/lib/mcp/tools/nitroXTools.d.ts +23 -0
- package/lib/mcp/tools/nitroXTools.js +863 -0
- package/lib/mcp/tools/nitroXTools.js.map +1 -0
- package/lib/mcp/tools/pageObjectGenerate.js +150 -57
- package/lib/mcp/tools/pageObjectGenerate.js.map +1 -1
- package/lib/mcp/tools/pageObjectValidate.js +143 -46
- package/lib/mcp/tools/pageObjectValidate.js.map +1 -1
- package/lib/mcp/tools/projectInspect.js +79 -32
- package/lib/mcp/tools/projectInspect.js.map +1 -1
- package/lib/mcp/tools/projectValidateFromPath.js +185 -58
- package/lib/mcp/tools/projectValidateFromPath.js.map +1 -1
- package/lib/mcp/tools/propertiesTools.d.ts +2 -0
- package/lib/mcp/tools/propertiesTools.js +358 -78
- package/lib/mcp/tools/propertiesTools.js.map +1 -1
- package/lib/mcp/tools/qualityHubApiTools.d.ts +3 -0
- package/lib/mcp/tools/qualityHubApiTools.js +139 -0
- package/lib/mcp/tools/qualityHubApiTools.js.map +1 -0
- package/lib/mcp/tools/qualityHubTools.js +292 -72
- package/lib/mcp/tools/qualityHubTools.js.map +1 -1
- package/lib/mcp/tools/rcaTools.d.ts +3 -2
- package/lib/mcp/tools/rcaTools.js +194 -56
- package/lib/mcp/tools/rcaTools.js.map +1 -1
- package/lib/mcp/tools/sfSpawn.d.ts +25 -3
- package/lib/mcp/tools/sfSpawn.js +154 -6
- package/lib/mcp/tools/sfSpawn.js.map +1 -1
- package/lib/mcp/tools/testCaseGenerate.js +285 -78
- package/lib/mcp/tools/testCaseGenerate.js.map +1 -1
- package/lib/mcp/tools/testCaseStepTools.d.ts +4 -0
- package/lib/mcp/tools/testCaseStepTools.js +244 -0
- package/lib/mcp/tools/testCaseStepTools.js.map +1 -0
- package/lib/mcp/tools/testCaseValidate.d.ts +11 -0
- package/lib/mcp/tools/testCaseValidate.js +381 -46
- package/lib/mcp/tools/testCaseValidate.js.map +1 -1
- package/lib/mcp/tools/testPlanTools.d.ts +1 -0
- package/lib/mcp/tools/testPlanTools.js +316 -59
- package/lib/mcp/tools/testPlanTools.js.map +1 -1
- package/lib/mcp/tools/testPlanValidate.js +114 -23
- package/lib/mcp/tools/testPlanValidate.js.map +1 -1
- package/lib/mcp/tools/testSuiteValidate.js +130 -15
- package/lib/mcp/tools/testSuiteValidate.js.map +1 -1
- package/lib/mcp/update/updateChecker.d.ts +14 -0
- package/lib/mcp/update/updateChecker.js +228 -0
- package/lib/mcp/update/updateChecker.js.map +1 -0
- package/lib/mcp/utils/detailLevel.d.ts +9 -0
- package/lib/mcp/utils/detailLevel.js +20 -0
- package/lib/mcp/utils/detailLevel.js.map +1 -0
- package/lib/mcp/utils/fieldMask.d.ts +17 -0
- package/lib/mcp/utils/fieldMask.js +75 -0
- package/lib/mcp/utils/fieldMask.js.map +1 -0
- package/lib/mcp/utils/tokenMeta.d.ts +40 -0
- package/lib/mcp/utils/tokenMeta.js +90 -0
- package/lib/mcp/utils/tokenMeta.js.map +1 -0
- package/lib/mcp/utils/validationDiff.d.ts +57 -0
- package/lib/mcp/utils/validationDiff.js +191 -0
- package/lib/mcp/utils/validationDiff.js.map +1 -0
- package/lib/mcp/utils/validationScore.d.ts +15 -0
- package/lib/mcp/utils/validationScore.js +31 -0
- package/lib/mcp/utils/validationScore.js.map +1 -0
- package/lib/services/auth/credentials.d.ts +21 -0
- package/lib/services/auth/credentials.js +75 -0
- package/lib/services/auth/credentials.js.map +1 -0
- package/lib/services/auth/loginFlow.d.ts +68 -0
- package/lib/services/auth/loginFlow.js +216 -0
- package/lib/services/auth/loginFlow.js.map +1 -0
- package/lib/services/projectValidation.d.ts +5 -2
- package/lib/services/projectValidation.js +83 -31
- package/lib/services/projectValidation.js.map +1 -1
- package/lib/services/qualityHub/client.d.ts +161 -0
- package/lib/services/qualityHub/client.js +226 -0
- package/lib/services/qualityHub/client.js.map +1 -0
- package/messages/sf.provar.auth.clear.md +16 -0
- package/messages/sf.provar.auth.login.md +31 -0
- package/messages/sf.provar.auth.rotate.md +23 -0
- package/messages/sf.provar.auth.status.md +16 -0
- package/messages/sf.provar.mcp.start.md +83 -48
- package/oclif.manifest.json +325 -28
- package/package.json +35 -12
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
|
12
|
+
import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
|
|
13
|
+
import { makeError, makeRequestId } from '../schemas/common.js';
|
|
14
|
+
import { log } from '../logging/logger.js';
|
|
15
|
+
import { validateTestCase } from './testCaseValidate.js';
|
|
16
|
+
import { desc } from './descHelper.js';
|
|
17
|
+
// ── XML parse / build config ──────────────────────────────────────────────────
|
|
18
|
+
const PARSER_OPTIONS = {
|
|
19
|
+
ignoreAttributes: false,
|
|
20
|
+
attributeNamePrefix: '@_',
|
|
21
|
+
parseAttributeValue: false,
|
|
22
|
+
isArray: (tagName) => tagName === 'apiCall',
|
|
23
|
+
};
|
|
24
|
+
const BUILDER_OPTIONS = {
|
|
25
|
+
ignoreAttributes: false,
|
|
26
|
+
attributeNamePrefix: '@_',
|
|
27
|
+
format: true,
|
|
28
|
+
indentBy: ' ',
|
|
29
|
+
suppressEmptyNode: false,
|
|
30
|
+
};
|
|
31
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
32
|
+
function parseTestCaseXml(xmlContent) {
|
|
33
|
+
const parser = new XMLParser(PARSER_OPTIONS);
|
|
34
|
+
return parser.parse(xmlContent);
|
|
35
|
+
}
|
|
36
|
+
function buildTestCaseXml(parsed) {
|
|
37
|
+
const builder = new XMLBuilder(BUILDER_OPTIONS);
|
|
38
|
+
return '<?xml version="1.0" encoding="UTF-8"?>\n' + builder.build(parsed);
|
|
39
|
+
}
|
|
40
|
+
function getApiCalls(parsed) {
|
|
41
|
+
const tc = parsed['testCase'];
|
|
42
|
+
if (!tc || typeof tc !== 'object')
|
|
43
|
+
return null;
|
|
44
|
+
const steps = tc['steps'];
|
|
45
|
+
if (!steps || typeof steps !== 'object')
|
|
46
|
+
return null;
|
|
47
|
+
const calls = steps['apiCall'];
|
|
48
|
+
if (!Array.isArray(calls))
|
|
49
|
+
return null;
|
|
50
|
+
return calls;
|
|
51
|
+
}
|
|
52
|
+
function collectAllTestItemIds(parsed) {
|
|
53
|
+
const calls = getApiCalls(parsed);
|
|
54
|
+
if (!calls)
|
|
55
|
+
return [];
|
|
56
|
+
return calls.map((c) => c['@_testItemId']).filter((id) => typeof id === 'string');
|
|
57
|
+
}
|
|
58
|
+
function parseNewStep(stepXml) {
|
|
59
|
+
try {
|
|
60
|
+
const fragParser = new XMLParser(PARSER_OPTIONS);
|
|
61
|
+
const fragDoc = fragParser.parse(`<root>${stepXml}</root>`);
|
|
62
|
+
const rootEl = fragDoc['root'];
|
|
63
|
+
const callEl = rootEl?.['apiCall'];
|
|
64
|
+
if (!callEl)
|
|
65
|
+
return { error: 'step_xml must contain exactly one <apiCall> element' };
|
|
66
|
+
const calls = Array.isArray(callEl) ? callEl : [callEl];
|
|
67
|
+
if (calls.length !== 1)
|
|
68
|
+
return { error: 'step_xml must contain exactly one <apiCall> element' };
|
|
69
|
+
return { step: calls[0] };
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
return { error: e.message };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ── Tool registration ─────────────────────────────────────────────────────────
|
|
76
|
+
export function registerTestCaseStepEdit(server, config) {
|
|
77
|
+
server.registerTool('provar_testcase_step_edit', {
|
|
78
|
+
// PDX-484: carry the AMENDMENT-ONLY contract into the `title:` field.
|
|
79
|
+
// "Amend" mirrors the AMENDMENT-ONLY framing in the description body
|
|
80
|
+
// and "Existing" signals that the tool does not construct new test cases.
|
|
81
|
+
// Length: 29 chars — well within the chip-render comfort threshold.
|
|
82
|
+
title: 'Amend Existing Test Case Step',
|
|
83
|
+
description: desc([
|
|
84
|
+
// ── Usage contract (READ FIRST — PDX-482) ─────────────────────────────
|
|
85
|
+
// This tool AMENDS an existing validated test case. It is NOT for
|
|
86
|
+
// constructing a test case from scratch — building one step-by-step via
|
|
87
|
+
// repeated step_edit calls produces structurally invalid test cases
|
|
88
|
+
// (dropped scenarios, flat asserts, inconsistent step types — see PDX-479).
|
|
89
|
+
'AMENDMENT-ONLY tool: this is for amending an existing, already-validated Provar test case (single-step add, attribute fix, debug edit).',
|
|
90
|
+
'NOT for constructing a test case from scratch — for new test cases use provar_testcase_generate with the FULL steps[] tree in a single call.',
|
|
91
|
+
'Building a test case step-by-step via repeated step_edit calls after a steps=[] generate produces structurally invalid output (dropped scenarios, flat asserts, inconsistent step types).',
|
|
92
|
+
// ── Mechanics (unchanged below) ───────────────────────────────────────
|
|
93
|
+
'Add or remove a single step (apiCall) in a Provar XML test case file.',
|
|
94
|
+
'Uses write-to-temp-then-rename to minimise partial-write risk.',
|
|
95
|
+
'Prerequisites: the test case must exist and be valid XML.',
|
|
96
|
+
'For mode=remove: supply test_item_id of the step to remove.',
|
|
97
|
+
'For mode=add: supply test_item_id of the anchor step, position (before|after, default after),',
|
|
98
|
+
'and step_xml (the <apiCall ...>...</apiCall> XML fragment for the new step; must contain exactly one <apiCall>).',
|
|
99
|
+
'A backup is written to <test_case_path>.bak before any mutation and restored automatically if',
|
|
100
|
+
'the post-edit validation fails.',
|
|
101
|
+
'Returns STEP_NOT_FOUND (with all_test_item_ids list) when the target step is absent.',
|
|
102
|
+
'Returns INVALID_STEP_XML when step_xml cannot be parsed or contains ≠1 <apiCall> elements.',
|
|
103
|
+
'Returns INVALID_XML_AFTER_EDIT (backup restored) when the mutated file fails validation.',
|
|
104
|
+
'Grounding for step_xml: call provar_qualityhub_examples_retrieve for corpus examples of the step type you need; if the response has count: 0 with a warning field, fall back: read the provar://docs/step-reference MCP resource.',
|
|
105
|
+
].join(' '), 'AMENDMENT-ONLY: add or remove a single apiCall step in an existing Provar test case (not for constructing new ones).'),
|
|
106
|
+
inputSchema: {
|
|
107
|
+
test_case_path: z
|
|
108
|
+
.string()
|
|
109
|
+
.describe(desc('Absolute path to the .testcase XML file; must be within --allowed-paths', 'string, absolute path to .testcase file')),
|
|
110
|
+
mode: z
|
|
111
|
+
.enum(['remove', 'add'])
|
|
112
|
+
.describe(desc('"remove" to delete a step; "add" to insert a new step', 'enum remove|add')),
|
|
113
|
+
test_item_id: z
|
|
114
|
+
.string()
|
|
115
|
+
.describe(desc('For mode=remove: testItemId of the step to delete. For mode=add: testItemId of the anchor step.', 'string, testItemId of target or anchor step')),
|
|
116
|
+
position: z
|
|
117
|
+
.enum(['before', 'after'])
|
|
118
|
+
.optional()
|
|
119
|
+
.default('after')
|
|
120
|
+
.describe(desc('Where to insert relative to the anchor step (mode=add only; default: after)', 'enum before|after; default after')),
|
|
121
|
+
step_xml: z
|
|
122
|
+
.string()
|
|
123
|
+
.optional()
|
|
124
|
+
.describe(desc('The <apiCall ...>...</apiCall> XML fragment for the new step (mode=add only). Must be well-formed XML.', 'string, optional; <apiCall> XML fragment for new step')),
|
|
125
|
+
validate_after_edit: z
|
|
126
|
+
.boolean()
|
|
127
|
+
.optional()
|
|
128
|
+
.default(true)
|
|
129
|
+
.describe(desc('Run provar_testcase_validate after the mutation; restores backup on failure (default: true)', 'bool, optional; default true, validate after edit')),
|
|
130
|
+
},
|
|
131
|
+
}, (input) => {
|
|
132
|
+
const requestId = makeRequestId();
|
|
133
|
+
log('info', 'provar_testcase_step_edit', { requestId, mode: input.mode, test_item_id: input.test_item_id });
|
|
134
|
+
try {
|
|
135
|
+
const resolvedPath = path.resolve(input.test_case_path);
|
|
136
|
+
const bakPath = resolvedPath + '.bak';
|
|
137
|
+
// Path policy — validate both the target file and its backup path
|
|
138
|
+
assertPathAllowed(resolvedPath, config.allowedPaths);
|
|
139
|
+
assertPathAllowed(bakPath, config.allowedPaths);
|
|
140
|
+
// Validate step_xml up-front before touching the file
|
|
141
|
+
let newStep = null;
|
|
142
|
+
if (input.mode === 'add') {
|
|
143
|
+
if (!input.step_xml) {
|
|
144
|
+
const err = makeError('MISSING_INPUT', 'step_xml is required for mode=add', requestId);
|
|
145
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
146
|
+
}
|
|
147
|
+
const parsed_step = parseNewStep(input.step_xml);
|
|
148
|
+
if ('error' in parsed_step) {
|
|
149
|
+
const err = makeError('INVALID_STEP_XML', `step_xml parse error: ${parsed_step.error}`, requestId);
|
|
150
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
151
|
+
}
|
|
152
|
+
newStep = parsed_step.step;
|
|
153
|
+
}
|
|
154
|
+
// Read the test case file
|
|
155
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
156
|
+
const err = makeError('FILE_NOT_FOUND', `Test case not found: ${resolvedPath}`, requestId);
|
|
157
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
158
|
+
}
|
|
159
|
+
const original = fs.readFileSync(resolvedPath, 'utf-8');
|
|
160
|
+
// Parse
|
|
161
|
+
let parsed;
|
|
162
|
+
try {
|
|
163
|
+
parsed = parseTestCaseXml(original);
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
const err = makeError('INVALID_XML', `Cannot parse test case: ${e.message}`, requestId);
|
|
167
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
168
|
+
}
|
|
169
|
+
const apiCalls = getApiCalls(parsed);
|
|
170
|
+
if (!apiCalls) {
|
|
171
|
+
const err = makeError('INVALID_XML', 'Test case XML does not contain a <testCase><steps><apiCall> structure', requestId);
|
|
172
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
173
|
+
}
|
|
174
|
+
// Find target step
|
|
175
|
+
const targetIndex = apiCalls.findIndex((c) => String(c['@_testItemId']) === input.test_item_id);
|
|
176
|
+
if (targetIndex === -1) {
|
|
177
|
+
const allIds = collectAllTestItemIds(parsed);
|
|
178
|
+
const err = makeError('STEP_NOT_FOUND', `Step with testItemId "${input.test_item_id}" not found in ${resolvedPath}`, requestId, false, { all_test_item_ids: allIds });
|
|
179
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
180
|
+
}
|
|
181
|
+
// Mutate the parsed tree
|
|
182
|
+
if (input.mode === 'remove') {
|
|
183
|
+
apiCalls.splice(targetIndex, 1);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// mode=add
|
|
187
|
+
const insertAt = input.position === 'before' ? targetIndex : targetIndex + 1;
|
|
188
|
+
apiCalls.splice(insertAt, 0, newStep);
|
|
189
|
+
}
|
|
190
|
+
// Rebuild XML
|
|
191
|
+
const mutatedXml = buildTestCaseXml(parsed);
|
|
192
|
+
// Write backup, then write mutated file via temp→rename to minimise partial-write risk
|
|
193
|
+
const tmpPath = resolvedPath + '.tmp';
|
|
194
|
+
fs.writeFileSync(bakPath, original, 'utf-8');
|
|
195
|
+
fs.writeFileSync(tmpPath, mutatedXml, 'utf-8');
|
|
196
|
+
fs.renameSync(tmpPath, resolvedPath);
|
|
197
|
+
// Validate if requested
|
|
198
|
+
let validation;
|
|
199
|
+
if (input.validate_after_edit) {
|
|
200
|
+
try {
|
|
201
|
+
validation = validateTestCase(mutatedXml, path.basename(resolvedPath, '.testcase'));
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// treat thrown validation errors as failures
|
|
205
|
+
validation = null;
|
|
206
|
+
}
|
|
207
|
+
if (!validation || !validation.is_valid) {
|
|
208
|
+
// Restore from backup
|
|
209
|
+
fs.writeFileSync(resolvedPath, original, 'utf-8');
|
|
210
|
+
fs.unlinkSync(bakPath);
|
|
211
|
+
const err = makeError('INVALID_XML_AFTER_EDIT', `Validation failed after ${input.mode}; original file restored from backup`, requestId, false, { validation_issues: validation?.issues ?? ['Validation threw an unexpected error'] });
|
|
212
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Success — delete backup
|
|
216
|
+
try {
|
|
217
|
+
fs.unlinkSync(bakPath);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// non-fatal
|
|
221
|
+
}
|
|
222
|
+
const result = {
|
|
223
|
+
requestId,
|
|
224
|
+
success: true,
|
|
225
|
+
test_item_id: input.test_item_id,
|
|
226
|
+
mode: input.mode,
|
|
227
|
+
...(input.validate_after_edit && validation ? { validation } : {}),
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
const error = err;
|
|
235
|
+
const errResult = makeError(error instanceof PathPolicyError ? error.code : 'STEP_EDIT_ERROR', error.message, requestId);
|
|
236
|
+
log('error', 'provar_testcase_step_edit failed', { requestId, error: error.message });
|
|
237
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
export function registerAllTestCaseStepTools(server, config) {
|
|
242
|
+
registerTestCaseStepEdit(server, config);
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=testCaseStepTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testCaseStepTools.js","sourceRoot":"","sources":["../../../src/mcp/tools/testCaseStepTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,17 @@ export interface TestCaseValidationResult {
|
|
|
15
15
|
/** Violations from the Best Practices Engine (same rules as the Quality Hub API). */
|
|
16
16
|
best_practices_violations?: Array<import('./bestPracticesEngine.js').BPViolation>;
|
|
17
17
|
best_practices_rules_evaluated?: number;
|
|
18
|
+
/** Which ruleset produced this result. Always present. */
|
|
19
|
+
validation_source: 'quality_hub' | 'local' | 'local_fallback';
|
|
20
|
+
/** Set when falling back to local — explains why and what to do. */
|
|
21
|
+
validation_warning?: string;
|
|
18
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Reads a test case file from disk, validates it, and returns the result.
|
|
25
|
+
* Used by Wave 2 (testCaseGenerate) and Wave 3 (testCaseStepEdit) to validate
|
|
26
|
+
* after mutations without spawning a separate MCP tool call.
|
|
27
|
+
* Throws on path-policy violation or missing file.
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateTestCaseXml(filePath: string, config: ServerConfig): TestCaseValidationResult;
|
|
19
30
|
/** Pure function — exported for unit testing */
|
|
20
31
|
export declare function validateTestCase(xmlContent: string, testName?: string): TestCaseValidationResult;
|