Skip to content

Commit c1f57e2

Browse files
Merge pull request #13 from cypress-io/issue-12-whitelist-returnable-commands
Whitelist returnable commands
2 parents 02391a0 + 91cda77 commit c1f57e2

File tree

5 files changed

+83
-62
lines changed

5 files changed

+83
-62
lines changed

lib/config/recommended.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
'use strict';
1+
'use strict'
22

33
module.exports = {
44
plugins: ['cypress'],
55
rules: {
66
'cypress/no-assigning-return-values': 'error',
7-
'cypress/no-unnecessary-waiting': 'error'
8-
}
9-
};
7+
'cypress/no-unnecessary-waiting': 'error',
8+
},
9+
}

lib/rules/no-assigning-return-values.js

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,64 @@
33
* @author Elad Shahar
44
*/
55

6-
'use strict';
6+
'use strict'
7+
8+
// safely get nested object property
9+
function get (obj, propertyString = '') {
10+
const properties = propertyString.split('.')
11+
for (let i = 0; i < properties.length; i++) {
12+
const value = (obj || {})[properties[i]]
13+
if (value == null) return value
14+
obj = value
15+
}
16+
return obj
17+
}
718

819
module.exports = {
920
meta: {
1021
docs: {
1122
description: 'Prevent assigning return values of cy calls',
1223
category: 'Possible Errors',
1324
recommended: true,
14-
url: 'https://docs.cypress.io/guides/references/best-practices.html#Assigning-Return-Values'
25+
url: 'https://docs.cypress.io/guides/references/best-practices.html#Assigning-Return-Values',
1526
},
1627
schema: [],
1728
messages: {
18-
unexpected: 'Do not assign the return value of a Cypress command'
19-
}
29+
unexpected: 'Do not assign the return value of a Cypress command',
30+
},
2031
},
21-
create(context) {
32+
create (context) {
2233
return {
23-
VariableDeclaration(node) {
34+
VariableDeclaration (node) {
2435
if (node.declarations.some(isCypressCommandDeclaration)) {
25-
context.report({ node, messageId: 'unexpected' });
36+
context.report({ node, messageId: 'unexpected' })
2637
}
27-
}
28-
};
29-
}
30-
};
38+
},
39+
}
40+
},
41+
}
3142

32-
function isCypressCommandDeclaration(declarator) {
33-
if (!declarator) { return; }
34-
if (!declarator.init) { return; }
35-
if (!declarator.init.callee) { return; }
43+
const whitelistedCommands = {
44+
now: true,
45+
spy: true,
46+
state: true,
47+
stub: true,
48+
}
3649

37-
let object = declarator.init.callee.object;
50+
function isCypressCommandDeclaration (declarator) {
51+
let object = get(declarator, 'init.callee.object')
3852

39-
if (!object) { return; }
53+
if (!object) return
4054

4155
while (object.callee) {
42-
object = object.callee.object;
43-
if (!object) {
44-
return;
45-
}
56+
object = object.callee.object
57+
58+
if (!object) return
4659
}
4760

48-
return object.name === 'cy';
61+
const commandName = get(object, 'parent.property.name')
62+
63+
if (commandName && whitelistedCommands[commandName]) return
64+
65+
return object.name === 'cy'
4966
}

lib/rules/no-unnecessary-waiting.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,42 @@
33
* @author Elad Shahar
44
*/
55

6-
'use strict';
6+
'use strict'
77

88
module.exports = {
99
meta: {
1010
docs: {
1111
description: 'Prevent waiting for arbitrary time periods',
1212
category: 'Possible Errors',
1313
recommended: true,
14-
url: 'https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting'
14+
url: 'https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting',
1515
},
1616
schema: [],
1717
messages: {
18-
unexpected: 'Do not wait for arbitrary time periods'
19-
}
18+
unexpected: 'Do not wait for arbitrary time periods',
19+
},
2020
},
21-
create(context) {
21+
create (context) {
2222
return {
23-
CallExpression(node) {
23+
CallExpression (node) {
2424
if (isCallingCyWait(node) && isNumberArgument(node)) {
25-
context.report({ node, messageId: 'unexpected' });
25+
context.report({ node, messageId: 'unexpected' })
2626
}
27-
}
28-
};
29-
}
30-
};
27+
},
28+
}
29+
},
30+
}
3131

