Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,14 @@ Validates an XML test case for schema correctness (validity score) and best prac
- **`APEX-CONNECT-ARGS-001`** (`apexConnectValidArguments`, critical) — an `ApexConnect` step using an argument id outside the 20-id whitelist (overridable per rule via `check.validArgumentIds`).
- **`APEX-CONNECT-CONNID-001`** (`apexConnectConnectionIdValueClass`, critical) — an `ApexConnect` `connectionId` value that uses `valueClass="string"` (or any non-`id` class) instead of `valueClass="id"`; leave it empty if there is no GUID.
- **`APEX-REUSE-CONN-001`** (`apexConnectReuseConnection`, major) — an `ApexConnect` `reuseConnectionName` argument that carries a value; it must be left blank.
- **Runtime anti-pattern rules** — Major (`weight 5`) checks for XML that loads but silently misbehaves at runtime — typically variable references or expressions written as plain string literals. Like the rules above they run offline / in `local_fallback` and keep score parity with the Quality Hub back-end. Currently enforced:
- **`VAR-STRING-LITERAL-001`** (`varStringLiteral`) — an argument value is a whole-token `{VarName}` / `{Obj.Field}` stored as `class="value" valueClass="string"`; Provar passes the literal text instead of resolving the variable. Use `<value class="variable">`. (The interpolation-tolerant target args `sfUiTargetObjectId` / `sfUiTargetResultName` are exempt.) Emits one violation per offending value.
- **`ASSERT-STR-VAR-001`** (`assertValuesStringExpr`) — an `AssertValues` `expectedValue`/`actualValue` is a whole `{…}` string literal, so the assertion compares the literal text instead of the variable's value. Use `class="variable"`.
- **`SETVALUES-FUNC-STR-001`** (`setValuesFuncCallString`) — a `SetValues` assigned value embeds a `{Func(args)}` call as a string literal; Provar will not evaluate it. Use a `class="funcCall"` value.
- **`SETVALUES-ZERO-IDX-001`** (`setValuesZeroIndexString`) — a `SetValues` string-template expression uses a `[0]` index; Provar string templates are 1-indexed, so this is out-of-bounds at runtime. Use `[1]` for the first item (or the XML variable-path structure).
- **`CONN-DB-002`** (`dbConnectResultNameMismatch`) — a DB operation (`SqlQuery`/`DbRead`/`DbInsert`/`DbUpdate`/`DbDelete`) sets a `dbConnectionName` that does not match any `DbConnect` `resultName` in the test, so the open connection can't be found. Defers to `CONN-DB-001` when there is no `DbConnect` at all.
- **`UI-LOCATOR-BUTTON-CASING-001`** (`uiLocatorButtonCasing`) — a `UiDoAction` locator uses a wrong-cased standard-button name: `name=Cancel` (use lowercase `name=cancel`) or `name=Continue`/`name=continue` on the record-type screen (use `name=save&path=selectRecordType`).
- **`UI-LOCATOR-RECORDTYPE-001`** (`uiLocatorRecordTypeField`) — a `UiDoAction` Record Type picker locator uses `name=recordTypeId`/`name=recordType` instead of `name=RecordType` with `field=RecordTypeId` in the binding.

**Error codes**

