diff --git a/README.md b/README.md index ef81b79..67ce34f 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ These rules enforce some of the [best practices recommended for using Cypress](h | [no-force](docs/rules/no-force.md) | disallow using `force: true` with action commands | | | [no-pause](docs/rules/no-pause.md) | disallow using `cy.pause()` calls | | | [no-unnecessary-waiting](docs/rules/no-unnecessary-waiting.md) | disallow waiting for arbitrary time periods | ✅ | +| [no-xpath](docs/rules/no-xpath.md) | disallow using `cy.xpath()` calls | | | [require-data-selectors](docs/rules/require-data-selectors.md) | require `data-*` attribute selectors | | | [unsafe-to-chain-command](docs/rules/unsafe-to-chain-command.md) | disallow actions within chains | ✅ | diff --git a/docs/rules/no-xpath.md b/docs/rules/no-xpath.md new file mode 100644 index 0000000..3e03d6f --- /dev/null +++ b/docs/rules/no-xpath.md @@ -0,0 +1,25 @@ +# Disallow using `cy.xpath()` calls (`cypress/no-xpath`) + + + +This rule disallows the usage of `cy.xpath()` for selecting elements. + +## Rule Details + +Examples of **incorrect** code for this rule: + +```js +cy.xpath('//div[@class=\"container\"]').click() +``` + +Examples of **correct** code for this rule: + +```js +cy.get('[data-cy="container"]').click(); +``` + +## Further Reading + +Both `@cypress/xpath` and `cypress-xpath` are deprecated. + +See [the Cypress Best Practices guide](https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements). diff --git a/legacy.js b/legacy.js index 36f2b78..d5a7535 100644 --- a/legacy.js +++ b/legacy.js @@ -12,6 +12,7 @@ module.exports = { 'no-force': require('./lib/rules/no-force'), 'no-pause': require('./lib/rules/no-pause'), 'no-debug': require('./lib/rules/no-debug'), + 'no-xpath': require('./lib/rules/no-xpath'), }, configs: { recommended: require('./lib/config/recommended'), diff --git a/lib/flat.js b/lib/flat.js index 53c4fe4..2e0e9bd 100644 --- a/lib/flat.js +++ b/lib/flat.js @@ -15,6 +15,7 @@ const plugin = { 'no-force': require('./rules/no-force'), 'no-pause': require('./rules/no-pause'), 'no-debug': require('./rules/no-debug'), + 'no-xpath': require('./rules/no-xpath'), }, } diff --git a/lib/rules/no-xpath.js b/lib/rules/no-xpath.js new file mode 100644 index 0000000..1e15763 --- /dev/null +++ b/lib/rules/no-xpath.js @@ -0,0 +1,35 @@ +'use strict' + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'disallow using `cy.xpath()` calls', + recommended: false, + url: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-xpath.md' + }, + fixable: null, // Or `code` or `whitespace` + schema: [], // Add a schema if the rule has options + messages: { + unexpected: 'Avoid using cy.xpath command', + }, + }, + + create (context) { + return { + CallExpression (node) { + if (isCallingCyXpath(node)) { + context.report({ node, messageId: 'unexpected' }) + } + }, + } + }, +}; + +function isCallingCyXpath (node) { + return node.callee.type === 'MemberExpression' && + node.callee.object.type === 'Identifier' && + node.callee.object.name === 'cy' && + node.callee.property.type === 'Identifier' && + node.callee.property.name === 'xpath' +} diff --git a/tests/lib/rules/no-xpath.js b/tests/lib/rules/no-xpath.js new file mode 100644 index 0000000..0ba4e7b --- /dev/null +++ b/tests/lib/rules/no-xpath.js @@ -0,0 +1,30 @@ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/no-xpath"), + RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester(); +ruleTester.run("no-xpath", rule, { + valid: [ + { code: 'cy.get("button").click({force: true})' }, + ], + + invalid: [ + { + code: "cy.xpath('//div[@class=\"container\"]/p[1]').click()", + errors: [{ messageId: "unexpected" }], + }, + { + code: "cy.xpath('//p[1]').should('exist')", + errors: [{ messageId: "unexpected" }] + } + ], +});