@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,81 @@
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 parseJestVersion = rawVersion => {
10
+ if (typeof rawVersion === 'number') {
11
+ return rawVersion;
12
+ }
13
+ const [majorVersion] = rawVersion.split('.');
14
+ return parseInt(majorVersion, 10);
15
+ };
16
+ var _default = exports.default = (0, _utils2.createRule)({
17
+ name: __filename,
18
+ meta: {
19
+ docs: {
20
+ description: 'Disallow use of deprecated functions'
21
+ },
22
+ messages: {
23
+ deprecatedFunction: '`{{ deprecation }}` has been deprecated in favor of `{{ replacement }}`'
24
+ },
25
+ type: 'suggestion',
26
+ schema: [],
27
+ fixable: 'code'
28
+ },
29
+ defaultOptions: [],
30
+ create(context) {
31
+ const jestVersion = parseJestVersion(context.settings?.jest?.version || (0, _utils2.detectJestVersion)());
32
+ const deprecations = {
33
+ ...(jestVersion >= 15 && {
34
+ 'jest.resetModuleRegistry': 'jest.resetModules'
35
+ }),
36
+ ...(jestVersion >= 17 && {
37
+ 'jest.addMatchers': 'expect.extend'
38
+ }),
39
+ ...(jestVersion >= 21 && {
40
+ 'require.requireMock': 'jest.requireMock',
41
+ 'require.requireActual': 'jest.requireActual'
42
+ }),
43
+ ...(jestVersion >= 22 && {
44
+ 'jest.runTimersToTime': 'jest.advanceTimersByTime'
45
+ }),
46
+ ...(jestVersion >= 26 && {
47
+ 'jest.genMockFromModule': 'jest.createMockFromModule'
48
+ })
49
+ };
50
+ return {
51
+ CallExpression(node) {
52
+ if (node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression) {
53
+ return;
54
+ }
55
+ const deprecation = (0, _utils2.getNodeName)(node);
56
+ if (!deprecation || !(deprecation in deprecations)) {
57
+ return;
58
+ }
59
+ const replacement = deprecations[deprecation];
60
+ const {
61
+ callee
62
+ } = node;
63
+ context.report({
64
+ messageId: 'deprecatedFunction',
65
+ data: {
66
+ deprecation,
67
+ replacement
68
+ },
69
+ node,
70
+ fix(fixer) {
71
+ let [name, func] = replacement.split('.');
72
+ if (callee.property.type === _utils.AST_NODE_TYPES.Literal) {
73
+ func = `'${func}'`;
74
+ }
75
+ return [fixer.replaceText(callee.object, name), fixer.replaceText(callee.property, func)];
76
+ }
77
+ });
78
+ }
79
+ };
80
+ }
81
+ });
@@ -0,0 +1,57 @@
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: 'Disallow disabled tests'
13
+ },
14
+ messages: {
15
+ missingFunction: 'Test is missing function argument',
16
+ skippedTest: 'Tests should not be skipped'
17
+ },
18
+ schema: [],
19
+ type: 'suggestion'
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ return {
24
+ CallExpression(node) {
25
+ const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
26
+ if (!jestFnCall) {
27
+ return;
28
+ }
29
+ if (jestFnCall.type === 'test') {
30
+ if (node.arguments.length < 2 && jestFnCall.members.every(s => (0, _utils.getAccessorValue)(s) !== 'todo')) {
31
+ context.report({
32
+ messageId: 'missingFunction',
33
+ node
34
+ });
35
+ }
36
+ }
37
+ if (
38
+ // the only jest functions that are with "x" are "xdescribe", "xtest", and "xit"
39
+ jestFnCall.name.startsWith('x') || jestFnCall.members.some(s => (0, _utils.getAccessorValue)(s) === 'skip')) {
40
+ context.report({
41
+ messageId: 'skippedTest',
42
+ node
43
+ });
44
+ }
45
+ },
46
+ 'CallExpression[callee.name="pending"]'(node) {
47
+ if ((0, _utils.resolveScope)(context.sourceCode.getScope(node), 'pending')) {
48
+ return;
49
+ }
50
+ context.report({
51
+ messageId: 'skippedTest',
52
+ node
53
+ });
54
+ }
55
+ };
56
+ }
57
+ });
@@ -0,0 +1,120 @@
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 findCallbackArg = (node, isJestEach, context) => {
10
+ if (isJestEach) {
11
+ return node.arguments[1];
12
+ }
13
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
14
+ if (jestFnCall?.type === 'hook' && node.arguments.length >= 1) {
15
+ return node.arguments[0];
16
+ }
17
+ if (jestFnCall?.type === 'test' && node.arguments.length >= 2) {
18
+ return node.arguments[1];
19
+ }
20
+ return null;
21
+ };
22
+ var _default = exports.default = (0, _utils2.createRule)({
23
+ name: __filename,
24
+ meta: {
25
+ docs: {
26
+ description: 'Disallow using a callback in asynchronous tests and hooks'
27
+ },
28
+ messages: {
29
+ noDoneCallback: 'Return a Promise instead of relying on callback parameter',
30
+ suggestWrappingInPromise: 'Wrap in `new Promise({{ callback }} => ...`',
31
+ useAwaitInsteadOfCallback: 'Use await instead of callback in async functions'
32
+ },
33
+ schema: [],
34
+ type: 'suggestion',
35
+ hasSuggestions: true
36
+ },
37
+ defaultOptions: [],
38
+ create(context) {
39
+ return {
40
+ CallExpression(node) {
41
+ // done is the second argument for it.each, not the first
42
+ const isJestEach = (0, _utils2.getNodeName)(node.callee)?.endsWith('.each') ?? false;
43
+ if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
44
+ // isJestEach but not a TaggedTemplateExpression, so this must be
45
+ // the `jest.each([])()` syntax which this rule doesn't support due
46
+ // to its complexity (see jest-community/eslint-plugin-jest#710)
47
+ return;
48
+ }
49
+ const callback = findCallbackArg(node, isJestEach, context);
50
+ const callbackArgIndex = Number(isJestEach);
51
+ if (!callback || !(0, _utils2.isFunction)(callback) || callback.params.length !== 1 + callbackArgIndex) {
52
+ return;
53
+ }
54
+ const argument = callback.params[callbackArgIndex];
55
+ if (argument.type !== _utils.AST_NODE_TYPES.Identifier) {
56
+ context.report({
57
+ node: argument,
58
+ messageId: 'noDoneCallback'
59
+ });
60
+ return;
61
+ }
62
+ if (callback.async) {
63
+ context.report({
64
+ node: argument,
65
+ messageId: 'useAwaitInsteadOfCallback'
66
+ });
67
+ return;
68
+ }
69
+ context.report({
70
+ node: argument,
71
+ messageId: 'noDoneCallback',
72
+ suggest: [{
73
+ messageId: 'suggestWrappingInPromise',
74
+ data: {
75
+ callback: argument.name
76
+ },
77
+ fix(fixer) {
78
+ const {
79
+ body,
80
+ params
81
+ } = callback;
82
+ const {
83
+ sourceCode
84
+ } = context;
85
+ const firstBodyToken = sourceCode.getFirstToken(body);
86
+ const lastBodyToken = sourceCode.getLastToken(body);
87
+ const [firstParam] = params;
88
+ const lastParam = params[params.length - 1];
89
+ const tokenBeforeFirstParam = sourceCode.getTokenBefore(firstParam);
90
+ let tokenAfterLastParam = sourceCode.getTokenAfter(lastParam);
91
+ if (tokenAfterLastParam?.value === ',') {
92
+ tokenAfterLastParam = sourceCode.getTokenAfter(tokenAfterLastParam);
93
+ }
94
+
95
+ /* istanbul ignore if */
96
+ if (!firstBodyToken || !lastBodyToken || !tokenBeforeFirstParam || !tokenAfterLastParam) {
97
+ throw new Error(`Unexpected null when attempting to fix ${context.filename} - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
98
+ }
99
+ let argumentFix = fixer.replaceText(firstParam, '()');
100
+ if (tokenBeforeFirstParam.value === '(' && tokenAfterLastParam.value === ')') {
101
+ argumentFix = fixer.removeRange([tokenBeforeFirstParam.range[1], tokenAfterLastParam.range[0]]);
102
+ }
103
+ const newCallback = argument.name;
104
+ let beforeReplacement = `new Promise(${newCallback} => `;
105
+ let afterReplacement = ')';
106
+ let replaceBefore = true;
107
+ if (body.type === _utils.AST_NODE_TYPES.BlockStatement) {
108
+ const keyword = 'return';
109
+ beforeReplacement = `${keyword} ${beforeReplacement}{`;
110
+ afterReplacement += '}';
111
+ replaceBefore = false;
112
+ }
113
+ return [argumentFix, replaceBefore ? fixer.insertTextBefore(firstBodyToken, beforeReplacement) : fixer.insertTextAfter(firstBodyToken, beforeReplacement), fixer.insertTextAfter(lastBodyToken, afterReplacement)];
114
+ }
115
+ }]
116
+ });
117
+ }
118
+ };
119
+ }
120
+ });
@@ -0,0 +1,52 @@
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: 'Disallow duplicate setup and teardown hooks'
13
+ },
14
+ messages: {
15
+ noDuplicateHook: 'Duplicate {{hook}} in describe block'
16
+ },
17
+ schema: [],
18
+ type: 'suggestion'
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ const hookContexts = [{}];
23
+ return {
24
+ CallExpression(node) {
25
+ const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
26
+ if (jestFnCall?.type === 'describe') {
27
+ hookContexts.push({});
28
+ }
29
+ if (jestFnCall?.type !== 'hook') {
30
+ return;
31
+ }
32
+ const currentLayer = hookContexts[hookContexts.length - 1];
33
+ currentLayer[jestFnCall.name] ||= 0;
34
+ currentLayer[jestFnCall.name] += 1;
35
+ if (currentLayer[jestFnCall.name] > 1) {
36
+ context.report({
37
+ messageId: 'noDuplicateHook',
38
+ data: {
39
+ hook: jestFnCall.name
40
+ },
41
+ node
42
+ });
43
+ }
44
+ },
45
+ 'CallExpression:exit'(node) {
46
+ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) {
47
+ hookContexts.pop();
48
+ }
49
+ }
50
+ };
51
+ }
52
+ });
@@ -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("@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: 'Disallow using equality matchers on error types',
14
+ requiresTypeChecking: true
15
+ },
16
+ messages: {
17
+ equalError: 'Avoid using equality matchers to check errors'
18
+ },
19
+ type: 'suggestion',
20
+ schema: []
21
+ },
22
+ defaultOptions: [],
23
+ create(context) {
24
+ const services = _utils.ESLintUtils.getParserServices(context);
25
+ return {
26
+ CallExpression(node) {
27
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
28
+ if (jestFnCall?.type !== 'expect' || jestFnCall.head.node.parent.type !== _utils.AST_NODE_TYPES.CallExpression || !['toEqual', 'toStrictEqual'].includes((0, _utils2.getAccessorValue)(jestFnCall.matcher))) {
29
+ return;
30
+ }
31
+ const [argument] = jestFnCall.head.node.parent.arguments;
32
+ if ((0, _utils2.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(argument), 'Error')) {
33
+ context.report({
34
+ messageId: 'equalError',
35
+ node
36
+ });
37
+ }
38
+ }
39
+ };
40
+ }
41
+ });
@@ -0,0 +1,61 @@
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: 'Disallow using `exports` in files containing tests'
14
+ },
15
+ messages: {
16
+ unexpectedExport: `Do not export from a test file`
17
+ },
18
+ type: 'suggestion',
19
+ schema: []
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ const exportNodes = [];
24
+ let hasTestCase = false;
25
+ return {
26
+ 'Program:exit'() {
27
+ if (hasTestCase && exportNodes.length > 0) {
28
+ for (const node of exportNodes) {
29
+ context.report({
30
+ node,
31
+ messageId: 'unexpectedExport'
32
+ });
33
+ }
34
+ }
35
+ },
36
+ CallExpression(node) {
37
+ if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
38
+ hasTestCase = true;
39
+ }
40
+ },
41
+ 'ExportNamedDeclaration, ExportDefaultDeclaration, TSExportAssignment'(node) {
42
+ exportNodes.push(node);
43
+ },
44
+ 'AssignmentExpression > MemberExpression'(node) {
45
+ let {
46
+ object,
47
+ property
48
+ } = node;
49
+ if (object.type === _utils.AST_NODE_TYPES.MemberExpression) {
50
+ ({
51
+ object,
52
+ property
53
+ } = object);
54
+ }
55
+ if ('name' in object && object.name === 'module' && property.type === _utils.AST_NODE_TYPES.Identifier && /^exports?$/u.test(property.name)) {
56
+ exportNodes.push(node);
57
+ }
58
+ }
59
+ };
60
+ }
61
+ });
@@ -0,0 +1,63 @@
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: 'Disallow focused tests'
14
+ },
15
+ messages: {
16
+ focusedTest: 'Unexpected focused test',
17
+ suggestRemoveFocus: 'Remove focus from test'
18
+ },
19
+ schema: [],
20
+ type: 'suggestion',
21
+ hasSuggestions: true
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ return {
26
+ CallExpression(node) {
27
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
28
+ if (jestFnCall?.type !== 'test' && jestFnCall?.type !== 'describe') {
29
+ return;
30
+ }
31
+ if (jestFnCall.name.startsWith('f')) {
32
+ context.report({
33
+ messageId: 'focusedTest',
34
+ node: jestFnCall.head.node,
35
+ suggest: [{
36
+ messageId: 'suggestRemoveFocus',
37
+ fix(fixer) {
38
+ // don't apply the fixer if we're an aliased import
39
+ if (jestFnCall.head.type === 'import' && jestFnCall.name !== jestFnCall.head.local) {
40
+ return null;
41
+ }
42
+ return fixer.removeRange([node.range[0], node.range[0] + 1]);
43
+ }
44
+ }]
45
+ });
46
+ return;
47
+ }
48
+ const onlyNode = jestFnCall.members.find(s => (0, _utils2.getAccessorValue)(s) === 'only');
49
+ if (!onlyNode) {
50
+ return;
51
+ }
52
+ context.report({
53
+ messageId: 'focusedTest',
54
+ node: onlyNode,
55
+ suggest: [{
56
+ messageId: 'suggestRemoveFocus',
57
+ fix: fixer => fixer.removeRange([onlyNode.range[0] - 1, onlyNode.range[1] + Number(onlyNode.type !== _utils.AST_NODE_TYPES.Identifier)])
58
+ }]
59
+ });
60
+ }
61
+ };
62
+ }
63
+ });
@@ -0,0 +1,51 @@
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: 'Disallow setup and teardown hooks'
13
+ },
14
+ messages: {
15
+ unexpectedHook: "Unexpected '{{ hookName }}' hook"
16
+ },
17
+ schema: [{
18
+ type: 'object',
19
+ properties: {
20
+ allow: {
21
+ type: 'array',
22
+ // @ts-expect-error https://github.com/eslint/eslint/discussions/17573
23
+ contains: ['beforeAll', 'beforeEach', 'afterAll', 'afterEach']
24
+ }
25
+ },
26
+ additionalProperties: false
27
+ }],
28
+ type: 'suggestion'
29
+ },
30
+ defaultOptions: [{
31
+ allow: []
32
+ }],
33
+ create(context, [{
34
+ allow = []
35
+ }]) {
36
+ return {
37
+ CallExpression(node) {
38
+ const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
39
+ if (jestFnCall?.type === 'hook' && !allow.includes(jestFnCall.name)) {
40
+ context.report({
41
+ node,
42
+ messageId: 'unexpectedHook',
43
+ data: {
44
+ hookName: jestFnCall.name
45
+ }
46
+ });
47
+ }
48
+ }
49
+ };
50
+ }
51
+ });
@@ -0,0 +1,73 @@
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 newDescribeContext = () => ({
9
+ describeTitles: [],
10
+ testTitles: []
11
+ });
12
+ var _default = exports.default = (0, _utils.createRule)({
13
+ name: __filename,
14
+ meta: {
15
+ docs: {
16
+ description: 'Disallow identical titles'
17
+ },
18
+ messages: {
19
+ multipleTestTitle: 'Test title is used multiple times in the same describe block',
20
+ multipleDescribeTitle: 'Describe block title is used multiple times in the same describe block'
21
+ },
22
+ schema: [],
23
+ type: 'suggestion'
24
+ },
25
+ defaultOptions: [],
26
+ create(context) {
27
+ const contexts = [newDescribeContext()];
28
+ return {
29
+ CallExpression(node) {
30
+ const currentLayer = contexts[contexts.length - 1];
31
+ const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
32
+ if (!jestFnCall) {
33
+ return;
34
+ }
35
+ if (jestFnCall.type === 'describe') {
36
+ contexts.push(newDescribeContext());
37
+ }
38
+ if (jestFnCall.members.find(s => (0, _utils.isSupportedAccessor)(s, 'each'))) {
39
+ return;
40
+ }
41
+ const [argument] = node.arguments;
42
+ if (!argument || !(0, _utils.isStringNode)(argument)) {
43
+ return;
44
+ }
45
+ const title = (0, _utils.getStringValue)(argument);
46
+ if (jestFnCall.type === 'test') {
47
+ if (currentLayer.testTitles.includes(title)) {
48
+ context.report({
49
+ messageId: 'multipleTestTitle',
50
+ node: argument
51
+ });
52
+ }
53
+ currentLayer.testTitles.push(title);
54
+ }
55
+ if (jestFnCall.type !== 'describe') {
56
+ return;
57
+ }
58
+ if (currentLayer.describeTitles.includes(title)) {
59
+ context.report({
60
+ messageId: 'multipleDescribeTitle',
61
+ node: argument
62
+ });
63
+ }
64
+ currentLayer.describeTitles.push(title);
65
+ },
66
+ 'CallExpression:exit'(node) {
67
+ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) {
68
+ contexts.pop();
69
+ }
70
+ }
71
+ };
72
+ }
73
+ });
@@ -0,0 +1,43 @@
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: 'Disallow string interpolation inside snapshots'
14
+ },
15
+ messages: {
16
+ noInterpolation: 'Do not use string interpolation inside of snapshots'
17
+ },
18
+ schema: [],
19
+ type: 'problem'
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ return {
24
+ CallExpression(node) {
25
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
26
+ if (jestFnCall?.type !== 'expect') {
27
+ return;
28
+ }
29
+ if (['toMatchInlineSnapshot', 'toThrowErrorMatchingInlineSnapshot'].includes((0, _utils2.getAccessorValue)(jestFnCall.matcher))) {
30
+ // Check all since the optional 'propertyMatchers' argument might be present
31
+ jestFnCall.args.forEach(argument => {
32
+ if (argument.type === _utils.AST_NODE_TYPES.TemplateLiteral && argument.expressions.length > 0) {
33
+ context.report({
34
+ messageId: 'noInterpolation',
35
+ node: argument
36
+ });
37
+ }
38
+ });
39
+ }
40
+ }
41
+ };
42
+ }
43
+ });