Skip to content

Commit bb1c9a8

Browse files
committed
feat(rules): add 'correct-chaining' rule
1 parent 9d62e67 commit bb1c9a8

File tree

5 files changed

+153
-1
lines changed

5 files changed

+153
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Rule | Default | Options
3838
---- | ------- | ---------
3939
[missing-perform][] | 2 |
4040
[no-browser-pause][] | 2 |
41+
[correct-chaining][] | 2 |
4142
[missing-wait-message][] | 1 |
4243
[no-browser-sleep][] | 1 |
4344
[no-by-xpath][] | 1 |
@@ -93,6 +94,7 @@ See [configuring rules][] for more information.
9394
[no-expect-in-po]: docs/rules/no-expect-in-po.md
9495
[no-promise-in-if]: docs/rules/no-promise-in-if.md
9596
[no-execute-script]: docs/rules/no-execute-script.md
97+
[correct-chaining]: docs/rules/correct-chaining.md
9698
[configuring rules]: http://eslint.org/docs/user-guide/configuring#configuring-rules
9799

98100
## Recommended configuration

docs/rules/correct-chaining.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Prohibit incorrect chaining of `element` and `element.all`
2+
3+
A rather common mistake can occur when it is needed to [find multiple elements in the context of an element using chaining](https://github.com/angular/protractor/blob/master/docs/locators.md#finding-sub-elements). Example:
4+
5+
```js
6+
element(by.css('.parent')).element.all(by.css('.child'));
7+
// element IS NOT NEEDED^^^^^^^
8+
```
9+
10+
Correct chaining:
11+
12+
```js
13+
element(by.css('.parent')).all(by.css('.child'));
14+
```
15+
16+
**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line.
17+
18+
## Rule details
19+
20+
Any use of the following patterns are considered warnings:
21+
22+
```js
23+
element(by.css('.parent')).element.all(by.css('.child'));
24+
$('.parent').element.all(by.css('.child'));
25+
element.all(by.css('.child')).first().element.all(by.css('.child'));
26+
$$('.parent').first().element.all(by.css('.child'));
27+
```
28+
29+
The following patterns are not warnings:
30+
31+
```js
32+
element(by.css('.parent')).all(by.css('.child'));
33+
$('.parent').all(by.css('.child'));
34+
element.all(by.css('.child')).first().all(by.css('.child'));
35+
$$('.parent').first().all(by.css('.child'));
36+
element(by.css('.parent')).element(by.css('.child'));
37+
```

index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var noAbsoluteURL = require('./lib/rules/no-absolute-url')
1919
var noExpectInPO = require('./lib/rules/no-expect-in-po')
2020
var noPromiseInIf = require('./lib/rules/no-promise-in-if')
2121
var noExecuteScript = require('./lib/rules/no-execute-script')
22+
var correctChaining = require('./lib/rules/correct-chaining')
2223

2324
module.exports = {
2425
rules: {
@@ -40,13 +41,15 @@ module.exports = {
4041
'no-absolute-url': noAbsoluteURL,
4142
'no-expect-in-po': noExpectInPO,
4243
'no-promise-in-if': noPromiseInIf,
43-
'no-execute-script': noExecuteScript
44+
'no-execute-script': noExecuteScript,
45+
'correct-chaining': correctChaining
4446
},
4547
configs: {
4648
recommended: {
4749
rules: {
4850
'protractor/missing-perform': 2,
4951
'protractor/no-browser-pause': 2,
52+
'protractor/correct-chaining': 2,
5053
'protractor/missing-wait-message': 1,
5154
'protractor/no-browser-sleep': 1,
5255
'protractor/no-by-xpath': 1,

lib/rules/correct-chaining.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview Prohibit incorrect chaining of `element` and `element.all`
5+
* @author Alexander Afanasyev
6+
*/
7+
8+
module.exports = {
9+
meta: {
10+
fixable: 'code',
11+
schema: []
12+
},
13+
14+
create: function (context) {
15+
function isElementAllChained (node) {
16+
var property = node.property
17+
if (property && property.name === 'element') {
18+
var parent = node.parent
19+
if (parent && parent.type === 'MemberExpression') {
20+
var parentProperty = parent.property
21+
return parentProperty && parentProperty.name === 'all'
22+
}
23+
}
24+
return false
25+
}
26+
27+
function createCorrectChainingAutoFixFunction (node) {
28+
var property = node.property
29+
var startRange = property.range[0] - 1 // -1 to get the "." as well
30+
var endRange = property.range[1]
31+
32+
return function (fixer) {
33+
// remove .element from .element.all incorrect chain
34+
if (property && property.name === 'element') { // self-check
35+
return fixer.removeRange([startRange, endRange])
36+
}
37+
}
38+
}
39+
40+
return {
41+
MemberExpression: function (node) {
42+
if (isElementAllChained(node)) {
43+
context.report({
44+
node: node,
45+
message: 'Incorrect "element" and "element.all" chaining detected',
46+
fix: createCorrectChainingAutoFixFunction(node)
47+
})
48+
}
49+
}
50+
}
51+
}
52+
}

test/rules/correct-chaining.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use strict'
2+
3+
var rule = require('../../lib/rules/correct-chaining')
4+
var RuleTester = require('eslint').RuleTester
5+
6+
var eslintTester = new RuleTester()
7+
8+
eslintTester.run('correct-chaining', rule, {
9+
valid: [
10+
'element(by.css(".parent")).all(by.css(".child"));',
11+
'$(".parent").all(by.css(".child"));',
12+
'element.all(by.css(".child")).first().all(by.css(".child"));',
13+
'$$(".parent").first().all(by.css(".child"));',
14+
'element(by.css(".parent")).element(by.css(".child"));',
15+
'element(by.css(".parent"))',
16+
'element.all(by.css(".child"))',
17+
'element.all(by.css(".parent")).all(by.css(".child"))'
18+
],
19+
20+
invalid: [
21+
{
22+
code: 'element(by.css(".parent")).element.all(by.css(".child"));',
23+
errors: [
24+
{
25+
message: 'Incorrect "element" and "element.all" chaining detected'
26+
}
27+
],
28+
output: 'element(by.css(".parent")).all(by.css(".child"));'
29+
},
30+
{
31+
code: '$(".parent").element.all(by.css(".child"));',
32+
errors: [
33+
{
34+
message: 'Incorrect "element" and "element.all" chaining detected'
35+
}
36+
],
37+
output: '$(".parent").all(by.css(".child"));'
38+
},
39+
{
40+
code: 'element.all(by.css(".child")).first().element.all(by.css(".child"));',
41+
errors: [
42+
{
43+
message: 'Incorrect "element" and "element.all" chaining detected'
44+
}
45+
],
46+
output: 'element.all(by.css(".child")).first().all(by.css(".child"));'
47+
},
48+
{
49+
code: '$$(".parent").first().element.all(by.css(".child"));',
50+
errors: [
51+
{
52+
message: 'Incorrect "element" and "element.all" chaining detected'
53+
}
54+
],
55+
output: '$$(".parent").first().all(by.css(".child"));'
56+
}
57+
]
58+
})

0 commit comments

Comments
 (0)