@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.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/changes.json +10 -0
- package/docs/rules/consistent-test-it.md +96 -0
- package/docs/rules/expect-expect.md +152 -0
- package/docs/rules/max-expects.md +78 -0
- package/docs/rules/max-nested-describe.md +134 -0
- package/docs/rules/no-alias-methods.md +57 -0
- package/docs/rules/no-commented-out-tests.md +68 -0
- package/docs/rules/no-conditional-expect.md +142 -0
- package/docs/rules/no-conditional-in-test.md +123 -0
- package/docs/rules/no-confusing-set-timeout.md +64 -0
- package/docs/rules/no-deprecated-functions.md +59 -0
- package/docs/rules/no-disabled-tests.md +72 -0
- package/docs/rules/no-done-callback.md +100 -0
- package/docs/rules/no-duplicate-hooks.md +79 -0
- package/docs/rules/no-error-equal.md +37 -0
- package/docs/rules/no-export.md +52 -0
- package/docs/rules/no-focused-tests.md +67 -0
- package/docs/rules/no-hooks.md +178 -0
- package/docs/rules/no-identical-title.md +59 -0
- package/docs/rules/no-interpolation-in-snapshots.md +67 -0
- package/docs/rules/no-jasmine-globals.md +69 -0
- package/docs/rules/no-large-snapshots.md +180 -0
- package/docs/rules/no-mocks-import.md +34 -0
- package/docs/rules/no-restricted-jest-methods.md +53 -0
- package/docs/rules/no-restricted-matchers.md +64 -0
- package/docs/rules/no-standalone-expect.md +106 -0
- package/docs/rules/no-test-prefixes.md +42 -0
- package/docs/rules/no-test-return-statement.md +50 -0
- package/docs/rules/no-unnecessary-assertion.md +41 -0
- package/docs/rules/no-unneeded-async-expect-function.md +41 -0
- package/docs/rules/no-untyped-mock-factory.md +74 -0
- package/docs/rules/padding-around-after-all-blocks.md +34 -0
- package/docs/rules/padding-around-after-each-blocks.md +38 -0
- package/docs/rules/padding-around-all.md +20 -0
- package/docs/rules/padding-around-before-all-blocks.md +37 -0
- package/docs/rules/padding-around-before-each-blocks.md +38 -0
- package/docs/rules/padding-around-describe-blocks.md +42 -0
- package/docs/rules/padding-around-expect-groups.md +44 -0
- package/docs/rules/padding-around-test-blocks.md +48 -0
- package/docs/rules/prefer-called-with.md +39 -0
- package/docs/rules/prefer-comparison-matcher.md +62 -0
- package/docs/rules/prefer-each.md +58 -0
- package/docs/rules/prefer-ending-with-an-expect.md +170 -0
- package/docs/rules/prefer-equality-matcher.md +36 -0
- package/docs/rules/prefer-expect-assertions.md +230 -0
- package/docs/rules/prefer-expect-resolves.md +62 -0
- package/docs/rules/prefer-hooks-in-order.md +137 -0
- package/docs/rules/prefer-hooks-on-top.md +124 -0
- package/docs/rules/prefer-importing-jest-globals.md +85 -0
- package/docs/rules/prefer-jest-mocked.md +40 -0
- package/docs/rules/prefer-lowercase-title.md +128 -0
- package/docs/rules/prefer-mock-promise-shorthand.md +41 -0
- package/docs/rules/prefer-mock-return-shorthand.md +50 -0
- package/docs/rules/prefer-snapshot-hint.md +192 -0
- package/docs/rules/prefer-spy-on.md +46 -0
- package/docs/rules/prefer-strict-equal.md +29 -0
- package/docs/rules/prefer-to-be.md +63 -0
- package/docs/rules/prefer-to-contain.md +53 -0
- package/docs/rules/prefer-to-have-been-called-times.md +43 -0
- package/docs/rules/prefer-to-have-been-called.md +35 -0
- package/docs/rules/prefer-to-have-length.md +41 -0
- package/docs/rules/prefer-todo.md +33 -0
- package/docs/rules/require-hook.md +187 -0
- package/docs/rules/require-to-throw-message.md +43 -0
- package/docs/rules/require-top-level-describe.md +86 -0
- package/docs/rules/unbound-method.md +61 -0
- package/docs/rules/valid-describe-callback.md +69 -0
- package/docs/rules/valid-expect-in-promise.md +79 -0
- package/docs/rules/valid-expect-with-promise.md +43 -0
- package/docs/rules/valid-expect.md +155 -0
- package/docs/rules/valid-mock-module-path.md +72 -0
- package/docs/rules/valid-title.md +319 -0
- package/index.d.ts +28 -0
- package/lib/globals.json +15 -0
- package/lib/index.js +85 -0
- package/lib/rules/consistent-test-it.js +101 -0
- package/lib/rules/expect-expect.js +102 -0
- package/lib/rules/max-expects.js +70 -0
- package/lib/rules/max-nested-describe.js +59 -0
- package/lib/rules/no-alias-methods.js +62 -0
- package/lib/rules/no-commented-out-tests.js +44 -0
- package/lib/rules/no-conditional-expect.js +80 -0
- package/lib/rules/no-conditional-in-test.js +63 -0
- package/lib/rules/no-confusing-set-timeout.js +61 -0
- package/lib/rules/no-deprecated-functions.js +81 -0
- package/lib/rules/no-disabled-tests.js +57 -0
- package/lib/rules/no-done-callback.js +120 -0
- package/lib/rules/no-duplicate-hooks.js +52 -0
- package/lib/rules/no-error-equal.js +41 -0
- package/lib/rules/no-export.js +61 -0
- package/lib/rules/no-focused-tests.js +63 -0
- package/lib/rules/no-hooks.js +51 -0
- package/lib/rules/no-identical-title.js +73 -0
- package/lib/rules/no-interpolation-in-snapshots.js +43 -0
- package/lib/rules/no-jasmine-globals.js +140 -0
- package/lib/rules/no-large-snapshots.js +100 -0
- package/lib/rules/no-mocks-import.js +46 -0
- package/lib/rules/no-restricted-jest-methods.js +53 -0
- package/lib/rules/no-restricted-matchers.js +60 -0
- package/lib/rules/no-standalone-expect.js +114 -0
- package/lib/rules/no-test-prefixes.js +48 -0
- package/lib/rules/no-test-return-statement.js +62 -0
- package/lib/rules/no-unnecessary-assertion.js +87 -0
- package/lib/rules/no-unneeded-async-expect-function.js +57 -0
- package/lib/rules/no-untyped-mock-factory.js +61 -0
- package/lib/rules/padding-around-after-all-blocks.js +17 -0
- package/lib/rules/padding-around-after-each-blocks.js +17 -0
- package/lib/rules/padding-around-all.js +15 -0
- package/lib/rules/padding-around-before-all-blocks.js +17 -0
- package/lib/rules/padding-around-before-each-blocks.js +17 -0
- package/lib/rules/padding-around-describe-blocks.js +17 -0
- package/lib/rules/padding-around-expect-groups.js +21 -0
- package/lib/rules/padding-around-test-blocks.js +17 -0
- package/lib/rules/prefer-called-with.js +47 -0
- package/lib/rules/prefer-comparison-matcher.js +111 -0
- package/lib/rules/prefer-each.js +77 -0
- package/lib/rules/prefer-ending-with-an-expect.js +102 -0
- package/lib/rules/prefer-equality-matcher.js +87 -0
- package/lib/rules/prefer-expect-assertions.js +237 -0
- package/lib/rules/prefer-expect-resolves.js +47 -0
- package/lib/rules/prefer-hooks-in-order.js +67 -0
- package/lib/rules/prefer-hooks-on-top.js +41 -0
- package/lib/rules/prefer-importing-jest-globals.js +126 -0
- package/lib/rules/prefer-jest-mocked.js +66 -0
- package/lib/rules/prefer-lowercase-title.js +128 -0
- package/lib/rules/prefer-mock-promise-shorthand.js +88 -0
- package/lib/rules/prefer-mock-return-shorthand.js +122 -0
- package/lib/rules/prefer-snapshot-hint.js +111 -0
- package/lib/rules/prefer-spy-on.js +80 -0
- package/lib/rules/prefer-strict-equal.js +46 -0
- package/lib/rules/prefer-to-be.js +98 -0
- package/lib/rules/prefer-to-contain.js +82 -0
- package/lib/rules/prefer-to-have-been-called-times.js +70 -0
- package/lib/rules/prefer-to-have-been-called.js +59 -0
- package/lib/rules/prefer-to-have-length.js +57 -0
- package/lib/rules/prefer-todo.js +72 -0
- package/lib/rules/require-hook.js +93 -0
- package/lib/rules/require-to-throw-message.js +45 -0
- package/lib/rules/require-top-level-describe.js +86 -0
- package/lib/rules/unbound-method.js +86 -0
- package/lib/rules/utils/accessors.js +127 -0
- package/lib/rules/utils/ast-utils.js +59 -0
- package/lib/rules/utils/detectJestVersion.js +24 -0
- package/lib/rules/utils/followTypeAssertionChain.js +10 -0
- package/lib/rules/utils/index.js +71 -0
- package/lib/rules/utils/misc.js +168 -0
- package/lib/rules/utils/padding.js +308 -0
- package/lib/rules/utils/parseJestFnCall.js +325 -0
- package/lib/rules/utils/ts.js +73 -0
- package/lib/rules/valid-describe-callback.js +94 -0
- package/lib/rules/valid-expect-in-promise.js +311 -0
- package/lib/rules/valid-expect-with-promise.js +54 -0
- package/lib/rules/valid-expect.js +302 -0
- package/lib/rules/valid-mock-module-path.js +90 -0
- package/lib/rules/valid-title.js +252 -0
- 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
|
+
});
|