diff --git a/README.md b/README.md index 70aa4e0..ab32cf7 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ There are various types of rules implemented in the plugin. Here is a rough cate * [no-get-location-abs-url][]: Warn about using deprecated `getLocationAbsUrl()` method * [no-promise-in-if][]: Warn if promise is checked for truthiness inside an `if` condition * [bare-element-finders][]: Warn if a bare `ElementFinder` or `ElementArrayFinder` is declared with no applied action +* [empty-script][]: Warn if `executeScript()` or `executeAsyncScript()` are called with missing or empty script #### Locating Elements @@ -137,6 +138,7 @@ Rule | Default Error Level | Auto-fixable | Options [valid-by-tagname][] | 1 | | [limit-selector-depth][] | 1 | | number of nodes (default 5) [bare-element-finders][] | 1 | | +[empty-script][] | 1 | | [use-promise-all][] | 0 (Turned off) | | [by-css-shortcut][] | 0 | | [no-browser-driver][] | 0 | | @@ -195,6 +197,7 @@ See [configuring rules][] for more information. [no-get-raw-id]: docs/rules/no-get-raw-id.md [no-get-location-abs-url]: docs/rules/no-get-location-abs-url.md [bare-element-finders]: docs/rules/bare-element-finders.md +[empty-script]: docs/rules/empty-script.md [configuring rules]: http://eslint.org/docs/user-guide/configuring#configuring-rules ## Recommended configuration diff --git a/docs/rules/empty-script.md b/docs/rules/empty-script.md new file mode 100644 index 0000000..a8ab0c6 --- /dev/null +++ b/docs/rules/empty-script.md @@ -0,0 +1,23 @@ +# Warn if `executeScript()` or `executeAsyncScript()` are called with missing or empty script + +This is a simple rule that would warn if `executeScript()`/`executeAsyncScript()` calls are missing arguments, or if the first argument is an empty string. + +## Rule details + +:thumbsdown: Any use of the following patterns are considered warnings: + +```js +browser.executeScript(); +browser.executeAsyncScript(); +browser.executeScript(""); +browser.executeAsyncScript(''); +``` + +:thumbsup: The following patterns are not errors: + +```js +browser.executeScript("var a = 1;"); +browser.executeAsyncScript("var a = 1;"); +var tag = browser.executeScript('return arguments[0].tagName', el); +browser.executeAsyncScript('var callback = arguments[arguments.length - 1];'); +``` diff --git a/index.js b/index.js index 692686e..55346bc 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,7 @@ var noGetRawId = require('./lib/rules/no-get-raw-id') var noGetLocationAbsUrl = require('./lib/rules/no-get-location-abs-url') var limitSelectorDepth = require('./lib/rules/limit-selector-depth') var bareElementFinders = require('./lib/rules/bare-element-finders') +var emptyScript = require('./lib/rules/empty-script') module.exports = { rules: { @@ -76,7 +77,8 @@ module.exports = { 'no-get-raw-id': noGetRawId, 'no-get-location-abs-url': noGetLocationAbsUrl, 'limit-selector-depth': limitSelectorDepth, - 'bare-element-finders': bareElementFinders + 'bare-element-finders': bareElementFinders, + 'empty-script': emptyScript }, configs: { recommended: { @@ -115,6 +117,7 @@ module.exports = { 'protractor/limit-selector-depth': 1, 'protractor/no-get-location-abs-url': 1, 'protractor/bare-element-finders': 1, + 'protractor/empty-script': 1, 'protractor/use-promise-all': 0, 'protractor/by-css-shortcut': 0, 'protractor/no-browser-driver': 0 diff --git a/lib/rules/empty-script.js b/lib/rules/empty-script.js new file mode 100644 index 0000000..78eccd6 --- /dev/null +++ b/lib/rules/empty-script.js @@ -0,0 +1,44 @@ +'use strict' + +/** + * @fileoverview Warn if `executeScript()` or `executeAsyncScript()` are called with no arguments + * @author Alexander Afanasyev + */ + +module.exports = { + meta: { + schema: [] + }, + + create: function (context) { + return { + 'CallExpression': function (node) { + var object = node.callee.object + var property = node.callee.property + + if (object && property && object.name === 'browser') { + if (property.name === 'executeScript' || property.name === 'executeAsyncScript') { + var argumentExists = node.arguments && node.arguments.length + + if (!argumentExists) { + context.report({ + node: property, + message: property.name + '() call without arguments' + }) + + return + } + + var firstArgumentNonEmpty = argumentExists && node.arguments[0].value + if (!firstArgumentNonEmpty) { + context.report({ + node: property, + message: property.name + '() called with an empty script' + }) + } + } + } + } + } + } +} diff --git a/test/rules/empty-script.js b/test/rules/empty-script.js new file mode 100644 index 0000000..5302816 --- /dev/null +++ b/test/rules/empty-script.js @@ -0,0 +1,42 @@ +'use strict' + +var rule = require('../../lib/rules/empty-script') +var RuleTester = require('eslint').RuleTester + +var eslintTester = new RuleTester() + +eslintTester.run('empty-script', rule, { + valid: [ + 'browser.executeScript("var a = 1;");', + 'browser.executeAsyncScript("var a = 1;");', + 'var tag = browser.executeScript("return arguments[0].tagName", el);', + 'browser.executeAsyncScript("var callback = arguments[arguments.length - 1];");' + ], + + invalid: [ + { + code: 'browser.executeScript();', + errors: [{ + message: 'executeScript() call without arguments' + }] + }, + { + code: 'browser.executeAsyncScript();', + errors: [{ + message: 'executeAsyncScript() call without arguments' + }] + }, + { + code: 'browser.executeScript("");', + errors: [{ + message: 'executeScript() called with an empty script' + }] + }, + { + code: 'browser.executeAsyncScript("");', + errors: [{ + message: 'executeAsyncScript() called with an empty script' + }] + } + ] +})