-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(rules): add 'limit-selector-depth' rule
- Loading branch information
Showing
6 changed files
with
202 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Warn about potentially complex selectors with too many nodes | ||
|
||
This rule would warn if a CSS selector is too "deep" - has a significant number of nodes in the path. | ||
|
||
For instance, this CSS selector would be considered fragile and complex, because of 6 nodes in the path: | ||
|
||
```css | ||
.content > table > tbody > tr:nth-child(2) > td.cell > input#email | ||
``` | ||
|
||
A simpler version in this case could be (2 nodes): | ||
|
||
```css | ||
.content input#email | ||
``` | ||
|
||
The idea behind this rule is that the more nodes you have in your CSS selector path - the more fragile, the more dependant on the HTML structure of the page it is. | ||
|
||
Number of nodes is configurable, default value is `5`. | ||
|
||
## Rule details | ||
|
||
This rule is based on [`css-selector-parser`](https://github.com/mdevils/node-css-selector-parser) parsing abilities. | ||
|
||
Any use of the following patterns are considered warnings (with the default depth value of `5`): | ||
|
||
```js | ||
element(by.css(".content > table > tbody > tr:nth-child(2) > td.cell > input#email")); | ||
element.all(by.css(".content > table > tbody > tr:nth-child(2) > td.cell > input#email")); | ||
$(".content > table > tbody > tr:nth-child(2) > td.cell > input#email"); | ||
$$(".content > table > tbody > tr:nth-child(2) > td.cell > input#email"); | ||
``` | ||
|
||
The following patterns are not warnings: | ||
|
||
```js | ||
element(by.css(".myclass")); | ||
element.all(by.css(".content input#email")); | ||
$("#email"); | ||
$$("tr:nth-child(2)"); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
'use strict' | ||
|
||
/** | ||
* @fileoverview Utility function to calculate the number of nodes in a given CSS selector | ||
* @author Alexander Afanasyev | ||
*/ | ||
|
||
var parser = require('./get-css-parser') | ||
|
||
module.exports = function (cssSelector) { | ||
var parsedSelector = parser.parse(cssSelector) | ||
|
||
if (!parsedSelector) { | ||
return 0 | ||
} | ||
|
||
var rule = parsedSelector.rule | ||
var depth = 0 | ||
while (rule) { | ||
rule = rule.rule | ||
depth += 1 | ||
} | ||
return depth | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
'use strict' | ||
|
||
/** | ||
* @fileoverview Warn about potentially "deep" CSS selectors with too many nodes in the path | ||
* @author Alexander Afanasyev | ||
*/ | ||
var isCSSLocator = require('../find-css-locator') | ||
var getSelectorDepth = require('../get-selector-depth') | ||
|
||
module.exports = { | ||
meta: { | ||
schema: [ | ||
{ | ||
type: 'integer', | ||
additionalProperties: false | ||
} | ||
] | ||
}, | ||
|
||
create: function (context) { | ||
var maxDepth = context.options.length ? context.options[0] : 5 | ||
|
||
return { | ||
'CallExpression': function (node) { | ||
if (node.arguments && node.arguments.length && node.arguments[0].hasOwnProperty('value')) { | ||
if (isCSSLocator(node)) { | ||
var cssSelector = node.arguments[0].value | ||
var depth = getSelectorDepth(cssSelector) | ||
|
||
if (depth > maxDepth) { | ||
context.report({ | ||
node: node.arguments[0], | ||
message: 'CSS selector has too many nodes.' | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
'use strict' | ||
|
||
var rule = require('../../lib/rules/limit-selector-depth') | ||
var RuleTester = require('eslint').RuleTester | ||
|
||
var eslintTester = new RuleTester() | ||
|
||
eslintTester.run('limit-selector-depth', rule, { | ||
valid: [ | ||
'element(by.css(".myclass"));', | ||
'element.all(by.css(".myclass"));', | ||
'someOtherFunction("input[name=email]");', | ||
{ | ||
options: [ | ||
5 | ||
], | ||
code: 'element(by.css(".content > table > tbody td.cell > input#email"));' | ||
}, | ||
'element(by.css("input.email.email-input.custom-input.other.classValue"));', | ||
{ | ||
options: [ | ||
1 | ||
], | ||
code: '$(".content");' | ||
}, | ||
'$$("");', | ||
'$();' | ||
], | ||
|
||
invalid: [ | ||
{ | ||
code: 'element(by.css(".content > table > tbody > tr:nth-child(2) > td.cell > input#email"));', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
}, | ||
{ | ||
code: 'element(by.css("div div div div div div"));', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
}, | ||
{ | ||
code: 'element(by.css("div > div > div > div > div > div"));', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
}, | ||
{ | ||
options: [ | ||
1 | ||
], | ||
code: '$(".content > table");', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
}, | ||
{ | ||
options: [ | ||
0 | ||
], | ||
code: '$(".content");', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
}, | ||
{ | ||
options: [ | ||
4 | ||
], | ||
code: '$$(".content > table > tbody td.cell > input#email");', | ||
errors: [ | ||
{ | ||
message: 'CSS selector has too many nodes.' | ||
} | ||
] | ||
} | ||
] | ||
}) |