eslint-plugin-cypress 2.11.1 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -3
- package/docs/rules/no-pause.md +16 -0
- package/index.js +1 -0
- package/lib/rules/no-assigning-return-values.js +2 -2
- package/lib/rules/no-force.js +1 -1
- package/lib/rules/no-pause.js +56 -0
- package/lib/rules/no-unnecessary-waiting.js +2 -1
- package/package.json +1 -1
- package/tests/lib/rules/no-force.js +8 -7
- package/tests/lib/rules/no-pause.js +33 -0
- package/tests/lib/rules/no-unnecessary-waiting.js +23 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install eslint-plugin-cypress --save-dev
|
|
|
11
11
|
```
|
|
12
12
|
or
|
|
13
13
|
```sh
|
|
14
|
-
yarn add eslint-plugin-cypress --
|
|
14
|
+
yarn add eslint-plugin-cypress --dev
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
@@ -35,12 +35,13 @@ You can add rules:
|
|
|
35
35
|
"cypress/no-unnecessary-waiting": "error",
|
|
36
36
|
"cypress/assertion-before-screenshot": "warn",
|
|
37
37
|
"cypress/no-force": "warn",
|
|
38
|
-
"cypress/no-async-tests": "error"
|
|
38
|
+
"cypress/no-async-tests": "error",
|
|
39
|
+
"cypress/no-pause": "error"
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
You can
|
|
44
|
+
You can allow certain globals provided by Cypress:
|
|
44
45
|
|
|
45
46
|
```json
|
|
46
47
|
{
|
|
@@ -62,6 +63,51 @@ Use the recommended configuration and you can forego configuring _plugins_, _rul
|
|
|
62
63
|
}
|
|
63
64
|
```
|
|
64
65
|
|
|
66
|
+
## Disable rules
|
|
67
|
+
|
|
68
|
+
You can disable specific rules per file, for a portion of a file, or for a single line.
|
|
69
|
+
|
|
70
|
+
Disable the `cypress/no-unnecessary-waiting` rule for the entire file by placing this at the start of the file:
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
/* eslint-disable cypress/no-unnecessary-waiting */
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Disable the `cypress/no-unnecessary-waiting` rule for a portion of the file:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
it('waits for a second', () => {
|
|
80
|
+
...
|
|
81
|
+
/* eslint-disable cypress/no-unnecessary-waiting */
|
|
82
|
+
cy.wait(1000)
|
|
83
|
+
/* eslint-enable cypress/no-unnecessary-waiting */
|
|
84
|
+
...
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Disable the `cypress/no-unnecessary-waiting` rule for a specific line:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
it('waits for a second', () => {
|
|
92
|
+
...
|
|
93
|
+
cy.wait(1000) // eslint-disable-line cypress/no-unnecessary-waiting
|
|
94
|
+
...
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can also disable a rule for the next line:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
it('waits for a second', () => {
|
|
102
|
+
...
|
|
103
|
+
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
104
|
+
cy.wait(1000)
|
|
105
|
+
...
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For more, see the [ESLint rules](https://eslint.org/docs/user-guide/configuring/rules) documentation.
|
|
110
|
+
|
|
65
111
|
## Rules
|
|
66
112
|
|
|
67
113
|
These rules enforce some of the [best practices recommended for using Cypress](https://on.cypress.io/best-practices).
|
|
@@ -78,6 +124,7 @@ Rules with a check mark (✅) are enabled by default while using the `plugin:cyp
|
|
|
78
124
|
| | [no-force](./docs/rules/no-force.md) | Disallow using `force: true` with action commands |
|
|
79
125
|
| | [assertion-before-screenshot](./docs/rules/assertion-before-screenshot.md) | Ensure screenshots are preceded by an assertion |
|
|
80
126
|
| | [require-data-selectors](./docs/rules/require-data-selectors.md) | Only allow data-\* attribute selectors (require-data-selectors) |
|
|
127
|
+
| | [no-pause](./docs/rules/no-pause.md) | Disallow `cy.pause()` parent command |
|
|
81
128
|
|
|
82
129
|
## Chai and `no-unused-expressions`
|
|
83
130
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Do not use `cy.pause` command
|
|
2
|
+
|
|
3
|
+
It is recommended to remove [cy.pause](https://on.cypress.io/pause) command before committing the specs to avoid other developers getting unexpected results.
|
|
4
|
+
|
|
5
|
+
Invalid:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
cy.pause();
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Valid:
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
// only the parent cy.pause command is detected
|
|
15
|
+
cy.get('selector').pause();
|
|
16
|
+
```
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ module.exports = {
|
|
|
8
8
|
'assertion-before-screenshot': require('./lib/rules/assertion-before-screenshot'),
|
|
9
9
|
'require-data-selectors': require('./lib/rules/require-data-selectors'),
|
|
10
10
|
'no-force': require('./lib/rules/no-force'),
|
|
11
|
+
'no-pause': require('./lib/rules/no-pause'),
|
|
11
12
|
},
|
|
12
13
|
configs: {
|
|
13
14
|
recommended: require('./lib/config/recommended'),
|
|
@@ -39,7 +39,7 @@ module.exports = {
|
|
|
39
39
|
},
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const allowedCommands = {
|
|
43
43
|
now: true,
|
|
44
44
|
spy: true,
|
|
45
45
|
state: true,
|
|
@@ -61,7 +61,7 @@ function isCypressCommandDeclaration (declarator) {
|
|
|
61
61
|
|
|
62
62
|
const parent = get(object, 'parent.property.name') || get(declarator, 'id.name')
|
|
63
63
|
|
|
64
|
-
if (commandName && (
|
|
64
|
+
if (commandName && (allowedCommands[commandName] || allowedCommands[parent])) return
|
|
65
65
|
|
|
66
66
|
return object.name === 'cy'
|
|
67
67
|
}
|
package/lib/rules/no-force.js
CHANGED
|
@@ -42,7 +42,7 @@ module.exports = {
|
|
|
42
42
|
|
|
43
43
|
return node.arguments && node.arguments.length &&
|
|
44
44
|
node.arguments.some((arg) => {
|
|
45
|
-
return arg.type === 'ObjectExpression' && arg.properties.some((propNode) => propNode.key.name === 'force')
|
|
45
|
+
return arg.type === 'ObjectExpression' && arg.properties.some((propNode) => propNode.key && propNode.key.name === 'force')
|
|
46
46
|
})
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
//------------------------------------------------------------------------------
|
|
4
|
+
// Rule Definition
|
|
5
|
+
//------------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
meta: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Disallow using of \'cy.pause\' calls',
|
|
11
|
+
category: 'Possible Errors',
|
|
12
|
+
recommended: false,
|
|
13
|
+
},
|
|
14
|
+
fixable: null, // or "code" or "whitespace"
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
unexpected: 'Do not use cy.pause command',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
create (context) {
|
|
22
|
+
|
|
23
|
+
// variables should be defined here
|
|
24
|
+
|
|
25
|
+
//----------------------------------------------------------------------
|
|
26
|
+
// Helpers
|
|
27
|
+
//----------------------------------------------------------------------
|
|
28
|
+
function isCallingPause (node) {
|
|
29
|
+
return node.callee &&
|
|
30
|
+
node.callee.property &&
|
|
31
|
+
node.callee.property.type === 'Identifier' &&
|
|
32
|
+
node.callee.property.name === 'pause'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isCypressCall (node) {
|
|
36
|
+
return node.callee &&
|
|
37
|
+
node.callee.type === 'MemberExpression' &&
|
|
38
|
+
node.callee.object.type === 'Identifier' &&
|
|
39
|
+
node.callee.object.name === 'cy'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//----------------------------------------------------------------------
|
|
43
|
+
// Public
|
|
44
|
+
//----------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
|
|
48
|
+
CallExpression (node) {
|
|
49
|
+
if (isCypressCall(node) && isCallingPause(node)) {
|
|
50
|
+
context.report({ node, messageId: 'unexpected' })
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
}
|
|
@@ -56,7 +56,8 @@ function isIdentifierNumberConstArgument (node, scope) {
|
|
|
56
56
|
|
|
57
57
|
if (node.arguments[0].type !== 'Identifier') return false
|
|
58
58
|
|
|
59
|
-
const
|
|
59
|
+
const identifier = node.arguments[0]
|
|
60
|
+
const resolvedIdentifier = scope.references.find((ref) => ref.identifier === identifier).resolved
|
|
60
61
|
const definition = resolvedIdentifier.defs[0]
|
|
61
62
|
const isVariable = definition.type === 'Variable'
|
|
62
63
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ const rule = require('../../../lib/rules/no-force')
|
|
|
9
9
|
const RuleTester = require('eslint').RuleTester
|
|
10
10
|
|
|
11
11
|
const errors = [{ messageId: 'unexpected' }]
|
|
12
|
-
const parserOptions = { ecmaVersion:
|
|
12
|
+
const parserOptions = { ecmaVersion: 2018 }
|
|
13
13
|
|
|
14
14
|
//------------------------------------------------------------------------------
|
|
15
15
|
// Tests
|
|
@@ -24,12 +24,13 @@ ruleTester.run('no-force', rule, {
|
|
|
24
24
|
{ code: `cy.get('button').click({multiple: true})`, parserOptions },
|
|
25
25
|
{ code: `cy.get('button').dblclick()`, parserOptions },
|
|
26
26
|
{ code: `cy.get('input').type('somth')`, parserOptions },
|
|
27
|
-
{ code: `cy.get('input').type('somth', {anyoption: true})`, parserOptions
|
|
28
|
-
{ code: `cy.get('input').trigger('click', {anyoption: true})`, parserOptions
|
|
29
|
-
{ code: `cy.get('input').rightclick({anyoption: true})`, parserOptions
|
|
30
|
-
{ code: `cy.get('input').check()`, parserOptions
|
|
31
|
-
{ code: `cy.get('input').select()`, parserOptions
|
|
32
|
-
{ code: `cy.get('input').focus()`, parserOptions
|
|
27
|
+
{ code: `cy.get('input').type('somth', {anyoption: true})`, parserOptions },
|
|
28
|
+
{ code: `cy.get('input').trigger('click', {anyoption: true})`, parserOptions },
|
|
29
|
+
{ code: `cy.get('input').rightclick({anyoption: true})`, parserOptions },
|
|
30
|
+
{ code: `cy.get('input').check()`, parserOptions },
|
|
31
|
+
{ code: `cy.get('input').select()`, parserOptions },
|
|
32
|
+
{ code: `cy.get('input').focus()`, parserOptions },
|
|
33
|
+
{ code: `cy.document().trigger("keydown", { ...event })`, parserOptions },
|
|
33
34
|
],
|
|
34
35
|
|
|
35
36
|
invalid: [
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
//------------------------------------------------------------------------------
|
|
4
|
+
// Requirements
|
|
5
|
+
//------------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
const rule = require('../../../lib/rules/no-pause')
|
|
8
|
+
|
|
9
|
+
const RuleTester = require('eslint').RuleTester
|
|
10
|
+
|
|
11
|
+
const errors = [{ messageId: 'unexpected' }]
|
|
12
|
+
const parserOptions = { ecmaVersion: 2018 }
|
|
13
|
+
|
|
14
|
+
//------------------------------------------------------------------------------
|
|
15
|
+
// Tests
|
|
16
|
+
//------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
const ruleTester = new RuleTester()
|
|
19
|
+
|
|
20
|
+
ruleTester.run('no-pause', rule, {
|
|
21
|
+
|
|
22
|
+
valid: [
|
|
23
|
+
// for now, we do not detect .pause() child command
|
|
24
|
+
{ code: `cy.get('button').pause()`, parserOptions },
|
|
25
|
+
{ code: `pause()`, parserOptions },
|
|
26
|
+
{ code: `cy.get('button').dblclick()`, parserOptions },
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
invalid: [
|
|
30
|
+
{ code: `cy.pause()`, parserOptions, errors },
|
|
31
|
+
{ code: `cy.pause({ log: false })`, parserOptions, errors },
|
|
32
|
+
],
|
|
33
|
+
})
|
|
@@ -26,6 +26,29 @@ ruleTester.run('no-unnecessary-waiting', rule, {
|
|
|
26
26
|
{ code: 'const customWait = (alias = "@someRequest") => { cy.wait(alias) }', parserOptions, errors },
|
|
27
27
|
{ code: 'function customWait (ms) { cy.wait(ms) }', parserOptions, errors },
|
|
28
28
|
{ code: 'const customWait = (ms) => { cy.wait(ms) }', parserOptions, errors },
|
|
29
|
+
|
|
30
|
+
// disable the eslint rule
|
|
31
|
+
{
|
|
32
|
+
code: `
|
|
33
|
+
cy.wait(100); // eslint-disable-line no-unnecessary-waiting
|
|
34
|
+
`,
|
|
35
|
+
parserOptions,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
code: `
|
|
39
|
+
/* eslint-disable-next-line no-unnecessary-waiting */
|
|
40
|
+
cy.wait(100)
|
|
41
|
+
`,
|
|
42
|
+
parserOptions,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
code: `
|
|
46
|
+
/* eslint-disable no-unnecessary-waiting */
|
|
47
|
+
cy.wait(100)
|
|
48
|
+
/* eslint-enable no-unnecessary-waiting */
|
|
49
|
+
`,
|
|
50
|
+
parserOptions,
|
|
51
|
+
},
|
|
29
52
|
],
|
|
30
53
|
|
|
31
54
|
invalid: [
|