@provartesting/provardx-cli 1.5.0-beta.1 → 1.5.0-beta.10

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.
Files changed (78) hide show
  1. package/README.md +137 -13
  2. package/lib/commands/provar/auth/clear.d.ts +7 -0
  3. package/lib/commands/provar/auth/clear.js +36 -0
  4. package/lib/commands/provar/auth/clear.js.map +1 -0
  5. package/lib/commands/provar/auth/login.d.ts +10 -0
  6. package/lib/commands/provar/auth/login.js +90 -0
  7. package/lib/commands/provar/auth/login.js.map +1 -0
  8. package/lib/commands/provar/auth/rotate.d.ts +7 -0
  9. package/lib/commands/provar/auth/rotate.js +42 -0
  10. package/lib/commands/provar/auth/rotate.js.map +1 -0
  11. package/lib/commands/provar/auth/status.d.ts +7 -0
  12. package/lib/commands/provar/auth/status.js +107 -0
  13. package/lib/commands/provar/auth/status.js.map +1 -0
  14. package/lib/mcp/docs/PROVAR_TEST_STEP_REFERENCE.md +1430 -0
  15. package/lib/mcp/licensing/licenseValidator.d.ts +3 -3
  16. package/lib/mcp/licensing/licenseValidator.js +4 -4
  17. package/lib/mcp/prompts/index.d.ts +2 -0
  18. package/lib/mcp/prompts/index.js +19 -0
  19. package/lib/mcp/prompts/index.js.map +1 -0
  20. package/lib/mcp/prompts/loopPrompts.d.ts +6 -0
  21. package/lib/mcp/prompts/loopPrompts.js +435 -0
  22. package/lib/mcp/prompts/loopPrompts.js.map +1 -0
  23. package/lib/mcp/prompts/migrationPrompts.d.ts +4 -0
  24. package/lib/mcp/prompts/migrationPrompts.js +207 -0
  25. package/lib/mcp/prompts/migrationPrompts.js.map +1 -0
  26. package/lib/mcp/rules/provar_best_practices_rules.json +256 -544
  27. package/lib/mcp/server.js +45 -1
  28. package/lib/mcp/server.js.map +1 -1
  29. package/lib/mcp/tools/antTools.d.ts +15 -0
  30. package/lib/mcp/tools/antTools.js +204 -50
  31. package/lib/mcp/tools/antTools.js.map +1 -1
  32. package/lib/mcp/tools/automationTools.d.ts +36 -3
  33. package/lib/mcp/tools/automationTools.js +335 -42
  34. package/lib/mcp/tools/automationTools.js.map +1 -1
  35. package/lib/mcp/tools/bestPracticesEngine.js +161 -23
  36. package/lib/mcp/tools/bestPracticesEngine.js.map +1 -1
  37. package/lib/mcp/tools/connectionTools.d.ts +4 -0
  38. package/lib/mcp/tools/connectionTools.js +168 -0
  39. package/lib/mcp/tools/connectionTools.js.map +1 -0
  40. package/lib/mcp/tools/nitroXTools.d.ts +22 -0
  41. package/lib/mcp/tools/nitroXTools.js +750 -0
  42. package/lib/mcp/tools/nitroXTools.js.map +1 -0
  43. package/lib/mcp/tools/pageObjectGenerate.js +103 -35
  44. package/lib/mcp/tools/pageObjectGenerate.js.map +1 -1
  45. package/lib/mcp/tools/propertiesTools.d.ts +2 -0
  46. package/lib/mcp/tools/propertiesTools.js +277 -39
  47. package/lib/mcp/tools/propertiesTools.js.map +1 -1
  48. package/lib/mcp/tools/qualityHubApiTools.d.ts +3 -0
  49. package/lib/mcp/tools/qualityHubApiTools.js +134 -0
  50. package/lib/mcp/tools/qualityHubApiTools.js.map +1 -0
  51. package/lib/mcp/tools/qualityHubTools.js +127 -19
  52. package/lib/mcp/tools/qualityHubTools.js.map +1 -1
  53. package/lib/mcp/tools/rcaTools.d.ts +3 -2
  54. package/lib/mcp/tools/rcaTools.js +145 -20
  55. package/lib/mcp/tools/rcaTools.js.map +1 -1
  56. package/lib/mcp/tools/testCaseGenerate.js +88 -59
  57. package/lib/mcp/tools/testCaseGenerate.js.map +1 -1
  58. package/lib/mcp/tools/testCaseStepTools.d.ts +4 -0
  59. package/lib/mcp/tools/testCaseStepTools.js +221 -0
  60. package/lib/mcp/tools/testCaseStepTools.js.map +1 -0
  61. package/lib/mcp/tools/testCaseValidate.d.ts +11 -0
  62. package/lib/mcp/tools/testCaseValidate.js +146 -19
  63. package/lib/mcp/tools/testCaseValidate.js.map +1 -1
  64. package/lib/services/auth/credentials.d.ts +21 -0
  65. package/lib/services/auth/credentials.js +75 -0
  66. package/lib/services/auth/credentials.js.map +1 -0
  67. package/lib/services/auth/loginFlow.d.ts +68 -0
  68. package/lib/services/auth/loginFlow.js +216 -0
  69. package/lib/services/auth/loginFlow.js.map +1 -0
  70. package/lib/services/qualityHub/client.d.ts +161 -0
  71. package/lib/services/qualityHub/client.js +226 -0
  72. package/lib/services/qualityHub/client.js.map +1 -0
  73. package/messages/sf.provar.auth.clear.md +16 -0
  74. package/messages/sf.provar.auth.login.md +31 -0
  75. package/messages/sf.provar.auth.rotate.md +23 -0
  76. package/messages/sf.provar.auth.status.md +16 -0
  77. package/oclif.manifest.json +214 -1
  78. package/package.json +8 -4
