source: frontend/node_modules/eslint-plugin-jest/lib/rules/prefer-expect-assertions.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.2 KB
Line 
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
10var _utils = require("./utils");
11
12const isExpectAssertionsOrHasAssertionsCall = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && expression.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(expression.callee.object, 'expect') && (0, _utils.isSupportedAccessor)(expression.callee.property) && ['assertions', 'hasAssertions'].includes((0, _utils.getAccessorValue)(expression.callee.property));
13
14const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement;
15
16const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
17 messageId: 'suggestRemovingExtraArguments',
18 fix: fixer => fixer.removeRange([args[extraArgsStartAt].range[0] - Math.sign(extraArgsStartAt), args[args.length - 1].range[1]])
19});
20
21const suggestions = [['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']];
22
23var _default = (0, _utils.createRule)({
24 name: __filename,
25 meta: {
26 docs: {
27 category: 'Best Practices',
28 description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`',
29 recommended: false,
30 suggestion: true
31 },
32 messages: {
33 hasAssertionsTakesNoArguments: '`expect.hasAssertions` expects no arguments',
34 assertionsRequiresOneArgument: '`expect.assertions` excepts a single argument of type number',
35 assertionsRequiresNumberArgument: 'This argument should be a number',
36 haveExpectAssertions: 'Every test should have either `expect.assertions(<number of assertions>)` or `expect.hasAssertions()` as its first expression',
37 suggestAddingHasAssertions: 'Add `expect.hasAssertions()`',
38 suggestAddingAssertions: 'Add `expect.assertions(<number of assertions>)`',
39 suggestRemovingExtraArguments: 'Remove extra arguments'
40 },
41 type: 'suggestion',
42 hasSuggestions: true,
43 schema: [{
44 type: 'object',
45 properties: {
46 onlyFunctionsWithAsyncKeyword: {
47 type: 'boolean'
48 },
49 onlyFunctionsWithExpectInLoop: {
50 type: 'boolean'
51 },
52 onlyFunctionsWithExpectInCallback: {
53 type: 'boolean'
54 }
55 },
56 additionalProperties: false
57 }]
58 },
59 defaultOptions: [{
60 onlyFunctionsWithAsyncKeyword: false,
61 onlyFunctionsWithExpectInLoop: false,
62 onlyFunctionsWithExpectInCallback: false
63 }],
64
65 create(context, [options]) {
66 let expressionDepth = 0;
67 let hasExpectInCallback = false;
68 let hasExpectInLoop = false;
69 let inTestCaseCall = false;
70 let inForLoop = false;
71
72 const shouldCheckFunction = testFunction => {
73 if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) {
74 return true;
75 }
76
77 if (options.onlyFunctionsWithAsyncKeyword) {
78 if (testFunction.async) {
79 return true;
80 }
81 }
82
83 if (options.onlyFunctionsWithExpectInLoop) {
84 if (hasExpectInLoop) {
85 return true;
86 }
87 }
88
89 if (options.onlyFunctionsWithExpectInCallback) {
90 if (hasExpectInCallback) {
91 return true;
92 }
93 }
94
95 return false;
96 };
97
98 const enterExpression = () => inTestCaseCall && expressionDepth++;
99
100 const exitExpression = () => inTestCaseCall && expressionDepth--;
101
102 const enterForLoop = () => inForLoop = true;
103
104 const exitForLoop = () => inForLoop = false;
105
106 return {
107 FunctionExpression: enterExpression,
108 'FunctionExpression:exit': exitExpression,
109 ArrowFunctionExpression: enterExpression,
110 'ArrowFunctionExpression:exit': exitExpression,
111 ForStatement: enterForLoop,
112 'ForStatement:exit': exitForLoop,
113 ForInStatement: enterForLoop,
114 'ForInStatement:exit': exitForLoop,
115 ForOfStatement: enterForLoop,
116 'ForOfStatement:exit': exitForLoop,
117
118 CallExpression(node) {
119 if ((0, _utils.isTestCaseCall)(node)) {
120 inTestCaseCall = true;
121 return;
122 }
123
124 if ((0, _utils.isExpectCall)(node) && inTestCaseCall) {
125 if (inForLoop) {
126 hasExpectInLoop = true;
127 }
128
129 if (expressionDepth > 1) {
130 hasExpectInCallback = true;
131 }
132 }
133 },
134
135 'CallExpression:exit'(node) {
136 if (!(0, _utils.isTestCaseCall)(node)) {
137 return;
138 }
139
140 if (node.arguments.length < 2) {
141 return;
142 }
143
144 const [, testFn] = node.arguments;
145
146 if (!(0, _utils.isFunction)(testFn) || testFn.body.type !== _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
147 return;
148 }
149
150 if (!shouldCheckFunction(testFn)) {
151 return;
152 }
153
154 hasExpectInLoop = false;
155 hasExpectInCallback = false;
156 const testFuncBody = testFn.body.body;
157
158 if (!isFirstLineExprStmt(testFuncBody)) {
159 context.report({
160 messageId: 'haveExpectAssertions',
161 node,
162 suggest: suggestions.map(([messageId, text]) => ({
163 messageId,
164 fix: fixer => fixer.insertTextBeforeRange([testFn.body.range[0] + 1, testFn.body.range[1]], text)
165 }))
166 });
167 return;
168 }
169
170 const testFuncFirstLine = testFuncBody[0].expression;
171
172 if (!isExpectAssertionsOrHasAssertionsCall(testFuncFirstLine)) {
173 context.report({
174 messageId: 'haveExpectAssertions',
175 node,
176 suggest: suggestions.map(([messageId, text]) => ({
177 messageId,
178 fix: fixer => fixer.insertTextBefore(testFuncBody[0], text)
179 }))
180 });
181 return;
182 }
183
184 if ((0, _utils.isSupportedAccessor)(testFuncFirstLine.callee.property, 'hasAssertions')) {
185 if (testFuncFirstLine.arguments.length) {
186 context.report({
187 messageId: 'hasAssertionsTakesNoArguments',
188 node: testFuncFirstLine.callee.property,
189 suggest: [suggestRemovingExtraArguments(testFuncFirstLine.arguments, 0)]
190 });
191 }
192
193 return;
194 }
195
196 if (!(0, _utils.hasOnlyOneArgument)(testFuncFirstLine)) {
197 let {
198 loc
199 } = testFuncFirstLine.callee.property;
200 const suggest = [];
201
202 if (testFuncFirstLine.arguments.length) {
203 loc = testFuncFirstLine.arguments[1].loc;
204 suggest.push(suggestRemovingExtraArguments(testFuncFirstLine.arguments, 1));
205 }
206
207 context.report({
208 messageId: 'assertionsRequiresOneArgument',
209 suggest,
210 loc
211 });
212 return;
213 }
214
215 const [arg] = testFuncFirstLine.arguments;
216
217 if (arg.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
218 return;
219 }
220
221 context.report({
222 messageId: 'assertionsRequiresNumberArgument',
223 node: arg
224 });
225 }
226
227 };
228 }
229
230});
231
232exports.default = _default;
Note: See TracBrowser for help on using the repository browser.