diff --git a/README.md b/README.md index 5806f79..02e4255 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Rule | Default | Options ---- | ------- | ------- [missing-perform][] | 2 | [no-browser-pause][] | 2 | +[no-shadowing][] | 2 | [missing-wait-message][] | 1 | [no-browser-sleep][] | 1 | [no-by-xpath][] | 1 | @@ -61,6 +62,7 @@ See [configuring rules][] for more information. [missing-perform]: docs/rules/missing-perform.md [no-browser-pause]: docs/rules/no-browser-pause.md +[no-shadowing]: docs/rules/no-shadowing.md [missing-wait-message]: docs/rules/missing-wait-message.md [no-browser-sleep]: docs/rules/no-browser-sleep.md [no-by-xpath]: docs/rules/no-by-xpath.md diff --git a/docs/rules/no-shadowing.md b/docs/rules/no-shadowing.md new file mode 100644 index 0000000..5bc8668 --- /dev/null +++ b/docs/rules/no-shadowing.md @@ -0,0 +1,41 @@ +# Don't allow to shadow the built-in Protractor globals + +The rule is to prevent shadowing the built-in Protractor globals, like `element` or `by`. + +## Rule details + +Here is the list of global variables checked for not to be shadowed: + + * `browser` + * `protractor` + * `element` + * `by` + * `$` + * `$$` + +The following patterns are considered warnings: + +```js +var element = "something"; +function test (browser) {}; +var protractor; +function by () {}; +var $ = 1; +var a = 2, $$ = 3; +for (var by = 0; by < 10; ++by) {} +try { json = JSON.parse(input) } catch (browser) {} +switch (element) { case 1: break; default: break; } +``` + +The following patterns are not warnings: + +```js +var element2 = "something"; +element(by.id("test")); +var EC = protractor.ExpectedConditions; +var elm = $(".myclass"); +var elements = $$(".myclass"); +for (var i = 0; i < 10; ++i) {} +try { json = JSON.parse(input) } catch (e) {} +switch (a) { case 1: break; default: break; } +``` diff --git a/index.js b/index.js index 8da7605..c55ad8c 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ module.exports = { rules: { 'missing-perform': require('./lib/rules/missing-perform'), 'no-browser-pause': require('./lib/rules/no-browser-pause'), + 'no-shadowing': require('./lib/rules/no-shadowing'), 'missing-wait-message': require('./lib/rules/missing-wait-message'), 'no-browser-sleep': require('./lib/rules/no-browser-sleep'), 'no-by-xpath': require('./lib/rules/no-by-xpath'), @@ -18,6 +19,7 @@ module.exports = { rules: { 'protractor/missing-perform': 2, 'protractor/no-browser-pause': 2, + 'protractor/no-shadowing': 2, 'protractor/missing-wait-message': 1, 'protractor/no-browser-sleep': 1, 'protractor/no-by-xpath': 1, diff --git a/lib/rules/no-shadowing.js b/lib/rules/no-shadowing.js new file mode 100644 index 0000000..760924e --- /dev/null +++ b/lib/rules/no-shadowing.js @@ -0,0 +1,41 @@ +'use strict' + +/** + * @fileoverview Don't allow to shadow the built-in Protractor globals + * @author Alexander Afanasyev + */ + +module.exports = function (context) { + var protractorGlobals = [ + 'browser', + 'protractor', + 'element', + 'by', + '$', + '$$' + ] + + function checkVariables (node) { + var variables = context.getDeclaredVariables(node) + for (var i = 0; i < variables.length; ++i) { + if (protractorGlobals.indexOf(variables[i].name) !== -1) { + context.report(node, 'Unexpected Protractor built-in global variable shadowing') + } + } + + // handling switch manually - getDeclaredVariables() does not return the switch discriminant + if (node.type === 'SwitchStatement' && node.discriminant) { + if (protractorGlobals.indexOf(node.discriminant.name) !== -1) { + context.report(node, 'Unexpected Protractor built-in global variable shadowing') + } + } + } + + return { + 'VariableDeclaration': checkVariables, + 'FunctionDeclaration': checkVariables, + 'FunctionExpression': checkVariables, + 'CatchClause': checkVariables, + 'SwitchStatement': checkVariables + } +} diff --git a/test/rules/no-shadowing.js b/test/rules/no-shadowing.js new file mode 100644 index 0000000..1c19239 --- /dev/null +++ b/test/rules/no-shadowing.js @@ -0,0 +1,94 @@ +'use strict' + +var rule = require('../../lib/rules/no-shadowing') +var RuleTester = require('eslint').RuleTester + +var eslintTester = new RuleTester() + +eslintTester.run('no-shadowing', rule, { + valid: [ + 'var element2 = "something";', + 'element(by.id("test"));', + 'var EC = protractor.ExpectedConditions;', + 'var elm = $(".myclass");', + 'var elements = $$(".myclass");', + 'for (var i = 0; i < variables.length; ++i) {}', + 'try { json = JSON.parse(input) } catch (e) {}', + 'switch (a) { case 1: break; default: break; }' + ], + + invalid: [ + { + code: 'var element = "something";', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'function test (browser) {};', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'var protractor;', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'function by () {};', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'var $ = 1;', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'var a = 2, $$ = 3;', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'for (var by = 0; by < 10; ++by) {}', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'try { json = JSON.parse(input) } catch (browser) {}', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + }, + { + code: 'switch (element) { case 1: break; default: break; }', + errors: [ + { + message: 'Unexpected Protractor built-in global variable shadowing' + } + ] + } + ] +})