-
Notifications
You must be signed in to change notification settings - Fork 5
/
unsafe-to-chain-command.js
96 lines (89 loc) · 2.5 KB
/
unsafe-to-chain-command.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/** This rule was copied from the original `eslint-plugin-cypress` so we can use the fork (which
* supports eslint 8) while having the same recommended rules as the upstream
* https://github.com/foretagsplatsen/eslint-plugin-cypress
* https://github.com/cypress-io/eslint-plugin-cypress/blob/c626ad543f65babf1def5caabd1bc9bb9900d2c7/lib/rules/unsafe-to-chain-command.js
*/
// eslint-disable-next-line strict
'use strict';
/** @type {import("eslint").Rule.RuleModule} */
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Actions should be at the end of chains, not in the middle',
category: 'Possible Errors',
recommended: true,
url: 'https://docs.cypress.io/guides/core-concepts/retry-ability#Actions-should-be-at-the-end-of-chains-not-the-middle',
},
schema: [],
fixable: 'code',
messages: {
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 the next command.',
},
},
create(context) {
return {
CallExpression(node) {
if (
isRootCypress(node) &&
isActionUnsafeToChain(node) &&
node.parent.type === 'MemberExpression'
) {
context.report({
node,
messageId: 'unexpected',
});
}
},
};
},
};
/** @param {import("eslint").Rule.Node} node */
function isRootCypress(node) {
while (node.type === 'CallExpression') {
if (node.callee.type !== 'MemberExpression') {
return false;
}
if (
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'cy'
) {
return true;
}
// eslint-disable-next-line no-param-reassign
node = node.callee.object;
}
return false;
}
/** @param {import("eslint").Rule.Node} node */
function isActionUnsafeToChain(node) {
// commands listed in the documentation with text: 'It is unsafe to chain further commands that rely on the subject after xxx'
const unsafeToChainActions = [
'blur',
'clear',
'click',
'check',
'dblclick',
'each',
'focus',
'rightclick',
'screenshot',
'scrollIntoView',
'scrollTo',
'select',
'selectFile',
'spread',
'submit',
'type',
'trigger',
'uncheck',
'within',
];
return (
node.callee &&
node.callee.property &&
node.callee.property.type === 'Identifier' &&
unsafeToChainActions.includes(node.callee.property.name)
);
}