Skip to content

Commit e04d43c

Browse files
Merge pull request #247 from duranbe/no-xpath-rule
feat: add rule to disallow usage of cypress-xpath
2 parents 9f2b565 + 873c7a0 commit e04d43c

File tree

6 files changed

+93
-0
lines changed

6 files changed

+93
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ These rules enforce some of the [best practices recommended for using Cypress](h
5454
| [no-force](docs/rules/no-force.md) | disallow using `force: true` with action commands | |
5555
| [no-pause](docs/rules/no-pause.md) | disallow using `cy.pause()` calls | |
5656
| [no-unnecessary-waiting](docs/rules/no-unnecessary-waiting.md) | disallow waiting for arbitrary time periods ||
57+
| [no-xpath](docs/rules/no-xpath.md) | disallow using `cy.xpath()` calls | |
5758
| [require-data-selectors](docs/rules/require-data-selectors.md) | require `data-*` attribute selectors | |
5859
| [unsafe-to-chain-command](docs/rules/unsafe-to-chain-command.md) | disallow actions within chains ||
5960

docs/rules/no-xpath.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Disallow using `cy.xpath()` calls (`cypress/no-xpath`)
2+
3+
<!-- end auto-generated rule header -->
4+
5+
This rule disallows the usage of `cy.xpath()` for selecting elements.
6+
7+
## Rule Details
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
cy.xpath('//div[@class=\"container\"]').click()
13+
```
14+
15+
Examples of **correct** code for this rule:
16+
17+
```js
18+
cy.get('[data-cy="container"]').click();
19+
```
20+
21+
## Further Reading
22+
23+
Both `@cypress/xpath` and `cypress-xpath` are deprecated.
24+
25+
See [the Cypress Best Practices guide](https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements).

legacy.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = {
1212
'no-force': require('./lib/rules/no-force'),
1313
'no-pause': require('./lib/rules/no-pause'),
1414
'no-debug': require('./lib/rules/no-debug'),
15+
'no-xpath': require('./lib/rules/no-xpath'),
1516
},
1617
configs: {
1718
recommended: require('./lib/config/recommended'),

lib/flat.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const plugin = {
1515
'no-force': require('./rules/no-force'),
1616
'no-pause': require('./rules/no-pause'),
1717
'no-debug': require('./rules/no-debug'),
18+
'no-xpath': require('./rules/no-xpath'),
1819
},
1920
}
2021

lib/rules/no-xpath.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict'
2+
3+
module.exports = {
4+
meta: {
5+
type: 'suggestion',
6+
docs: {
7+
description: 'disallow using `cy.xpath()` calls',
8+
recommended: false,
9+
url: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-xpath.md'
10+
},
11+
fixable: null, // Or `code` or `whitespace`
12+
schema: [], // Add a schema if the rule has options
13+
messages: {
14+
unexpected: 'Avoid using cy.xpath command',
15+
},
16+
},
17+
18+
create (context) {
19+
return {
20+
CallExpression (node) {
21+
if (isCallingCyXpath(node)) {
22+
context.report({ node, messageId: 'unexpected' })
23+
}
24+
},
25+
}
26+
},
27+
};
28+
29+
function isCallingCyXpath (node) {
30+
return node.callee.type === 'MemberExpression' &&
31+
node.callee.object.type === 'Identifier' &&
32+
node.callee.object.name === 'cy' &&
33+
node.callee.property.type === 'Identifier' &&
34+
node.callee.property.name === 'xpath'
35+
}

tests/lib/rules/no-xpath.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"use strict";
2+
3+
//------------------------------------------------------------------------------
4+
// Requirements
5+
//------------------------------------------------------------------------------
6+
7+
const rule = require("../../../lib/rules/no-xpath"),
8+
RuleTester = require("eslint").RuleTester;
9+
10+
//------------------------------------------------------------------------------
11+
// Tests
12+
//------------------------------------------------------------------------------
13+
14+
const ruleTester = new RuleTester();
15+
ruleTester.run("no-xpath", rule, {
16+
valid: [
17+
{ code: 'cy.get("button").click({force: true})' },
18+
],
19+
20+
invalid: [
21+
{
22+
code: "cy.xpath('//div[@class=\"container\"]/p[1]').click()",
23+
errors: [{ messageId: "unexpected" }],
24+
},
25+
{
26+
code: "cy.xpath('//p[1]').should('exist')",
27+
errors: [{ messageId: "unexpected" }]
28+
}
29+
],
30+
});

0 commit comments

Comments
 (0)