Skip to content

Commit

Permalink
feat(rules): add 'no-compound-classes' rule
Browse files Browse the repository at this point in the history
  • Loading branch information
alecxe committed Dec 3, 2016
1 parent 65a6b5c commit 640eeef
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Rule | Default Error Level | Auto-fixable | Options
[no-invalid-selectors][] | 2 | |
[no-array-finder-methods][] | 2 | |
[valid-locator-type][] | 2 | |
[no-compound-classes][] | 2 | |
[missing-wait-message][] | 1 (Warning) | |
[no-browser-sleep][] | 1 | |
[no-by-xpath][] | 1 | |
Expand Down Expand Up @@ -115,6 +116,7 @@ See [configuring rules][] for more information.
[use-promise-all]: docs/rules/use-promise-all.md
[no-array-finder-methods]: docs/rules/no-array-finder-methods.md
[valid-locator-type]: docs/rules/valid-locator-type.md
[no-compound-classes]: docs/rules/no-compound-classes.md
[configuring rules]: http://eslint.org/docs/user-guide/configuring#configuring-rules

## Recommended configuration
Expand Down
28 changes: 28 additions & 0 deletions docs/rules/no-compound-classes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Do not allow compound class names in the by.className locator

Ensure that there are no compound class names (multiple space-delimited classes) used as a value for the `by.className` locator.

`by.className()` expects a single valid class name.

## Rule details

Any use of the following patterns are considered errors:

```js
element(by.className("class1 class2"));
element.all(by.className("class1 class2"));
element(by.id("myid")).all(by.className("class1 class2 class3"));
element(by.id("myid")).element(by.className("class1 class2 class3"));
```

The following patterns are not errors:

```js
element(by.css("tag1 tag2"));
element(by.css(".class1"));
element(by.className("class1"));
element.all(by.className("somevalue"));
element.all(by.css("tag1 tag2"));
$("tag1 tag2");
$$("tag1 tag2")
```
5 changes: 4 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var noInvalidSelectors = require('./lib/rules/no-invalid-selectors')
var usePromiseAll = require('./lib/rules/use-promise-all')
var noArrayFinderMethods = require('./lib/rules/no-array-finder-methods')
var validLocatorType = require('./lib/rules/valid-locator-type')
var noCompoundClasses = require('./lib/rules/no-compound-classes')

module.exports = {
rules: {
Expand Down Expand Up @@ -58,7 +59,8 @@ module.exports = {
'no-invalid-selectors': noInvalidSelectors,
'use-promise-all': usePromiseAll,
'no-array-finder-methods': noArrayFinderMethods,
'valid-locator-type': validLocatorType
'valid-locator-type': validLocatorType,
'no-compound-classes': noCompoundClasses
},
configs: {
recommended: {
Expand All @@ -69,6 +71,7 @@ module.exports = {
'protractor/no-invalid-selectors': 2,
'protractor/no-array-finder-methods': 2,
'protractor/valid-locator-type': 2,
'protractor/no-compound-classes': 2,
'protractor/missing-wait-message': 1,
'protractor/no-browser-sleep': 1,
'protractor/no-by-xpath': 1,
Expand Down
12 changes: 12 additions & 0 deletions lib/find-locator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'

/**
* @fileoverview Utility function to determine if a node contains a given Protractor locator
* @author Alexander Afanasyev
*/
module.exports = function (node, locator) {
var object = node.callee.object
var property = node.callee.property

return object && property && object.name === 'by' && property.name === locator
}
32 changes: 32 additions & 0 deletions lib/rules/no-compound-classes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict'

/**
* @fileoverview Do not allow compound class names in the by.className locator
* @author Alexander Afanasyev
*/
var isLocator = require('../find-locator')

module.exports = {
meta: {
schema: []
},

create: function (context) {
return {
'CallExpression': function (node) {
if (node.arguments && node.arguments.length && node.arguments[0].hasOwnProperty('value')) {
if (isLocator(node, 'className')) {
var locatorValue = node.arguments[0].value.trim()

if (locatorValue.indexOf(' ') >= 0) {
context.report({
node: node,
message: 'No compound class names allowed.'
})
}
}
}
}
}
}
}
65 changes: 65 additions & 0 deletions test/rules/no-compound-classes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict'

var rule = require('../../lib/rules/no-compound-classes')
var RuleTester = require('eslint').RuleTester

var eslintTester = new RuleTester()

eslintTester.run('no-compound-classes', rule, {
valid: [
'element(by.css("tag1 tag2"));',
'element(by.css(".class1"));',
'element(by.className("class1"));',
'element.all(by.className("somevalue"));',
'element.all(by.css("tag1 tag2"));',
'$("tag1 tag2");',
'$$("tag1 tag2");',
'element.all(by.className());',
'element(by.className(""));',
'by.className();',
'someotherfunction()'
],

invalid: [
{
code: 'element(by.className("class1 class2"));',
errors: [
{
message: 'No compound class names allowed.'
}
]
},
{
code: 'element.all(by.className("class1 class2"));',
errors: [
{
message: 'No compound class names allowed.'
}
]
},
{
code: 'element.all(by.className("class1 class2 class3"));',
errors: [
{
message: 'No compound class names allowed.'
}
]
},
{
code: 'element(by.id("myid")).all(by.className("class1 class2 class3"));',
errors: [
{
message: 'No compound class names allowed.'
}
]
},
{
code: 'element(by.id("myid")).element(by.className("class1 class2 class3"));',
errors: [
{
message: 'No compound class names allowed.'
}
]
}
]
})

0 comments on commit 640eeef

Please sign in to comment.