eslint-plugin-cypress 2.12.1 → 2.13.0
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/.github/workflows/add-issue-triage-board.yml +12 -0
- package/.github/workflows/triage_closed_issue_comment.yml +9 -0
- package/README.md +2 -1
- package/docs/rules/no-unnecessary-waiting.md +1 -1
- package/docs/rules/unsafe-to-chain-command.md +3 -0
- package/lib/config/recommended.js +1 -0
- package/lib/rules/unsafe-to-chain-command.js +47 -0
- package/package.json +1 -1
- package/tests/lib/rules/unsafe-to-chain-command.js +20 -0
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ Disable the `cypress/no-unnecessary-waiting` rule for the entire file by placing
|
|
|
73
73
|
/* eslint-disable cypress/no-unnecessary-waiting */
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Disable the `cypress/no-unnecessary-waiting` rule for a portion of the file:
|
|
76
|
+
Disable the `cypress/no-unnecessary-waiting` rule for only a portion of the file:
|
|
77
77
|
|
|
78
78
|
```js
|
|
79
79
|
it('waits for a second', () => {
|
|
@@ -121,6 +121,7 @@ Rules with a check mark (✅) are enabled by default while using the `plugin:cyp
|
|
|
121
121
|
| ✅ | [no-assigning-return-values](./docs/rules/no-assigning-return-values.md) | Prevent assigning return values of cy calls |
|
|
122
122
|
| ✅ | [no-unnecessary-waiting](./docs/rules/no-unnecessary-waiting.md) | Prevent waiting for arbitrary time periods |
|
|
123
123
|
| ✅ | [no-async-tests](./docs/rules/no-async-tests.md) | Prevent using async/await in Cypress test case |
|
|
124
|
+
| ✅ | [unsafe-to-chain-command](./docs/rules/unsafe-to-chain-command.md) | Prevent chaining from unsafe to chain commands |
|
|
124
125
|
| | [no-force](./docs/rules/no-force.md) | Disallow using `force: true` with action commands |
|
|
125
126
|
| | [assertion-before-screenshot](./docs/rules/assertion-before-screenshot.md) | Ensure screenshots are preceded by an assertion |
|
|
126
127
|
| | [require-data-selectors](./docs/rules/require-data-selectors.md) | Only allow data-\* attribute selectors (require-data-selectors) |
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Actions should be in the end of chains, not in the middle',
|
|
7
|
+
category: 'Possible Errors',
|
|
8
|
+
recommended: true,
|
|
9
|
+
url: 'https://docs.cypress.io/guides/core-concepts/retry-ability#Actions-should-be-at-the-end-of-chains-not-the-middle',
|
|
10
|
+
},
|
|
11
|
+
schema: [],
|
|
12
|
+
messages: {
|
|
13
|
+
unexpected: 'It is unsafe to chain further commands that rely on the subject after this command. It is best to split the chain, chaining again from `cy.` in a next command line.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
create (context) {
|
|
17
|
+
return {
|
|
18
|
+
CallExpression (node) {
|
|
19
|
+
if (isRootCypress(node) && isActionUnsafeToChain(node) && node.parent.type === 'MemberExpression') {
|
|
20
|
+
context.report({ node, messageId: 'unexpected' })
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isRootCypress (node) {
|
|
28
|
+
while (node.type === 'CallExpression') {
|
|
29
|
+
if (node.callee.type !== 'MemberExpression') return false
|
|
30
|
+
|
|
31
|
+
if (node.callee.object.type === 'Identifier' &&
|
|
32
|
+
node.callee.object.name === 'cy') {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
node = node.callee.object
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isActionUnsafeToChain (node) {
|
|
43
|
+
// commands listed in the documentation with text: 'It is unsafe to chain further commands that rely on the subject after xxx'
|
|
44
|
+
const unsafeToChainActions = ['blur', 'clear', 'click', 'check', 'dblclick', 'each', 'focus', 'rightclick', 'screenshot', 'scrollIntoView', 'scrollTo', 'select', 'selectFile', 'spread', 'submit', 'type', 'trigger', 'uncheck', 'wait', 'within']
|
|
45
|
+
|
|
46
|
+
return node.callee && node.callee.property && node.callee.property.type === 'Identifier' && unsafeToChainActions.includes(node.callee.property.name)
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const rule = require('../../../lib/rules/unsafe-to-chain-command')
|
|
4
|
+
const RuleTester = require('eslint').RuleTester
|
|
5
|
+
|
|
6
|
+
const ruleTester = new RuleTester()
|
|
7
|
+
|
|
8
|
+
const errors = [{ messageId: 'unexpected' }]
|
|
9
|
+
const parserOptions = { ecmaVersion: 6 }
|
|
10
|
+
|
|
11
|
+
ruleTester.run('action-ends-chain', rule, {
|
|
12
|
+
valid: [
|
|
13
|
+
{ code: 'cy.get("new-todo").type("todo A{enter}"); cy.get("new-todo").type("todo B{enter}"); cy.get("new-todo").should("have.class", "active");', parserOptions },
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
invalid: [
|
|
17
|
+
{ code: 'cy.get("new-todo").type("todo A{enter}").should("have.class", "active");', parserOptions, errors },
|
|
18
|
+
{ code: 'cy.get("new-todo").type("todo A{enter}").type("todo B{enter}");', parserOptions, errors },
|
|
19
|
+
],
|
|
20
|
+
})
|