Skip to content

Commit 9d62e67

Browse files
committed
feat(rules): add 'no-execute-script' rule
1 parent f9f9c79 commit 9d62e67

File tree

6 files changed

+268
-1
lines changed

6 files changed

+268
-1
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,15 @@ Rule | Default | Options
5353
[no-absolute-url][] | 1 |
5454
[no-expect-in-po][] | 1 | requires plugin "settings"
5555
[no-promise-in-if][] | 1 |
56+
[no-execute-script][] | 1 | requires plugin "settings"
5657
[by-css-shortcut][] | 0 |
5758

5859
For example, the `missing-perform` rule is enabled by default and will cause
5960
ESLint to throw an error (with an exit code of `1`) when triggered.
6061

62+
The `requires plugin "settings"` note indicates that a rule needs the plugin to have configured settings in your eslint config.
63+
For example, `no-execute-script` rule expects configured paths to either spec, or page object files, or both.
64+
6165
You may customise each rule by adding a value in your `.eslintrc` `rules`
6266
property:
6367

@@ -88,6 +92,7 @@ See [configuring rules][] for more information.
8892
[by-css-shortcut]: docs/rules/by-css-shortcut.md
8993
[no-expect-in-po]: docs/rules/no-expect-in-po.md
9094
[no-promise-in-if]: docs/rules/no-promise-in-if.md
95+
[no-execute-script]: docs/rules/no-execute-script.md
9196
[configuring rules]: http://eslint.org/docs/user-guide/configuring#configuring-rules
9297

9398
## Recommended configuration