Expand Down
111 changes: 111 additions & 0 deletions src/mcp/rules/provar_best_practices_rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -2958,6 +2958,117 @@
},
"notes": "Mirrors QH UiActionNestingStructureValidator (lambda/src/validator/best_practices_engine.py). Emits one violation per offending step so that (rule_id, test_item_id) de-dups against the API. UiWithRow plays a dual role: itself a UI action that must be nested, and a container whose substeps clause satisfies the rule for its descendants.",
"source": "Field observation: flat-emitted UI actions (sibling of UiWithScreen) fail to render in Provar IDE despite scoring 100/94 in earlier local validation"
},
{
"id": "VAR-STRING-LITERAL-001",
"category": "TestCaseDesign",
"name": "Variable reference stored as plain string",
"description": "An argument value contains a {VarName} or {Obj.Field} pattern stored as class=\"value\" valueClass=\"string\". Provar passes the literal string to the API instead of resolving the variable — the step will silently receive the wrong input.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Replace with <value class=\"variable\"><path element=\"VarName\"/></value>. Use dotted paths for nested references: <path element=\"Obj\"/><path element=\"Field\"/>. If using provar.testcase.generate, the {VarName} syntax in attributes is converted automatically.",
"check": {
"type": "varStringLiteral"
},
"source": "Provar Test Step Schema: variable references must use class=\"variable\", not string literals"
},
{
"id": "CONN-DB-002",
"category": "ConnectionsAndEnvironments",
"name": "DbConnect resultName must match dbConnectionName in DB operations",
"description": "The resultName set on a DbConnect step is the connection handle variable that all subsequent DB operations (SqlQuery, DbRead, DbInsert, DbUpdate, DbDelete) must reference via their dbConnectionName argument. A mismatch between DbConnect resultName and dbConnectionName causes a runtime failure because the operation cannot find the open connection. This is the leading cause of silent Database step failures in Provar test suites.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Ensure every DB operation step's dbConnectionName argument exactly matches the resultName set on the preceding DbConnect step. For example, if DbConnect sets resultName='SQLServer', every SqlQuery/DbRead/DbInsert/DbUpdate/DbDelete in the same test must set dbConnectionName='SQLServer'.",
"check": {
"type": "dbConnectResultNameMismatch",
"target": "testCase"
},
"source": "Provar DB Connection Best Practices - DbConnect resultName / dbConnectionName alignment"
},
{
"id": "SETVALUES-FUNC-STR-001",
"category": "StructureAndGrouping",
"name": "SetValues must not use string interpolation for function calls",
"description": "SetValues steps must use the correct XML structure for function calls (<value class=\"funcCall\">) rather than embedding Provar's curly-brace template syntax as a plain string literal (e.g. {Count(AccountList)}). At runtime Provar reads the string literally and does not evaluate it, so the target variable is set to the text \"{Count(AccountList)}\" instead of the computed count. This pattern is generated by AI models that reproduce the Provar UI tooltip syntax verbatim.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Replace the string literal with the proper funcCall XML: <value class=\"funcCall\" id=\"Count\"><argument id=\"value\"><value class=\"variable\"><path element=\"ListVariableName\"/></value></argument></value>. Supported functions include Count, Sum, Avg, Min, Max, Concat, StringLength, etc.",
"check": {
"type": "setValuesFuncCallString",
"target": "step"
},
"notes": "AI models output {Count(var)} in a valueClass=string element because they mirror Provar's UI tooltip. The correct form is a funcCall value element. This causes silent test failures where the variable receives the literal string rather than the computed value.",
"source": "Field observation: SetValues function-call string interpolation anti-pattern"
},
{
"id": "SETVALUES-ZERO-IDX-001",
"category": "StructureAndGrouping",
"name": "SetValues string expression must not use [0] index",
"description": "Provar's string-template engine is 1-indexed: {List[1]} accesses the first element. Using {List[0].Field} in a valueClass=string expression causes an out-of-bounds exception at runtime because index 0 is invalid in the template system. Note: the XML variable-path structure (<filter class=\"index\"><index valueClass=\"decimal\">0</index>) correctly uses 0-based indexing via a different code path — this rule targets only the broken string-template form.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Either switch to the proper XML variable path structure (<value class=\"variable\"><path element=\"List\"><filter class=\"index\"><index valueClass=\"decimal\">0</index></filter></path><path element=\"FieldName\"/></value>) or, if you must use string interpolation, change [0] to [1] to access the first element.",
"check": {
"type": "setValuesZeroIndexString",
"target": "step"
},
"notes": "AI models that generate string-template expressions derive index numbers from the literal test intent (e.g. 'first item = index 0') but Provar string templates are 1-indexed. This causes runtime out-of-bounds errors.",
"source": "Field observation: SetValues zero-index string interpolation anti-pattern"
},
{
"id": "ASSERT-STR-VAR-001",
"category": "StructureAndGrouping",
"name": "AssertValues must not use string literal to reference a variable",
"description": "AssertValues steps must use a proper XML variable reference (<value class=\"variable\">) when comparing against a stored variable. Using a string literal that wraps a variable name — e.g. <value class=\"value\" valueClass=\"string\">{RowCount}</value> — causes Provar to compare the literal text \"{RowCount}\" against the actual value, which always produces a false failure. The same applies to function-call expressions such as {Count(Results)}.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Replace the string literal with a proper variable reference: <value class=\"variable\"><path element=\"RowCount\"/></value>. For function calls, use a preceding SetValues step to compute the value into a variable, then reference that variable in AssertValues.",
"check": {
"type": "assertValuesStringExpr",
"target": "step"
},
"notes": "AI models generate {VarName} in a valueClass=string element on the expectedValue side because they reproduce the Provar UI display format. The correct form is a class=variable element. This causes every assertion to fail with a string-vs-value mismatch.",
"source": "Field observation: AssertValues string-variable reference anti-pattern"
},
{
"id": "UI-LOCATOR-BUTTON-CASING-001",
"category": "TestCaseDesign",
"name": "Standard Salesforce flow buttons must use correct locator pattern",
"description": "Standard Salesforce flow buttons must use the correct locator name. Cancel must use lowercase 'name=cancel'. The Continue button on the Record Type selection screen uses a special path-based locator 'name=save&path=selectRecordType' — using 'name=continue' or 'name=Continue' will not resolve and causes Provar to show 'Not Available' at runtime. AI models commonly generate these incorrectly.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Cancel button: use name=cancel (lowercase). Continue button on record type selection: use name=save&path=selectRecordType (NOT name=continue or name=Continue). Corpus-validated patterns from 2000+ real test cases.",
"check": {
"type": "uiLocatorButtonCasing",
"target": "step",
"apiId": "com.provar.plugins.forcedotcom.core.ui.UiDoAction"
},
"notes": "Corpus analysis: Cancel uses name=cancel (10 occurrences) vs name=Cancel (4). Continue on record type selection consistently uses name=save&path=selectRecordType across all corpus examples.",
"source": "Corpus analysis: AllPOCProjects + InternalProjects (2108 test cases)"
},
{
"id": "UI-LOCATOR-RECORDTYPE-001",
"category": "TestCaseDesign",
"name": "Record Type field locator must use name=RecordType not name=recordTypeId",
"description": "On the Record Type selection screen (action=recordTypeNew), the Record Type picker field must use 'name=RecordType' in the locator URI with 'field=RecordTypeId' in the binding. AI models commonly generate 'name=recordTypeId' (the camelCase API name), which causes Provar to show 'Not Available' and the step fails at runtime.",
"appliesTo": ["Step"],
"severity": "major",
"weight": 5,
"recommendation": "Use name=RecordType (not name=recordTypeId or name=recordType) with field=RecordTypeId in the binding. Correct example: ui:locator?name=RecordType&binding=sf%3Aui%3Abinding%3Aobject%3Fobject%3D%7BtargetUrl%3Aobject%7D%26field%3DRecordTypeId",
"check": {
"type": "uiLocatorRecordTypeField",
"target": "step",
"apiId": "com.provar.plugins.forcedotcom.core.ui.UiDoAction"
},
"notes": "Corpus analysis: 258 occurrences of name=RecordType+field=RecordTypeId vs 0 occurrences of name=recordTypeId. The {targetUrl:object} binding resolves dynamically to the current screen's object.",
"source": "Corpus analysis: AllPOCProjects + InternalProjects (2108 test cases)"
}
]
}
Loading
Loading