@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,140 @@
|
|
|
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 Jasmine globals'
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
illegalGlobal: 'Illegal usage of global `{{ global }}`, prefer `{{ replacement }}`',
|
|
17
|
+
illegalMethod: 'Illegal usage of `{{ method }}`, prefer `{{ replacement }}`',
|
|
18
|
+
illegalFail: 'Illegal usage of `fail`, prefer throwing an error, or the `done.fail` callback',
|
|
19
|
+
illegalPending: 'Illegal usage of `pending`, prefer explicitly skipping a test using `test.skip`',
|
|
20
|
+
illegalJasmine: 'Illegal usage of jasmine global'
|
|
21
|
+
},
|
|
22
|
+
fixable: 'code',
|
|
23
|
+
schema: [],
|
|
24
|
+
type: 'suggestion'
|
|
25
|
+
},
|
|
26
|
+
defaultOptions: [],
|
|
27
|
+
create(context) {
|
|
28
|
+
return {
|
|
29
|
+
CallExpression(node) {
|
|
30
|
+
const {
|
|
31
|
+
callee
|
|
32
|
+
} = node;
|
|
33
|
+
const calleeName = (0, _utils2.getNodeName)(callee);
|
|
34
|
+
if (!calleeName) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (calleeName === 'spyOn' || calleeName === 'spyOnProperty' || calleeName === 'fail' || calleeName === 'pending') {
|
|
38
|
+
if ((0, _utils2.resolveScope)(context.sourceCode.getScope(node), calleeName)) {
|
|
39
|
+
// It's a local variable, not a jasmine global.
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
switch (calleeName) {
|
|
43
|
+
case 'spyOn':
|
|
44
|
+
case 'spyOnProperty':
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: 'illegalGlobal',
|
|
48
|
+
data: {
|
|
49
|
+
global: calleeName,
|
|
50
|
+
replacement: 'jest.spyOn'
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
break;
|
|
54
|
+
case 'fail':
|
|
55
|
+
context.report({
|
|
56
|
+
node,
|
|
57
|
+
messageId: 'illegalFail'
|
|
58
|
+
});
|
|
59
|
+
break;
|
|
60
|
+
case 'pending':
|
|
61
|
+
context.report({
|
|
62
|
+
node,
|
|
63
|
+
messageId: 'illegalPending'
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (callee.type === _utils.AST_NODE_TYPES.MemberExpression && calleeName.startsWith('jasmine.')) {
|
|
70
|
+
const functionName = calleeName.replace('jasmine.', '');
|
|
71
|
+
if (functionName === 'any' || functionName === 'anything' || functionName === 'arrayContaining' || functionName === 'objectContaining' || functionName === 'stringMatching') {
|
|
72
|
+
context.report({
|
|
73
|
+
fix: fixer => [fixer.replaceText(callee.object, 'expect')],
|
|
74
|
+
node,
|
|
75
|
+
messageId: 'illegalMethod',
|
|
76
|
+
data: {
|
|
77
|
+
method: calleeName,
|
|
78
|
+
replacement: `expect.${functionName}`
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (functionName === 'addMatchers') {
|
|
84
|
+
context.report({
|
|
85
|
+
node,
|
|
86
|
+
messageId: 'illegalMethod',
|
|
87
|
+
data: {
|
|
88
|
+
method: calleeName,
|
|
89
|
+
replacement: 'expect.extend'
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (functionName === 'createSpy') {
|
|
95
|
+
context.report({
|
|
96
|
+
node,
|
|
97
|
+
messageId: 'illegalMethod',
|
|
98
|
+
data: {
|
|
99
|
+
method: calleeName,
|
|
100
|
+
replacement: 'jest.fn'
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
context.report({
|
|
106
|
+
node,
|
|
107
|
+
messageId: 'illegalJasmine'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
MemberExpression(node) {
|
|
112
|
+
if ((0, _utils2.isSupportedAccessor)(node.object, 'jasmine')) {
|
|
113
|
+
const {
|
|
114
|
+
parent,
|
|
115
|
+
property
|
|
116
|
+
} = node;
|
|
117
|
+
if (parent && parent.type === _utils.AST_NODE_TYPES.AssignmentExpression) {
|
|
118
|
+
if ((0, _utils2.isSupportedAccessor)(property, 'DEFAULT_TIMEOUT_INTERVAL')) {
|
|
119
|
+
const {
|
|
120
|
+
right
|
|
121
|
+
} = parent;
|
|
122
|
+
if (right.type === _utils.AST_NODE_TYPES.Literal) {
|
|
123
|
+
context.report({
|
|
124
|
+
fix: fixer => [fixer.replaceText(parent, `jest.setTimeout(${right.value})`)],
|
|
125
|
+
node,
|
|
126
|
+
messageId: 'illegalJasmine'
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
context.report({
|
|
132
|
+
node,
|
|
133
|
+
messageId: 'illegalJasmine'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _path = require("path");
|
|
8
|
+
var _utils = require("@typescript-eslint/utils");
|
|
9
|
+
var _utils2 = require("./utils");
|
|
10
|
+
const reportOnViolation = (context, node, {
|
|
11
|
+
maxSize: lineLimit = 50,
|
|
12
|
+
allowedSnapshots = {}
|
|
13
|
+
}) => {
|
|
14
|
+
const startLine = node.loc.start.line;
|
|
15
|
+
const endLine = node.loc.end.line;
|
|
16
|
+
const lineCount = endLine - startLine;
|
|
17
|
+
const allPathsAreAbsolute = Object.keys(allowedSnapshots).every(_path.isAbsolute);
|
|
18
|
+
if (!allPathsAreAbsolute) {
|
|
19
|
+
throw new Error('All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`');
|
|
20
|
+
}
|
|
21
|
+
let isAllowed = false;
|
|
22
|
+
if (node.type === _utils.AST_NODE_TYPES.ExpressionStatement && 'left' in node.expression && node.expression.left.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.expression.left.property)) {
|
|
23
|
+
const fileName = context.filename;
|
|
24
|
+
const allowedSnapshotsInFile = allowedSnapshots[fileName];
|
|
25
|
+
if (allowedSnapshotsInFile) {
|
|
26
|
+
const snapshotName = (0, _utils2.getAccessorValue)(node.expression.left.property);
|
|
27
|
+
isAllowed = allowedSnapshotsInFile.some(name => {
|
|
28
|
+
if (typeof name === 'string') {
|
|
29
|
+
return snapshotName === name;
|
|
30
|
+
}
|
|
31
|
+
return name.test(snapshotName);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!isAllowed && lineCount > lineLimit) {
|
|
36
|
+
context.report({
|
|
37
|
+
messageId: lineLimit === 0 ? 'noSnapshot' : 'tooLongSnapshots',
|
|
38
|
+
data: {
|
|
39
|
+
lineLimit,
|
|
40
|
+
lineCount
|
|
41
|
+
},
|
|
42
|
+
node
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var _default = exports.default = (0, _utils2.createRule)({
|
|
47
|
+
name: __filename,
|
|
48
|
+
meta: {
|
|
49
|
+
docs: {
|
|
50
|
+
description: 'Disallow large snapshots'
|
|
51
|
+
},
|
|
52
|
+
messages: {
|
|
53
|
+
noSnapshot: 'Expected to not encounter a Jest snapshot but one was found that is {{ lineCount }} lines long',
|
|
54
|
+
tooLongSnapshots: 'Expected Jest snapshot to be smaller than {{ lineLimit }} lines but was {{ lineCount }} lines long'
|
|
55
|
+
},
|
|
56
|
+
type: 'suggestion',
|
|
57
|
+
schema: [{
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
maxSize: {
|
|
61
|
+
type: 'number'
|
|
62
|
+
},
|
|
63
|
+
inlineMaxSize: {
|
|
64
|
+
type: 'number'
|
|
65
|
+
},
|
|
66
|
+
allowedSnapshots: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
additionalProperties: {
|
|
69
|
+
type: 'array'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
additionalProperties: false
|
|
74
|
+
}]
|
|
75
|
+
},
|
|
76
|
+
defaultOptions: [{}],
|
|
77
|
+
create(context, [options]) {
|
|
78
|
+
if (context.filename.endsWith('.snap')) {
|
|
79
|
+
return {
|
|
80
|
+
ExpressionStatement(node) {
|
|
81
|
+
reportOnViolation(context, node, options);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
CallExpression(node) {
|
|
87
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
88
|
+
if (jestFnCall?.type !== 'expect') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (['toMatchInlineSnapshot', 'toThrowErrorMatchingInlineSnapshot'].includes((0, _utils2.getAccessorValue)(jestFnCall.matcher)) && jestFnCall.args.length) {
|
|
92
|
+
reportOnViolation(context, jestFnCall.args[0], {
|
|
93
|
+
...options,
|
|
94
|
+
maxSize: options.inlineMaxSize ?? options.maxSize
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _path = require("path");
|
|
8
|
+
var _utils = require("./utils");
|
|
9
|
+
const mocksDirName = '__mocks__';
|
|
10
|
+
const isMockPath = path => path.split(_path.posix.sep).includes(mocksDirName);
|
|
11
|
+
const isMockImportLiteral = expression => (0, _utils.isStringNode)(expression) && isMockPath((0, _utils.getStringValue)(expression));
|
|
12
|
+
var _default = exports.default = (0, _utils.createRule)({
|
|
13
|
+
name: __filename,
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'problem',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Disallow manually importing from `__mocks__`'
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
noManualImport: `Mocks should not be manually imported from a ${mocksDirName} directory. Instead use \`jest.mock\` and import from the original module path`
|
|
21
|
+
},
|
|
22
|
+
schema: []
|
|
23
|
+
},
|
|
24
|
+
defaultOptions: [],
|
|
25
|
+
create(context) {
|
|
26
|
+
return {
|
|
27
|
+
ImportDeclaration(node) {
|
|
28
|
+
if (isMockImportLiteral(node.source)) {
|
|
29
|
+
context.report({
|
|
30
|
+
node,
|
|
31
|
+
messageId: 'noManualImport'
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
'CallExpression[callee.name="require"]'(node) {
|
|
36
|
+
const [arg] = node.arguments;
|
|
37
|
+
if (arg && isMockImportLiteral(arg)) {
|
|
38
|
+
context.report({
|
|
39
|
+
node: arg,
|
|
40
|
+
messageId: 'noManualImport'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
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 messages = {
|
|
9
|
+
restrictedJestMethod: 'Use of `{{ restriction }}` is disallowed',
|
|
10
|
+
restrictedJestMethodWithMessage: '{{ message }}'
|
|
11
|
+
};
|
|
12
|
+
var _default = exports.default = (0, _utils.createRule)({
|
|
13
|
+
name: __filename,
|
|
14
|
+
meta: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Disallow specific `jest.` methods'
|
|
17
|
+
},
|
|
18
|
+
type: 'suggestion',
|
|
19
|
+
schema: [{
|
|
20
|
+
type: 'object',
|
|
21
|
+
additionalProperties: {
|
|
22
|
+
type: ['string', 'null']
|
|
23
|
+
}
|
|
24
|
+
}],
|
|
25
|
+
messages
|
|
26
|
+
},
|
|
27
|
+
defaultOptions: [{}],
|
|
28
|
+
create(context, [restrictedMethods]) {
|
|
29
|
+
return {
|
|
30
|
+
CallExpression(node) {
|
|
31
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
32
|
+
if (jestFnCall?.type !== 'jest' || jestFnCall.members.length === 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const method = (0, _utils.getAccessorValue)(jestFnCall.members[0]);
|
|
36
|
+
if (method in restrictedMethods) {
|
|
37
|
+
const message = restrictedMethods[method];
|
|
38
|
+
context.report({
|
|
39
|
+
messageId: message ? 'restrictedJestMethodWithMessage' : 'restrictedJestMethod',
|
|
40
|
+
data: {
|
|
41
|
+
message,
|
|
42
|
+
restriction: method
|
|
43
|
+
},
|
|
44
|
+
loc: {
|
|
45
|
+
start: jestFnCall.members[0].loc.start,
|
|
46
|
+
end: jestFnCall.members[jestFnCall.members.length - 1].loc.end
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
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 isChainRestricted = (chain, restriction) => {
|
|
9
|
+
if (_utils.ModifierName.hasOwnProperty(restriction) || restriction.endsWith('.not')) {
|
|
10
|
+
return chain.startsWith(restriction);
|
|
11
|
+
}
|
|
12
|
+
return chain === restriction;
|
|
13
|
+
};
|
|
14
|
+
var _default = exports.default = (0, _utils.createRule)({
|
|
15
|
+
name: __filename,
|
|
16
|
+
meta: {
|
|
17
|
+
docs: {
|
|
18
|
+
description: 'Disallow specific matchers & modifiers'
|
|
19
|
+
},
|
|
20
|
+
type: 'suggestion',
|
|
21
|
+
schema: [{
|
|
22
|
+
type: 'object',
|
|
23
|
+
additionalProperties: {
|
|
24
|
+
type: ['string', 'null']
|
|
25
|
+
}
|
|
26
|
+
}],
|
|
27
|
+
messages: {
|
|
28
|
+
restrictedChain: 'Use of `{{ restriction }}` is disallowed',
|
|
29
|
+
restrictedChainWithMessage: '{{ message }}'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [{}],
|
|
33
|
+
create(context, [restrictedChains]) {
|
|
34
|
+
return {
|
|
35
|
+
CallExpression(node) {
|
|
36
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
37
|
+
if (jestFnCall?.type !== 'expect') {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const chain = jestFnCall.members.map(nod => (0, _utils.getAccessorValue)(nod)).join('.');
|
|
41
|
+
for (const [restriction, message] of Object.entries(restrictedChains)) {
|
|
42
|
+
if (isChainRestricted(chain, restriction)) {
|
|
43
|
+
context.report({
|
|
44
|
+
messageId: message ? 'restrictedChainWithMessage' : 'restrictedChain',
|
|
45
|
+
data: {
|
|
46
|
+
message,
|
|
47
|
+
restriction
|
|
48
|
+
},
|
|
49
|
+
loc: {
|
|
50
|
+
start: jestFnCall.members[0].loc.start,
|
|
51
|
+
end: jestFnCall.members[jestFnCall.members.length - 1].loc.end
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
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 getBlockType = (statement, context) => {
|
|
10
|
+
const func = statement.parent;
|
|
11
|
+
|
|
12
|
+
// functionDeclaration: function func() {}
|
|
13
|
+
if (func.type === _utils.AST_NODE_TYPES.FunctionDeclaration) {
|
|
14
|
+
return 'function';
|
|
15
|
+
}
|
|
16
|
+
if ((0, _utils2.isFunction)(func)) {
|
|
17
|
+
const expr = func.parent;
|
|
18
|
+
|
|
19
|
+
// arrow function or function expr
|
|
20
|
+
if (expr.type === _utils.AST_NODE_TYPES.VariableDeclarator) {
|
|
21
|
+
return 'function';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// if it's not a variable, it will be callExpr, we only care about describe
|
|
25
|
+
if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(expr, context, ['describe'])) {
|
|
26
|
+
return 'describe';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
var _default = exports.default = (0, _utils2.createRule)({
|
|
32
|
+
name: __filename,
|
|
33
|
+
meta: {
|
|
34
|
+
docs: {
|
|
35
|
+
description: 'Disallow using `expect` outside of `it` or `test` blocks'
|
|
36
|
+
},
|
|
37
|
+
messages: {
|
|
38
|
+
unexpectedExpect: 'Expect must be inside of a test block'
|
|
39
|
+
},
|
|
40
|
+
type: 'suggestion',
|
|
41
|
+
schema: [{
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
additionalTestBlockFunctions: {
|
|
45
|
+
type: 'array',
|
|
46
|
+
items: {
|
|
47
|
+
type: 'string'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
additionalProperties: false
|
|
52
|
+
}]
|
|
53
|
+
},
|
|
54
|
+
defaultOptions: [{
|
|
55
|
+
additionalTestBlockFunctions: []
|
|
56
|
+
}],
|
|
57
|
+
create(context, [{
|
|
58
|
+
additionalTestBlockFunctions = []
|
|
59
|
+
}]) {
|
|
60
|
+
const callStack = [];
|
|
61
|
+
const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils2.getNodeName)(node) || '');
|
|
62
|
+
return {
|
|
63
|
+
CallExpression(node) {
|
|
64
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
65
|
+
if (jestFnCall?.type === 'expect') {
|
|
66
|
+
if (jestFnCall.head.node.parent.type === _utils.AST_NODE_TYPES.MemberExpression && jestFnCall.members.length === 1 && !['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const parent = callStack[callStack.length - 1];
|
|
70
|
+
if (!parent || parent === _utils2.DescribeAlias.describe) {
|
|
71
|
+
context.report({
|
|
72
|
+
node,
|
|
73
|
+
messageId: 'unexpectedExpect'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (jestFnCall?.type === 'test' || isCustomTestBlockFunction(node)) {
|
|
79
|
+
callStack.push('test');
|
|
80
|
+
}
|
|
81
|
+
if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
82
|
+
callStack.push('template');
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
'CallExpression:exit'(node) {
|
|
86
|
+
const top = callStack[callStack.length - 1];
|
|
87
|
+
if (top === 'test' && ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test']) || isCustomTestBlockFunction(node)) && node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression || top === 'template' && node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
88
|
+
callStack.pop();
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
BlockStatement(statement) {
|
|
92
|
+
const blockType = getBlockType(statement, context);
|
|
93
|
+
if (blockType) {
|
|
94
|
+
callStack.push(blockType);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
'BlockStatement:exit'(statement) {
|
|
98
|
+
if (callStack[callStack.length - 1] === getBlockType(statement, context)) {
|
|
99
|
+
callStack.pop();
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
ArrowFunctionExpression(node) {
|
|
103
|
+
if (node.parent.type !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
104
|
+
callStack.push('arrow');
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
'ArrowFunctionExpression:exit'() {
|
|
108
|
+
if (callStack[callStack.length - 1] === 'arrow') {
|
|
109
|
+
callStack.pop();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
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: 'Require using `.only` and `.skip` over `f` and `x`'
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
usePreferredName: 'Use "{{ preferredNodeName }}" instead'
|
|
17
|
+
},
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
schema: [],
|
|
20
|
+
type: 'suggestion'
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
return {
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
27
|
+
if (jestFnCall?.type !== 'describe' && jestFnCall?.type !== 'test') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (jestFnCall.name[0] !== 'f' && jestFnCall.name[0] !== 'x') {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const preferredNodeName = [jestFnCall.name.slice(1), jestFnCall.name[0] === 'f' ? 'only' : 'skip', ...jestFnCall.members.map(s => (0, _utils2.getAccessorValue)(s))].join('.');
|
|
34
|
+
const funcNode = node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _utils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
|
|
35
|
+
context.report({
|
|
36
|
+
messageId: 'usePreferredName',
|
|
37
|
+
node: node.callee,
|
|
38
|
+
data: {
|
|
39
|
+
preferredNodeName
|
|
40
|
+
},
|
|
41
|
+
fix(fixer) {
|
|
42
|
+
return [fixer.replaceText(funcNode, preferredNodeName)];
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
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 getBody = args => {
|
|
10
|
+
const [, secondArg] = args;
|
|
11
|
+
if (secondArg && (0, _utils2.isFunction)(secondArg) && secondArg.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
12
|
+
return secondArg.body.body;
|
|
13
|
+
}
|
|
14
|
+
return [];
|
|
15
|
+
};
|
|
16
|
+
var _default = exports.default = (0, _utils2.createRule)({
|
|
17
|
+
name: __filename,
|
|
18
|
+
meta: {
|
|
19
|
+
docs: {
|
|
20
|
+
description: 'Disallow explicitly returning from tests'
|
|
21
|
+
},
|
|
22
|
+
messages: {
|
|
23
|
+
noReturnValue: 'Jest tests should not return a value'
|
|
24
|
+
},
|
|
25
|
+
schema: [],
|
|
26
|
+
type: 'suggestion'
|
|
27
|
+
},
|
|
28
|
+
defaultOptions: [],
|
|
29
|
+
create(context) {
|
|
30
|
+
return {
|
|
31
|
+
CallExpression(node) {
|
|
32
|
+
if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const body = getBody(node.arguments);
|
|
36
|
+
const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
37
|
+
if (!returnStmt) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
context.report({
|
|
41
|
+
messageId: 'noReturnValue',
|
|
42
|
+
node: returnStmt
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
FunctionDeclaration(node) {
|
|
46
|
+
const declaredVariables = context.sourceCode.getDeclaredVariables(node);
|
|
47
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context);
|
|
48
|
+
if (testCallExpressions.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const returnStmt = node.body.body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
52
|
+
if (!returnStmt) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
context.report({
|
|
56
|
+
messageId: 'noReturnValue',
|
|
57
|
+
node: returnStmt
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
});
|