@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,45 @@
|
|
|
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: 'Require a message for `toThrow()`'
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
addErrorMessage: 'Add an error message to {{ matcherName }}()'
|
|
16
|
+
},
|
|
17
|
+
type: 'suggestion',
|
|
18
|
+
schema: []
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
return {
|
|
23
|
+
CallExpression(node) {
|
|
24
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
25
|
+
if (jestFnCall?.type !== 'expect') {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const {
|
|
29
|
+
matcher
|
|
30
|
+
} = jestFnCall;
|
|
31
|
+
const matcherName = (0, _utils.getAccessorValue)(matcher);
|
|
32
|
+
if (jestFnCall.args.length === 0 && ['toThrow', 'toThrowError'].includes(matcherName) && !jestFnCall.modifiers.some(nod => (0, _utils.getAccessorValue)(nod) === 'not')) {
|
|
33
|
+
// Look for `toThrow` calls with no arguments.
|
|
34
|
+
context.report({
|
|
35
|
+
messageId: 'addErrorMessage',
|
|
36
|
+
data: {
|
|
37
|
+
matcherName
|
|
38
|
+
},
|
|
39
|
+
node: matcher
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
tooManyDescribes: 'There should not be more than {{ max }} describe{{ s }} at the top level',
|
|
10
|
+
unexpectedTestCase: 'All test cases must be wrapped in a describe block.',
|
|
11
|
+
unexpectedHook: 'All hooks must be wrapped in a describe block.'
|
|
12
|
+
};
|
|
13
|
+
var _default = exports.default = (0, _utils.createRule)({
|
|
14
|
+
name: __filename,
|
|
15
|
+
meta: {
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Require test cases and hooks to be inside a `describe` block'
|
|
18
|
+
},
|
|
19
|
+
messages,
|
|
20
|
+
type: 'suggestion',
|
|
21
|
+
schema: [{
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
maxNumberOfTopLevelDescribes: {
|
|
25
|
+
type: 'number',
|
|
26
|
+
minimum: 1
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}]
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [{}],
|
|
33
|
+
create(context) {
|
|
34
|
+
const {
|
|
35
|
+
maxNumberOfTopLevelDescribes = Infinity
|
|
36
|
+
} = context.options[0] ?? {};
|
|
37
|
+
let numberOfTopLevelDescribeBlocks = 0;
|
|
38
|
+
let numberOfDescribeBlocks = 0;
|
|
39
|
+
return {
|
|
40
|
+
CallExpression(node) {
|
|
41
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
42
|
+
if (!jestFnCall) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (jestFnCall.type === 'describe') {
|
|
46
|
+
numberOfDescribeBlocks++;
|
|
47
|
+
if (numberOfDescribeBlocks === 1) {
|
|
48
|
+
numberOfTopLevelDescribeBlocks++;
|
|
49
|
+
if (numberOfTopLevelDescribeBlocks > maxNumberOfTopLevelDescribes) {
|
|
50
|
+
context.report({
|
|
51
|
+
node,
|
|
52
|
+
messageId: 'tooManyDescribes',
|
|
53
|
+
data: {
|
|
54
|
+
max: maxNumberOfTopLevelDescribes,
|
|
55
|
+
s: maxNumberOfTopLevelDescribes === 1 ? '' : 's'
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (numberOfDescribeBlocks === 0) {
|
|
63
|
+
if (jestFnCall.type === 'test') {
|
|
64
|
+
context.report({
|
|
65
|
+
node,
|
|
66
|
+
messageId: 'unexpectedTestCase'
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (jestFnCall.type === 'hook') {
|
|
71
|
+
context.report({
|
|
72
|
+
node,
|
|
73
|
+
messageId: 'unexpectedHook'
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
'CallExpression:exit'(node) {
|
|
80
|
+
if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) {
|
|
81
|
+
numberOfDescribeBlocks--;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
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 toThrowMatchers = ['toThrow', 'toThrowError', 'toThrowErrorMatchingSnapshot', 'toThrowErrorMatchingInlineSnapshot'];
|
|
10
|
+
const baseRule = (() => {
|
|
11
|
+
try {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
13
|
+
const TSESLintPlugin = require('@typescript-eslint/eslint-plugin');
|
|
14
|
+
return TSESLintPlugin.rules['unbound-method'];
|
|
15
|
+
} catch (e) {
|
|
16
|
+
const error = e;
|
|
17
|
+
if (error.code === 'MODULE_NOT_FOUND') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
const DEFAULT_MESSAGE = 'This rule requires `@typescript-eslint/eslint-plugin`';
|
|
24
|
+
var _default = exports.default = (0, _utils2.createRule)({
|
|
25
|
+
defaultOptions: [{
|
|
26
|
+
ignoreStatic: false
|
|
27
|
+
}],
|
|
28
|
+
...baseRule,
|
|
29
|
+
name: __filename,
|
|
30
|
+
meta: {
|
|
31
|
+
messages: {
|
|
32
|
+
unbound: DEFAULT_MESSAGE,
|
|
33
|
+
unboundWithoutThisAnnotation: DEFAULT_MESSAGE
|
|
34
|
+
},
|
|
35
|
+
schema: [],
|
|
36
|
+
type: 'problem',
|
|
37
|
+
...baseRule?.meta,
|
|
38
|
+
docs: {
|
|
39
|
+
description: 'Enforce unbound methods are called with their expected scope',
|
|
40
|
+
...baseRule?.meta.docs
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
create(context) {
|
|
44
|
+
const baseSelectors = baseRule?.create(context);
|
|
45
|
+
if (!baseSelectors) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Checks if a MemberExpression is an argument to a `jest.mocked()` call.
|
|
51
|
+
* This handles cases like `jest.mocked(service.method)` where `service.method`
|
|
52
|
+
* should not be flagged as an unbound method.
|
|
53
|
+
*/
|
|
54
|
+
const isArgumentToJestMocked = node => {
|
|
55
|
+
// Check if the immediate parent is a CallExpression
|
|
56
|
+
if (node.parent?.type !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const parentCall = node.parent;
|
|
60
|
+
return parentCall.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(parentCall.callee.object, 'jest') && (0, _utils2.isSupportedAccessor)(parentCall.callee.property, 'mocked');
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
...baseSelectors,
|
|
64
|
+
MemberExpression(node) {
|
|
65
|
+
if (isArgumentToJestMocked(node)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (node.parent?.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
69
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)((0, _utils2.findTopMostCallExpression)(node.parent), context);
|
|
70
|
+
if (jestFnCall?.type === 'jest' && jestFnCall.members.length >= 1 && (0, _utils2.isIdentifier)(jestFnCall.members[0], 'mocked')) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (jestFnCall?.type === 'expect') {
|
|
74
|
+
const {
|
|
75
|
+
matcher
|
|
76
|
+
} = jestFnCall;
|
|
77
|
+
if (!toThrowMatchers.includes((0, _utils2.getAccessorValue)(matcher))) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
baseSelectors.MemberExpression?.(node);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isSupportedAccessor = exports.isStringNode = exports.isIdentifier = exports.getStringValue = exports.getAccessorValue = void 0;
|
|
7
|
+
var _utils = require("@typescript-eslint/utils");
|
|
8
|
+
/**
|
|
9
|
+
* A `Literal` with a `value` of type `string`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Checks if the given `node` is a `StringLiteral`.
|
|
14
|
+
*
|
|
15
|
+
* If a `value` is provided & the `node` is a `StringLiteral`,
|
|
16
|
+
* the `value` will be compared to that of the `StringLiteral`.
|
|
17
|
+
*
|
|
18
|
+
* @param {Node} node
|
|
19
|
+
* @param {V} [value]
|
|
20
|
+
*
|
|
21
|
+
* @return {node is StringLiteral<V>}
|
|
22
|
+
*
|
|
23
|
+
* @template V
|
|
24
|
+
*/
|
|
25
|
+
const isStringLiteral = (node, value) => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'string' && (value === undefined || node.value === value);
|
|
26
|
+
/**
|
|
27
|
+
* Checks if the given `node` is a `TemplateLiteral`.
|
|
28
|
+
*
|
|
29
|
+
* Complex `TemplateLiteral`s are not considered specific, and so will return `false`.
|
|
30
|
+
*
|
|
31
|
+
* If a `value` is provided & the `node` is a `TemplateLiteral`,
|
|
32
|
+
* the `value` will be compared to that of the `TemplateLiteral`.
|
|
33
|
+
*
|
|
34
|
+
* @param {Node} node
|
|
35
|
+
* @param {V} [value]
|
|
36
|
+
*
|
|
37
|
+
* @return {node is TemplateLiteral<V>}
|
|
38
|
+
*
|
|
39
|
+
* @template V
|
|
40
|
+
*/
|
|
41
|
+
const isTemplateLiteral = (node, value) => node.type === _utils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1 && (
|
|
42
|
+
// bail out if not simple
|
|
43
|
+
value === undefined || node.quasis[0].value.raw === value);
|
|
44
|
+
/**
|
|
45
|
+
* Checks if the given `node` is a {@link StringNode}.
|
|
46
|
+
*
|
|
47
|
+
* @param {Node} node
|
|
48
|
+
* @param {V} [specifics]
|
|
49
|
+
*
|
|
50
|
+
* @return {node is StringNode}
|
|
51
|
+
*
|
|
52
|
+
* @template V
|
|
53
|
+
*/
|
|
54
|
+
const isStringNode = (node, specifics) => isStringLiteral(node, specifics) || isTemplateLiteral(node, specifics);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gets the value of the given `StringNode`.
|
|
58
|
+
*
|
|
59
|
+
* If the `node` is a `TemplateLiteral`, the `raw` value is used;
|
|
60
|
+
* otherwise, `value` is returned instead.
|
|
61
|
+
*
|
|
62
|
+
* @param {StringNode<S>} node
|
|
63
|
+
*
|
|
64
|
+
* @return {S}
|
|
65
|
+
*
|
|
66
|
+
* @template S
|
|
67
|
+
*/
|
|
68
|
+
exports.isStringNode = isStringNode;
|
|
69
|
+
const getStringValue = node => isTemplateLiteral(node) ? node.quasis[0].value.raw : node.value;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* An `Identifier` with a known `name` value - i.e `expect`.
|
|
73
|
+
*/
|
|
74
|
+
exports.getStringValue = getStringValue;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if the given `node` is an `Identifier`.
|
|
77
|
+
*
|
|
78
|
+
* If a `name` is provided, & the `node` is an `Identifier`,
|
|
79
|
+
* the `name` will be compared to that of the `identifier`.
|
|
80
|
+
*
|
|
81
|
+
* @param {Node} node
|
|
82
|
+
* @param {V} [name]
|
|
83
|
+
*
|
|
84
|
+
* @return {node is KnownIdentifier<Name>}
|
|
85
|
+
*
|
|
86
|
+
* @template V
|
|
87
|
+
*/
|
|
88
|
+
const isIdentifier = (node, name) => node.type === _utils.AST_NODE_TYPES.Identifier && (name === undefined || node.name === name);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Checks if the given `node` is a "supported accessor".
|
|
92
|
+
*
|
|
93
|
+
* This means that it's a node can be used to access properties,
|
|
94
|
+
* and who's "value" can be statically determined.
|
|
95
|
+
*
|
|
96
|
+
* `MemberExpression` nodes most commonly contain accessors,
|
|
97
|
+
* but it's possible for other nodes to contain them.
|
|
98
|
+
*
|
|
99
|
+
* If a `value` is provided & the `node` is an `AccessorNode`,
|
|
100
|
+
* the `value` will be compared to that of the `AccessorNode`.
|
|
101
|
+
*
|
|
102
|
+
* Note that `value` here refers to the normalised value.
|
|
103
|
+
* The property that holds the value is not always called `name`.
|
|
104
|
+
*
|
|
105
|
+
* @param {Node} node
|
|
106
|
+
* @param {V} [value]
|
|
107
|
+
*
|
|
108
|
+
* @return {node is AccessorNode<V>}
|
|
109
|
+
*
|
|
110
|
+
* @template V
|
|
111
|
+
*/
|
|
112
|
+
exports.isIdentifier = isIdentifier;
|
|
113
|
+
const isSupportedAccessor = (node, value) => isIdentifier(node, value) || isStringNode(node, value);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Gets the value of the given `AccessorNode`,
|
|
117
|
+
* account for the different node types.
|
|
118
|
+
*
|
|
119
|
+
* @param {AccessorNode<S>} accessor
|
|
120
|
+
*
|
|
121
|
+
* @return {S}
|
|
122
|
+
*
|
|
123
|
+
* @template S
|
|
124
|
+
*/
|
|
125
|
+
exports.isSupportedAccessor = isSupportedAccessor;
|
|
126
|
+
const getAccessorValue = accessor => accessor.type === _utils.AST_NODE_TYPES.Identifier ? accessor.name : getStringValue(accessor);
|
|
127
|
+
exports.getAccessorValue = getAccessorValue;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isValidParent = exports.isTokenASemicolon = exports.getPaddingLineSequences = exports.getActualLastToken = exports.areTokensOnSameLine = void 0;
|
|
7
|
+
var _utils = require("@typescript-eslint/utils");
|
|
8
|
+
const isTokenASemicolon = token => token.value === ';' && token.type === _utils.AST_TOKEN_TYPES.Punctuator;
|
|
9
|
+
exports.isTokenASemicolon = isTokenASemicolon;
|
|
10
|
+
const areTokensOnSameLine = (left, right) => left.loc.end.line === right.loc.start.line;
|
|
11
|
+
|
|
12
|
+
// We'll only verify nodes with these parent types
|
|
13
|
+
exports.areTokensOnSameLine = areTokensOnSameLine;
|
|
14
|
+
const STATEMENT_LIST_PARENTS = new Set([_utils.AST_NODE_TYPES.Program, _utils.AST_NODE_TYPES.BlockStatement, _utils.AST_NODE_TYPES.SwitchCase, _utils.AST_NODE_TYPES.SwitchStatement]);
|
|
15
|
+
const isValidParent = parentType => {
|
|
16
|
+
return STATEMENT_LIST_PARENTS.has(parentType);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Gets the actual last token.
|
|
21
|
+
*
|
|
22
|
+
* If a semicolon is semicolon-less style's semicolon, this ignores it.
|
|
23
|
+
* For example:
|
|
24
|
+
*
|
|
25
|
+
* foo()
|
|
26
|
+
* ;[1, 2, 3].forEach(bar)
|
|
27
|
+
*/
|
|
28
|
+
exports.isValidParent = isValidParent;
|
|
29
|
+
const getActualLastToken = (sourceCode, node) => {
|
|
30
|
+
const semiToken = sourceCode.getLastToken(node);
|
|
31
|
+
const prevToken = sourceCode.getTokenBefore(semiToken);
|
|
32
|
+
const nextToken = sourceCode.getTokenAfter(semiToken);
|
|
33
|
+
const isSemicolonLessStyle = Boolean(prevToken && nextToken && prevToken.range[0] >= node.range[0] && isTokenASemicolon(semiToken) && semiToken.loc.start.line !== prevToken.loc.end.line && semiToken.loc.end.line === nextToken.loc.start.line);
|
|
34
|
+
return isSemicolonLessStyle ? prevToken : semiToken;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets padding line sequences between the given 2 statements.
|
|
39
|
+
* Comments are separators of the padding line sequences.
|
|
40
|
+
*/
|
|
41
|
+
exports.getActualLastToken = getActualLastToken;
|
|
42
|
+
const getPaddingLineSequences = (prevNode, nextNode, sourceCode) => {
|
|
43
|
+
const pairs = [];
|
|
44
|
+
const includeComments = true;
|
|
45
|
+
let prevToken = getActualLastToken(sourceCode, prevNode);
|
|
46
|
+
if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
|
|
47
|
+
do {
|
|
48
|
+
const token = sourceCode.getTokenAfter(prevToken, {
|
|
49
|
+
includeComments
|
|
50
|
+
});
|
|
51
|
+
if (token.loc.start.line - prevToken.loc.end.line >= 2) {
|
|
52
|
+
pairs.push([prevToken, token]);
|
|
53
|
+
}
|
|
54
|
+
prevToken = token;
|
|
55
|
+
} while (prevToken.range[0] < nextNode.range[0]);
|
|
56
|
+
}
|
|
57
|
+
return pairs;
|
|
58
|
+
};
|
|
59
|
+
exports.getPaddingLineSequences = getPaddingLineSequences;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.detectJestVersion = void 0;
|
|
7
|
+
let cachedJestVersion = null;
|
|
8
|
+
const detectJestVersion = () => {
|
|
9
|
+
if (cachedJestVersion) {
|
|
10
|
+
return cachedJestVersion;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const jestPath = require.resolve('jest/package.json');
|
|
14
|
+
const jestPackageJson =
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
+
require(jestPath);
|
|
17
|
+
if (jestPackageJson.version) {
|
|
18
|
+
const [majorVersion] = jestPackageJson.version.split('.');
|
|
19
|
+
return cachedJestVersion = parseInt(majorVersion, 10);
|
|
20
|
+
}
|
|
21
|
+
} catch {}
|
|
22
|
+
throw new Error('Unable to detect Jest version - please ensure jest package is installed, or otherwise set version explicitly');
|
|
23
|
+
};
|
|
24
|
+
exports.detectJestVersion = detectJestVersion;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.followTypeAssertionChain = void 0;
|
|
7
|
+
var _utils = require("@typescript-eslint/utils");
|
|
8
|
+
const isTypeCastExpression = node => node.type === _utils.AST_NODE_TYPES.TSAsExpression || node.type === _utils.AST_NODE_TYPES.TSTypeAssertion;
|
|
9
|
+
const followTypeAssertionChain = expression => isTypeCastExpression(expression) ? followTypeAssertionChain(expression.expression) : expression;
|
|
10
|
+
exports.followTypeAssertionChain = followTypeAssertionChain;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _accessors = require("./accessors");
|
|
7
|
+
Object.keys(_accessors).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _accessors[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _accessors[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
var _detectJestVersion = require("./detectJestVersion");
|
|
18
|
+
Object.keys(_detectJestVersion).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _detectJestVersion[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _detectJestVersion[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
var _followTypeAssertionChain = require("./followTypeAssertionChain");
|
|
29
|
+
Object.keys(_followTypeAssertionChain).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _followTypeAssertionChain[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () {
|
|
35
|
+
return _followTypeAssertionChain[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
var _misc = require("./misc");
|
|
40
|
+
Object.keys(_misc).forEach(function (key) {
|
|
41
|
+
if (key === "default" || key === "__esModule") return;
|
|
42
|
+
if (key in exports && exports[key] === _misc[key]) return;
|
|
43
|
+
Object.defineProperty(exports, key, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _misc[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
var _parseJestFnCall = require("./parseJestFnCall");
|
|
51
|
+
Object.keys(_parseJestFnCall).forEach(function (key) {
|
|
52
|
+
if (key === "default" || key === "__esModule") return;
|
|
53
|
+
if (key in exports && exports[key] === _parseJestFnCall[key]) return;
|
|
54
|
+
Object.defineProperty(exports, key, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _parseJestFnCall[key];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
var _ts = require("./ts");
|
|
62
|
+
Object.keys(_ts).forEach(function (key) {
|
|
63
|
+
if (key === "default" || key === "__esModule") return;
|
|
64
|
+
if (key in exports && exports[key] === _ts[key]) return;
|
|
65
|
+
Object.defineProperty(exports, key, {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
get: function () {
|
|
68
|
+
return _ts[key];
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getFirstMatcherArg = exports.findTopMostCallExpression = exports.findModuleName = exports.createRule = exports.TestCaseName = exports.ModifierName = exports.HookName = exports.EqualityMatcher = exports.DescribeAlias = void 0;
|
|
7
|
+
exports.getNodeName = getNodeName;
|
|
8
|
+
exports.replaceAccessorFixer = exports.removeExtraArgumentsFixer = exports.isFunction = exports.isBooleanLiteral = exports.hasOnlyOneArgument = exports.getTestCallExpressionsFromDeclaredVariables = void 0;
|
|
9
|
+
var _path = require("path");
|
|
10
|
+
var _utils = require("@typescript-eslint/utils");
|
|
11
|
+
var _package = require("../../../package.json");
|
|
12
|
+
var _accessors = require("./accessors");
|
|
13
|
+
var _followTypeAssertionChain = require("./followTypeAssertionChain");
|
|
14
|
+
var _parseJestFnCall = require("./parseJestFnCall");
|
|
15
|
+
const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest';
|
|
16
|
+
const createRule = exports.createRule = _utils.ESLintUtils.RuleCreator(name => {
|
|
17
|
+
const ruleName = (0, _path.parse)(name).name;
|
|
18
|
+
return `${REPO_URL}/blob/v${_package.version}/docs/rules/${ruleName}.md`;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents a `MemberExpression` with a "known" `property`.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Represents a `CallExpression` with a "known" `property` accessor.
|
|
27
|
+
*
|
|
28
|
+
* i.e `KnownCallExpression<'includes'>` represents `.includes()`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents a `MemberExpression` with a "known" `property`, that is called.
|
|
33
|
+
*
|
|
34
|
+
* This is `KnownCallExpression` from the perspective of the `MemberExpression` node.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Represents a `CallExpression` with a single argument.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Guards that the given `call` has only one `argument`.
|
|
43
|
+
*
|
|
44
|
+
* @param {CallExpression} call
|
|
45
|
+
*
|
|
46
|
+
* @return {call is CallExpressionWithSingleArgument}
|
|
47
|
+
*/
|
|
48
|
+
const hasOnlyOneArgument = call => call.arguments.length === 1;
|
|
49
|
+
exports.hasOnlyOneArgument = hasOnlyOneArgument;
|
|
50
|
+
let DescribeAlias = exports.DescribeAlias = /*#__PURE__*/function (DescribeAlias) {
|
|
51
|
+
DescribeAlias["describe"] = "describe";
|
|
52
|
+
DescribeAlias["fdescribe"] = "fdescribe";
|
|
53
|
+
DescribeAlias["xdescribe"] = "xdescribe";
|
|
54
|
+
return DescribeAlias;
|
|
55
|
+
}({});
|
|
56
|
+
let TestCaseName = exports.TestCaseName = /*#__PURE__*/function (TestCaseName) {
|
|
57
|
+
TestCaseName["fit"] = "fit";
|
|
58
|
+
TestCaseName["it"] = "it";
|
|
59
|
+
TestCaseName["test"] = "test";
|
|
60
|
+
TestCaseName["xit"] = "xit";
|
|
61
|
+
TestCaseName["xtest"] = "xtest";
|
|
62
|
+
return TestCaseName;
|
|
63
|
+
}({});
|
|
64
|
+
let HookName = exports.HookName = /*#__PURE__*/function (HookName) {
|
|
65
|
+
HookName["beforeAll"] = "beforeAll";
|
|
66
|
+
HookName["beforeEach"] = "beforeEach";
|
|
67
|
+
HookName["afterAll"] = "afterAll";
|
|
68
|
+
HookName["afterEach"] = "afterEach";
|
|
69
|
+
return HookName;
|
|
70
|
+
}({});
|
|
71
|
+
let ModifierName = exports.ModifierName = /*#__PURE__*/function (ModifierName) {
|
|
72
|
+
ModifierName["not"] = "not";
|
|
73
|
+
ModifierName["rejects"] = "rejects";
|
|
74
|
+
ModifierName["resolves"] = "resolves";
|
|
75
|
+
return ModifierName;
|
|
76
|
+
}({});
|
|
77
|
+
let EqualityMatcher = exports.EqualityMatcher = /*#__PURE__*/function (EqualityMatcher) {
|
|
78
|
+
EqualityMatcher["toBe"] = "toBe";
|
|
79
|
+
EqualityMatcher["toEqual"] = "toEqual";
|
|
80
|
+
EqualityMatcher["toStrictEqual"] = "toStrictEqual";
|
|
81
|
+
return EqualityMatcher;
|
|
82
|
+
}({});
|
|
83
|
+
const joinNames = (a, b) => a && b ? `${a}.${b}` : null;
|
|
84
|
+
function getNodeName(node) {
|
|
85
|
+
if ((0, _accessors.isSupportedAccessor)(node)) {
|
|
86
|
+
return (0, _accessors.getAccessorValue)(node);
|
|
87
|
+
}
|
|
88
|
+
switch (node.type) {
|
|
89
|
+
case _utils.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
90
|
+
return getNodeName(node.tag);
|
|
91
|
+
case _utils.AST_NODE_TYPES.MemberExpression:
|
|
92
|
+
return joinNames(getNodeName(node.object), getNodeName(node.property));
|
|
93
|
+
case _utils.AST_NODE_TYPES.NewExpression:
|
|
94
|
+
case _utils.AST_NODE_TYPES.CallExpression:
|
|
95
|
+
return getNodeName(node.callee);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const isFunction = node => node.type === _utils.AST_NODE_TYPES.FunctionExpression || node.type === _utils.AST_NODE_TYPES.ArrowFunctionExpression;
|
|
100
|
+
exports.isFunction = isFunction;
|
|
101
|
+
const getTestCallExpressionsFromDeclaredVariables = (declaredVariables, context) => {
|
|
102
|
+
return declaredVariables.flatMap(({
|
|
103
|
+
references
|
|
104
|
+
}) => references.map(({
|
|
105
|
+
identifier
|
|
106
|
+
}) => identifier.parent).filter(node => node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _parseJestFnCall.isTypeOfJestFnCall)(node, context, ['test'])));
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Replaces an accessor node with the given `text`, surrounding it in quotes if required.
|
|
111
|
+
*
|
|
112
|
+
* This ensures that fixes produce valid code when replacing both dot-based and
|
|
113
|
+
* bracket-based property accessors.
|
|
114
|
+
*/
|
|
115
|
+
exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
|
|
116
|
+
const replaceAccessorFixer = (fixer, node, text) => {
|
|
117
|
+
return fixer.replaceText(node, node.type === _utils.AST_NODE_TYPES.Identifier ? text : `'${text}'`);
|
|
118
|
+
};
|
|
119
|
+
exports.replaceAccessorFixer = replaceAccessorFixer;
|
|
120
|
+
const removeExtraArgumentsFixer = (fixer, context, func, from) => {
|
|
121
|
+
const firstArg = func.arguments[from];
|
|
122
|
+
const lastArg = func.arguments[func.arguments.length - 1];
|
|
123
|
+
const {
|
|
124
|
+
sourceCode
|
|
125
|
+
} = context;
|
|
126
|
+
let tokenAfterLastParam = sourceCode.getTokenAfter(lastArg);
|
|
127
|
+
if (tokenAfterLastParam.value === ',') {
|
|
128
|
+
tokenAfterLastParam = sourceCode.getTokenAfter(tokenAfterLastParam);
|
|
129
|
+
}
|
|
130
|
+
return fixer.removeRange([firstArg.range[0], tokenAfterLastParam.range[0]]);
|
|
131
|
+
};
|
|
132
|
+
exports.removeExtraArgumentsFixer = removeExtraArgumentsFixer;
|
|
133
|
+
const findTopMostCallExpression = node => {
|
|
134
|
+
let topMostCallExpression = node;
|
|
135
|
+
let {
|
|
136
|
+
parent
|
|
137
|
+
} = node;
|
|
138
|
+
while (parent) {
|
|
139
|
+
if (parent.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
140
|
+
topMostCallExpression = parent;
|
|
141
|
+
parent = parent.parent;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (parent.type !== _utils.AST_NODE_TYPES.MemberExpression) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
parent = parent.parent;
|
|
148
|
+
}
|
|
149
|
+
return topMostCallExpression;
|
|
150
|
+
};
|
|
151
|
+
exports.findTopMostCallExpression = findTopMostCallExpression;
|
|
152
|
+
const isBooleanLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
|
|
153
|
+
exports.isBooleanLiteral = isBooleanLiteral;
|
|
154
|
+
const getFirstMatcherArg = expectFnCall => {
|
|
155
|
+
const [firstArg] = expectFnCall.args;
|
|
156
|
+
if (firstArg.type === _utils.AST_NODE_TYPES.SpreadElement) {
|
|
157
|
+
return firstArg;
|
|
158
|
+
}
|
|
159
|
+
return (0, _followTypeAssertionChain.followTypeAssertionChain)(firstArg);
|
|
160
|
+
};
|
|
161
|
+
exports.getFirstMatcherArg = getFirstMatcherArg;
|
|
162
|
+
const findModuleName = node => {
|
|
163
|
+
if (node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'string') {
|
|
164
|
+
return node;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
};
|
|
168
|
+
exports.findModuleName = findModuleName;
|