Linting
UTAM provides the ability to statically analyze JSON files to prevent common bad practices, such as duplication of page objects or violations of the encapsulation pattern.
We encourage you not to disable any linting rules and to make sure that your page objects comply with recommended best practices.
This documentation is relevant for UTAM Java versions after 2.0.4 and UTAM JavaScript versions after 2.1.2. Prior to these versions UTAM also produced console output from the linter, this is no longer the case.
Run linting
Linting is run during the page object compilation process. All warnings and errors are printed into a Static Analysis Results Interchange Format (SARIF) report generated after compilation.
SARIF is a common format to store linting results. UTAM creates utam-lint.sarif
in the SARIF JSON format, which looks like this:
{
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "UTAM",
"semanticVersion": "2.1.0",
"informationUri": "https://github.com/salesforce/utam-java",
"rules": [
{
"id": "ULR01",
"name": "Unique local selectors",
"shortDescription": {
"text": "Check for unique selectors inside the same file. By default, this is a warning because a list element can have the same selector."
}
}
// other rules
]
}
},
// all page objects being analyzed
"artifacts": [
{
"description": {
"text": "page object utam/pageObjects/test"
},
"location": {
"uri": "src/test/resources/lint/changeDefaultConfig/test.utam.json",
"uriBaseId": "%srcroot%",
"index": 0
}
}
],
// violations
"results": [
{
"ruleId": "ULR02",
"message": {
"text": "root description is missing",
"id": "2002"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/test/resources/lint/changeDefaultConfig/test.utam.json",
"uriBaseId": "%srcroot%",
"index": 0
},
"region": {
"startLine": 2
}
}
}
],
"fixes": [
{
"description": {
"text": "add \"author\" property to the root description"
}
}
]
}
]
}
]
}
Linting report
The SARIF file is in JSON format. To view (pretty print) SARIF files in a terminal or in your IDE, use available tools, such as sarif-fmt or Sarif VSCode extension.
If at least one linting violation of level error
occurs and the throwError
configuration parameter is set to true
(see the next section), the page object compiler throws an exception.
A file in SARIF format can be integrated with development tools such as GitHub to show linting rule violations:
GitHub documentation is here.
Configuring linting rules and violations
All linting rules and violation types (error or warning) are configurable as lint
properties in the compiler configuration.
If a compiler configuration doesn't have a lint
section, default values are applied.
{
"lint": {
"lintingOutputFile": "utam-lint.sarif",
"disable": false,
"throwError": false,
"<name of the rule>": {
"violation": "error",
"exclude": []
},
"<name of the rule>": {
"violation": "error",
"exclude": ["my/test/component1", "my/test/component2"]
},
"<name of the rule>": {
"violation": "warning"
}
}
}
-
lintingOutputFile
String, default is"utam-lint.sarif"
. This parameter sets the path for a SARIF log file generated by the UTAM linter. The path is relative to the root of the project. -
disable
Boolean, default isfalse
. If set totrue
, linting rules are not applied after the compilation. -
throwError
Boolean, default isfalse
. If set totrue
, the linting process throws an error after reporting errors to the log. -
<name of the rule>
is one of the rules listed in the next section.violation
The violation type. Possible values are:warning
,error
, ordisabled
(disable the rule). Starting from compiler versions 2.0.3 (utam-js) and 2.0.2 (utam-java), the default is alwayswarning
.exclude
Is an array of strings that are excluded from the rule. Each string value is a page object URI.additionalConfiguration
Is an object containing additional configuration data for the rule, if any applies. See the rule description for information about what additional configuration the rule supports.
Linting rules
Note: Rules with error codes that start with 2 are applicable for one page object only. Rules with error codes that start with 3 are relevant for multiple page objects only, such as detecting duplicates from the earlier example.
duplicateSelectors
- Rule: page object elements in the same scope (with the same immediate parent) can't have duplicate selectors except if one of the elements is a list.
- How to fix: remove one or more duplicate elements.
- Error code: 2001
- Default violation type:
warning
Example:
{
"elements": [
{
"name": "element1",
"selector": {
"css": "css"
}
},
{
// violation - same selector as element1
"name": "element2",
"selector": {
"css": "css"
},
"elements": [
{
// not a violation - element has a different parent
"name": "element3",
"selector": {
"css": "css"
}
},
{
// not a violation - element is a list
"name": "element4",
"selector": {
"css": "css",
"returnAll": true
}
}
]
}
]
}
requiredRootDescription
- Rule: it's a good practice to provide a description at the page object root level to explain the intended usage of the page object.
- How to fix: add a page object description.
- Error code: 2002
- Default violation type:
warning
Example:
{
// violation - description is empty
"elements": []
}
requiredAuthor
- Rule: The page object description should include an author.
- How to fix: add an author property to the description.
- Error code: 2005
- Default violation type:
warning
Example:
{
// violation - description has no author
"description": "description is a string"
}
{
// not a violation - author is provided
"description": {
"text": ["description is a string"],
"author": "myTeam"
}
}
requiredMethodDescription
- Rule: it's a good practice to provide a description at the method level that explains the use cases. This rule isn't applied to elements; it's for compose methods only.
- How to fix: add a method description.
- Error code: 2003
- Default violation type:
warning
Example:
{
"description": "root description here",
"methods": [
{
// violation - description is empty
"name": "doSomething",
"compose": []
}
]
}
duplicateRootSelectors
- Rule: two page objects with the same root selector usually means a violation of the encapsulation rule (1:1 mapping between a component and a page object).
- How to fix: remove the duplicate page object. Make sure that you keep all functionality.
- Error code: 3001
- Default violation type:
warning
Example:
{
// first page object
"root": true,
"selector": {
"css": "my-root"
}
}
{
// second page object
"root": true,
"selector": {
// violation - same root selector
"css": "my-root"
}
}
elementCantHaveRootSelector
- Rule: if an element has the same selector as the root selector of a different page object, it should have the same type as the given page object.
- How to fix: add the proper type, which is the type of the page object with the root selector.
- Error code: 3002
- Default violation type:
warning
Example:
{
// first page object my/test/Component
"root": true,
"selector": {
"css": "my-root"
}
}
{
// second page object
"elements": [
{
// violation - element should have the proper type
"name": "element1",
"selector": {
"css": "my-root"
}
},
{
// not a violation - element has the proper type
"name": "element2",
"type": "my/test/Component",
"selector": {
"css": "my-root"
}
}
]
}
duplicateCustomSelectors
- Rule: if an element in one page object has a custom type and a custom selector (with "-"), any element with the same selector in a different page object should have the same custom type.
- How to fix: change the element type to custom.
- Error code: 3003
- Default violation type:
warning
Example:
{
// first page object
"elements": [
{
"name": "customElement",
"type": "my/test/Component",
"selector": {
"css": "my-test-component"
}
},
{
"name": "basicElement",
"selector": {
"css": ".myClass"
}
}
]
}
{
// second page object
"elements": [
{
// violation - set type to "my/test/Component"
"name": "basicElement1",
"selector": {
"css": "my-test-component"
}
},
{
// not a violation - basic elements can have the same selectors
"name": "basicElement2",
"selector": {
"css": ".myClass"
}
}
]
}
requiredMetadata
- Rule: if a page object does not contain a
metadata
property, or the object value of themetadata
property does not contain the specified values. - How to fix: add a metadata object containing mandatory fields (if any) to the page object.
- Error code: 2006
- Default violation type:
disabled
- Note:
additionalConfiguration
should contain arequiredProperties
array, which will contain objects defining the required properties in the metadata.
Example:
{
// Compiler configuration lint section
"lint": {
"lintingOutputFile": "utam-lint.sarif",
"disable": false,
"throwError": false,
"requiredMetadata": {
"violation": "warning",
"exclude": [],
"additionalConfiguration": {
"requiredProperties": [
{
"name": "firstRequiredProperty"
},
{
"name": "secondRequiredProperty",
"values": ["allowedValue1", "allowedValue2", "allowedValue3"]
}
]
}
}
}
}
{
// violation: page object has no metadata property
"elements": [
{
"name": "basicElement1",
"selector": {
"css": ".my-test-component"
}
}
]
}
{
"metadata": {
// violation: metadata object does not contain "firstRequiredProperty"
// property with a non-empty value
// violation: "secondRequiredProperty" value is not one of the acceptable
// values for the property
"secondRequiredProperty": "invalidValue"
},
"elements": [
{
"name": "basicElement1",
"selector": {
"css": ".my-test-component"
}
}
]
}