@depup/eslint-plugin-jest 29.15.1-depup.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.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/changes.json +10 -0
  4. package/docs/rules/consistent-test-it.md +96 -0
  5. package/docs/rules/expect-expect.md +152 -0
  6. package/docs/rules/max-expects.md +78 -0
  7. package/docs/rules/max-nested-describe.md +134 -0
  8. package/docs/rules/no-alias-methods.md +57 -0
  9. package/docs/rules/no-commented-out-tests.md +68 -0
  10. package/docs/rules/no-conditional-expect.md +142 -0
  11. package/docs/rules/no-conditional-in-test.md +123 -0
  12. package/docs/rules/no-confusing-set-timeout.md +64 -0
  13. package/docs/rules/no-deprecated-functions.md +59 -0
  14. package/docs/rules/no-disabled-tests.md +72 -0
  15. package/docs/rules/no-done-callback.md +100 -0
  16. package/docs/rules/no-duplicate-hooks.md +79 -0
  17. package/docs/rules/no-error-equal.md +37 -0
  18. package/docs/rules/no-export.md +52 -0
  19. package/docs/rules/no-focused-tests.md +67 -0
  20. package/docs/rules/no-hooks.md +178 -0
  21. package/docs/rules/no-identical-title.md +59 -0
  22. package/docs/rules/no-interpolation-in-snapshots.md +67 -0
  23. package/docs/rules/no-jasmine-globals.md +69 -0
  24. package/docs/rules/no-large-snapshots.md +180 -0
  25. package/docs/rules/no-mocks-import.md +34 -0
  26. package/docs/rules/no-restricted-jest-methods.md +53 -0
  27. package/docs/rules/no-restricted-matchers.md +64 -0
  28. package/docs/rules/no-standalone-expect.md +106 -0
  29. package/docs/rules/no-test-prefixes.md +42 -0
  30. package/docs/rules/no-test-return-statement.md +50 -0
  31. package/docs/rules/no-unnecessary-assertion.md +41 -0
  32. package/docs/rules/no-unneeded-async-expect-function.md +41 -0
  33. package/docs/rules/no-untyped-mock-factory.md +74 -0
  34. package/docs/rules/padding-around-after-all-blocks.md +34 -0
  35. package/docs/rules/padding-around-after-each-blocks.md +38 -0
  36. package/docs/rules/padding-around-all.md +20 -0
  37. package/docs/rules/padding-around-before-all-blocks.md +37 -0
  38. package/docs/rules/padding-around-before-each-blocks.md +38 -0
  39. package/docs/rules/padding-around-describe-blocks.md +42 -0
  40. package/docs/rules/padding-around-expect-groups.md +44 -0
  41. package/docs/rules/padding-around-test-blocks.md +48 -0
  42. package/docs/rules/prefer-called-with.md +39 -0
  43. package/docs/rules/prefer-comparison-matcher.md +62 -0
  44. package/docs/rules/prefer-each.md +58 -0
  45. package/docs/rules/prefer-ending-with-an-expect.md +170 -0
  46. package/docs/rules/prefer-equality-matcher.md +36 -0
  47. package/docs/rules/prefer-expect-assertions.md +230 -0
  48. package/docs/rules/prefer-expect-resolves.md +62 -0
  49. package/docs/rules/prefer-hooks-in-order.md +137 -0
  50. package/docs/rules/prefer-hooks-on-top.md +124 -0
  51. package/docs/rules/prefer-importing-jest-globals.md +85 -0
  52. package/docs/rules/prefer-jest-mocked.md +40 -0
  53. package/docs/rules/prefer-lowercase-title.md +128 -0
  54. package/docs/rules/prefer-mock-promise-shorthand.md +41 -0
  55. package/docs/rules/prefer-mock-return-shorthand.md +50 -0
  56. package/docs/rules/prefer-snapshot-hint.md +192 -0
  57. package/docs/rules/prefer-spy-on.md +46 -0
  58. package/docs/rules/prefer-strict-equal.md +29 -0
  59. package/docs/rules/prefer-to-be.md +63 -0
  60. package/docs/rules/prefer-to-contain.md +53 -0
  61. package/docs/rules/prefer-to-have-been-called-times.md +43 -0
  62. package/docs/rules/prefer-to-have-been-called.md +35 -0
  63. package/docs/rules/prefer-to-have-length.md +41 -0
  64. package/docs/rules/prefer-todo.md +33 -0
  65. package/docs/rules/require-hook.md +187 -0
  66. package/docs/rules/require-to-throw-message.md +43 -0
  67. package/docs/rules/require-top-level-describe.md +86 -0
  68. package/docs/rules/unbound-method.md +61 -0
  69. package/docs/rules/valid-describe-callback.md +69 -0
  70. package/docs/rules/valid-expect-in-promise.md +79 -0
  71. package/docs/rules/valid-expect-with-promise.md +43 -0
  72. package/docs/rules/valid-expect.md +155 -0
  73. package/docs/rules/valid-mock-module-path.md +72 -0
  74. package/docs/rules/valid-title.md +319 -0
  75. package/index.d.ts +28 -0
  76. package/lib/globals.json +15 -0
  77. package/lib/index.js +85 -0
  78. package/lib/rules/consistent-test-it.js +101 -0
  79. package/lib/rules/expect-expect.js +102 -0
  80. package/lib/rules/max-expects.js +70 -0
  81. package/lib/rules/max-nested-describe.js +59 -0
  82. package/lib/rules/no-alias-methods.js +62 -0
  83. package/lib/rules/no-commented-out-tests.js +44 -0
  84. package/lib/rules/no-conditional-expect.js +80 -0
  85. package/lib/rules/no-conditional-in-test.js +63 -0
  86. package/lib/rules/no-confusing-set-timeout.js +61 -0
  87. package/lib/rules/no-deprecated-functions.js +81 -0
  88. package/lib/rules/no-disabled-tests.js +57 -0
  89. package/lib/rules/no-done-callback.js +120 -0
  90. package/lib/rules/no-duplicate-hooks.js +52 -0
  91. package/lib/rules/no-error-equal.js +41 -0
  92. package/lib/rules/no-export.js +61 -0
  93. package/lib/rules/no-focused-tests.js +63 -0
  94. package/lib/rules/no-hooks.js +51 -0
  95. package/lib/rules/no-identical-title.js +73 -0
  96. package/lib/rules/no-interpolation-in-snapshots.js +43 -0
  97. package/lib/rules/no-jasmine-globals.js +140 -0
  98. package/lib/rules/no-large-snapshots.js +100 -0
  99. package/lib/rules/no-mocks-import.js +46 -0
  100. package/lib/rules/no-restricted-jest-methods.js +53 -0
  101. package/lib/rules/no-restricted-matchers.js +60 -0
  102. package/lib/rules/no-standalone-expect.js +114 -0
  103. package/lib/rules/no-test-prefixes.js +48 -0
  104. package/lib/rules/no-test-return-statement.js +62 -0
  105. package/lib/rules/no-unnecessary-assertion.js +87 -0
  106. package/lib/rules/no-unneeded-async-expect-function.js +57 -0
  107. package/lib/rules/no-untyped-mock-factory.js +61 -0
  108. package/lib/rules/padding-around-after-all-blocks.js +17 -0
  109. package/lib/rules/padding-around-after-each-blocks.js +17 -0
  110. package/lib/rules/padding-around-all.js +15 -0
  111. package/lib/rules/padding-around-before-all-blocks.js +17 -0
  112. package/lib/rules/padding-around-before-each-blocks.js +17 -0
  113. package/lib/rules/padding-around-describe-blocks.js +17 -0
  114. package/lib/rules/padding-around-expect-groups.js +21 -0
  115. package/lib/rules/padding-around-test-blocks.js +17 -0
  116. package/lib/rules/prefer-called-with.js +47 -0
  117. package/lib/rules/prefer-comparison-matcher.js +111 -0
  118. package/lib/rules/prefer-each.js +77 -0
  119. package/lib/rules/prefer-ending-with-an-expect.js +102 -0
  120. package/lib/rules/prefer-equality-matcher.js +87 -0
  121. package/lib/rules/prefer-expect-assertions.js +237 -0
  122. package/lib/rules/prefer-expect-resolves.js +47 -0
  123. package/lib/rules/prefer-hooks-in-order.js +67 -0
  124. package/lib/rules/prefer-hooks-on-top.js +41 -0
  125. package/lib/rules/prefer-importing-jest-globals.js +126 -0
  126. package/lib/rules/prefer-jest-mocked.js +66 -0
  127. package/lib/rules/prefer-lowercase-title.js +128 -0
  128. package/lib/rules/prefer-mock-promise-shorthand.js +88 -0
  129. package/lib/rules/prefer-mock-return-shorthand.js +122 -0
  130. package/lib/rules/prefer-snapshot-hint.js +111 -0
  131. package/lib/rules/prefer-spy-on.js +80 -0
  132. package/lib/rules/prefer-strict-equal.js +46 -0
  133. package/lib/rules/prefer-to-be.js +98 -0
  134. package/lib/rules/prefer-to-contain.js +82 -0
  135. package/lib/rules/prefer-to-have-been-called-times.js +70 -0
  136. package/lib/rules/prefer-to-have-been-called.js +59 -0
  137. package/lib/rules/prefer-to-have-length.js +57 -0
  138. package/lib/rules/prefer-todo.js +72 -0
  139. package/lib/rules/require-hook.js +93 -0
  140. package/lib/rules/require-to-throw-message.js +45 -0
  141. package/lib/rules/require-top-level-describe.js +86 -0
  142. package/lib/rules/unbound-method.js +86 -0
  143. package/lib/rules/utils/accessors.js +127 -0
  144. package/lib/rules/utils/ast-utils.js +59 -0
  145. package/lib/rules/utils/detectJestVersion.js +24 -0
  146. package/lib/rules/utils/followTypeAssertionChain.js +10 -0
  147. package/lib/rules/utils/index.js +71 -0
  148. package/lib/rules/utils/misc.js +168 -0
  149. package/lib/rules/utils/padding.js +308 -0
  150. package/lib/rules/utils/parseJestFnCall.js +325 -0
  151. package/lib/rules/utils/ts.js +73 -0
  152. package/lib/rules/valid-describe-callback.js +94 -0
  153. package/lib/rules/valid-expect-in-promise.js +311 -0
  154. package/lib/rules/valid-expect-with-promise.js +54 -0
  155. package/lib/rules/valid-expect.js +302 -0
  156. package/lib/rules/valid-mock-module-path.js +90 -0
  157. package/lib/rules/valid-title.js +252 -0
  158. package/package.json +164 -0
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _utils2 = require("./utils");
9
+ /*
10
+ * This implementation is adapted from eslint-plugin-jasmine.
11
+ * MIT license, Remco Haszing.
12
+ */
13
+
14
+ /**
15
+ * Checks if node names returned by getNodeName matches any of the given star patterns
16
+ * Pattern examples:
17
+ * request.*.expect
18
+ * request.**.expect
19
+ * request.**.expect*
20
+ */
21
+ function matchesAssertFunctionName(nodeName, patterns) {
22
+ return patterns.some(p => new RegExp(`^${p.split('.').map(x => {
23
+ if (x === '**') {
24
+ return '[a-z\\d\\.]*';
25
+ }
26
+ return x.replace(/\*/gu, '[a-z\\d]*');
27
+ }).join('\\.')}(\\.|$)`, 'ui').test(nodeName));
28
+ }
29
+ function getLastStatement(fn) {
30
+ if (fn.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
31
+ if (fn.body.body.length === 0) {
32
+ return null;
33
+ }
34
+ const lastStatement = fn.body.body[fn.body.body.length - 1];
35
+ if (lastStatement.type === _utils.AST_NODE_TYPES.ExpressionStatement) {
36
+ return lastStatement.expression;
37
+ }
38
+ return lastStatement;
39
+ }
40
+ return fn.body;
41
+ }
42
+ var _default = exports.default = (0, _utils2.createRule)({
43
+ name: __filename,
44
+ meta: {
45
+ docs: {
46
+ description: 'Prefer having the last statement in a test be an assertion'
47
+ },
48
+ messages: {
49
+ mustEndWithExpect: 'Tests should end with an assertion'
50
+ },
51
+ schema: [{
52
+ type: 'object',
53
+ properties: {
54
+ assertFunctionNames: {
55
+ type: 'array',
56
+ items: {
57
+ type: 'string'
58
+ }
59
+ },
60
+ additionalTestBlockFunctions: {
61
+ type: 'array',
62
+ items: {
63
+ type: 'string'
64
+ }
65
+ }
66
+ },
67
+ additionalProperties: false
68
+ }],
69
+ type: 'suggestion'
70
+ },
71
+ defaultOptions: [{
72
+ assertFunctionNames: ['expect'],
73
+ additionalTestBlockFunctions: []
74
+ }],
75
+ create(context, [{
76
+ assertFunctionNames = ['expect'],
77
+ additionalTestBlockFunctions = []
78
+ }]) {
79
+ return {
80
+ CallExpression(node) {
81
+ const name = (0, _utils2.getNodeName)(node.callee) ?? '';
82
+ if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test']) && !additionalTestBlockFunctions.includes(name)) {
83
+ return;
84
+ }
85
+ if (node.arguments.length < 2 || !(0, _utils2.isFunction)(node.arguments[1])) {
86
+ return;
87
+ }
88
+ let lastStatement = getLastStatement(node.arguments[1]);
89
+ if (lastStatement?.type === _utils.AST_NODE_TYPES.AwaitExpression) {
90
+ lastStatement = lastStatement.argument;
91
+ }
92
+ if (lastStatement?.type === _utils.AST_NODE_TYPES.CallExpression && ((0, _utils2.isTypeOfJestFnCall)(lastStatement, context, ['expect']) || matchesAssertFunctionName((0, _utils2.getNodeName)(lastStatement.callee), assertFunctionNames))) {
93
+ return;
94
+ }
95
+ context.report({
96
+ messageId: 'mustEndWithExpect',
97
+ node: node.callee
98
+ });
99
+ }
100
+ };
101
+ }
102
+ });
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _utils2 = require("./utils");
9
+ var _default = exports.default = (0, _utils2.createRule)({
10
+ name: __filename,
11
+ meta: {
12
+ docs: {
13
+ description: 'Suggest using the built-in equality matchers'
14
+ },
15
+ messages: {
16
+ useEqualityMatcher: 'Prefer using one of the equality matchers instead',
17
+ suggestEqualityMatcher: 'Use `{{ equalityMatcher }}`'
18
+ },
19
+ hasSuggestions: true,
20
+ type: 'suggestion',
21
+ schema: []
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ return {
26
+ CallExpression(node) {
27
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
28
+ if (jestFnCall?.type !== 'expect' || jestFnCall.args.length === 0) {
29
+ return;
30
+ }
31
+ const {
32
+ parent: expect
33
+ } = jestFnCall.head.node;
34
+ if (expect.type !== _utils.AST_NODE_TYPES.CallExpression) {
35
+ return;
36
+ }
37
+ const {
38
+ arguments: [comparison],
39
+ range: [, expectCallEnd]
40
+ } = expect;
41
+ const {
42
+ matcher
43
+ } = jestFnCall;
44
+ const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
45
+ if (comparison.type !== _utils.AST_NODE_TYPES.BinaryExpression || comparison.operator !== '===' && comparison.operator !== '!==' || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) {
46
+ return;
47
+ }
48
+ const matcherValue = matcherArg.value;
49
+ const [modifier] = jestFnCall.modifiers;
50
+ const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
51
+
52
+ // we need to negate the expectation if the current expected
53
+ // value is itself negated by the "not" modifier
54
+ const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === hasNot;
55
+ const buildFixer = equalityMatcher => fixer => {
56
+ const {
57
+ sourceCode
58
+ } = context;
59
+
60
+ // preserve the existing modifier if it's not a negation
61
+ let modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : '';
62
+ if (addNotModifier) {
63
+ modifierText += `.${_utils2.ModifierName.not}`;
64
+ }
65
+ return [
66
+ // replace the comparison argument with the left-hand side of the comparison
67
+ fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
68
+ // replace the current matcher & modifier with the preferred matcher
69
+ fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`),
70
+ // replace the matcher argument with the right-hand side of the comparison
71
+ fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))];
72
+ };
73
+ context.report({
74
+ messageId: 'useEqualityMatcher',
75
+ suggest: ['toBe', 'toEqual', 'toStrictEqual'].map(equalityMatcher => ({
76
+ messageId: 'suggestEqualityMatcher',
77
+ data: {
78
+ equalityMatcher
79
+ },
80
+ fix: buildFixer(equalityMatcher)
81
+ })),
82
+ node: matcher
83
+ });
84
+ }
85
+ };
86
+ }
87
+ });
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _utils2 = require("./utils");
9
+ const isFirstStatement = node => {
10
+ let parent = node;
11
+ while (parent) {
12
+ if (parent.parent?.type === _utils.AST_NODE_TYPES.BlockStatement) {
13
+ return parent.parent.body[0] === parent;
14
+ }
15
+
16
+ // if we've hit an arrow function, then it must have a single expression
17
+ // as its body, as otherwise we would have hit the block statement already
18
+ if (parent.parent?.type === _utils.AST_NODE_TYPES.ArrowFunctionExpression) {
19
+ return true;
20
+ }
21
+ parent = parent.parent;
22
+ }
23
+
24
+ /* istanbul ignore next */
25
+ throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
26
+ };
27
+ const suggestRemovingExtraArguments = (context, func, from) => ({
28
+ messageId: 'suggestRemovingExtraArguments',
29
+ fix: fixer => (0, _utils2.removeExtraArgumentsFixer)(fixer, context, func, from)
30
+ });
31
+ var _default = exports.default = (0, _utils2.createRule)({
32
+ name: __filename,
33
+ meta: {
34
+ docs: {
35
+ description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`'
36
+ },
37
+ messages: {
38
+ hasAssertionsTakesNoArguments: '`expect.hasAssertions` expects no arguments',
39
+ assertionsRequiresOneArgument: '`expect.assertions` expects a single argument of type number',
40
+ assertionsRequiresNumberArgument: 'This argument should be a number',
41
+ haveExpectAssertions: 'Every test should have either `expect.assertions(<number of assertions>)` or `expect.hasAssertions()` as its first expression',
42
+ suggestAddingHasAssertions: 'Add `expect.hasAssertions()`',
43
+ suggestAddingAssertions: 'Add `expect.assertions(<number of assertions>)`',
44
+ suggestRemovingExtraArguments: 'Remove extra arguments'
45
+ },
46
+ type: 'suggestion',
47
+ hasSuggestions: true,
48
+ schema: [{
49
+ type: 'object',
50
+ properties: {
51
+ onlyFunctionsWithAsyncKeyword: {
52
+ type: 'boolean'
53
+ },
54
+ onlyFunctionsWithExpectInLoop: {
55
+ type: 'boolean'
56
+ },
57
+ onlyFunctionsWithExpectInCallback: {
58
+ type: 'boolean'
59
+ }
60
+ },
61
+ additionalProperties: false
62
+ }]
63
+ },
64
+ defaultOptions: [{
65
+ onlyFunctionsWithAsyncKeyword: false,
66
+ onlyFunctionsWithExpectInLoop: false,
67
+ onlyFunctionsWithExpectInCallback: false
68
+ }],
69
+ create(context, [options]) {
70
+ let expressionDepth = 0;
71
+ let describeDepth = 0;
72
+ let hasExpectInCallback = false;
73
+ let hasExpectInLoop = false;
74
+ let hasExpectAssertionsAsFirstStatement = false;
75
+ let inTestCaseCall = false;
76
+ let inForLoop = false;
77
+ const shouldCheckFunction = testFunction => {
78
+ if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) {
79
+ return true;
80
+ }
81
+ if (options.onlyFunctionsWithAsyncKeyword) {
82
+ if (testFunction.async) {
83
+ return true;
84
+ }
85
+ }
86
+ if (options.onlyFunctionsWithExpectInLoop) {
87
+ if (hasExpectInLoop) {
88
+ return true;
89
+ }
90
+ }
91
+ if (options.onlyFunctionsWithExpectInCallback) {
92
+ if (hasExpectInCallback) {
93
+ return true;
94
+ }
95
+ }
96
+ return false;
97
+ };
98
+ const checkExpectHasAssertions = (expectFnCall, func) => {
99
+ if ((0, _utils2.getAccessorValue)(expectFnCall.members[0]) === 'hasAssertions') {
100
+ if (expectFnCall.args.length) {
101
+ context.report({
102
+ messageId: 'hasAssertionsTakesNoArguments',
103
+ node: expectFnCall.matcher,
104
+ suggest: [suggestRemovingExtraArguments(context, func, 0)]
105
+ });
106
+ }
107
+ return;
108
+ }
109
+ if (expectFnCall.args.length !== 1) {
110
+ let {
111
+ loc
112
+ } = expectFnCall.matcher;
113
+ const suggest = [];
114
+ if (expectFnCall.args.length) {
115
+ loc = expectFnCall.args[1].loc;
116
+ suggest.push(suggestRemovingExtraArguments(context, func, 1));
117
+ }
118
+ context.report({
119
+ messageId: 'assertionsRequiresOneArgument',
120
+ suggest,
121
+ loc
122
+ });
123
+ return;
124
+ }
125
+ const [arg] = expectFnCall.args;
126
+ if (arg.type === _utils.AST_NODE_TYPES.Literal && Number.isInteger(arg.value)) {
127
+ return;
128
+ }
129
+ context.report({
130
+ messageId: 'assertionsRequiresNumberArgument',
131
+ node: arg
132
+ });
133
+ };
134
+ const enterExpression = () => inTestCaseCall && expressionDepth++;
135
+ const exitExpression = () => inTestCaseCall && expressionDepth--;
136
+ const enterForLoop = () => inForLoop = true;
137
+ const exitForLoop = () => inForLoop = false;
138
+ let inEachHook = false;
139
+
140
+ // when set to a non-negative value, all expect calls within describes whose depth
141
+ // are equal to or higher than this value are covered by an expect.hasAssertions set
142
+ // up within a beforeEach or afterEach hook
143
+ //
144
+ // when the describe depth is lower than the current value, it gets reset to -1
145
+ let coveredByHookAtDepth = -1;
146
+ return {
147
+ FunctionExpression: enterExpression,
148
+ 'FunctionExpression:exit': exitExpression,
149
+ ArrowFunctionExpression: enterExpression,
150
+ 'ArrowFunctionExpression:exit': exitExpression,
151
+ ForStatement: enterForLoop,
152
+ 'ForStatement:exit': exitForLoop,
153
+ ForInStatement: enterForLoop,
154
+ 'ForInStatement:exit': exitForLoop,
155
+ ForOfStatement: enterForLoop,
156
+ 'ForOfStatement:exit': exitForLoop,
157
+ CallExpression(node) {
158
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
159
+ if (jestFnCall?.type === 'describe') {
160
+ describeDepth += 1;
161
+ }
162
+ if (jestFnCall?.type === 'hook' && jestFnCall.name.endsWith('Each')) {
163
+ inEachHook = true;
164
+ }
165
+ if (jestFnCall?.type === 'test') {
166
+ inTestCaseCall = true;
167
+ return;
168
+ }
169
+ if (jestFnCall?.type === 'expect' && inEachHook && (0, _utils2.getAccessorValue)(jestFnCall.members[0]) === 'hasAssertions') {
170
+ checkExpectHasAssertions(jestFnCall, node);
171
+ if (coveredByHookAtDepth < 0) {
172
+ coveredByHookAtDepth = describeDepth;
173
+ }
174
+ }
175
+ if (jestFnCall?.type === 'expect' && inTestCaseCall) {
176
+ if (expressionDepth === 1 && isFirstStatement(node) && ['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) {
177
+ checkExpectHasAssertions(jestFnCall, node);
178
+ hasExpectAssertionsAsFirstStatement = true;
179
+ }
180
+ if (inForLoop) {
181
+ hasExpectInLoop = true;
182
+ }
183
+ if (expressionDepth > 1) {
184
+ hasExpectInCallback = true;
185
+ }
186
+ }
187
+ },
188
+ 'CallExpression:exit'(node) {
189
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
190
+ if (jestFnCall?.type === 'describe') {
191
+ describeDepth -= 1;
192
+
193
+ // clear the "covered by each hook" flag if we have left the describe
194
+ // depth that it applies to
195
+ if (coveredByHookAtDepth > describeDepth) {
196
+ coveredByHookAtDepth = -1;
197
+ }
198
+ }
199
+ if (jestFnCall?.type === 'hook' && jestFnCall.name.endsWith('Each')) {
200
+ inEachHook = false;
201
+ }
202
+ if (jestFnCall?.type !== 'test') {
203
+ return;
204
+ }
205
+ inTestCaseCall = false;
206
+ if (node.arguments.length < 2) {
207
+ return;
208
+ }
209
+ const [, testFn] = node.arguments;
210
+ if (!(0, _utils2.isFunction)(testFn) || !shouldCheckFunction(testFn)) {
211
+ return;
212
+ }
213
+ hasExpectInLoop = false;
214
+ hasExpectInCallback = false;
215
+ if (hasExpectAssertionsAsFirstStatement) {
216
+ hasExpectAssertionsAsFirstStatement = false;
217
+ return;
218
+ }
219
+ if (coveredByHookAtDepth >= 0 && coveredByHookAtDepth <= describeDepth) {
220
+ return;
221
+ }
222
+ const suggestions = [];
223
+ if (testFn.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
224
+ suggestions.push(['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']);
225
+ }
226
+ context.report({
227
+ messageId: 'haveExpectAssertions',
228
+ node,
229
+ suggest: suggestions.map(([messageId, text]) => ({
230
+ messageId,
231
+ fix: fixer => fixer.insertTextBeforeRange([testFn.body.range[0] + 1, testFn.body.range[1]], text)
232
+ }))
233
+ });
234
+ }
235
+ };
236
+ }
237
+ });
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _utils2 = require("./utils");
9
+ var _default = exports.default = (0, _utils2.createRule)({
10
+ name: __filename,
11
+ meta: {
12
+ docs: {
13
+ description: 'Prefer `await expect(...).resolves` over `expect(await ...)` syntax'
14
+ },
15
+ fixable: 'code',
16
+ messages: {
17
+ expectResolves: 'Use `await expect(...).resolves instead'
18
+ },
19
+ schema: [],
20
+ type: 'suggestion'
21
+ },
22
+ defaultOptions: [],
23
+ create: context => ({
24
+ CallExpression(node) {
25
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
26
+ if (jestFnCall?.type !== 'expect') {
27
+ return;
28
+ }
29
+ const {
30
+ parent
31
+ } = jestFnCall.head.node;
32
+ if (parent.type !== _utils.AST_NODE_TYPES.CallExpression) {
33
+ return;
34
+ }
35
+ const [awaitNode] = parent.arguments;
36
+ if (awaitNode.type === _utils.AST_NODE_TYPES.AwaitExpression) {
37
+ context.report({
38
+ node: awaitNode,
39
+ messageId: 'expectResolves',
40
+ fix(fixer) {
41
+ return [fixer.insertTextBefore(parent, 'await '), fixer.removeRange([awaitNode.range[0], awaitNode.argument.range[0]]), fixer.insertTextAfter(parent, '.resolves')];
42
+ }
43
+ });
44
+ }
45
+ }
46
+ })
47
+ });
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("./utils");
8
+ const HooksOrder = ['beforeAll', 'beforeEach', 'afterEach', 'afterAll'];
9
+ var _default = exports.default = (0, _utils.createRule)({
10
+ name: __filename,
11
+ meta: {
12
+ docs: {
13
+ description: 'Prefer having hooks in a consistent order'
14
+ },
15
+ messages: {
16
+ reorderHooks: `\`{{ currentHook }}\` hooks should be before any \`{{ previousHook }}\` hooks`
17
+ },
18
+ schema: [],
19
+ type: 'suggestion'
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ let previousHookIndex = -1;
24
+ let inHook = false;
25
+ return {
26
+ CallExpression(node) {
27
+ if (inHook) {
28
+ // Ignore everything that is passed into a hook
29
+ return;
30
+ }
31
+ const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
32
+ if (jestFnCall?.type !== 'hook') {
33
+ // Reset the previousHookIndex when encountering something different from a hook
34
+ previousHookIndex = -1;
35
+ return;
36
+ }
37
+ inHook = true;
38
+ const currentHook = jestFnCall.name;
39
+ const currentHookIndex = HooksOrder.indexOf(currentHook);
40
+ if (currentHookIndex < previousHookIndex) {
41
+ context.report({
42
+ messageId: 'reorderHooks',
43
+ node,
44
+ data: {
45
+ previousHook: HooksOrder[previousHookIndex],
46
+ currentHook
47
+ }
48
+ });
49
+ return;
50
+ }
51
+ previousHookIndex = currentHookIndex;
52
+ },
53
+ 'CallExpression:exit'(node) {
54
+ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['hook'])) {
55
+ inHook = false;
56
+ return;
57
+ }
58
+ if (inHook) {
59
+ return;
60
+ }
61
+
62
+ // Reset the previousHookIndex when encountering something different from a hook
63
+ previousHookIndex = -1;
64
+ }
65
+ };
66
+ }
67
+ });
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("./utils");
8
+ var _default = exports.default = (0, _utils.createRule)({
9
+ name: __filename,
10
+ meta: {
11
+ docs: {
12
+ description: 'Suggest having hooks before any test cases'
13
+ },
14
+ messages: {
15
+ noHookOnTop: 'Hooks should come before test cases'
16
+ },
17
+ schema: [],
18
+ type: 'suggestion'
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ const hooksContext = [false];
23
+ return {
24
+ CallExpression(node) {
25
+ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['test'])) {
26
+ hooksContext[hooksContext.length - 1] = true;
27
+ }
28
+ if (hooksContext[hooksContext.length - 1] && (0, _utils.isTypeOfJestFnCall)(node, context, ['hook'])) {
29
+ context.report({
30
+ messageId: 'noHookOnTop',
31
+ node
32
+ });
33
+ }
34
+ hooksContext.push(false);
35
+ },
36
+ 'CallExpression:exit'() {
37
+ hooksContext.pop();
38
+ }
39
+ };
40
+ }
41
+ });