@provartesting/provardx-cli 1.4.7 → 1.5.0-dev
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 +264 -9
- package/lib/commands/provar/automation/config/validate.js.map +1 -1
- package/lib/commands/provar/automation/project/validate.d.ts +14 -0
- package/lib/commands/provar/automation/project/validate.js +69 -0
- package/lib/commands/provar/automation/project/validate.js.map +1 -0
- package/lib/commands/provar/mcp/start.d.ts +16 -0
- package/lib/commands/provar/mcp/start.js +62 -0
- package/lib/commands/provar/mcp/start.js.map +1 -0
- package/lib/commands/provar/quality-hub/connect.d.ts +5 -0
- package/lib/commands/provar/quality-hub/connect.js +12 -0
- package/lib/commands/provar/quality-hub/connect.js.map +1 -0
- package/lib/commands/provar/quality-hub/display.d.ts +5 -0
- package/lib/commands/provar/quality-hub/display.js +12 -0
- package/lib/commands/provar/quality-hub/display.js.map +1 -0
- package/lib/commands/provar/quality-hub/open.d.ts +5 -0
- package/lib/commands/provar/quality-hub/open.js +12 -0
- package/lib/commands/provar/quality-hub/open.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run/abort.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run/abort.js +12 -0
- package/lib/commands/provar/quality-hub/test/run/abort.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run/report.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run/report.js +12 -0
- package/lib/commands/provar/quality-hub/test/run/report.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run.js +12 -0
- package/lib/commands/provar/quality-hub/test/run.js.map +1 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.d.ts +5 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.js +12 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.js.map +1 -0
- package/lib/mcp/licensing/algasClient.d.ts +19 -0
- package/lib/mcp/licensing/algasClient.js +144 -0
- package/lib/mcp/licensing/algasClient.js.map +1 -0
- package/lib/mcp/licensing/ideDetection.d.ts +34 -0
- package/lib/mcp/licensing/ideDetection.js +179 -0
- package/lib/mcp/licensing/ideDetection.js.map +1 -0
- package/lib/mcp/licensing/index.d.ts +5 -0
- package/lib/mcp/licensing/index.js +10 -0
- package/lib/mcp/licensing/index.js.map +1 -0
- package/lib/mcp/licensing/licenseCache.d.ts +20 -0
- package/lib/mcp/licensing/licenseCache.js +79 -0
- package/lib/mcp/licensing/licenseCache.js.map +1 -0
- package/lib/mcp/licensing/licenseError.d.ts +4 -0
- package/lib/mcp/licensing/licenseError.js +15 -0
- package/lib/mcp/licensing/licenseError.js.map +1 -0
- package/lib/mcp/licensing/licenseValidator.d.ts +33 -0
- package/lib/mcp/licensing/licenseValidator.js +103 -0
- package/lib/mcp/licensing/licenseValidator.js.map +1 -0
- package/lib/mcp/logging/logger.d.ts +7 -0
- package/lib/mcp/logging/logger.js +22 -0
- package/lib/mcp/logging/logger.js.map +1 -0
- package/lib/mcp/rules/page_object_validation_rules.json +344 -0
- package/lib/mcp/rules/provar_best_practices_rules.json +3192 -0
- package/lib/mcp/schemas/common.d.ts +20 -0
- package/lib/mcp/schemas/common.js +16 -0
- package/lib/mcp/schemas/common.js.map +1 -0
- package/lib/mcp/security/pathPolicy.d.ts +14 -0
- package/lib/mcp/security/pathPolicy.js +38 -0
- package/lib/mcp/security/pathPolicy.js.map +1 -0
- package/lib/mcp/server.d.ts +5 -0
- package/lib/mcp/server.js +59 -0
- package/lib/mcp/server.js.map +1 -0
- package/lib/mcp/tools/antTools.d.ts +21 -0
- package/lib/mcp/tools/antTools.js +602 -0
- package/lib/mcp/tools/antTools.js.map +1 -0
- package/lib/mcp/tools/automationTools.d.ts +14 -0
- package/lib/mcp/tools/automationTools.js +386 -0
- package/lib/mcp/tools/automationTools.js.map +1 -0
- package/lib/mcp/tools/bestPracticesEngine.d.ts +30 -0
- package/lib/mcp/tools/bestPracticesEngine.js +632 -0
- package/lib/mcp/tools/bestPracticesEngine.js.map +1 -0
- package/lib/mcp/tools/defectTools.d.ts +15 -0
- package/lib/mcp/tools/defectTools.js +199 -0
- package/lib/mcp/tools/defectTools.js.map +1 -0
- package/lib/mcp/tools/hierarchyValidate.d.ts +139 -0
- package/lib/mcp/tools/hierarchyValidate.js +540 -0
- package/lib/mcp/tools/hierarchyValidate.js.map +1 -0
- package/lib/mcp/tools/pageObjectGenerate.d.ts +3 -0
- package/lib/mcp/tools/pageObjectGenerate.js +153 -0
- package/lib/mcp/tools/pageObjectGenerate.js.map +1 -0
- package/lib/mcp/tools/pageObjectValidate.d.ts +18 -0
- package/lib/mcp/tools/pageObjectValidate.js +420 -0
- package/lib/mcp/tools/pageObjectValidate.js.map +1 -0
- package/lib/mcp/tools/projectInspect.d.ts +3 -0
- package/lib/mcp/tools/projectInspect.js +694 -0
- package/lib/mcp/tools/projectInspect.js.map +1 -0
- package/lib/mcp/tools/projectValidateFromPath.d.ts +3 -0
- package/lib/mcp/tools/projectValidateFromPath.js +153 -0
- package/lib/mcp/tools/projectValidateFromPath.js.map +1 -0
- package/lib/mcp/tools/propertiesTools.d.ts +7 -0
- package/lib/mcp/tools/propertiesTools.js +314 -0
- package/lib/mcp/tools/propertiesTools.js.map +1 -0
- package/lib/mcp/tools/qualityHubTools.d.ts +8 -0
- package/lib/mcp/tools/qualityHubTools.js +178 -0
- package/lib/mcp/tools/qualityHubTools.js.map +1 -0
- package/lib/mcp/tools/rcaTools.d.ts +4 -0
- package/lib/mcp/tools/rcaTools.js +620 -0
- package/lib/mcp/tools/rcaTools.js.map +1 -0
- package/lib/mcp/tools/sfSpawn.d.ts +28 -0
- package/lib/mcp/tools/sfSpawn.js +50 -0
- package/lib/mcp/tools/sfSpawn.js.map +1 -0
- package/lib/mcp/tools/testCaseGenerate.d.ts +3 -0
- package/lib/mcp/tools/testCaseGenerate.js +221 -0
- package/lib/mcp/tools/testCaseGenerate.js.map +1 -0
- package/lib/mcp/tools/testCaseValidate.d.ts +20 -0
- package/lib/mcp/tools/testCaseValidate.js +227 -0
- package/lib/mcp/tools/testCaseValidate.js.map +1 -0
- package/lib/mcp/tools/testPlanTools.d.ts +6 -0
- package/lib/mcp/tools/testPlanTools.js +311 -0
- package/lib/mcp/tools/testPlanTools.js.map +1 -0
- package/lib/mcp/tools/testPlanValidate.d.ts +2 -0
- package/lib/mcp/tools/testPlanValidate.js +75 -0
- package/lib/mcp/tools/testPlanValidate.js.map +1 -0
- package/lib/mcp/tools/testSuiteValidate.d.ts +2 -0
- package/lib/mcp/tools/testSuiteValidate.js +63 -0
- package/lib/mcp/tools/testSuiteValidate.js.map +1 -0
- package/lib/services/projectValidation.d.ts +119 -0
- package/lib/services/projectValidation.js +678 -0
- package/lib/services/projectValidation.js.map +1 -0
- package/messages/sf.provar.automation.project.validate.md +52 -0
- package/messages/sf.provar.mcp.start.md +74 -0
- package/oclif.manifest.json +1298 -1
- package/package.json +29 -15
|
@@ -0,0 +1,153 @@
|
|
|
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 { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
|
|
12
|
+
import { makeError, makeRequestId } from '../schemas/common.js';
|
|
13
|
+
import { log } from '../logging/logger.js';
|
|
14
|
+
const VALID_LOCATOR_STRATEGIES = [
|
|
15
|
+
'xpath', 'id', 'css', 'name', 'className', 'tagName',
|
|
16
|
+
'linkText', 'partialLinkText', 'visualforce', 'label',
|
|
17
|
+
];
|
|
18
|
+
const VALID_ELEMENT_TYPES = [
|
|
19
|
+
'TextType', 'ButtonType', 'LinkType', 'ChoiceListType',
|
|
20
|
+
'RadioType', 'FileType', 'DateType', 'RichTextType', 'BooleanType',
|
|
21
|
+
];
|
|
22
|
+
const FieldSchema = z.object({
|
|
23
|
+
name: z.string().describe('camelCase WebElement field name'),
|
|
24
|
+
locator_strategy: z.enum(VALID_LOCATOR_STRATEGIES).default('xpath'),
|
|
25
|
+
locator_value: z
|
|
26
|
+
.string()
|
|
27
|
+
.default('')
|
|
28
|
+
.describe('Locator value (empty string is valid — AI healing populates at runtime)'),
|
|
29
|
+
element_type: z.enum(VALID_ELEMENT_TYPES).default('TextType'),
|
|
30
|
+
});
|
|
31
|
+
export function registerPageObjectGenerate(server, config) {
|
|
32
|
+
server.tool('provar.pageobject.generate', 'Generate a Provar Java Page Object skeleton with @Page/@SalesforcePage annotation, standard imports, and @FindBy WebElement fields. Returns Java source. Writes to disk only when dry_run=false.', {
|
|
33
|
+
class_name: z.string().describe('PascalCase class name, e.g. AccountDetailPage'),
|
|
34
|
+
package_name: z
|
|
35
|
+
.string()
|
|
36
|
+
.default('pageobjects')
|
|
37
|
+
.describe('Java package, e.g. pageobjects or pageobjects.accounts'),
|
|
38
|
+
page_type: z
|
|
39
|
+
.enum(['standard', 'salesforce'])
|
|
40
|
+
.default('standard')
|
|
41
|
+
.describe('@Page (standard) or @SalesforcePage (salesforce)'),
|
|
42
|
+
title: z
|
|
43
|
+
.string()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Page title attribute; defaults to class_name if omitted'),
|
|
46
|
+
connection_name: z
|
|
47
|
+
.string()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Salesforce connection name (required when page_type=salesforce)'),
|
|
50
|
+
salesforce_page_attribute: z
|
|
51
|
+
.enum(['page', 'auraComponent', 'object', 'lightningWebComponent'])
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Page type attribute for @SalesforcePage'),
|
|
54
|
+
fields: z.array(FieldSchema).default([]).describe('WebElement fields to generate'),
|
|
55
|
+
output_path: z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Suggested file path for the .java file (returned in response)'),
|
|
59
|
+
overwrite: z
|
|
60
|
+
.boolean()
|
|
61
|
+
.default(false)
|
|
62
|
+
.describe('Overwrite existing file when dry_run=false'),
|
|
63
|
+
dry_run: z
|
|
64
|
+
.boolean()
|
|
65
|
+
.default(true)
|
|
66
|
+
.describe('true = return source only (default); false = write to output_path'),
|
|
67
|
+
idempotency_key: z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Caller-provided key echoed back for deduplication tracking'),
|
|
71
|
+
}, (input) => {
|
|
72
|
+
const requestId = makeRequestId();
|
|
73
|
+
log('info', 'provar.pageobject.generate', {
|
|
74
|
+
requestId,
|
|
75
|
+
class_name: input.class_name,
|
|
76
|
+
dry_run: input.dry_run,
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
const javaSource = buildPageObjectSource(input);
|
|
80
|
+
const filePath = input.output_path
|
|
81
|
+
? path.resolve(input.output_path)
|
|
82
|
+
: undefined;
|
|
83
|
+
let written = false;
|
|
84
|
+
if (filePath && !input.dry_run) {
|
|
85
|
+
assertPathAllowed(filePath, config.allowedPaths);
|
|
86
|
+
if (fs.existsSync(filePath) && !input.overwrite) {
|
|
87
|
+
const err = makeError('FILE_EXISTS', `File already exists: ${filePath}. Set overwrite=true to replace.`, requestId);
|
|
88
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
89
|
+
}
|
|
90
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
91
|
+
fs.writeFileSync(filePath, javaSource, 'utf-8');
|
|
92
|
+
written = true;
|
|
93
|
+
log('info', 'provar.pageobject.generate: wrote file', { requestId, filePath });
|
|
94
|
+
}
|
|
95
|
+
const result = {
|
|
96
|
+
requestId,
|
|
97
|
+
java_source: javaSource,
|
|
98
|
+
file_path: filePath,
|
|
99
|
+
written,
|
|
100
|
+
dry_run: input.dry_run,
|
|
101
|
+
idempotency_key: input.idempotency_key,
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
105
|
+
structuredContent: result,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
const error = err;
|
|
110
|
+
const errResult = makeError(error instanceof PathPolicyError ? error.code : (error.code ?? 'GENERATE_ERROR'), error.message, requestId, false);
|
|
111
|
+
log('error', 'provar.pageobject.generate failed', { requestId, error: error.message });
|
|
112
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// ── Source builder ────────────────────────────────────────────────────────────
|
|
117
|
+
function buildPageObjectSource(input) {
|
|
118
|
+
const { class_name, package_name, page_type, title, connection_name, salesforce_page_attribute, fields } = input;
|
|
119
|
+
const pageTitle = title ?? class_name;
|
|
120
|
+
let annotation;
|
|
121
|
+
if (page_type === 'salesforce') {
|
|
122
|
+
const conn = connection_name ? `, connection = "${connection_name}"` : '';
|
|
123
|
+
const sfAttr = salesforce_page_attribute ? `, ${salesforce_page_attribute} = ""` : '';
|
|
124
|
+
annotation = `@SalesforcePage(title = "${pageTitle}"${conn}${sfAttr})`;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
annotation = `@Page(title = "${pageTitle}")`;
|
|
128
|
+
}
|
|
129
|
+
const fieldBlocks = fields.length > 0
|
|
130
|
+
? fields
|
|
131
|
+
.map((f) => {
|
|
132
|
+
const locArg = f.locator_strategy === 'xpath'
|
|
133
|
+
? `xpath = "${f.locator_value}"`
|
|
134
|
+
: `${f.locator_strategy} = "${f.locator_value}"`;
|
|
135
|
+
return ` @FindBy(${locArg})\n @${f.element_type}()\n public WebElement ${f.name};`;
|
|
136
|
+
})
|
|
137
|
+
.join('\n\n')
|
|
138
|
+
: ' // TODO: Add @FindBy WebElement fields';
|
|
139
|
+
return `package ${package_name};
|
|
140
|
+
|
|
141
|
+
import com.provar.core.testapi.annotations.*;
|
|
142
|
+
import org.openqa.selenium.WebElement;
|
|
143
|
+
import org.openqa.selenium.support.FindBy;
|
|
144
|
+
|
|
145
|
+
${annotation}
|
|
146
|
+
public class ${class_name} {
|
|
147
|
+
|
|
148
|
+
${fieldBlocks}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=pageObjectGenerate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageObjectGenerate.js","sourceRoot":"","sources":["../../../src/mcp/tools/pageObjectGenerate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAE3C,MAAM,wBAAwB,GAAG;IAC/B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS;IACpD,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO;CAC7C,CAAC;AAEX,MAAM,mBAAmB,GAAG;IAC1B,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB;IACtD,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa;CAC1D,CAAC;AAEX,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IAC5D,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACnE,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,yEAAyE,CAAC;IACtF,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;CAC9D,CAAC,CAAC;AAEH,MAAM,UAAU,0BAA0B,CAAC,MAAiB,EAAE,MAAoB;IAChF,MAAM,CAAC,IAAI,CACT,4BAA4B,EAC5B,kMAAkM,EAClM;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QAChF,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,OAAO,CAAC,aAAa,CAAC;aACtB,QAAQ,CAAC,wDAAwD,CAAC;QACrE,SAAS,EAAE,CAAC;aACT,IAAI,CAAC,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;aAChC,OAAO,CAAC,UAAU,CAAC;aACnB,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,iEAAiE,CAAC;QAC9E,yBAAyB,EAAE,CAAC;aACzB,IAAI,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,uBAAuB,CAAC,CAAC;aAClE,QAAQ,EAAE;aACV,QAAQ,CAAC,yCAAyC,CAAC;QACtD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAClF,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,SAAS,EAAE,CAAC;aACT,OAAO,EAAE;aACT,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,4CAA4C,CAAC;QACzD,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,OAAO,CAAC,IAAI,CAAC;aACb,QAAQ,CAAC,mEAAmE,CAAC;QAChF,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,4DAA4D,CAAC;KAC1E,EACD,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,GAAG,CAAC,MAAM,EAAE,4BAA4B,EAAE;YACxC,SAAS;YACT,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAuB,KAAK,CAAC,WAAW;gBACpD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;gBACjC,CAAC,CAAC,SAAS,CAAC;YACd,IAAI,OAAO,GAAG,KAAK,CAAC;YAEpB,IAAI,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC/B,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;gBAEjD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;oBAChD,MAAM,GAAG,GAAG,SAAS,CACnB,aAAa,EACb,wBAAwB,QAAQ,kCAAkC,EAClE,SAAS,CACV,CAAC;oBACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5F,CAAC;gBAED,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;gBAChD,OAAO,GAAG,IAAI,CAAC;gBACf,GAAG,CAAC,MAAM,EAAE,wCAAwC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YACjF,CAAC;YAED,MAAM,MAAM,GAAG;gBACb,SAAS;gBACT,WAAW,EAAE,UAAU;gBACvB,SAAS,EAAE,QAAQ;gBACnB,OAAO;gBACP,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,eAAe,EAAE,KAAK,CAAC,eAAe;aACvC,CAAC;YACF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAAM;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,GAAgC,CAAC;YAC/C,MAAM,SAAS,GAAG,SAAS,CACzB,KAAK,YAAY,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,gBAAgB,CAAC,EAChF,KAAK,CAAC,OAAO,EACb,SAAS,EACT,KAAK,CACN,CAAC;YACF,GAAG,CAAC,OAAO,EAAE,mCAAmC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACvF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;QAClG,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,SAAS,qBAAqB,CAAC,KAQ9B;IACC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,EAAE,GACtG,KAAK,CAAC;IACR,MAAM,SAAS,GAAG,KAAK,IAAI,UAAU,CAAC;IAEtC,IAAI,UAAkB,CAAC;IACvB,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,mBAAmB,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,MAAM,MAAM,GAAG,yBAAyB,CAAC,CAAC,CAAC,KAAK,yBAAyB,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,UAAU,GAAG,4BAA4B,SAAS,IAAI,IAAI,GAAG,MAAM,GAAG,CAAC;IACzE,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,kBAAkB,SAAS,IAAI,CAAC;IAC/C,CAAC;IAED,MAAM,WAAW,GACf,MAAM,CAAC,MAAM,GAAG,CAAC;QACf,CAAC,CAAC,MAAM;aACH,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,MAAM,GACV,CAAC,CAAC,gBAAgB,KAAK,OAAO;gBAC5B,CAAC,CAAC,YAAY,CAAC,CAAC,aAAa,GAAG;gBAChC,CAAC,CAAC,GAAG,CAAC,CAAC,gBAAgB,OAAO,CAAC,CAAC,aAAa,GAAG,CAAC;YACrD,OAAO,eAAe,MAAM,WAAW,CAAC,CAAC,YAAY,6BAA6B,CAAC,CAAC,IAAI,GAAG,CAAC;QAC9F,CAAC,CAAC;aACD,IAAI,CAAC,MAAM,CAAC;QACjB,CAAC,CAAC,4CAA4C,CAAC;IAEnD,OAAO,WAAW,YAAY;;;;;;EAM9B,UAAU;eACG,UAAU;;EAEvB,WAAW;;;CAGZ,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ServerConfig } from '../server.js';
|
|
3
|
+
import { type ValidationIssue } from '../schemas/common.js';
|
|
4
|
+
export declare function registerPageObjectValidate(server: McpServer, config: ServerConfig): void;
|
|
5
|
+
export interface PageObjectValidationResult {
|
|
6
|
+
is_valid: boolean;
|
|
7
|
+
quality_score: number;
|
|
8
|
+
class_name: string | null;
|
|
9
|
+
package_name: string | null;
|
|
10
|
+
field_count: number;
|
|
11
|
+
frame_count: number;
|
|
12
|
+
error_count: number;
|
|
13
|
+
warning_count: number;
|
|
14
|
+
info_count: number;
|
|
15
|
+
issues: ValidationIssue[];
|
|
16
|
+
}
|
|
17
|
+
/** Pure function — exported for unit testing */
|
|
18
|
+
export declare function validatePageObject(source: string, expectedClassName?: string): PageObjectValidationResult;
|
|
@@ -0,0 +1,420 @@
|
|
|
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, { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
|
|
13
|
+
import { makeError, makeRequestId } from '../schemas/common.js';
|
|
14
|
+
import { log } from '../logging/logger.js';
|
|
15
|
+
export function registerPageObjectValidate(server, config) {
|
|
16
|
+
server.tool('provar.pageobject.validate', 'Validate a Provar Java Page Object against naming conventions, locator best practices, and structural requirements. Returns quality score (0–100) and list of issues.', {
|
|
17
|
+
content: z.string().optional().describe('Java source code to validate directly'),
|
|
18
|
+
file_path: z.string().optional().describe('Path to .java Page Object file'),
|
|
19
|
+
expected_class_name: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('Expected class name for PO_006 check; inferred from file_path when omitted'),
|
|
23
|
+
}, ({ content, file_path, expected_class_name }) => {
|
|
24
|
+
const requestId = makeRequestId();
|
|
25
|
+
log('info', 'provar.pageobject.validate', { requestId, has_content: !!content, file_path });
|
|
26
|
+
try {
|
|
27
|
+
let source = content;
|
|
28
|
+
let inferredClassName = expected_class_name;
|
|
29
|
+
if (!source && file_path) {
|
|
30
|
+
assertPathAllowed(file_path, config.allowedPaths);
|
|
31
|
+
const resolved = path.resolve(file_path);
|
|
32
|
+
if (!fs.existsSync(resolved)) {
|
|
33
|
+
const err = makeError('FILE_NOT_FOUND', `File not found: ${resolved}`, requestId);
|
|
34
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
35
|
+
}
|
|
36
|
+
source = fs.readFileSync(resolved, 'utf-8');
|
|
37
|
+
if (!inferredClassName) {
|
|
38
|
+
inferredClassName = path.basename(resolved, '.java');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!source) {
|
|
42
|
+
const err = makeError('MISSING_INPUT', 'Provide either content or file_path.', requestId);
|
|
43
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
44
|
+
}
|
|
45
|
+
const validation = validatePageObject(source, inferredClassName);
|
|
46
|
+
const result = { requestId, ...validation };
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
49
|
+
structuredContent: result,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const error = err;
|
|
54
|
+
const errResult = makeError(error instanceof PathPolicyError ? error.code : 'VALIDATE_ERROR', error.message, requestId, false);
|
|
55
|
+
log('error', 'provar.pageobject.validate failed', { requestId, error: error.message });
|
|
56
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// ── Validator (ported from quality-hub-agents/lambda/src/validator/page_object_validator.py) ──
|
|
61
|
+
const VALID_LOCATOR_STRATEGIES = new Set([
|
|
62
|
+
'xpath', 'id', 'css', 'name', 'className', 'tagName',
|
|
63
|
+
'linkText', 'partialLinkText', 'visualforce', 'label',
|
|
64
|
+
]);
|
|
65
|
+
const VALID_ELEMENT_TYPES = new Set([
|
|
66
|
+
'TextType', 'ButtonType', 'LinkType', 'ChoiceListType',
|
|
67
|
+
'RadioType', 'FileType', 'DateType', 'RichTextType', 'BooleanType',
|
|
68
|
+
]);
|
|
69
|
+
const PASCAL_CASE_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
70
|
+
const VALID_JAVA_IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
71
|
+
const JAVA_RESERVED = new Set([
|
|
72
|
+
'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class',
|
|
73
|
+
'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extends', 'final',
|
|
74
|
+
'finally', 'float', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'int',
|
|
75
|
+
'interface', 'long', 'native', 'new', 'package', 'private', 'protected', 'public',
|
|
76
|
+
'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this',
|
|
77
|
+
'throw', 'throws', 'transient', 'try', 'void', 'volatile', 'while',
|
|
78
|
+
]);
|
|
79
|
+
const SF_DYNAMIC_ATTRS_RE = /data-aura-rendered-by|data-aura-class|aura-id|data-component-id/i;
|
|
80
|
+
const INDEXED_XPATH_RE = /\[\d+\]/;
|
|
81
|
+
const POSITION_FN_RE = /\b(last|first|position)\s*\(\s*\)/;
|
|
82
|
+
const poRulesDirPath = dirname(fileURLToPath(import.meta.url));
|
|
83
|
+
let poRulePenaltiesCache = null;
|
|
84
|
+
function getRulePenalties() {
|
|
85
|
+
if (!poRulePenaltiesCache) {
|
|
86
|
+
try {
|
|
87
|
+
const raw = fs.readFileSync(join(poRulesDirPath, '..', 'rules', 'page_object_validation_rules.json'), 'utf-8');
|
|
88
|
+
const rules = JSON.parse(raw);
|
|
89
|
+
poRulePenaltiesCache = Object.fromEntries(rules.map((r) => [r.id, r.penalty]));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
poRulePenaltiesCache = {}; // unknown rules fall back to the default 5-point penalty
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return poRulePenaltiesCache;
|
|
96
|
+
}
|
|
97
|
+
/** Pure function — exported for unit testing */
|
|
98
|
+
export function validatePageObject(source, expectedClassName) {
|
|
99
|
+
const issues = [];
|
|
100
|
+
const stripped = stripComments(source);
|
|
101
|
+
// ── Package ──────────────────────────────────────────────────────────────────
|
|
102
|
+
const packageMatch = /^\s*package\s+([\w.]+)\s*;/m.exec(stripped);
|
|
103
|
+
const packageName = packageMatch ? packageMatch[1] : null;
|
|
104
|
+
if (!packageMatch) {
|
|
105
|
+
issues.push({
|
|
106
|
+
rule_id: 'PO_001', severity: 'ERROR',
|
|
107
|
+
message: 'Missing package declaration.',
|
|
108
|
+
applies_to: 'class',
|
|
109
|
+
suggestion: "Add 'package pageobjects;' at the top of the file.",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/.test(packageName)) {
|
|
113
|
+
issues.push({
|
|
114
|
+
rule_id: 'PO_002', severity: 'ERROR',
|
|
115
|
+
message: `Invalid package name: "${packageName}".`,
|
|
116
|
+
applies_to: 'class',
|
|
117
|
+
suggestion: 'Package names should be valid lower-case Java identifiers separated by dots.',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// ── Class declaration ────────────────────────────────────────────────────────
|
|
121
|
+
const className = checkClassDeclaration(stripped, expectedClassName, issues);
|
|
122
|
+
// ── Brace balance ────────────────────────────────────────────────────────────
|
|
123
|
+
const openBraces = (stripped.match(/\{/g) ?? []).length;
|
|
124
|
+
const closeBraces = (stripped.match(/\}/g) ?? []).length;
|
|
125
|
+
if (openBraces !== closeBraces) {
|
|
126
|
+
issues.push({
|
|
127
|
+
rule_id: 'PO_060', severity: 'ERROR',
|
|
128
|
+
message: `Mismatched braces: ${openBraces} opening vs ${closeBraces} closing.`,
|
|
129
|
+
applies_to: 'class',
|
|
130
|
+
suggestion: 'Check for missing or extra curly braces.',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// ── Imports ──────────────────────────────────────────────────────────────────
|
|
134
|
+
if (!stripped.includes('import com.provar.core.testapi.annotations')) {
|
|
135
|
+
issues.push({
|
|
136
|
+
rule_id: 'PO_012', severity: 'WARNING',
|
|
137
|
+
message: 'Missing import for Provar annotations.',
|
|
138
|
+
applies_to: 'class',
|
|
139
|
+
suggestion: "Add 'import com.provar.core.testapi.annotations.*;'",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// ── Page annotation ──────────────────────────────────────────────────────────
|
|
143
|
+
const hasSalesforceAnnotation = checkAnnotations(stripped, issues);
|
|
144
|
+
// ── Fields ───────────────────────────────────────────────────────────────────
|
|
145
|
+
// Use original source (not stripped) so XPath "//" inside string literals
|
|
146
|
+
// is not mistakenly treated as a line comment by stripComments.
|
|
147
|
+
const fields = extractFields(source);
|
|
148
|
+
if (fields.length === 0 && !issues.some((i) => i.rule_id === 'PO_003')) {
|
|
149
|
+
issues.push({
|
|
150
|
+
rule_id: 'PO_030', severity: 'WARNING',
|
|
151
|
+
message: 'No WebElement or WebComponent fields found.',
|
|
152
|
+
applies_to: 'class',
|
|
153
|
+
suggestion: 'Add at least one WebElement field with @FindBy locator and type annotation.',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
validateFields(fields, hasSalesforceAnnotation, issues);
|
|
157
|
+
// ── Frames ───────────────────────────────────────────────────────────────────
|
|
158
|
+
const frameCount = (stripped.match(/@PageFrame\b/g) ?? []).length;
|
|
159
|
+
// ── Commented code ───────────────────────────────────────────────────────────
|
|
160
|
+
if (/\/\/\s*(public|private|protected|@FindBy|WebElement|@\w+Type)/.test(source)) {
|
|
161
|
+
issues.push({
|
|
162
|
+
rule_id: 'PO_080', severity: 'INFO',
|
|
163
|
+
message: 'Commented-out code detected.',
|
|
164
|
+
applies_to: 'class',
|
|
165
|
+
suggestion: 'Remove commented code. Use version control to track history.',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// ── Quality score (sum penalties, capped at 100) ──────────────────────────
|
|
169
|
+
const rulePenalties = getRulePenalties();
|
|
170
|
+
let penalty = 0;
|
|
171
|
+
for (const issue of issues) {
|
|
172
|
+
penalty += rulePenalties[issue.rule_id] ?? 5;
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
is_valid: issues.filter((i) => i.severity === 'ERROR').length === 0,
|
|
176
|
+
quality_score: Math.max(0, Math.min(100, 100 - penalty)),
|
|
177
|
+
class_name: className,
|
|
178
|
+
package_name: packageName,
|
|
179
|
+
field_count: fields.length,
|
|
180
|
+
frame_count: frameCount,
|
|
181
|
+
error_count: issues.filter((i) => i.severity === 'ERROR').length,
|
|
182
|
+
warning_count: issues.filter((i) => i.severity === 'WARNING').length,
|
|
183
|
+
info_count: issues.filter((i) => i.severity === 'INFO').length,
|
|
184
|
+
issues,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function checkClassDeclaration(stripped, expectedClassName, issues) {
|
|
188
|
+
const classMatch = /public\s+class\s+(\w+)/.exec(stripped);
|
|
189
|
+
const className = classMatch ? classMatch[1] : null;
|
|
190
|
+
if (!classMatch) {
|
|
191
|
+
issues.push({
|
|
192
|
+
rule_id: 'PO_003', severity: 'ERROR',
|
|
193
|
+
message: 'Missing public class declaration.',
|
|
194
|
+
applies_to: 'class',
|
|
195
|
+
suggestion: "Ensure the file has a 'public class ClassName' declaration.",
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
if (!PASCAL_CASE_RE.test(className)) {
|
|
200
|
+
issues.push({
|
|
201
|
+
rule_id: 'PO_004', severity: 'WARNING',
|
|
202
|
+
message: `Class name "${className}" is not PascalCase.`,
|
|
203
|
+
applies_to: 'class',
|
|
204
|
+
suggestion: "Rename to PascalCase (e.g., 'MyPageObject').",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (!VALID_JAVA_IDENT_RE.test(className)) {
|
|
208
|
+
issues.push({
|
|
209
|
+
rule_id: 'PO_005', severity: 'ERROR',
|
|
210
|
+
message: `Class name "${className}" is not a valid Java identifier.`,
|
|
211
|
+
applies_to: 'class',
|
|
212
|
+
suggestion: 'Class names must start with a letter, $, or _ and contain only letters, digits, $, or _.',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (expectedClassName && className !== expectedClassName) {
|
|
216
|
+
issues.push({
|
|
217
|
+
rule_id: 'PO_006', severity: 'ERROR',
|
|
218
|
+
message: `Class name "${className}" does not match expected "${expectedClassName}".`,
|
|
219
|
+
applies_to: 'class',
|
|
220
|
+
suggestion: 'Class name must match the filename.',
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return className;
|
|
225
|
+
}
|
|
226
|
+
function checkAnnotations(stripped, issues) {
|
|
227
|
+
const hasPageAnnotation = /@Page\s*\(/.test(stripped);
|
|
228
|
+
const hasSalesforceAnnotation = /@SalesforcePage\s*\(/.test(stripped);
|
|
229
|
+
if (!hasPageAnnotation && !hasSalesforceAnnotation) {
|
|
230
|
+
issues.push({
|
|
231
|
+
rule_id: 'PO_020', severity: 'WARNING',
|
|
232
|
+
message: 'Missing @Page or @SalesforcePage annotation.',
|
|
233
|
+
applies_to: 'annotation',
|
|
234
|
+
suggestion: 'Add @Page annotation before the class declaration.',
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
else if (hasPageAnnotation) {
|
|
238
|
+
const m = /@Page\s*\(([^)]*)\)/.exec(stripped);
|
|
239
|
+
if (m && !m[1].includes('title')) {
|
|
240
|
+
issues.push({
|
|
241
|
+
rule_id: 'PO_021', severity: 'WARNING',
|
|
242
|
+
message: '@Page annotation missing title attribute.',
|
|
243
|
+
applies_to: 'annotation',
|
|
244
|
+
suggestion: 'Add title attribute to @Page annotation.',
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else if (hasSalesforceAnnotation) {
|
|
249
|
+
const m = /@SalesforcePage\s*\(([^)]*)\)/.exec(stripped);
|
|
250
|
+
if (m) {
|
|
251
|
+
if (!m[1].includes('title') || !m[1].includes('connection')) {
|
|
252
|
+
issues.push({
|
|
253
|
+
rule_id: 'PO_022', severity: 'ERROR',
|
|
254
|
+
message: '@SalesforcePage missing required title or connection attribute.',
|
|
255
|
+
applies_to: 'annotation',
|
|
256
|
+
suggestion: 'Add required attributes to @SalesforcePage annotation.',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const pageTypes = ['page', 'auraComponent', 'object', 'lightningWebComponent'];
|
|
260
|
+
if (!pageTypes.some((t) => m[1].includes(t))) {
|
|
261
|
+
issues.push({
|
|
262
|
+
rule_id: 'PO_023', severity: 'WARNING',
|
|
263
|
+
message: '@SalesforcePage should specify page type attribute.',
|
|
264
|
+
applies_to: 'annotation',
|
|
265
|
+
suggestion: 'Add one of: page, auraComponent, object, or lightningWebComponent.',
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return hasSalesforceAnnotation;
|
|
271
|
+
}
|
|
272
|
+
function validateFields(fields, hasSalesforceAnnotation, issues) {
|
|
273
|
+
const fieldNames = new Set();
|
|
274
|
+
for (const field of fields) {
|
|
275
|
+
if (fieldNames.has(field.name)) {
|
|
276
|
+
issues.push({
|
|
277
|
+
rule_id: 'PO_031', severity: 'ERROR',
|
|
278
|
+
message: `Duplicate field name: "${field.name}".`,
|
|
279
|
+
applies_to: 'field',
|
|
280
|
+
suggestion: 'Rename one of the duplicate fields.',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
fieldNames.add(field.name);
|
|
285
|
+
}
|
|
286
|
+
if (!VALID_JAVA_IDENT_RE.test(field.name)) {
|
|
287
|
+
issues.push({
|
|
288
|
+
rule_id: 'PO_032', severity: 'ERROR',
|
|
289
|
+
message: `Invalid field name: "${field.name}".`,
|
|
290
|
+
applies_to: 'field',
|
|
291
|
+
suggestion: 'Field names must be valid Java identifiers.',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (JAVA_RESERVED.has(field.name)) {
|
|
295
|
+
issues.push({
|
|
296
|
+
rule_id: 'PO_033', severity: 'ERROR',
|
|
297
|
+
message: `Field name "${field.name}" is a Java reserved word.`,
|
|
298
|
+
applies_to: 'field',
|
|
299
|
+
suggestion: 'Rename field to avoid Java reserved words.',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (field.locatorStrategy && !VALID_LOCATOR_STRATEGIES.has(field.locatorStrategy)) {
|
|
303
|
+
issues.push({
|
|
304
|
+
rule_id: 'PO_034', severity: 'ERROR',
|
|
305
|
+
message: `Invalid locator strategy: "${field.locatorStrategy}".`,
|
|
306
|
+
applies_to: 'field',
|
|
307
|
+
suggestion: 'Use one of: xpath, id, css, name, className, tagName, linkText, partialLinkText, visualforce, label.',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (field.elementType && !VALID_ELEMENT_TYPES.has(field.elementType)) {
|
|
311
|
+
issues.push({
|
|
312
|
+
rule_id: 'PO_036', severity: 'WARNING',
|
|
313
|
+
message: `Invalid element type: "@${field.elementType}". (CheckboxType is not valid — use BooleanType.)`,
|
|
314
|
+
applies_to: 'field',
|
|
315
|
+
suggestion: 'Use a valid Provar element type: TextType, ButtonType, LinkType, ChoiceListType, RadioType, FileType, DateType, RichTextType, BooleanType.',
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
checkLocatorQuality(field, hasSalesforceAnnotation, issues);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function checkLocatorQuality(field, hasSalesforceAnnotation, issues) {
|
|
322
|
+
const lv = field.locatorValue ?? '';
|
|
323
|
+
const strat = field.locatorStrategy ?? '';
|
|
324
|
+
if (!lv)
|
|
325
|
+
return;
|
|
326
|
+
if ((strat === 'xpath' || strat === '') && /^\/html|^\/body/i.test(lv)) {
|
|
327
|
+
issues.push({
|
|
328
|
+
rule_id: 'PO_071', severity: 'ERROR',
|
|
329
|
+
message: `Absolute XPath for field "${field.name}".`,
|
|
330
|
+
applies_to: 'field',
|
|
331
|
+
suggestion: 'Use relative XPath starting with // or .//',
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (SF_DYNAMIC_ATTRS_RE.test(lv)) {
|
|
335
|
+
issues.push({
|
|
336
|
+
rule_id: 'PO_073', severity: 'ERROR',
|
|
337
|
+
message: `Salesforce dynamic attribute in locator for "${field.name}".`,
|
|
338
|
+
applies_to: 'field',
|
|
339
|
+
suggestion: 'Use stable identifiers like labels, data-testid, or semantic selectors.',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
if (strat === 'id' && hasSalesforceAnnotation) {
|
|
343
|
+
issues.push({
|
|
344
|
+
rule_id: 'PO_070', severity: 'WARNING',
|
|
345
|
+
message: `ID-based locator on Salesforce page for "${field.name}". IDs may be dynamic.`,
|
|
346
|
+
applies_to: 'field',
|
|
347
|
+
suggestion: 'Prefer xpath/css with stable attributes like data-testid, aria-label, name.',
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (INDEXED_XPATH_RE.test(lv)) {
|
|
351
|
+
issues.push({
|
|
352
|
+
rule_id: 'PO_072', severity: 'WARNING',
|
|
353
|
+
message: `Indexed XPath [n] for field "${field.name}".`,
|
|
354
|
+
applies_to: 'field',
|
|
355
|
+
suggestion: 'Prefer attribute-based selection over positional indexes.',
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
if (strat === 'xpath') {
|
|
359
|
+
const segments = (lv.match(/\/{2}/g) ?? []).length;
|
|
360
|
+
if (segments > 4) {
|
|
361
|
+
issues.push({
|
|
362
|
+
rule_id: 'PO_076', severity: 'WARNING',
|
|
363
|
+
message: `Complex XPath (${segments} descent operators) for "${field.name}".`,
|
|
364
|
+
applies_to: 'field',
|
|
365
|
+
suggestion: 'Simplify with a more direct path or data-testid attributes.',
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (POSITION_FN_RE.test(lv)) {
|
|
370
|
+
issues.push({
|
|
371
|
+
rule_id: 'PO_079', severity: 'WARNING',
|
|
372
|
+
message: `Position function (last/first/position) in XPath for "${field.name}".`,
|
|
373
|
+
applies_to: 'field',
|
|
374
|
+
suggestion: 'Use unique identifiers instead of position-based selection.',
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
if (strat === 'css' && /[a-z0-9]+-[a-z0-9]+-[a-z0-9]+/.test(lv)) {
|
|
378
|
+
issues.push({
|
|
379
|
+
rule_id: 'PO_075', severity: 'INFO',
|
|
380
|
+
message: `Possibly autogenerated CSS class pattern for "${field.name}".`,
|
|
381
|
+
applies_to: 'field',
|
|
382
|
+
suggestion: 'Prefer stable attributes over autogenerated CSS classes.',
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
if (lv.length > 200) {
|
|
386
|
+
issues.push({
|
|
387
|
+
rule_id: 'PO_078', severity: 'INFO',
|
|
388
|
+
message: `Very long locator (${lv.length} chars) for "${field.name}".`,
|
|
389
|
+
applies_to: 'field',
|
|
390
|
+
suggestion: 'Consider a shorter, more maintainable locator.',
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
395
|
+
function stripComments(source) {
|
|
396
|
+
return source
|
|
397
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // block comments
|
|
398
|
+
.replace(/\/\/[^\n]*/g, ''); // line comments
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Extract @FindBy WebElement field declarations from stripped source.
|
|
402
|
+
* Regex captures: FindBy attrs | optional type annotation | field name.
|
|
403
|
+
*/
|
|
404
|
+
function extractFields(source) {
|
|
405
|
+
const fields = [];
|
|
406
|
+
const re = /@FindBy\s*\(([^)]*)\)[^;]*?(?:@(\w+)\s*\(\s*\)\s*)?(?:public|private|protected)?\s+(?:WebElement|WebComponent)\s+(\w+)\s*;/g;
|
|
407
|
+
let m;
|
|
408
|
+
while ((m = re.exec(source)) !== null) {
|
|
409
|
+
const attrs = m[1] ?? '';
|
|
410
|
+
const stratMatch = /(\w+)\s*=\s*"([^"]*)"/.exec(attrs);
|
|
411
|
+
fields.push({
|
|
412
|
+
name: m[3],
|
|
413
|
+
locatorStrategy: stratMatch ? stratMatch[1] : undefined,
|
|
414
|
+
locatorValue: stratMatch ? stratMatch[2] : undefined,
|
|
415
|
+
elementType: m[2],
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return fields;
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=pageObjectValidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageObjectValidate.js","sourceRoot":"","sources":["../../../src/mcp/tools/pageObjectValidate.ts"],"names":[],"mappings":"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"}
|