Skip to content

Commit 640eeef

Browse files
committed
feat(rules): add 'no-compound-classes' rule
1 parent 65a6b5c commit 640eeef

File tree

6 files changed

+143
-1
lines changed

6 files changed

+143
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Rule | Default Error Level | Auto-fixable | Options
4747
[no-invalid-selectors][] | 2 | |
4848
[no-array-finder-methods][] | 2 | |
4949
[valid-locator-type][] | 2 | |
50+
[no-compound-classes][] | 2 | |
5051
[missing-wait-message][] | 1 (Warning) | |
5152
[no-browser-sleep][] | 1 | |
5253
[no-by-xpath][] | 1 | |
@@ -115,6 +116,7 @@ See [configuring rules][] for more information.
115116
[use-promise-all]: docs/rules/use-promise-all.md
116117
[no-array-finder-methods]: docs/rules/no-array-finder-methods.md
117118
[valid-locator-type]: docs/rules/valid-locator-type.md
119+
[no-compound-classes]: docs/rules/no-compound-classes.md
118120
[configuring rules]: http://eslint.org/docs/user-guide/configuring#configuring-rules
119121

120122
## Recommended configuration

docs/rules/no-compound-classes.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Do not allow compound class names in the by.className locator
2+
3+
Ensure that there are no compound class names (multiple space-delimited classes) used as a value for the `by.className` locator.
4+
5+
`by.className()` expects a single valid class name.
6+
7+
## Rule details
8+
9+
Any use of the following patterns are considered errors:
10+
11+
```js
12+
element(by.className("class1 class2"));
13+
element.all(by.className("class1 class2"));
14+
element(by.id("myid")).all(by.className("class1 class2 class3"));
15+
element(by.id("myid")).element(by.className("class1 class2 class3"));
16+
```
17+
18+
The following patterns are not errors:
19+
20+
```js
21+
element(by.css("tag1 tag2"));
22+
element(by.css(".class1"));
23+
element(by.className("class1"));
24+
element.all(by.className("somevalue"));
25+
element.all(by.css("tag1 tag2"));
26+
$("tag1 tag2");
27+
$$("tag1 tag2")
28+
```

index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var noInvalidSelectors = require('./lib/rules/no-invalid-selectors')
2828
var usePromiseAll = require('./lib/rules/use-promise-all')
2929
var noArrayFinderMethods = require('./lib/rules/no-array-finder-methods')
3030
var validLocatorType = require('./lib/rules/valid-locator-type')
31+
var noCompoundClasses = require('./lib/rules/no-compound-classes')
3132

3233
module.exports = {
3334
rules: {
@@ -58,7 +59,8 @@ module.exports = {
5859
'no-invalid-selectors': noInvalidSelectors,
5960
'use-promise-all': usePromiseAll,
6061
'no-array-finder-methods': noArrayFinderMethods,
61-
'valid-locator-type': validLocatorType
62+
'valid-locator-type': validLocatorType,
63+
'no-compound-classes': noCompoundClasses
6264
},
6365
configs: {
6466
recommended: {
@@ -69,6 +71,7 @@ module.exports = {
6971
'protractor/no-invalid-selectors': 2,
7072
'protractor/no-array-finder-methods': 2,
7173
'protractor/valid-locator-type': 2,
74+
'protractor/no-compound-classes': 2,
7275
'protractor/missing-wait-message': 1,
7376
'protractor/no-browser-sleep': 1,
7477
'protractor/no-by-xpath': 1,

lib/find-locator.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview Utility function to determine if a node contains a given Protractor locator
5+
* @author Alexander Afanasyev
6+
*/
7+
module.exports = function (node, locator) {
8+
var object = node.callee.object
9+
var property = node.callee.property
10+
11+
return object && property && object.name === 'by' && property.name === locator
12+
}

lib/rules/no-compound-classes.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview Do not allow compound class names in the by.className locator
5+
* @author Alexander Afanasyev
6+
*/
7+
var isLocator = require('../find-locator')
8+
9+
module.exports = {
10+
meta: {
11+
schema: []
12+
},
13+
14+
create: function (context) {
15+
return {
16+
'CallExpression': function (node) {
17+
if (node.arguments && node.arguments.length && node.arguments[0].hasOwnProperty('value')) {
18+
if (isLocator(node, 'className')) {
19+
var locatorValue = node.arguments[0].value.trim()
20+
21+
if (locatorValue.indexOf(' ') >= 0) {
22+
context.report({
23+
node: node,
24+
message: 'No compound class names allowed.'
25+
})
26+
}
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}

test/rules/no-compound-classes.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict'
2+
3+
var rule = require('../../lib/rules/no-compound-classes')
4+
var RuleTester = require('eslint').RuleTester
5+
6+
var eslintTester = new RuleTester()
7+
8+
eslintTester.run('no-compound-classes', rule, {
9+
valid: [
10+
'element(by.css("tag1 tag2"));',
11+
'element(by.css(".class1"));',
12+
'element(by.className("class1"));',
13+
'element.all(by.className("somevalue"));',
14+
'element.all(by.css("tag1 tag2"));',
15+
'$("tag1 tag2");',
16+
'$$("tag1 tag2");',
17+
'element.all(by.className());',
18+
'element(by.className(""));',
19+
'by.className();',
20+
'someotherfunction()'
21+
],
22+
23+
invalid: [
24+
{
25+
code: 'element(by.className("class1 class2"));',
26+
errors: [
27+
{
28+
message: 'No compound class names allowed.'
29+
}
30+
]
31+
},
32+
{
33+
code: 'element.all(by.className("class1 class2"));',
34+
errors: [
35+
{
36+
message: 'No compound class names allowed.'
37+
}
38+
]
39+
},
40+
{
41+
code: 'element.all(by.className("class1 class2 class3"));',
42+
errors: [
43+
{
44+
message: 'No compound class names allowed.'
45+
}
46+
]
47+
},
48+
{
49+
code: 'element(by.id("myid")).all(by.className("class1 class2 class3"));',
50+
errors: [
51+
{
52+
message: 'No compound class names allowed.'
53+
}
54+
]
55+
},
56+
{
57+
code: 'element(by.id("myid")).element(by.className("class1 class2 class3"));',
58+
errors: [
59+
{
60+
message: 'No compound class names allowed.'
61+
}
62+
]
63+
}
64+
]
65+
})

0 commit comments

Comments
 (0)