@@ -1 +1 @@
1
- {"version":3,"file":"testCaseGenerate.js","sourceRoot":"","sources":["../../../src/mcp/tools/testCaseGenerate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testCaseGenerate.js","sourceRoot":"","sources":["../../../src/mcp/tools/testCaseGenerate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ServerConfig } from '../server.js';
3
+ export declare function registerTestCaseStepEdit(server: McpServer, config: ServerConfig): void;
4
+ export declare function registerAllTestCaseStepTools(server: McpServer, config: ServerConfig): void;
@@ -0,0 +1,221 @@
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
+ // ── XML parse / build config ──────────────────────────────────────────────────
17
+ const PARSER_OPTIONS = {
18
+ ignoreAttributes: false,
19
+ attributeNamePrefix: '@_',
20
+ parseAttributeValue: false,
21
+ isArray: (tagName) => tagName === 'apiCall',
22
+ };
23
+ const BUILDER_OPTIONS = {
24
+ ignoreAttributes: false,
25
+ attributeNamePrefix: '@_',
26
+ format: true,
27
+ indentBy: ' ',
28
+ suppressEmptyNode: false,
29
+ };
30
+ // ── Helpers ───────────────────────────────────────────────────────────────────
31
+ function parseTestCaseXml(xmlContent) {
32
+ const parser = new XMLParser(PARSER_OPTIONS);
33
+ return parser.parse(xmlContent);
34
+ }
35
+ function buildTestCaseXml(parsed) {
36
+ const builder = new XMLBuilder(BUILDER_OPTIONS);
37
+ return '<?xml version="1.0" encoding="UTF-8"?>\n' + builder.build(parsed);
38
+ }
39
+ function getApiCalls(parsed) {
40
+ const tc = parsed['testCase'];
41
+ if (!tc || typeof tc !== 'object')
42
+ return null;
43
+ const steps = tc['steps'];
44
+ if (!steps || typeof steps !== 'object')
45
+ return null;
46
+ const calls = steps['apiCall'];
47
+ if (!Array.isArray(calls))
48
+ return null;
49
+ return calls;
50
+ }
51
+ function collectAllTestItemIds(parsed) {
52
+ const calls = getApiCalls(parsed);
53
+ if (!calls)
54
+ return [];
55
+ return calls.map((c) => c['@_testItemId']).filter((id) => typeof id === 'string');
56
+ }
57
+ function parseNewStep(stepXml) {
58
+ try {
59
+ const fragParser = new XMLParser(PARSER_OPTIONS);
60
+ const fragDoc = fragParser.parse(`<root>${stepXml}</root>`);
61
+ const rootEl = fragDoc['root'];
62
+ const callEl = rootEl?.['apiCall'];
63
+ if (!callEl)
64
+ return { error: 'step_xml must contain exactly one <apiCall> element' };
65
+ const calls = Array.isArray(callEl) ? callEl : [callEl];
66
+ if (calls.length !== 1)
67
+ return { error: 'step_xml must contain exactly one <apiCall> element' };
68
+ return { step: calls[0] };
69
+ }
70
+ catch (e) {
71
+ return { error: e.message };
72
+ }
73
+ }
74
+ // ── Tool registration ─────────────────────────────────────────────────────────
75
+ export function registerTestCaseStepEdit(server, config) {
76
+ server.tool('provar.testcase.step.edit', [
77
+ 'Add or remove a single step (apiCall) in a Provar XML test case file.',
78
+ 'Uses write-to-temp-then-rename to minimise partial-write risk.',
79
+ 'Prerequisites: the test case must exist and be valid XML.',
80
+ 'For mode=remove: supply test_item_id of the step to remove.',
81
+ 'For mode=add: supply test_item_id of the anchor step, position (before|after, default after),',
82
+ 'and step_xml (the <apiCall ...>...</apiCall> XML fragment for the new step; must contain exactly one <apiCall>).',
83
+ 'A backup is written to <test_case_path>.bak before any mutation and restored automatically if',
84
+ 'the post-edit validation fails.',
85
+ 'Returns STEP_NOT_FOUND (with all_test_item_ids list) when the target step is absent.',
86
+ 'Returns INVALID_STEP_XML when step_xml cannot be parsed or contains ≠1 <apiCall> elements.',
87
+ 'Returns INVALID_XML_AFTER_EDIT (backup restored) when the mutated file fails validation.',
88
+ ].join(' '), {
89
+ test_case_path: z.string().describe('Absolute path to the .testcase XML file; must be within --allowed-paths'),
90
+ mode: z.enum(['remove', 'add']).describe('"remove" to delete a step; "add" to insert a new step'),
91
+ test_item_id: z
92
+ .string()
93
+ .describe('For mode=remove: testItemId of the step to delete. For mode=add: testItemId of the anchor step.'),
94
+ position: z
95
+ .enum(['before', 'after'])
96
+ .optional()
97
+ .default('after')
98
+ .describe('Where to insert relative to the anchor step (mode=add only; default: after)'),
99
+ step_xml: z
100
+ .string()
101
+ .optional()
102
+ .describe('The <apiCall ...>...</apiCall> XML fragment for the new step (mode=add only). Must be well-formed XML.'),
103
+ validate_after_edit: z
104
+ .boolean()
105
+ .optional()
106
+ .default(true)
107
+ .describe('Run provar.testcase.validate after the mutation; restores backup on failure (default: true)'),
108
+ }, (input) => {
109
+ const requestId = makeRequestId();
110
+ log('info', 'provar.testcase.step.edit', { requestId, mode: input.mode, test_item_id: input.test_item_id });
111
+ try {
112
+ const resolvedPath = path.resolve(input.test_case_path);
113
+ const bakPath = resolvedPath + '.bak';
114
+ // Path policy — validate both the target file and its backup path
115
+ assertPathAllowed(resolvedPath, config.allowedPaths);
116
+ assertPathAllowed(bakPath, config.allowedPaths);
117
+ // Validate step_xml up-front before touching the file
118
+ let newStep = null;
119
+ if (input.mode === 'add') {
120
+ if (!input.step_xml) {
121
+ const err = makeError('MISSING_INPUT', 'step_xml is required for mode=add', requestId);
122
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
123
+ }
124
+ const parsed_step = parseNewStep(input.step_xml);
125
+ if ('error' in parsed_step) {
126
+ const err = makeError('INVALID_STEP_XML', `step_xml parse error: ${parsed_step.error}`, requestId);
127
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
128
+ }
129
+ newStep = parsed_step.step;
130
+ }
131
+ // Read the test case file
132
+ if (!fs.existsSync(resolvedPath)) {
133
+ const err = makeError('FILE_NOT_FOUND', `Test case not found: ${resolvedPath}`, requestId);
134
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
135
+ }
136
+ const original = fs.readFileSync(resolvedPath, 'utf-8');
137
+ // Parse
138
+ let parsed;
139
+ try {
140
+ parsed = parseTestCaseXml(original);
141
+ }
142
+ catch (e) {
143
+ const err = makeError('INVALID_XML', `Cannot parse test case: ${e.message}`, requestId);
144
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
145
+ }
146
+ const apiCalls = getApiCalls(parsed);
147
+ if (!apiCalls) {
148
+ const err = makeError('INVALID_XML', 'Test case XML does not contain a <testCase><steps><apiCall> structure', requestId);
149
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
150
+ }
151
+ // Find target step
152
+ const targetIndex = apiCalls.findIndex((c) => String(c['@_testItemId']) === input.test_item_id);
153
+ if (targetIndex === -1) {
154
+ const allIds = collectAllTestItemIds(parsed);
155
+ const err = makeError('STEP_NOT_FOUND', `Step with testItemId "${input.test_item_id}" not found in ${resolvedPath}`, requestId, false, { all_test_item_ids: allIds });
156
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
157
+ }
158
+ // Mutate the parsed tree
159
+ if (input.mode === 'remove') {
160
+ apiCalls.splice(targetIndex, 1);
161
+ }
162
+ else {
163
+ // mode=add
164
+ const insertAt = input.position === 'before' ? targetIndex : targetIndex + 1;
165
+ apiCalls.splice(insertAt, 0, newStep);
166
+ }
167
+ // Rebuild XML
168
+ const mutatedXml = buildTestCaseXml(parsed);
169
+ // Write backup, then write mutated file via temp→rename to minimise partial-write risk
170
+ const tmpPath = resolvedPath + '.tmp';
171
+ fs.writeFileSync(bakPath, original, 'utf-8');
172
+ fs.writeFileSync(tmpPath, mutatedXml, 'utf-8');
173
+ fs.renameSync(tmpPath, resolvedPath);
174
+ // Validate if requested
175
+ let validation;
176
+ if (input.validate_after_edit) {
177
+ try {
178
+ validation = validateTestCase(mutatedXml, path.basename(resolvedPath, '.testcase'));
179
+ }
180
+ catch {
181
+ // treat thrown validation errors as failures
182
+ validation = null;
183
+ }
184
+ if (!validation || !validation.is_valid) {
185
+ // Restore from backup
186
+ fs.writeFileSync(resolvedPath, original, 'utf-8');
187
+ fs.unlinkSync(bakPath);
188
+ 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'] });
189
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
190
+ }
191
+ }
192
+ // Success — delete backup
193
+ try {
194
+ fs.unlinkSync(bakPath);
195
+ }
196
+ catch {
197
+ // non-fatal
198
+ }
199
+ const result = {
200
+ requestId,
201
+ success: true,
202
+ test_item_id: input.test_item_id,
203
+ mode: input.mode,
204
+ ...(input.validate_after_edit && validation ? { validation } : {}),
205
+ };
206
+ return {
207
+ content: [{ type: 'text', text: JSON.stringify(result) }],
208
+ };
209
+ }
210
+ catch (err) {
211
+ const error = err;
212
+ const errResult = makeError(error instanceof PathPolicyError ? error.code : 'STEP_EDIT_ERROR', error.message, requestId);
213
+ log('error', 'provar.testcase.step.edit failed', { requestId, error: error.message });
214
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
215
+ }
216
+ });
217
+ }
218
+ export function registerAllTestCaseStepTools(server, config) {
219
+ registerTestCaseStepEdit(server, config);
220
+ }
221
+ //# 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;
@@ -12,13 +12,24 @@ import { XMLParser } from 'fast-xml-parser';
12
12
  import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
13
13
  import { makeError, makeRequestId } from '../schemas/common.js';
14
14
  import { log } from '../logging/logger.js';
15
+ import { resolveApiKey } from '../../services/auth/credentials.js';
16
+ import { qualityHubClient, getQualityHubBaseUrl, QualityHubAuthError, QualityHubRateLimitError, REQUEST_ACCESS_URL, } from '../../services/qualityHub/client.js';
15
17
  import { runBestPractices } from './bestPracticesEngine.js';
18
+ const ONBOARDING_MESSAGE = 'Quality Hub validation unavailable — running local validation only (structural rules, no quality scoring).\n' +
19
+ 'To enable Quality Hub (170 rules): run sf provar auth login\n' +
20
+ 'For CI/CD: set the PROVAR_API_KEY environment variable.\n' +
21
+ `No account? Request access at: ${REQUEST_ACCESS_URL}`;
22
+ const AUTH_WARNING = 'Quality Hub API key is invalid or expired. Running local validation only.\n' +
23
+ `Run sf provar auth login to get a new key, or request access at: ${REQUEST_ACCESS_URL}`;
24
+ const RATE_LIMIT_WARNING = 'Quality Hub API rate limit reached. Running local validation only. Try again shortly.';
25
+ const UNREACHABLE_WARNING = 'Quality Hub API unreachable. Running local validation only (structural rules, no quality scoring).\n' +
26
+ 'For CI/CD: set PROVAR_QUALITY_HUB_URL and PROVAR_API_KEY environment variables.';
16
27
  export function registerTestCaseValidate(server, config) {
17
- server.tool('provar.testcase.validate', 'Validate a Provar XML test case for structural correctness and quality. Checks XML declaration, root element, required attributes (guid UUID v4, testItemId integer), <steps> presence, and applies best-practice rules (same ruleset and scoring as the Quality Hub batch validation API). Returns validity_score (schema compliance) and quality_score (best practices, 0–100).', {
28
+ server.tool('provar.testcase.validate', 'Validate a Provar XML test case for structural correctness and quality. Checks XML declaration, root element, required attributes (guid UUID v4, testItemId integer), <steps> presence, and applies best-practice rules. When a Provar API key is configured (via sf provar auth login or PROVAR_API_KEY env var), calls the Quality Hub API for full 170-rule scoring. Falls back to local validation if no key is set or the API is unavailable. Returns validity_score (schema compliance), quality_score (best practices, 0–100), and validation_source indicating which ruleset was applied.', {
18
29
  content: z.string().optional().describe('XML content to validate directly (alias: xml)'),
19
30
  xml: z.string().optional().describe('XML content to validate — API-compatible alias for content'),
20
31
  file_path: z.string().optional().describe('Path to .xml test case file'),
21
- }, ({ content, xml, file_path }) => {
32
+ }, async ({ content, xml, file_path }) => {
22
33
  const requestId = makeRequestId();
23
34
  log('info', 'provar.testcase.validate', { requestId, has_content: !!(content ?? xml), file_path });
24
35
  try {
@@ -37,8 +48,62 @@ export function registerTestCaseValidate(server, config) {
37
48
  const err = makeError('MISSING_INPUT', 'Provide either content or file_path.', requestId);
38
49
  return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
39
50
  }
40
- const validation = validateTestCase(source);
41
- const result = { requestId, ...validation };
51
+ const apiKey = resolveApiKey();
52
+ if (apiKey) {
53
+ const baseUrl = getQualityHubBaseUrl();
54
+ try {
55
+ const apiResult = await qualityHubClient.validateTestCaseViaApi(source, apiKey, baseUrl);
56
+ const localMeta = validateTestCase(source);
57
+ const result = {
58
+ requestId,
59
+ ...apiResult,
60
+ step_count: localMeta.step_count,
61
+ error_count: apiResult.issues.filter((i) => i.severity === 'ERROR').length,
62
+ warning_count: apiResult.issues.filter((i) => i.severity === 'WARNING').length,
63
+ test_case_id: localMeta.test_case_id,
64
+ test_case_name: localMeta.test_case_name,
65
+ validation_source: 'quality_hub',
66
+ };
67
+ log('info', 'provar.testcase.validate: quality_hub', { requestId });
68
+ return {
69
+ content: [{ type: 'text', text: JSON.stringify(result) }],
70
+ structuredContent: result,
71
+ };
72
+ }
73
+ catch (apiErr) {
74
+ // API failed — determine the warning and fall through to local validation
75
+ let warning;
76
+ if (apiErr instanceof QualityHubAuthError) {
77
+ warning = AUTH_WARNING;
78
+ log('warn', 'provar.testcase.validate: auth error, falling back', { requestId });
79
+ }
80
+ else if (apiErr instanceof QualityHubRateLimitError) {
81
+ warning = RATE_LIMIT_WARNING;
82
+ log('warn', 'provar.testcase.validate: rate limited, falling back', { requestId });
83
+ }
84
+ else {
85
+ warning = UNREACHABLE_WARNING;
86
+ log('warn', 'provar.testcase.validate: api unreachable, falling back', { requestId });
87
+ }
88
+ const localResult = {
89
+ requestId,
90
+ ...validateTestCase(source),
91
+ validation_source: 'local_fallback',
92
+ validation_warning: warning,
93
+ };
94
+ return {
95
+ content: [{ type: 'text', text: JSON.stringify(localResult) }],
96
+ structuredContent: localResult,
97
+ };
98
+ }
99
+ }
100
+ // No API key configured — run local validation with onboarding message
101
+ const result = {
102
+ requestId,
103
+ ...validateTestCase(source),
104
+ validation_source: 'local',
105
+ validation_warning: ONBOARDING_MESSAGE,
106
+ };
42
107
  return {
43
108
  content: [{ type: 'text', text: JSON.stringify(result) }],
44
109
  structuredContent: result,
@@ -54,13 +119,28 @@ export function registerTestCaseValidate(server, config) {
54
119
  }
55
120
  // ── Validator (ported from quality-hub-agents/lambda/src/validator/handler.py) ──
56
121
  const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
122
+ /**
123
+ * Reads a test case file from disk, validates it, and returns the result.
124
+ * Used by Wave 2 (testCaseGenerate) and Wave 3 (testCaseStepEdit) to validate
125
+ * after mutations without spawning a separate MCP tool call.
126
+ * Throws on path-policy violation or missing file.
127
+ */
128
+ export function validateTestCaseXml(filePath, config) {
129
+ assertPathAllowed(filePath, config.allowedPaths);
130
+ const resolved = path.resolve(filePath);
131
+ if (!fs.existsSync(resolved)) {
132
+ throw Object.assign(new Error(`File not found: ${resolved}`), { code: 'TESTCASE_FILE_NOT_FOUND' });
133
+ }
134
+ return validateTestCase(fs.readFileSync(resolved, 'utf-8'));
135
+ }
57
136
  /** Pure function — exported for unit testing */
58
137
  export function validateTestCase(xmlContent, testName) {
59
138
  const issues = [];
60
139
  // TC_001: XML declaration
61
140
  if (!xmlContent.trimStart().startsWith('<?xml')) {
62
141
  issues.push({
63
- rule_id: 'TC_001', severity: 'ERROR',
142
+ rule_id: 'TC_001',
143
+ severity: 'ERROR',
64
144
  message: 'Missing XML declaration. File must start with <?xml version="1.0" encoding="UTF-8"?>.',
65
145
  applies_to: 'document',
66
146
  suggestion: 'Add XML declaration as the first line.',
@@ -79,7 +159,8 @@ export function validateTestCase(xmlContent, testName) {
79
159
  catch (e) {
80
160
  const parseError = e;
81
161
  issues.push({
82
- rule_id: 'TC_002', severity: 'ERROR',
162
+ rule_id: 'TC_002',
163
+ severity: 'ERROR',
83
164
  message: `XML parse error: ${parseError.message}`,
84
165
  applies_to: 'document',
85
166
  suggestion: 'Fix XML syntax errors.',
@@ -89,7 +170,8 @@ export function validateTestCase(xmlContent, testName) {
89
170
  // TC_003: Root element
90
171
  if (!('testCase' in parsed)) {
91
172
  issues.push({
92
- rule_id: 'TC_003', severity: 'ERROR',
173
+ rule_id: 'TC_003',
174
+ severity: 'ERROR',
93
175
  message: 'Root element must be <testCase>.',
94
176
  applies_to: 'document',
95
177
  suggestion: 'Ensure root element is <testCase>.',
@@ -105,7 +187,8 @@ export function validateTestCase(xmlContent, testName) {
105
187
  const tcGuid = tc['@_guid'];
106
188
  if (!tcId) {
107
189
  issues.push({
108
- rule_id: 'TC_010', severity: 'ERROR',
190
+ rule_id: 'TC_010',
191
+ severity: 'ERROR',
109
192
  message: 'testCase missing required id attribute.',
110
193
  applies_to: 'testCase',
111
194
  suggestion: 'Add id attribute to testCase element.',
@@ -113,7 +196,8 @@ export function validateTestCase(xmlContent, testName) {
113
196
  }
114
197
  if (!tcGuid) {
115
198
  issues.push({
116
- rule_id: 'TC_011', severity: 'ERROR',
199
+ rule_id: 'TC_011',
200
+ severity: 'ERROR',
117
201
  message: 'testCase missing required guid attribute.',
118
202
  applies_to: 'testCase',
119
203
  suggestion: 'Add guid attribute (UUID v4) to testCase element.',
@@ -121,10 +205,11 @@ export function validateTestCase(xmlContent, testName) {
121
205
  }
122
206
  else if (!UUID_V4_RE.test(tcGuid)) {
123
207
  issues.push({
124
- rule_id: 'TC_012', severity: 'ERROR',
208
+ rule_id: 'TC_012',
209
+ severity: 'ERROR',
125
210
  message: `testCase guid "${tcGuid}" is not a valid UUID v4.`,
126
211
  applies_to: 'testCase',
127
- suggestion: 'Generate a proper UUID v4 for the guid attribute.',
212
+ suggestion: 'Replace with a valid UUID v4 e.g. crypto.randomUUID(). The 4th segment must begin with 8, 9, a, or b.',
128
213
  });
129
214
  }
130
215
  // TC_013 (registryId) is intentionally not checked here — registryId is a
@@ -134,13 +219,24 @@ export function validateTestCase(xmlContent, testName) {
134
219
  // TC_020: <steps> element
135
220
  if (!('steps' in tc)) {
136
221
  issues.push({
137
- rule_id: 'TC_020', severity: 'ERROR',
222
+ rule_id: 'TC_020',
223
+ severity: 'ERROR',
138
224
  message: 'testCase missing <steps> element.',
139
225
  applies_to: 'testCase',
140
226
  suggestion: 'Wrap all step elements in a <steps> element.',
141
227
  });
142
228
  return finalize(issues, tcId, tcName, 0, xmlContent, testName);
143
229
  }
230
+ // DATA-001: <dataTable> binding is silently ignored in standalone CLI execution
231
+ if ('dataTable' in tc && tc['dataTable'] != null) {
232
+ issues.push({
233
+ rule_id: 'DATA-001',
234
+ severity: 'WARNING',
235
+ message: 'testCase declares a <dataTable> but CLI standalone execution does not bind CSV column variables — steps using <value class="variable"> references will resolve to null.',
236
+ applies_to: 'testCase',
237
+ suggestion: 'Use SetValues (Test scope) steps to bind data for standalone CLI execution, or add this test case to a test plan.',
238
+ });
239
+ }
144
240
  // Same self-closing guard for <steps/> → fast-xml-parser yields ''
145
241
  const rawSteps = tc['steps'];
146
242
  const steps = rawSteps !== null && typeof rawSteps === 'object' ? rawSteps : {};
@@ -161,7 +257,8 @@ function validateApiCall(call, issues) {
161
257
  const label = apiId ? ` "${apiId}"` : '';
162
258
  if (!callGuid) {
163
259
  issues.push({
164
- rule_id: 'TC_030', severity: 'ERROR',
260
+ rule_id: 'TC_030',
261
+ severity: 'ERROR',
165
262
  message: `apiCall${label} missing guid attribute.`,
166
263
  applies_to: 'apiCall',
167
264
  suggestion: 'Add a UUID v4 guid to each apiCall.',
@@ -169,15 +266,17 @@ function validateApiCall(call, issues) {
169
266
  }
170
267
  else if (!UUID_V4_RE.test(callGuid)) {
171
268
  issues.push({
172
- rule_id: 'TC_031', severity: 'ERROR',
269
+ rule_id: 'TC_031',
270
+ severity: 'ERROR',
173
271
  message: `apiCall${label} guid "${callGuid}" is not a valid UUID v4.`,
174
272
  applies_to: 'apiCall',
175
- suggestion: 'Use proper UUID v4 format.',
273
+ suggestion: 'Replace with a valid UUID v4 — e.g. crypto.randomUUID(). The 4th segment must begin with 8, 9, a, or b.',
176
274
  });
177
275
  }
178
276
  if (!apiId) {
179
277
  issues.push({
180
- rule_id: 'TC_032', severity: 'ERROR',
278
+ rule_id: 'TC_032',
279
+ severity: 'ERROR',
181
280
  message: 'apiCall missing apiId attribute.',
182
281
  applies_to: 'apiCall',
183
282
  suggestion: 'Add apiId attribute (e.g., UiConnect, ApexSoqlQuery).',
@@ -185,7 +284,8 @@ function validateApiCall(call, issues) {
185
284
  }
186
285
  if (!name) {
187
286
  issues.push({
188
- rule_id: 'TC_033', severity: 'WARNING',
287
+ rule_id: 'TC_033',
288
+ severity: 'WARNING',
189
289
  message: `apiCall${label} missing name attribute.`,
190
290
  applies_to: 'apiCall',
191
291
  suggestion: 'Add a descriptive name attribute.',
@@ -193,7 +293,8 @@ function validateApiCall(call, issues) {
193
293
  }
194
294
  if (!testItemId) {
195
295
  issues.push({
196
- rule_id: 'TC_034', severity: 'ERROR',
296
+ rule_id: 'TC_034',
297
+ severity: 'ERROR',
197
298
  message: `apiCall${label} missing testItemId attribute.`,
198
299
  applies_to: 'apiCall',
199
300
  suggestion: 'Add sequential testItemId (1, 2, 3...).',
@@ -201,12 +302,35 @@ function validateApiCall(call, issues) {
201
302
  }
202
303
  else if (!/^\d+$/.test(testItemId)) {
203
304
  issues.push({
204
- rule_id: 'TC_035', severity: 'ERROR',
305
+ rule_id: 'TC_035',
306
+ severity: 'ERROR',
205
307
  message: `apiCall${label} testItemId "${testItemId}" must be a whole number.`,
206
308
  applies_to: 'apiCall',
207
309
  suggestion: 'Use sequential integers for testItemId.',
208
310
  });
209
311
  }
312
+ // ASSERT-001: AssertValues using UI namedValues format instead of variable format
313
+ if (apiId?.includes('AssertValues')) {
314
+ const rawArgs = call['arguments'];
315
+ if (rawArgs) {
316
+ const argRaw = rawArgs['argument'];
317
+ const argList = !argRaw
318
+ ? []
319
+ : Array.isArray(argRaw)
320
+ ? argRaw
321
+ : [argRaw];
322
+ const hasValuesArg = argList.some((a) => a['@_id'] === 'values');
323
+ if (hasValuesArg) {
324
+ issues.push({
325
+ rule_id: 'ASSERT-001',
326
+ severity: 'WARNING',
327
+ message: `AssertValues step "${name ?? '(unnamed)'}" uses namedValues format (argument id="values") — designed for UI element attribute assertions. For Apex/SOQL result or variable comparisons this silently passes as null=null.`,
328
+ applies_to: 'apiCall',
329
+ suggestion: 'Use separate expectedValue, actualValue, and comparisonType arguments for variable or Apex result comparisons.',
330
+ });
331
+ }
332
+ }
333
+ }
210
334
  }
211
335
  function finalize(issues, testCaseId, testCaseName, stepCount, xmlContent, testName) {
212
336
  const errorCount = issues.filter((i) => i.severity === 'ERROR').length;
@@ -227,6 +351,9 @@ function finalize(issues, testCaseId, testCaseName, stepCount, xmlContent, testN
227
351
  issues,
228
352
  best_practices_violations: bp.violations,
229
353
  best_practices_rules_evaluated: bp.rules_evaluated,
354
+ // validation_source is set by the caller (MCP tool handler or direct callers).
355
+ // Default to 'local' here so the pure validateTestCase() function is self-contained.
356
+ validation_source: 'local',
230
357
  };
231
358
  }
232
359
  //# sourceMappingURL=testCaseValidate.js.map