/
no-setup-in-describe.js
135 lines (118 loc) · 3.82 KB
/
no-setup-in-describe.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
'use strict';
const createAstUtils = require('../util/ast');
const FUNCTION = 1;
const DESCRIBE = 2;
// "Pure" nodes are hooks (like `beforeEach`) or `it` calls
const PURE = 3;
function isNestedInDescribeBlock(nesting) {
return (
nesting.length &&
!nesting.includes(PURE) &&
nesting.lastIndexOf(FUNCTION) < nesting.lastIndexOf(DESCRIBE)
);
}
function reportCallExpression(context, callExpression) {
const message = 'Unexpected function call in describe block.';
context.report({
message,
node: callExpression.callee
});
}
function reportMemberExpression(context, memberExpression) {
const message =
'Unexpected member expression in describe block. ' +
'Member expressions may call functions via getters.';
context.report({
message,
node: memberExpression
});
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow setup in describe blocks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-setup-in-describe.md'
},
schema: []
},
create(context) {
const nesting = [];
const astUtils = createAstUtils(context.settings);
const isDescribe = astUtils.buildIsDescribeAnswerer();
const isTestCase = astUtils.buildIsTestCaseAnswerer();
function isPureNode(node) {
return (
astUtils.isHookCall(node) ||
isTestCase(node) ||
astUtils.isSuiteConfigCall(node)
);
}
function handleCallExpressionInDescribe(node) {
if (isPureNode(node)) {
nesting.push(PURE);
} else if (isNestedInDescribeBlock(nesting)) {
reportCallExpression(context, node);
}
}
function isParentDescribe(node) {
return isDescribe(node.parent);
}
return {
CallExpression(node) {
if (isDescribe(node)) {
nesting.push(DESCRIBE);
return;
}
// don't process anything else if the first describe hasn't been processed
if (!nesting.length) {
return;
}
handleCallExpressionInDescribe(node);
},
'CallExpression:exit'(node) {
if (isDescribe(node) || nesting.length && isPureNode(node)) {
nesting.pop();
}
},
MemberExpression(node) {
if (
!isDescribe(node.parent) &&
isNestedInDescribeBlock(nesting)
) {
reportMemberExpression(context, node);
}
},
FunctionDeclaration() {
if (nesting.length) {
nesting.push(FUNCTION);
}
},
'FunctionDeclaration:exit'() {
if (nesting.length) {
nesting.pop();
}
},
FunctionExpression(node) {
if (nesting.length && !isParentDescribe(node)) {
nesting.push(FUNCTION);
}
},
'FunctionExpression:exit'(node) {
if (nesting.length && !isParentDescribe(node)) {
nesting.pop();
}
},
ArrowFunctionExpression(node) {
if (nesting.length && !isParentDescribe(node)) {
nesting.push(FUNCTION);
}
},
'ArrowFunctionExpression:exit'(node) {
if (nesting.length && !isParentDescribe(node)) {
nesting.pop();
}
}
};
}
};