docs/rules/no-execute-script.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Recommend against executing scripts in specs and page objects
2+
3+
This rule disallows using `browser.executeScript()` or `browser.executeAsyncScript()` or `browser.driver.executeScript()` or `browser.driver.executeAsyncScript()` inside spec files and page objects.
4+
Executing scripts should rather be a part of "helpers" or "libs".
5+
6+
**Important:** This rule requires plugin `settings` to have the configured "glob"-style paths (see [`minimatch`](https://github.com/isaacs/minimatch) to learn more about the supported "glob" syntax) to distinguish Page Object and Spec files from others.
7+
8+
Edit your ESLint config and add (this is example configuration):
9+
10+
settings: {
11+
"eslint-plugin-protractor":
12+
paths: {
13+
po: ["**/test/e2e/po/*.po.js"],
14+
specs: ["**/test/e2e/specs/*.spec.js"]
15+
}
16+
}
17+
}
18+
19+
If neither `po`, nor `specs` is specified, the rule would be disabled.
20+
21+
*Note: Because ESLint uses absolute paths and it is difficult to correctly locate base path of your project from within a plugin, so it is highly suggested to use complete paths to files you want to match to leverage the risk of targeting wrong directories and files.*
22+
23+
## Rule details
24+
25+
This rule would warn if it sees `browser.executeScript()` or `browser.executeAsyncScript()` or `browser.driver.executeScript()` or `browser.driver.executeAsyncScript()` function calls inside a file that matches at least one of the patterns configured in paths/po and paths/specs arrays.

index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var arrayCallbackReturn = require('./lib/rules/array-callback-return')
1818
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')
21+
var noExecuteScript = require('./lib/rules/no-execute-script')
2122

2223
module.exports = {
2324
rules: {
@@ -38,7 +39,8 @@ module.exports = {
3839
'array-callback-return': arrayCallbackReturn,
3940
'no-absolute-url': noAbsoluteURL,
4041
'no-expect-in-po': noExpectInPO,
41-
'no-promise-in-if': noPromiseInIf
42+
'no-promise-in-if': noPromiseInIf,
43+
'no-execute-script': noExecuteScript
4244
},
4345
configs: {
4446
recommended: {
@@ -60,6 +62,7 @@ module.exports = {
6062
'protractor/no-absolute-url': 1,
6163
'protractor/no-expect-in-po': 1,
6264
'protractor/no-promise-in-if': 1,
65+
'protractor/no-execute-script': 1,
6366
'protractor/by-css-shortcut': 0
6467
},
6568
globals: {

lib/is-browser-execute-script.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview Utility function to determine if a node is a browser.executeScript() or browser.driver.executeScript() or browser.executeAsyncScript() or browser.driver.executeAsyncScript() call
5+
* @author Alexander Afanasyev
6+
*/
7+
module.exports = function (node) {
8+
var object = node.callee.object
9+
var property = node.callee.property
10+
11+
if (object && property) {
12+
var isExecuteScript = property.name === 'executeScript'
13+
var isExecuteAsyncScript = property.name === 'executeAsyncScript'
14+
15+
if (isExecuteScript || isExecuteAsyncScript) {
16+
var isBrowser = object.name === 'browser'
17+
var isBrowserDriver = object.object && object.object.name === 'browser' &&
18+
object.property && object.property.name === 'driver'
19+
if (isBrowser || isBrowserDriver) {
20+
var objectName = isBrowser ? 'browser' : 'browser.driver'
21+
var methodName = isExecuteScript ? 'executeScript()' : 'executeAsyncScript()'
22+
return objectName + '.' + methodName
23+
}
24+
}
25+
}
26+
27+
return false
28+
}

lib/rules/no-execute-script.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview Recommend against executing scripts in specs and page objects
5+
* @author Alexander Afanasyev
6+
*/
7+
8+
var isBrowserExecuteScript = require('../is-browser-execute-script')
9+
10+
var PLUGIN_NAME = 'eslint-plugin-protractor'
11+
var multimatch = require('multimatch')
12+
13+
module.exports = {
14+
meta: {
15+
schema: []
16+
},
17+
18+
create: function (context) {
19+
// do nothing if appropriate settings are not present
20+
var settings = context.settings
21+
if (!settings || !settings[PLUGIN_NAME] || !settings[PLUGIN_NAME].paths || !(settings[PLUGIN_NAME].paths.po || settings[PLUGIN_NAME].paths.specs)) {
22+
return {}
23+
}
24+
25+
// get glob matches
26+
var filename = context.getFilename()
27+
var patternsPO = settings[PLUGIN_NAME].paths.po || []
28+
var patternsSpecs = settings[PLUGIN_NAME].paths.specs || []
29+
var matches = multimatch(filename, patternsPO.concat(patternsSpecs))
30+
31+
// do nothing if a filename does not match pre-configured patterns
32+
if (matches.length === 0) {
33+
return {}
34+
}
35+
36+
return {
37+
'CallExpression': function (node) {
38+
var result = isBrowserExecuteScript(node)
39+
40+
if (result) {
41+
context.report({
42+
node: node,
43+
message: 'Unexpected "' + result + '"'
44+
})
45+
}
46+
}
47+
}
48+
}
49+
}

test/rules/no-execute-script.js

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
'use strict'
2+
3+
var rule = require('../../lib/rules/no-execute-script')
4+
var RuleTester = require('eslint').RuleTester
5+
var eslintTester = new RuleTester()
6+
7+
eslintTester.run('no-execute-script', rule, {
8+
valid: [
9+
{
10+
code: 'var test = "bar"'
11+
},
12+
13+
{
14+
code: 'browser.executeScript("return 1;");'
15+
},
16+
17+
{
18+
code: 'browser.executeScript("return 2;");',
19+
settings: {
20+
'eslint-plugin-protractor': {
21+
paths: {
22+
po: ['*.txt']
23+
}
24+
}
25+
},
26+
filename: '/usr/app/test/e2e/specs/test.spec.js'
27+
},
28+
29+
{
30+
code: 'browser.executeScript("return 3;");',
31+
settings: {
32+
'eslint-plugin-protractor': {
33+
paths: {
34+
specs: ['*.somethingelse.js']
35+
}
36+
}
37+
},
38+
filename: 'test.spec.js'
39+
},
40+
41+
{
42+
code: 'browser.executeScript("return 4;");',
43+
settings: {
44+
'eslint-plugin-protractor': {
45+
paths: {
46+
po: [],
47+
specs: []
48+
}
49+
}
50+
},
51+
filename: 'test.po.js'
52+
},
53+
54+
{
55+
code: 'browser.executeScript("return 5;");',
56+
settings: {
57+
'eslint-plugin-protractor': {
58+
paths: {
59+
specs: ['*.somethingelse1.js', '*.somethingelse2.js']
60+
}
61+
}
62+
},
63+
filename: 'test.spec.js'
64+
},
65+
66+
{
67+
code: 'browser.get("url");',
68+
settings: {
69+
'eslint-plugin-protractor': {
70+
paths: {
71+
specs: ['**/*.spec.js', '*.spec.js']
72+
}
73+
}
74+
},
75+
filename: 'test.spec.js'
76+
}
77+
],
78+
79+
invalid: [
80+
{
81+
code: 'browser.executeScript("return -1;");',
82+
settings: {
83+
'eslint-plugin-protractor': {
84+
paths: {
85+
po: ['**/po/*.po.js']
86+
}
87+
}
88+
},
89+
filename: '/var/app/test/e2e/po/test.po.js',
90+
errors: [{
91+
message: 'Unexpected "browser.executeScript()"'
92+
}]
93+
},
94+
95+
{
96+
code: 'browser.executeAsyncScript("return -2;");',
97+
settings: {
98+
'eslint-plugin-protractor': {
99+
paths: {
100+
specs: ['**/*.spec.js']
101+
}
102+
}
103+
},
104+
filename: '/var/app/test/e2e/specs/test.spec.js',
105+
errors: [{
106+
message: 'Unexpected "browser.executeAsyncScript()"'
107+
}]
108+
},
109+
110+
{
111+
code: 'browser.driver.executeScript("return -3;");',
112+
settings: {
113+
'eslint-plugin-protractor': {
114+
paths: {
115+
po: ['**/*.somethingelse1.js', '**/*.po.js', '**/*.somethingelse2.js']
116+
}
117+
}
118+
},
119+
filename: '/var/app/test/e2e/po/test.po.js',
120+
errors: [{
121+
message: 'Unexpected "browser.driver.executeScript()"'
122+
}]
123+
},
124+
125+
{
126+
code: 'browser.driver.executeAsyncScript("return -4;");',
127+
settings: {
128+
'eslint-plugin-protractor': {
129+
paths: {
130+
po: [],
131+
specs: ['**/*.somethingelse1.js', '**/*.spec.js', '**/*.somethingelse2.js']
132+
}
133+
}
134+
},
135+
filename: '/var/app/test/e2e/specs/test.spec.js',
136+
errors: [{
137+
message: 'Unexpected "browser.driver.executeAsyncScript()"'
138+
}]
139+
},
140+
141+
{
142+
code: 'browser.executeAsyncScript("return -5;");',
143+
settings: {
144+
'eslint-plugin-protractor': {
145+
paths: {
146+
po: ['**/*.po.js'],
147+
specs: ['**/*.somethingelse1.js', '**/*.somethingelse2.js']
148+
}
149+
}
150+
},
151+
filename: '/var/app/test/e2e/po/test.po.js',
152+
errors: [{
153+
message: 'Unexpected "browser.executeAsyncScript()"'
154+
}]
155+
}
156+
]
157+
})

0 commit comments

Comments
 (0)