Skip to content

Commit a4a0e8e

Browse files
sandeepbaldawakuceb
authored andcommitted
feat(rule): add 'require-data-selectors' rule (#30)
Only allow `[data-*]` attribute selectors on `cy.get`
1 parent 7fabf07 commit a4a0e8e

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

docs/rules/require-data-selectors.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Only allow `data-*` attribute selectors (require-data-selectors)
2+
only allow `cy.get` to allow selectors that target `data-*` attributes
3+
4+
See [the Cypress Best Practices guide](https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements).
5+
6+
> Note: If you use this rule, consider only using the `warn` error level, since using `data-*` attribute selectors may not always be possible.
7+
8+
### Rule Details
9+
10+
examples of **incorrect** code with `require-data-selectors`:
11+
```js
12+
cy.get(".a")
13+
cy.get('[daedta-cy=submit]').click()
14+
cy.get('[d-cy=submit]')
15+
cy.get(".btn-large").click()
16+
cy.get(".btn-.large").click()
17+
```
18+
19+
examples of **correct** code with `require-data-selectors`:
20+
```js
21+
cy.get('[data-cy=submit]').click()
22+
cy.get('[data-QA=submit]')
23+
```

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
'no-assigning-return-values': require('./lib/rules/no-assigning-return-values'),
66
'no-unnecessary-waiting': require('./lib/rules/no-unnecessary-waiting'),
77
'assertion-before-screenshot': require('./lib/rules/assertion-before-screenshot'),
8+
'require-data-selectors': require('./lib/rules/require-data-selectors'),
89
},
910
configs: {
1011
recommended: require('./lib/config/recommended'),

lib/rules/require-data-selectors.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* @fileoverview Use data-* attribute selectors instead of classes or tag names
3+
* @author Sandeep Baldawa
4+
*/
5+
'use strict'
6+
7+
module.exports = {
8+
meta: {
9+
docs: {
10+
description: 'Use data-* attributes to provide context to your selectors and insulate them from CSS or JS changes https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements',
11+
category: 'Possible Errors',
12+
recommended: false,
13+
url: 'https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements',
14+
},
15+
schema: [],
16+
messages: {
17+
unexpected: 'use data-* attribute selectors instead of classes or tag names',
18+
},
19+
},
20+
21+
create (context) {
22+
return {
23+
CallExpression (node) {
24+
if (isCallingCyGet(node) && !isDataArgument(node)) {
25+
context.report({ node, messageId: 'unexpected' })
26+
}
27+
},
28+
}
29+
},
30+
}
31+
32+
function isCallingCyGet (node) {
33+
return node.callee.type === 'MemberExpression' &&
34+
node.callee.object.type === 'Identifier' &&
35+
node.callee.object.name === 'cy' &&
36+
node.callee.property.type === 'Identifier' &&
37+
node.callee.property.name === 'get'
38+
}
39+
40+
function isDataArgument (node) {
41+
return node.arguments.length > 0 &&
42+
node.arguments[0].type === 'Literal' &&
43+
String(node.arguments[0].value).startsWith('[data-')
44+
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict'
2+
3+
const rule = require('../../../lib/rules/require-data-selectors')
4+
const RuleTester = require('eslint').RuleTester
5+
6+
const ruleTester = new RuleTester()
7+
8+
const errors = [{ messageId: 'unexpected' }]
9+
const parserOptions = { ecmaVersion: 6 }
10+
11+
ruleTester.run('no-dynamic-id-classes', rule, {
12+
valid: [
13+
{ code: 'cy.get(\'[data-cy=submit]\').click()', parserOptions },
14+
{ code: 'cy.get(\'[data-QA=submit]\')', parserOptions },
15+
{ code: 'cy.clock(5000)', parserOptions },
16+
{ code: 'cy.scrollTo(0, 10)', parserOptions },
17+
{ code: 'cy.tick(500)', parserOptions },
18+
],
19+
20+
invalid: [
21+
{ code: 'cy.get(\'[daedta-cy=submit]\').click()', parserOptions, errors },
22+
{ code: 'cy.get(\'[d-cy=submit]\')', parserOptions, errors },
23+
{ code: 'cy.get(".btn-large").click()', parserOptions, errors },
24+
{ code: 'cy.get(".btn-.large").click()', parserOptions, errors },
25+
{ code: 'cy.get(".a")', parserOptions, errors },
26+
],
27+
})

0 commit comments

Comments
 (0)