32-
function isCallingCyWait(node) {
32+
function isCallingCyWait (node) {
3333
return node.callee.type === 'MemberExpression' &&
3434
node.callee.object.type === 'Identifier' &&
3535
node.callee.object.name === 'cy' &&
3636
node.callee.property.type === 'Identifier' &&
37-
node.callee.property.name === 'wait';
37+
node.callee.property.name === 'wait'
3838
}
3939

40-
function isNumberArgument(node) {
40+
function isNumberArgument (node) {
4141
return node.arguments.length > 0 &&
4242
node.arguments[0].type === 'Literal' &&
43-
typeof(node.arguments[0].value) === 'number';
43+
typeof (node.arguments[0].value) === 'number'
4444
}
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
"use strict";
1+
'use strict'
22

3-
const rule = require('../../../lib/rules/no-assigning-return-values');
4-
const RuleTester = require('eslint').RuleTester;
3+
const rule = require('../../../lib/rules/no-assigning-return-values')
4+
const RuleTester = require('eslint').RuleTester
55

6-
const ruleTester = new RuleTester();
6+
const ruleTester = new RuleTester()
77

8-
const errors = [{ messageId: 'unexpected' }];
9-
const parserOptions = { ecmaVersion: 6 };
8+
const errors = [{ messageId: 'unexpected' }]
9+
const parserOptions = { ecmaVersion: 6 }
1010

1111
ruleTester.run('no-assigning-return-values', rule, {
1212
valid: [
@@ -15,8 +15,12 @@ ruleTester.run('no-assigning-return-values', rule, {
1515
{ code: 'const foo = true;', parserOptions },
1616
{ code: 'const foo = bar();', parserOptions },
1717
{ code: 'const foo = bar().baz();', parserOptions },
18+
{ code: 'const spy = cy.spy();', parserOptions },
19+
{ code: 'const stub = cy.stub();', parserOptions },
20+
{ code: 'const result = cy.now();', parserOptions },
21+
{ code: 'const state = cy.state();', parserOptions },
1822
{ code: 'cy.get("foo");', parserOptions },
19-
{ code: 'cy.contains("foo").click();', parserOptions }
23+
{ code: 'cy.contains("foo").click();', parserOptions },
2024
],
2125

2226
invalid: [
@@ -28,6 +32,6 @@ ruleTester.run('no-assigning-return-values', rule, {
2832
{ code: 'let a = cy.window()', parserOptions, errors },
2933
{ code: 'let a = cy.wait("@something")', parserOptions, errors },
3034

31-
{ code: 'let a = cy.contains("foo").click()', parserOptions, errors }
32-
]
33-
});
35+
{ code: 'let a = cy.contains("foo").click()', parserOptions, errors },
36+
],
37+
})
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
"use strict";
1+
'use strict'
22

3-
const rule = require('../../../lib/rules/no-unnecessary-waiting');
4-
const RuleTester = require('eslint').RuleTester;
3+
const rule = require('../../../lib/rules/no-unnecessary-waiting')
4+
const RuleTester = require('eslint').RuleTester
55

6-
const ruleTester = new RuleTester();
6+
const ruleTester = new RuleTester()
77

8-
const errors = [{ messageId: 'unexpected' }];
9-
const parserOptions = { ecmaVersion: 6 };
8+
const errors = [{ messageId: 'unexpected' }]
9+
const parserOptions = { ecmaVersion: 6 }
1010

1111
ruleTester.run('no-unnecessary-waiting', rule, {
1212
valid: [
@@ -15,14 +15,14 @@ ruleTester.run('no-unnecessary-waiting', rule, {
1515
{ code: 'cy.wait("@someRequest").then((xhr) => xhr)', parserOptions },
1616
{ code: 'cy.wait(["@someRequest", "@anotherRequest"])', parserOptions },
1717

18-
{ code: 'cy.clock(5000)', parserOptions},
18+
{ code: 'cy.clock(5000)', parserOptions },
1919
{ code: 'cy.scrollTo(0, 10)', parserOptions },
20-
{ code: 'cy.tick(500)', parserOptions }
20+
{ code: 'cy.tick(500)', parserOptions },
2121
],
2222

2323
invalid: [
2424
{ code: 'cy.wait(0)', parserOptions, errors },
2525
{ code: 'cy.wait(100)', parserOptions, errors },
26-
{ code: 'cy.wait(5000)', parserOptions, errors }
27-
]
28-
});
26+
{ code: 'cy.wait(5000)', parserOptions, errors },
27+
],
28+
})

0 commit comments

Comments
 (0)