@vitest/eslint-plugin 1.5.4 → 1.6.1
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/README.md +1 -1
- package/dist/index.cjs +74 -65
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +74 -65
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -251,12 +251,12 @@ export default defineConfig({
|
|
|
251
251
|
| [prefer-to-be-object](docs/rules/prefer-to-be-object.md) | enforce using toBeObject() | | 🌐 | | 🔧 | | | |
|
|
252
252
|
| [prefer-to-be-truthy](docs/rules/prefer-to-be-truthy.md) | enforce using `toBeTruthy` | | | 🌐 | 🔧 | | | |
|
|
253
253
|
| [prefer-to-contain](docs/rules/prefer-to-contain.md) | enforce using toContain() | | 🌐 | | 🔧 | | | |
|
|
254
|
+
| [prefer-to-have-been-called-times](docs/rules/prefer-to-have-been-called-times.md) | Suggest using `toHaveBeenCalledTimes()` | | 🌐 | | 🔧 | | | |
|
|
254
255
|
| [prefer-to-have-length](docs/rules/prefer-to-have-length.md) | enforce using toHaveLength() | | 🌐 | | 🔧 | | | |
|
|
255
256
|
| [prefer-todo](docs/rules/prefer-todo.md) | enforce using `test.todo` | | 🌐 | | 🔧 | | | |
|
|
256
257
|
| [prefer-vi-mocked](docs/rules/prefer-vi-mocked.md) | require `vi.mocked()` over `fn as Mock` | | 🌐 | | 🔧 | | 💭 | |
|
|
257
258
|
| [require-awaited-expect-poll](docs/rules/require-awaited-expect-poll.md) | ensure that every `expect.poll` call is awaited | | 🌐 | | | | | |
|
|
258
259
|
| [require-hook](docs/rules/require-hook.md) | require setup and teardown to be within a hook | | 🌐 | | | | | |
|
|
259
|
-
| [require-import-vi-mock](docs/rules/require-import-vi-mock.md) | require usage of import in vi.mock() | | 🌐 | | 🔧 | | | |
|
|
260
260
|
| [require-local-test-context-for-concurrent-snapshots](docs/rules/require-local-test-context-for-concurrent-snapshots.md) | require local Test Context for concurrent snapshot tests | ✅ | 🌐 | | | | | |
|
|
261
261
|
| [require-mock-type-parameters](docs/rules/require-mock-type-parameters.md) | enforce using type parameters with vitest mock functions | | 🌐 | | 🔧 | | | |
|
|
262
262
|
| [require-to-throw-message](docs/rules/require-to-throw-message.md) | require toThrow() to be called with an error message | | 🌐 | | | | | |
|
package/dist/index.cjs
CHANGED
|
@@ -31,7 +31,7 @@ let __typescript_eslint_scope_manager = require("@typescript-eslint/scope-manage
|
|
|
31
31
|
__typescript_eslint_scope_manager = __toESM(__typescript_eslint_scope_manager);
|
|
32
32
|
|
|
33
33
|
//#region package.json
|
|
34
|
-
var version = "1.
|
|
34
|
+
var version = "1.6.1";
|
|
35
35
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/utils/index.ts
|
|
@@ -1738,7 +1738,16 @@ const resolveScope = (scope, identifier) => {
|
|
|
1738
1738
|
if ((property?.key.type === __typescript_eslint_utils.AST_NODE_TYPES.Identifier ? property.key : void 0)?.name === identifier) return "testContext";
|
|
1739
1739
|
}
|
|
1740
1740
|
/** if detect test function is created with `.extend()` */
|
|
1741
|
-
if (def.node.type === __typescript_eslint_utils.AST_NODE_TYPES.VariableDeclarator && def.node.id.type === __typescript_eslint_utils.AST_NODE_TYPES.Identifier &&
|
|
1741
|
+
if (def.node.type === __typescript_eslint_utils.AST_NODE_TYPES.VariableDeclarator && def.node.id.type === __typescript_eslint_utils.AST_NODE_TYPES.Identifier && def.node.init?.type === __typescript_eslint_utils.AST_NODE_TYPES.CallExpression && def.node.init.callee.type === __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && isIdentifier(def.node.init.callee.property, "extend")) {
|
|
1742
|
+
const rootName = getNodeName(def.node.init.callee.object)?.split(".")[0];
|
|
1743
|
+
if (rootName && rootName !== identifier) {
|
|
1744
|
+
const resolved = resolveScope(currentScope, rootName);
|
|
1745
|
+
if (resolved && typeof resolved === "object" && Object.hasOwn(TestCaseName, resolved.imported)) return {
|
|
1746
|
+
...resolved,
|
|
1747
|
+
local: identifier
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1742
1751
|
const namedParam = isFunction(def.node) ? def.node.params.find((params) => params.type === __typescript_eslint_utils.AST_NODE_TYPES.Identifier) : void 0;
|
|
1743
1752
|
if (namedParam && isAncestorTestCaseCall(namedParam.parent)) return "testContext";
|
|
1744
1753
|
const importDetails = describePossibleImportDef(def);
|
|
@@ -4725,11 +4734,11 @@ var prefer_import_in_mock_default = createEslintRule({
|
|
|
4725
4734
|
create(context) {
|
|
4726
4735
|
return { CallExpression(node) {
|
|
4727
4736
|
if (node.callee.type !== __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) return;
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4737
|
+
if (parseVitestFnCall(node, context)?.type !== "vi") return false;
|
|
4738
|
+
const { property } = node.callee;
|
|
4739
|
+
if (property.type != __typescript_eslint_utils.AST_NODE_TYPES.Identifier || property.name != "mock") return;
|
|
4731
4740
|
const pathArg = node.arguments[0];
|
|
4732
|
-
if (
|
|
4741
|
+
if (pathArg && pathArg.type === __typescript_eslint_utils.AST_NODE_TYPES.Literal) context.report({
|
|
4733
4742
|
messageId: "preferImport",
|
|
4734
4743
|
data: { path: pathArg.value },
|
|
4735
4744
|
node,
|
|
@@ -5657,47 +5666,11 @@ var require_hook_default = createEslintRule({
|
|
|
5657
5666
|
}
|
|
5658
5667
|
});
|
|
5659
5668
|
|
|
5660
|
-
//#endregion
|
|
5661
|
-
//#region src/rules/require-import-vi-mock.ts
|
|
5662
|
-
const RULE_NAME$10 = "require-import-vi-mock";
|
|
5663
|
-
var require_import_vi_mock_default = createEslintRule({
|
|
5664
|
-
name: RULE_NAME$10,
|
|
5665
|
-
meta: {
|
|
5666
|
-
fixable: "code",
|
|
5667
|
-
type: "suggestion",
|
|
5668
|
-
docs: {
|
|
5669
|
-
description: "require usage of import in vi.mock()",
|
|
5670
|
-
requiresTypeChecking: false,
|
|
5671
|
-
recommended: false
|
|
5672
|
-
},
|
|
5673
|
-
messages: { requireImport: "Replace '{{path}}' with import('{{path}}')" },
|
|
5674
|
-
schema: []
|
|
5675
|
-
},
|
|
5676
|
-
defaultOptions: [],
|
|
5677
|
-
create(context) {
|
|
5678
|
-
return { CallExpression(node) {
|
|
5679
|
-
if (node.callee.type !== __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) return;
|
|
5680
|
-
if (parseVitestFnCall(node, context)?.type !== "vi") return false;
|
|
5681
|
-
const { property } = node.callee;
|
|
5682
|
-
if (property.type !== __typescript_eslint_utils.AST_NODE_TYPES.Identifier || property.name !== "mock") return;
|
|
5683
|
-
const pathArg = node.arguments[0];
|
|
5684
|
-
if (pathArg && pathArg.type === __typescript_eslint_utils.AST_NODE_TYPES.Literal) context.report({
|
|
5685
|
-
messageId: "requireImport",
|
|
5686
|
-
data: { path: pathArg.value },
|
|
5687
|
-
node: pathArg,
|
|
5688
|
-
fix(fixer) {
|
|
5689
|
-
return fixer.replaceText(pathArg, `import('${pathArg.value}')`);
|
|
5690
|
-
}
|
|
5691
|
-
});
|
|
5692
|
-
} };
|
|
5693
|
-
}
|
|
5694
|
-
});
|
|
5695
|
-
|
|
5696
5669
|
//#endregion
|
|
5697
5670
|
//#region src/rules/require-local-test-context-for-concurrent-snapshots.ts
|
|
5698
|
-
const RULE_NAME$
|
|
5671
|
+
const RULE_NAME$10 = "require-local-test-context-for-concurrent-snapshots";
|
|
5699
5672
|
var require_local_test_context_for_concurrent_snapshots_default = createEslintRule({
|
|
5700
|
-
name: RULE_NAME$
|
|
5673
|
+
name: RULE_NAME$10,
|
|
5701
5674
|
meta: {
|
|
5702
5675
|
docs: {
|
|
5703
5676
|
description: "require local Test Context for concurrent snapshot tests",
|
|
@@ -5738,9 +5711,9 @@ var require_local_test_context_for_concurrent_snapshots_default = createEslintRu
|
|
|
5738
5711
|
|
|
5739
5712
|
//#endregion
|
|
5740
5713
|
//#region src/rules/require-mock-type-parameters.ts
|
|
5741
|
-
const RULE_NAME$
|
|
5714
|
+
const RULE_NAME$9 = "require-mock-type-parameters";
|
|
5742
5715
|
var require_mock_type_parameters_default = createEslintRule({
|
|
5743
|
-
name: RULE_NAME$
|
|
5716
|
+
name: RULE_NAME$9,
|
|
5744
5717
|
meta: {
|
|
5745
5718
|
type: "suggestion",
|
|
5746
5719
|
docs: {
|
|
@@ -5777,9 +5750,9 @@ var require_mock_type_parameters_default = createEslintRule({
|
|
|
5777
5750
|
|
|
5778
5751
|
//#endregion
|
|
5779
5752
|
//#region src/rules/require-to-throw-message.ts
|
|
5780
|
-
const RULE_NAME$
|
|
5753
|
+
const RULE_NAME$8 = "require-to-throw-message";
|
|
5781
5754
|
var require_to_throw_message_default = createEslintRule({
|
|
5782
|
-
name: RULE_NAME$
|
|
5755
|
+
name: RULE_NAME$8,
|
|
5783
5756
|
meta: {
|
|
5784
5757
|
type: "suggestion",
|
|
5785
5758
|
docs: {
|
|
@@ -5807,9 +5780,9 @@ var require_to_throw_message_default = createEslintRule({
|
|
|
5807
5780
|
|
|
5808
5781
|
//#endregion
|
|
5809
5782
|
//#region src/rules/require-top-level-describe.ts
|
|
5810
|
-
const RULE_NAME$
|
|
5783
|
+
const RULE_NAME$7 = "require-top-level-describe";
|
|
5811
5784
|
var require_top_level_describe_default = createEslintRule({
|
|
5812
|
-
name: RULE_NAME$
|
|
5785
|
+
name: RULE_NAME$7,
|
|
5813
5786
|
meta: {
|
|
5814
5787
|
docs: {
|
|
5815
5788
|
description: "enforce that all tests are in a top-level describe",
|
|
@@ -5878,7 +5851,7 @@ var require_top_level_describe_default = createEslintRule({
|
|
|
5878
5851
|
|
|
5879
5852
|
//#endregion
|
|
5880
5853
|
//#region src/rules/valid-describe-callback.ts
|
|
5881
|
-
const RULE_NAME$
|
|
5854
|
+
const RULE_NAME$6 = "valid-describe-callback";
|
|
5882
5855
|
const paramsLocation = (params) => {
|
|
5883
5856
|
const [first] = params;
|
|
5884
5857
|
const last = params[params.length - 1];
|
|
@@ -5900,7 +5873,7 @@ const reportUnexpectedReturnInDescribe = (blockStatement, context) => {
|
|
|
5900
5873
|
});
|
|
5901
5874
|
};
|
|
5902
5875
|
var valid_describe_callback_default = createEslintRule({
|
|
5903
|
-
name: RULE_NAME$
|
|
5876
|
+
name: RULE_NAME$6,
|
|
5904
5877
|
meta: {
|
|
5905
5878
|
type: "problem",
|
|
5906
5879
|
docs: {
|
|
@@ -5967,7 +5940,7 @@ var valid_describe_callback_default = createEslintRule({
|
|
|
5967
5940
|
|
|
5968
5941
|
//#endregion
|
|
5969
5942
|
//#region src/rules/valid-expect-in-promise.ts
|
|
5970
|
-
const RULE_NAME$
|
|
5943
|
+
const RULE_NAME$5 = "valid-expect-in-promise";
|
|
5971
5944
|
const defaultAsyncMatchers$1 = ["toRejectWith", "toResolveWith"];
|
|
5972
5945
|
const isPromiseChainCall = (node) => {
|
|
5973
5946
|
if (node.type === __typescript_eslint_utils.AST_NODE_TYPES.CallExpression && node.callee.type === __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && isSupportedAccessor(node.callee.property)) {
|
|
@@ -6099,7 +6072,7 @@ const isVariableAwaitedOrReturned = (variable, context) => {
|
|
|
6099
6072
|
return isValueAwaitedOrReturned(variable.id, body, context);
|
|
6100
6073
|
};
|
|
6101
6074
|
var valid_expect_in_promise_default = createEslintRule({
|
|
6102
|
-
name: RULE_NAME$
|
|
6075
|
+
name: RULE_NAME$5,
|
|
6103
6076
|
meta: {
|
|
6104
6077
|
docs: { description: "require promises that have expectations in their chain to be valid" },
|
|
6105
6078
|
messages: { expectInFloatingPromise: "This promise should either be returned or awaited to ensure the expects in its chain are called" },
|
|
@@ -6159,7 +6132,7 @@ var valid_expect_in_promise_default = createEslintRule({
|
|
|
6159
6132
|
|
|
6160
6133
|
//#endregion
|
|
6161
6134
|
//#region src/rules/valid-expect.ts
|
|
6162
|
-
const RULE_NAME$
|
|
6135
|
+
const RULE_NAME$4 = "valid-expect";
|
|
6163
6136
|
const defaultAsyncMatchers = ["toReject", "toResolve"];
|
|
6164
6137
|
/**
|
|
6165
6138
|
* Async assertions might be called in Promise
|
|
@@ -6194,7 +6167,7 @@ const isAcceptableReturnNode = (node, allowReturn) => {
|
|
|
6194
6167
|
return [__typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression, __typescript_eslint_utils.AST_NODE_TYPES.AwaitExpression].includes(node.type);
|
|
6195
6168
|
};
|
|
6196
6169
|
var valid_expect_default = createEslintRule({
|
|
6197
|
-
name: RULE_NAME$
|
|
6170
|
+
name: RULE_NAME$4,
|
|
6198
6171
|
meta: {
|
|
6199
6172
|
docs: {
|
|
6200
6173
|
description: "enforce valid `expect()` usage",
|
|
@@ -6387,7 +6360,7 @@ var valid_expect_default = createEslintRule({
|
|
|
6387
6360
|
|
|
6388
6361
|
//#endregion
|
|
6389
6362
|
//#region src/rules/valid-title.ts
|
|
6390
|
-
const RULE_NAME$
|
|
6363
|
+
const RULE_NAME$3 = "valid-title";
|
|
6391
6364
|
const trimFXPrefix = (word) => ["f", "x"].includes(word.charAt(0)) ? word.substring(1) : word;
|
|
6392
6365
|
const quoteStringValue = (node) => node.type === __typescript_eslint_utils.AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw;
|
|
6393
6366
|
const MatcherAndMessageSchema = {
|
|
@@ -6426,7 +6399,7 @@ const doesBinaryExpressionContainStringNode = (binaryExp) => {
|
|
|
6426
6399
|
return isStringNode(binaryExp.left);
|
|
6427
6400
|
};
|
|
6428
6401
|
var valid_title_default = createEslintRule({
|
|
6429
|
-
name: RULE_NAME$
|
|
6402
|
+
name: RULE_NAME$3,
|
|
6430
6403
|
meta: {
|
|
6431
6404
|
docs: {
|
|
6432
6405
|
description: "enforce valid titles",
|
|
@@ -6579,9 +6552,9 @@ var valid_title_default = createEslintRule({
|
|
|
6579
6552
|
|
|
6580
6553
|
//#endregion
|
|
6581
6554
|
//#region src/rules/warn-todo.ts
|
|
6582
|
-
const RULE_NAME$
|
|
6555
|
+
const RULE_NAME$2 = "warn-todo";
|
|
6583
6556
|
var warn_todo_default = createEslintRule({
|
|
6584
|
-
name: RULE_NAME$
|
|
6557
|
+
name: RULE_NAME$2,
|
|
6585
6558
|
meta: {
|
|
6586
6559
|
docs: {
|
|
6587
6560
|
description: "disallow `.todo` usage",
|
|
@@ -6608,7 +6581,7 @@ var warn_todo_default = createEslintRule({
|
|
|
6608
6581
|
|
|
6609
6582
|
//#endregion
|
|
6610
6583
|
//#region src/rules/no-unneeded-async-expect-function.ts
|
|
6611
|
-
const RULE_NAME = "no-unneeded-async-expect-function";
|
|
6584
|
+
const RULE_NAME$1 = "no-unneeded-async-expect-function";
|
|
6612
6585
|
const getAwaitedCallExpression = (expression) => {
|
|
6613
6586
|
if (!expression.async) return null;
|
|
6614
6587
|
if (expression.type === __typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression && expression.body.type === __typescript_eslint_utils.AST_NODE_TYPES.AwaitExpression && expression.body.argument.type === __typescript_eslint_utils.AST_NODE_TYPES.CallExpression) return expression.body.argument;
|
|
@@ -6618,7 +6591,7 @@ const getAwaitedCallExpression = (expression) => {
|
|
|
6618
6591
|
return null;
|
|
6619
6592
|
};
|
|
6620
6593
|
var no_unneeded_async_expect_function_default = createEslintRule({
|
|
6621
|
-
name: RULE_NAME,
|
|
6594
|
+
name: RULE_NAME$1,
|
|
6622
6595
|
meta: {
|
|
6623
6596
|
docs: { description: "Disallow unnecessary async function wrapper for expected promises" },
|
|
6624
6597
|
fixable: "code",
|
|
@@ -6649,6 +6622,42 @@ var no_unneeded_async_expect_function_default = createEslintRule({
|
|
|
6649
6622
|
}
|
|
6650
6623
|
});
|
|
6651
6624
|
|
|
6625
|
+
//#endregion
|
|
6626
|
+
//#region src/rules/prefer-to-have-been-called-times.ts
|
|
6627
|
+
const RULE_NAME = "prefer-to-have-been-called-times";
|
|
6628
|
+
var prefer_to_have_been_called_times_default = createEslintRule({
|
|
6629
|
+
name: RULE_NAME,
|
|
6630
|
+
meta: {
|
|
6631
|
+
fixable: "code",
|
|
6632
|
+
docs: { description: "Suggest using `toHaveBeenCalledTimes()`" },
|
|
6633
|
+
messages: { preferMatcher: "Prefer `toHaveBeenCalledTimes`" },
|
|
6634
|
+
type: "suggestion",
|
|
6635
|
+
schema: []
|
|
6636
|
+
},
|
|
6637
|
+
defaultOptions: [],
|
|
6638
|
+
create(context) {
|
|
6639
|
+
return { CallExpression(node) {
|
|
6640
|
+
const vitestFnCall = parseVitestFnCall(node, context);
|
|
6641
|
+
if (vitestFnCall?.type !== "expect") return;
|
|
6642
|
+
const { parent: expect } = vitestFnCall.head.node;
|
|
6643
|
+
if (expect?.type !== __typescript_eslint_utils.AST_NODE_TYPES.CallExpression) return;
|
|
6644
|
+
const { matcher } = vitestFnCall;
|
|
6645
|
+
if (!isSupportedAccessor(matcher, "toHaveLength")) return;
|
|
6646
|
+
const [argument] = expect.arguments;
|
|
6647
|
+
if (argument?.type !== __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression || !isSupportedAccessor(argument.property, "calls")) return;
|
|
6648
|
+
const { object } = argument;
|
|
6649
|
+
if (object.type !== __typescript_eslint_utils.AST_NODE_TYPES.MemberExpression || !isSupportedAccessor(object.property, "mock")) return;
|
|
6650
|
+
context.report({
|
|
6651
|
+
messageId: "preferMatcher",
|
|
6652
|
+
node: matcher,
|
|
6653
|
+
fix(fixer) {
|
|
6654
|
+
return [fixer.removeRange([object.property.range[0] - 1, argument.range[1]]), fixer.replaceTextRange([matcher.parent.object.range[1], matcher.parent.range[1]], ".toHaveBeenCalledTimes")];
|
|
6655
|
+
}
|
|
6656
|
+
});
|
|
6657
|
+
} };
|
|
6658
|
+
}
|
|
6659
|
+
});
|
|
6660
|
+
|
|
6652
6661
|
//#endregion
|
|
6653
6662
|
//#region src/rules/index.ts
|
|
6654
6663
|
const rules = {
|
|
@@ -6716,12 +6725,12 @@ const rules = {
|
|
|
6716
6725
|
"prefer-to-be-truthy": prefer_to_be_truthy_default,
|
|
6717
6726
|
"prefer-to-be": prefer_to_be_default,
|
|
6718
6727
|
"prefer-to-contain": prefer_to_contain_default,
|
|
6728
|
+
"prefer-to-have-been-called-times": prefer_to_have_been_called_times_default,
|
|
6719
6729
|
"prefer-to-have-length": prefer_to_have_length_default,
|
|
6720
6730
|
"prefer-todo": prefer_todo_default,
|
|
6721
6731
|
"prefer-vi-mocked": prefer_vi_mocked_default,
|
|
6722
6732
|
"require-awaited-expect-poll": require_awaited_expect_poll_default,
|
|
6723
6733
|
"require-hook": require_hook_default,
|
|
6724
|
-
"require-import-vi-mock": require_import_vi_mock_default,
|
|
6725
6734
|
"require-local-test-context-for-concurrent-snapshots": require_local_test_context_for_concurrent_snapshots_default,
|
|
6726
6735
|
"require-mock-type-parameters": require_mock_type_parameters_default,
|
|
6727
6736
|
"require-to-throw-message": require_to_throw_message_default,
|
|
@@ -6814,6 +6823,7 @@ const allRules = {
|
|
|
6814
6823
|
"prefer-to-be-truthy": "off",
|
|
6815
6824
|
"prefer-to-be": "warn",
|
|
6816
6825
|
"prefer-to-contain": "warn",
|
|
6826
|
+
"prefer-to-have-been-called-times": "warn",
|
|
6817
6827
|
"prefer-to-have-length": "warn",
|
|
6818
6828
|
"prefer-todo": "warn",
|
|
6819
6829
|
"prefer-vi-mocked": "warn",
|
|
@@ -6826,8 +6836,7 @@ const allRules = {
|
|
|
6826
6836
|
"valid-expect-in-promise": "warn",
|
|
6827
6837
|
"valid-expect": "warn",
|
|
6828
6838
|
"valid-title": "warn",
|
|
6829
|
-
"require-awaited-expect-poll": "warn"
|
|
6830
|
-
"require-import-vi-mock": "warn"
|
|
6839
|
+
"require-awaited-expect-poll": "warn"
|
|
6831
6840
|
};
|
|
6832
6841
|
const recommendedRules = {
|
|
6833
6842
|
"expect-expect": "error",
|
package/dist/index.d.cts
CHANGED
|
@@ -133,6 +133,7 @@ declare const plugin: {
|
|
|
133
133
|
readonly "vitest/prefer-to-be-truthy": "off";
|
|
134
134
|
readonly "vitest/prefer-to-be": "warn";
|
|
135
135
|
readonly "vitest/prefer-to-contain": "warn";
|
|
136
|
+
readonly "vitest/prefer-to-have-been-called-times": "warn";
|
|
136
137
|
readonly "vitest/prefer-to-have-length": "warn";
|
|
137
138
|
readonly "vitest/prefer-todo": "warn";
|
|
138
139
|
readonly "vitest/prefer-vi-mocked": "warn";
|
|
@@ -146,7 +147,6 @@ declare const plugin: {
|
|
|
146
147
|
readonly "vitest/valid-expect": "warn";
|
|
147
148
|
readonly "vitest/valid-title": "warn";
|
|
148
149
|
readonly "vitest/require-awaited-expect-poll": "warn";
|
|
149
|
-
readonly "vitest/require-import-vi-mock": "warn";
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
readonly env: {
|
package/dist/index.d.ts
CHANGED
|
@@ -133,6 +133,7 @@ declare const plugin: {
|
|
|
133
133
|
readonly "vitest/prefer-to-be-truthy": "off";
|
|
134
134
|
readonly "vitest/prefer-to-be": "warn";
|
|
135
135
|
readonly "vitest/prefer-to-contain": "warn";
|
|
136
|
+
readonly "vitest/prefer-to-have-been-called-times": "warn";
|
|
136
137
|
readonly "vitest/prefer-to-have-length": "warn";
|
|
137
138
|
readonly "vitest/prefer-todo": "warn";
|
|
138
139
|
readonly "vitest/prefer-vi-mocked": "warn";
|
|
@@ -146,7 +147,6 @@ declare const plugin: {
|
|
|
146
147
|
readonly "vitest/valid-expect": "warn";
|
|
147
148
|
readonly "vitest/valid-title": "warn";
|
|
148
149
|
readonly "vitest/require-awaited-expect-poll": "warn";
|
|
149
|
-
readonly "vitest/require-import-vi-mock": "warn";
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
readonly env: {
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { isAbsolute, posix } from "node:path";
|
|
|
4
4
|
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
5
5
|
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version = "1.
|
|
7
|
+
var version = "1.6.1";
|
|
8
8
|
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/utils/index.ts
|
|
@@ -1711,7 +1711,16 @@ const resolveScope = (scope, identifier) => {
|
|
|
1711
1711
|
if ((property?.key.type === AST_NODE_TYPES.Identifier ? property.key : void 0)?.name === identifier) return "testContext";
|
|
1712
1712
|
}
|
|
1713
1713
|
/** if detect test function is created with `.extend()` */
|
|
1714
|
-
if (def.node.type === AST_NODE_TYPES.VariableDeclarator && def.node.id.type === AST_NODE_TYPES.Identifier &&
|
|
1714
|
+
if (def.node.type === AST_NODE_TYPES.VariableDeclarator && def.node.id.type === AST_NODE_TYPES.Identifier && def.node.init?.type === AST_NODE_TYPES.CallExpression && def.node.init.callee.type === AST_NODE_TYPES.MemberExpression && isIdentifier(def.node.init.callee.property, "extend")) {
|
|
1715
|
+
const rootName = getNodeName(def.node.init.callee.object)?.split(".")[0];
|
|
1716
|
+
if (rootName && rootName !== identifier) {
|
|
1717
|
+
const resolved = resolveScope(currentScope, rootName);
|
|
1718
|
+
if (resolved && typeof resolved === "object" && Object.hasOwn(TestCaseName, resolved.imported)) return {
|
|
1719
|
+
...resolved,
|
|
1720
|
+
local: identifier
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1715
1724
|
const namedParam = isFunction(def.node) ? def.node.params.find((params) => params.type === AST_NODE_TYPES.Identifier) : void 0;
|
|
1716
1725
|
if (namedParam && isAncestorTestCaseCall(namedParam.parent)) return "testContext";
|
|
1717
1726
|
const importDetails = describePossibleImportDef(def);
|
|
@@ -4698,11 +4707,11 @@ var prefer_import_in_mock_default = createEslintRule({
|
|
|
4698
4707
|
create(context) {
|
|
4699
4708
|
return { CallExpression(node) {
|
|
4700
4709
|
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return;
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4710
|
+
if (parseVitestFnCall(node, context)?.type !== "vi") return false;
|
|
4711
|
+
const { property } = node.callee;
|
|
4712
|
+
if (property.type != AST_NODE_TYPES.Identifier || property.name != "mock") return;
|
|
4704
4713
|
const pathArg = node.arguments[0];
|
|
4705
|
-
if (
|
|
4714
|
+
if (pathArg && pathArg.type === AST_NODE_TYPES.Literal) context.report({
|
|
4706
4715
|
messageId: "preferImport",
|
|
4707
4716
|
data: { path: pathArg.value },
|
|
4708
4717
|
node,
|
|
@@ -5630,47 +5639,11 @@ var require_hook_default = createEslintRule({
|
|
|
5630
5639
|
}
|
|
5631
5640
|
});
|
|
5632
5641
|
|
|
5633
|
-
//#endregion
|
|
5634
|
-
//#region src/rules/require-import-vi-mock.ts
|
|
5635
|
-
const RULE_NAME$10 = "require-import-vi-mock";
|
|
5636
|
-
var require_import_vi_mock_default = createEslintRule({
|
|
5637
|
-
name: RULE_NAME$10,
|
|
5638
|
-
meta: {
|
|
5639
|
-
fixable: "code",
|
|
5640
|
-
type: "suggestion",
|
|
5641
|
-
docs: {
|
|
5642
|
-
description: "require usage of import in vi.mock()",
|
|
5643
|
-
requiresTypeChecking: false,
|
|
5644
|
-
recommended: false
|
|
5645
|
-
},
|
|
5646
|
-
messages: { requireImport: "Replace '{{path}}' with import('{{path}}')" },
|
|
5647
|
-
schema: []
|
|
5648
|
-
},
|
|
5649
|
-
defaultOptions: [],
|
|
5650
|
-
create(context) {
|
|
5651
|
-
return { CallExpression(node) {
|
|
5652
|
-
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return;
|
|
5653
|
-
if (parseVitestFnCall(node, context)?.type !== "vi") return false;
|
|
5654
|
-
const { property } = node.callee;
|
|
5655
|
-
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== "mock") return;
|
|
5656
|
-
const pathArg = node.arguments[0];
|
|
5657
|
-
if (pathArg && pathArg.type === AST_NODE_TYPES.Literal) context.report({
|
|
5658
|
-
messageId: "requireImport",
|
|
5659
|
-
data: { path: pathArg.value },
|
|
5660
|
-
node: pathArg,
|
|
5661
|
-
fix(fixer) {
|
|
5662
|
-
return fixer.replaceText(pathArg, `import('${pathArg.value}')`);
|
|
5663
|
-
}
|
|
5664
|
-
});
|
|
5665
|
-
} };
|
|
5666
|
-
}
|
|
5667
|
-
});
|
|
5668
|
-
|
|
5669
5642
|
//#endregion
|
|
5670
5643
|
//#region src/rules/require-local-test-context-for-concurrent-snapshots.ts
|
|
5671
|
-
const RULE_NAME$
|
|
5644
|
+
const RULE_NAME$10 = "require-local-test-context-for-concurrent-snapshots";
|
|
5672
5645
|
var require_local_test_context_for_concurrent_snapshots_default = createEslintRule({
|
|
5673
|
-
name: RULE_NAME$
|
|
5646
|
+
name: RULE_NAME$10,
|
|
5674
5647
|
meta: {
|
|
5675
5648
|
docs: {
|
|
5676
5649
|
description: "require local Test Context for concurrent snapshot tests",
|
|
@@ -5711,9 +5684,9 @@ var require_local_test_context_for_concurrent_snapshots_default = createEslintRu
|
|
|
5711
5684
|
|
|
5712
5685
|
//#endregion
|
|
5713
5686
|
//#region src/rules/require-mock-type-parameters.ts
|
|
5714
|
-
const RULE_NAME$
|
|
5687
|
+
const RULE_NAME$9 = "require-mock-type-parameters";
|
|
5715
5688
|
var require_mock_type_parameters_default = createEslintRule({
|
|
5716
|
-
name: RULE_NAME$
|
|
5689
|
+
name: RULE_NAME$9,
|
|
5717
5690
|
meta: {
|
|
5718
5691
|
type: "suggestion",
|
|
5719
5692
|
docs: {
|
|
@@ -5750,9 +5723,9 @@ var require_mock_type_parameters_default = createEslintRule({
|
|
|
5750
5723
|
|
|
5751
5724
|
//#endregion
|
|
5752
5725
|
//#region src/rules/require-to-throw-message.ts
|
|
5753
|
-
const RULE_NAME$
|
|
5726
|
+
const RULE_NAME$8 = "require-to-throw-message";
|
|
5754
5727
|
var require_to_throw_message_default = createEslintRule({
|
|
5755
|
-
name: RULE_NAME$
|
|
5728
|
+
name: RULE_NAME$8,
|
|
5756
5729
|
meta: {
|
|
5757
5730
|
type: "suggestion",
|
|
5758
5731
|
docs: {
|
|
@@ -5780,9 +5753,9 @@ var require_to_throw_message_default = createEslintRule({
|
|
|
5780
5753
|
|
|
5781
5754
|
//#endregion
|
|
5782
5755
|
//#region src/rules/require-top-level-describe.ts
|
|
5783
|
-
const RULE_NAME$
|
|
5756
|
+
const RULE_NAME$7 = "require-top-level-describe";
|
|
5784
5757
|
var require_top_level_describe_default = createEslintRule({
|
|
5785
|
-
name: RULE_NAME$
|
|
5758
|
+
name: RULE_NAME$7,
|
|
5786
5759
|
meta: {
|
|
5787
5760
|
docs: {
|
|
5788
5761
|
description: "enforce that all tests are in a top-level describe",
|
|
@@ -5851,7 +5824,7 @@ var require_top_level_describe_default = createEslintRule({
|
|
|
5851
5824
|
|
|
5852
5825
|
//#endregion
|
|
5853
5826
|
//#region src/rules/valid-describe-callback.ts
|
|
5854
|
-
const RULE_NAME$
|
|
5827
|
+
const RULE_NAME$6 = "valid-describe-callback";
|
|
5855
5828
|
const paramsLocation = (params) => {
|
|
5856
5829
|
const [first] = params;
|
|
5857
5830
|
const last = params[params.length - 1];
|
|
@@ -5873,7 +5846,7 @@ const reportUnexpectedReturnInDescribe = (blockStatement, context) => {
|
|
|
5873
5846
|
});
|
|
5874
5847
|
};
|
|
5875
5848
|
var valid_describe_callback_default = createEslintRule({
|
|
5876
|
-
name: RULE_NAME$
|
|
5849
|
+
name: RULE_NAME$6,
|
|
5877
5850
|
meta: {
|
|
5878
5851
|
type: "problem",
|
|
5879
5852
|
docs: {
|
|
@@ -5940,7 +5913,7 @@ var valid_describe_callback_default = createEslintRule({
|
|
|
5940
5913
|
|
|
5941
5914
|
//#endregion
|
|
5942
5915
|
//#region src/rules/valid-expect-in-promise.ts
|
|
5943
|
-
const RULE_NAME$
|
|
5916
|
+
const RULE_NAME$5 = "valid-expect-in-promise";
|
|
5944
5917
|
const defaultAsyncMatchers$1 = ["toRejectWith", "toResolveWith"];
|
|
5945
5918
|
const isPromiseChainCall = (node) => {
|
|
5946
5919
|
if (node.type === AST_NODE_TYPES.CallExpression && node.callee.type === AST_NODE_TYPES.MemberExpression && isSupportedAccessor(node.callee.property)) {
|
|
@@ -6072,7 +6045,7 @@ const isVariableAwaitedOrReturned = (variable, context) => {
|
|
|
6072
6045
|
return isValueAwaitedOrReturned(variable.id, body, context);
|
|
6073
6046
|
};
|
|
6074
6047
|
var valid_expect_in_promise_default = createEslintRule({
|
|
6075
|
-
name: RULE_NAME$
|
|
6048
|
+
name: RULE_NAME$5,
|
|
6076
6049
|
meta: {
|
|
6077
6050
|
docs: { description: "require promises that have expectations in their chain to be valid" },
|
|
6078
6051
|
messages: { expectInFloatingPromise: "This promise should either be returned or awaited to ensure the expects in its chain are called" },
|
|
@@ -6132,7 +6105,7 @@ var valid_expect_in_promise_default = createEslintRule({
|
|
|
6132
6105
|
|
|
6133
6106
|
//#endregion
|
|
6134
6107
|
//#region src/rules/valid-expect.ts
|
|
6135
|
-
const RULE_NAME$
|
|
6108
|
+
const RULE_NAME$4 = "valid-expect";
|
|
6136
6109
|
const defaultAsyncMatchers = ["toReject", "toResolve"];
|
|
6137
6110
|
/**
|
|
6138
6111
|
* Async assertions might be called in Promise
|
|
@@ -6167,7 +6140,7 @@ const isAcceptableReturnNode = (node, allowReturn) => {
|
|
|
6167
6140
|
return [AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.AwaitExpression].includes(node.type);
|
|
6168
6141
|
};
|
|
6169
6142
|
var valid_expect_default = createEslintRule({
|
|
6170
|
-
name: RULE_NAME$
|
|
6143
|
+
name: RULE_NAME$4,
|
|
6171
6144
|
meta: {
|
|
6172
6145
|
docs: {
|
|
6173
6146
|
description: "enforce valid `expect()` usage",
|
|
@@ -6360,7 +6333,7 @@ var valid_expect_default = createEslintRule({
|
|
|
6360
6333
|
|
|
6361
6334
|
//#endregion
|
|
6362
6335
|
//#region src/rules/valid-title.ts
|
|
6363
|
-
const RULE_NAME$
|
|
6336
|
+
const RULE_NAME$3 = "valid-title";
|
|
6364
6337
|
const trimFXPrefix = (word) => ["f", "x"].includes(word.charAt(0)) ? word.substring(1) : word;
|
|
6365
6338
|
const quoteStringValue = (node) => node.type === AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw;
|
|
6366
6339
|
const MatcherAndMessageSchema = {
|
|
@@ -6399,7 +6372,7 @@ const doesBinaryExpressionContainStringNode = (binaryExp) => {
|
|
|
6399
6372
|
return isStringNode(binaryExp.left);
|
|
6400
6373
|
};
|
|
6401
6374
|
var valid_title_default = createEslintRule({
|
|
6402
|
-
name: RULE_NAME$
|
|
6375
|
+
name: RULE_NAME$3,
|
|
6403
6376
|
meta: {
|
|
6404
6377
|
docs: {
|
|
6405
6378
|
description: "enforce valid titles",
|
|
@@ -6552,9 +6525,9 @@ var valid_title_default = createEslintRule({
|
|
|
6552
6525
|
|
|
6553
6526
|
//#endregion
|
|
6554
6527
|
//#region src/rules/warn-todo.ts
|
|
6555
|
-
const RULE_NAME$
|
|
6528
|
+
const RULE_NAME$2 = "warn-todo";
|
|
6556
6529
|
var warn_todo_default = createEslintRule({
|
|
6557
|
-
name: RULE_NAME$
|
|
6530
|
+
name: RULE_NAME$2,
|
|
6558
6531
|
meta: {
|
|
6559
6532
|
docs: {
|
|
6560
6533
|
description: "disallow `.todo` usage",
|
|
@@ -6581,7 +6554,7 @@ var warn_todo_default = createEslintRule({
|
|
|
6581
6554
|
|
|
6582
6555
|
//#endregion
|
|
6583
6556
|
//#region src/rules/no-unneeded-async-expect-function.ts
|
|
6584
|
-
const RULE_NAME = "no-unneeded-async-expect-function";
|
|
6557
|
+
const RULE_NAME$1 = "no-unneeded-async-expect-function";
|
|
6585
6558
|
const getAwaitedCallExpression = (expression) => {
|
|
6586
6559
|
if (!expression.async) return null;
|
|
6587
6560
|
if (expression.type === AST_NODE_TYPES.ArrowFunctionExpression && expression.body.type === AST_NODE_TYPES.AwaitExpression && expression.body.argument.type === AST_NODE_TYPES.CallExpression) return expression.body.argument;
|
|
@@ -6591,7 +6564,7 @@ const getAwaitedCallExpression = (expression) => {
|
|
|
6591
6564
|
return null;
|
|
6592
6565
|
};
|
|
6593
6566
|
var no_unneeded_async_expect_function_default = createEslintRule({
|
|
6594
|
-
name: RULE_NAME,
|
|
6567
|
+
name: RULE_NAME$1,
|
|
6595
6568
|
meta: {
|
|
6596
6569
|
docs: { description: "Disallow unnecessary async function wrapper for expected promises" },
|
|
6597
6570
|
fixable: "code",
|
|
@@ -6622,6 +6595,42 @@ var no_unneeded_async_expect_function_default = createEslintRule({
|
|
|
6622
6595
|
}
|
|
6623
6596
|
});
|
|
6624
6597
|
|
|
6598
|
+
//#endregion
|
|
6599
|
+
//#region src/rules/prefer-to-have-been-called-times.ts
|
|
6600
|
+
const RULE_NAME = "prefer-to-have-been-called-times";
|
|
6601
|
+
var prefer_to_have_been_called_times_default = createEslintRule({
|
|
6602
|
+
name: RULE_NAME,
|
|
6603
|
+
meta: {
|
|
6604
|
+
fixable: "code",
|
|
6605
|
+
docs: { description: "Suggest using `toHaveBeenCalledTimes()`" },
|
|
6606
|
+
messages: { preferMatcher: "Prefer `toHaveBeenCalledTimes`" },
|
|
6607
|
+
type: "suggestion",
|
|
6608
|
+
schema: []
|
|
6609
|
+
},
|
|
6610
|
+
defaultOptions: [],
|
|
6611
|
+
create(context) {
|
|
6612
|
+
return { CallExpression(node) {
|
|
6613
|
+
const vitestFnCall = parseVitestFnCall(node, context);
|
|
6614
|
+
if (vitestFnCall?.type !== "expect") return;
|
|
6615
|
+
const { parent: expect } = vitestFnCall.head.node;
|
|
6616
|
+
if (expect?.type !== AST_NODE_TYPES.CallExpression) return;
|
|
6617
|
+
const { matcher } = vitestFnCall;
|
|
6618
|
+
if (!isSupportedAccessor(matcher, "toHaveLength")) return;
|
|
6619
|
+
const [argument] = expect.arguments;
|
|
6620
|
+
if (argument?.type !== AST_NODE_TYPES.MemberExpression || !isSupportedAccessor(argument.property, "calls")) return;
|
|
6621
|
+
const { object } = argument;
|
|
6622
|
+
if (object.type !== AST_NODE_TYPES.MemberExpression || !isSupportedAccessor(object.property, "mock")) return;
|
|
6623
|
+
context.report({
|
|
6624
|
+
messageId: "preferMatcher",
|
|
6625
|
+
node: matcher,
|
|
6626
|
+
fix(fixer) {
|
|
6627
|
+
return [fixer.removeRange([object.property.range[0] - 1, argument.range[1]]), fixer.replaceTextRange([matcher.parent.object.range[1], matcher.parent.range[1]], ".toHaveBeenCalledTimes")];
|
|
6628
|
+
}
|
|
6629
|
+
});
|
|
6630
|
+
} };
|
|
6631
|
+
}
|
|
6632
|
+
});
|
|
6633
|
+
|
|
6625
6634
|
//#endregion
|
|
6626
6635
|
//#region src/rules/index.ts
|
|
6627
6636
|
const rules = {
|
|
@@ -6689,12 +6698,12 @@ const rules = {
|
|
|
6689
6698
|
"prefer-to-be-truthy": prefer_to_be_truthy_default,
|
|
6690
6699
|
"prefer-to-be": prefer_to_be_default,
|
|
6691
6700
|
"prefer-to-contain": prefer_to_contain_default,
|
|
6701
|
+
"prefer-to-have-been-called-times": prefer_to_have_been_called_times_default,
|
|
6692
6702
|
"prefer-to-have-length": prefer_to_have_length_default,
|
|
6693
6703
|
"prefer-todo": prefer_todo_default,
|
|
6694
6704
|
"prefer-vi-mocked": prefer_vi_mocked_default,
|
|
6695
6705
|
"require-awaited-expect-poll": require_awaited_expect_poll_default,
|
|
6696
6706
|
"require-hook": require_hook_default,
|
|
6697
|
-
"require-import-vi-mock": require_import_vi_mock_default,
|
|
6698
6707
|
"require-local-test-context-for-concurrent-snapshots": require_local_test_context_for_concurrent_snapshots_default,
|
|
6699
6708
|
"require-mock-type-parameters": require_mock_type_parameters_default,
|
|
6700
6709
|
"require-to-throw-message": require_to_throw_message_default,
|
|
@@ -6787,6 +6796,7 @@ const allRules = {
|
|
|
6787
6796
|
"prefer-to-be-truthy": "off",
|
|
6788
6797
|
"prefer-to-be": "warn",
|
|
6789
6798
|
"prefer-to-contain": "warn",
|
|
6799
|
+
"prefer-to-have-been-called-times": "warn",
|
|
6790
6800
|
"prefer-to-have-length": "warn",
|
|
6791
6801
|
"prefer-todo": "warn",
|
|
6792
6802
|
"prefer-vi-mocked": "warn",
|
|
@@ -6799,8 +6809,7 @@ const allRules = {
|
|
|
6799
6809
|
"valid-expect-in-promise": "warn",
|
|
6800
6810
|
"valid-expect": "warn",
|
|
6801
6811
|
"valid-title": "warn",
|
|
6802
|
-
"require-awaited-expect-poll": "warn"
|
|
6803
|
-
"require-import-vi-mock": "warn"
|
|
6812
|
+
"require-awaited-expect-poll": "warn"
|
|
6804
6813
|
};
|
|
6805
6814
|
const recommendedRules = {
|
|
6806
6815
|
"expect-expect": "error",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest/eslint-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ESLint plugin for Vitest",
|
|
6
6
|
"repository": "vitest-dev/eslint-plugin-vitest",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"eslint": "^9.37.0",
|
|
43
43
|
"eslint-config-flat-gitignore": "^2.1.0",
|
|
44
44
|
"eslint-config-prettier": "^10.1.8",
|
|
45
|
-
"eslint-doc-generator": "^2.
|
|
45
|
+
"eslint-doc-generator": "^2.4.0",
|
|
46
46
|
"eslint-plugin-eslint-plugin": "^7.0.0",
|
|
47
47
|
"eslint-remote-tester": "^4.0.3",
|
|
48
48
|
"eslint-remote-tester-repositories": "^2.0.2",
|