mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(linter/eslint-plugin-vitest): implement no-restricted-vi-methods (#4956)
Related to #4656
This commit is contained in:
parent
ddf83ff1b9
commit
14bf5d5177
5 changed files with 100 additions and 19 deletions
|
|
@ -13,14 +13,14 @@ use crate::{
|
|||
},
|
||||
};
|
||||
|
||||
fn restricted_jest_method(x0: &str, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Disallow specific `jest.` methods")
|
||||
fn restricted_jest_method(method_name: &str, x0: &str, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("Disallow specific `{method_name}.` methods"))
|
||||
.with_help(format!("Use of `{x0:?}` is disallowed"))
|
||||
.with_label(span1)
|
||||
}
|
||||
|
||||
fn restricted_jest_method_with_message(x0: &str, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Disallow specific `jest.` methods")
|
||||
fn restricted_jest_method_with_message(method_name: &str, x0: &str, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("Disallow specific `{method_name}.` methods"))
|
||||
.with_help(format!("{x0:?}"))
|
||||
.with_label(span1)
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ impl std::ops::Deref for NoRestrictedJestMethods {
|
|||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Restrict the use of specific `jest` methods.
|
||||
/// Restrict the use of specific `jest` and `vi` methods.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
|
|
@ -106,7 +106,10 @@ impl NoRestrictedJestMethods {
|
|||
call_expr,
|
||||
possible_jest_node,
|
||||
ctx,
|
||||
&[JestFnKind::General(JestGeneralFnKind::Jest)],
|
||||
&[
|
||||
JestFnKind::General(JestGeneralFnKind::Jest),
|
||||
JestFnKind::General(JestGeneralFnKind::Vitest),
|
||||
],
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -122,15 +125,21 @@ impl NoRestrictedJestMethods {
|
|||
};
|
||||
|
||||
if self.contains(property_name) {
|
||||
let method_name =
|
||||
mem_expr.object().get_identifier_reference().map_or("jest", |id| id.name.as_str());
|
||||
self.get_message(property_name).map_or_else(
|
||||
|| {
|
||||
ctx.diagnostic(restricted_jest_method(property_name, span));
|
||||
ctx.diagnostic(restricted_jest_method(method_name, property_name, span));
|
||||
},
|
||||
|message| {
|
||||
if message.trim() == "" {
|
||||
ctx.diagnostic(restricted_jest_method(property_name, span));
|
||||
ctx.diagnostic(restricted_jest_method(method_name, property_name, span));
|
||||
} else {
|
||||
ctx.diagnostic(restricted_jest_method_with_message(&message, span));
|
||||
ctx.diagnostic(restricted_jest_method_with_message(
|
||||
method_name,
|
||||
&message,
|
||||
span,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -156,7 +165,7 @@ impl NoRestrictedJestMethods {
|
|||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
let mut pass = vec![
|
||||
("jest", None),
|
||||
("jest()", None),
|
||||
("jest.mock()", None),
|
||||
|
|
@ -172,7 +181,7 @@ fn test() {
|
|||
),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
let mut fail = vec![
|
||||
("jest.fn()", Some(serde_json::json!([{ "fn": null }]))),
|
||||
("jest[\"fn\"]()", Some(serde_json::json!([{ "fn": null }]))),
|
||||
("jest.mock()", Some(serde_json::json!([{ "mock": "Do not use mocks" }]))),
|
||||
|
|
@ -186,7 +195,39 @@ fn test() {
|
|||
),
|
||||
];
|
||||
|
||||
let pass_vitest = vec![
|
||||
("vi", None),
|
||||
("vi()", None),
|
||||
("vi.mock()", None),
|
||||
("expect(a).rejects;", None),
|
||||
("expect(a);", None),
|
||||
(
|
||||
"
|
||||
import { vi } from 'vitest';
|
||||
vi;
|
||||
",
|
||||
None,
|
||||
), // { "parserOptions": { "sourceType": "module" } }
|
||||
];
|
||||
|
||||
let fail_vitest = vec![
|
||||
("vi.fn()", Some(serde_json::json!([{ "fn": null }]))),
|
||||
("vi.mock()", Some(serde_json::json!([{ "mock": "Do not use mocks" }]))),
|
||||
(
|
||||
"
|
||||
import { vi } from 'vitest';
|
||||
vi.advanceTimersByTime();
|
||||
",
|
||||
Some(serde_json::json!([{ "advanceTimersByTime": null }])),
|
||||
), // { "parserOptions": { "sourceType": "module" } },
|
||||
(r#"vi["fn"]()"#, Some(serde_json::json!([{ "fn": null }]))),
|
||||
];
|
||||
|
||||
pass.extend(pass_vitest);
|
||||
fail.extend(fail_vitest);
|
||||
|
||||
Tester::new(NoRestrictedJestMethods::NAME, pass, fail)
|
||||
.with_jest_plugin(true)
|
||||
.with_vitest_plugin(true)
|
||||
.test_and_snapshot();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
⚠ eslint-plugin-jest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:6]
|
||||
1 │ jest.fn()
|
||||
· ──
|
||||
╰────
|
||||
help: Use of `"fn"` is disallowed
|
||||
|
||||
⚠ eslint-plugin-jest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:6]
|
||||
1 │ jest["fn"]()
|
||||
· ────
|
||||
╰────
|
||||
help: Use of `"fn"` is disallowed
|
||||
|
||||
⚠ eslint-plugin-jest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:6]
|
||||
1 │ jest.mock()
|
||||
· ────
|
||||
╰────
|
||||
help: "Do not use mocks"
|
||||
|
||||
⚠ eslint-plugin-jest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:6]
|
||||
1 │ jest["mock"]()
|
||||
· ──────
|
||||
╰────
|
||||
help: "Do not use mocks"
|
||||
|
||||
⚠ eslint-plugin-jest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `jest.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:3:22]
|
||||
2 │ import { jest } from '@jest/globals';
|
||||
3 │ jest.advanceTimersByTime();
|
||||
|
|
@ -37,3 +37,33 @@ source: crates/oxc_linter/src/tester.rs
|
|||
4 │
|
||||
╰────
|
||||
help: Use of `"advanceTimersByTime"` is disallowed
|
||||
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `vi.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:4]
|
||||
1 │ vi.fn()
|
||||
· ──
|
||||
╰────
|
||||
help: Use of `"fn"` is disallowed
|
||||
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `vi.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:4]
|
||||
1 │ vi.mock()
|
||||
· ────
|
||||
╰────
|
||||
help: "Do not use mocks"
|
||||
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `vi.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:3:12]
|
||||
2 │ import { vi } from 'vitest';
|
||||
3 │ vi.advanceTimersByTime();
|
||||
· ───────────────────
|
||||
4 │
|
||||
╰────
|
||||
help: Use of `"advanceTimersByTime"` is disallowed
|
||||
|
||||
⚠ eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `vi.` methods
|
||||
╭─[no_restricted_jest_methods.tsx:1:4]
|
||||
1 │ vi["fn"]()
|
||||
· ────
|
||||
╰────
|
||||
help: Use of `"fn"` is disallowed
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ pub const JEST_METHOD_NAMES: phf::Set<&'static str> = phf_set![
|
|||
"fit",
|
||||
"it",
|
||||
"jest",
|
||||
"vi",
|
||||
"test",
|
||||
"xdescribe",
|
||||
"xit",
|
||||
|
|
@ -51,6 +52,7 @@ impl JestFnKind {
|
|||
match name {
|
||||
"expect" => Self::Expect,
|
||||
"expectTypeOf" => Self::ExpectTypeOf,
|
||||
"vi" => Self::General(JestGeneralFnKind::Vitest),
|
||||
"jest" => Self::General(JestGeneralFnKind::Jest),
|
||||
"describe" | "fdescribe" | "xdescribe" => Self::General(JestGeneralFnKind::Describe),
|
||||
"fit" | "it" | "test" | "xit" | "xtest" => Self::General(JestGeneralFnKind::Test),
|
||||
|
|
@ -75,6 +77,7 @@ pub enum JestGeneralFnKind {
|
|||
Describe,
|
||||
Test,
|
||||
Jest,
|
||||
Vitest,
|
||||
}
|
||||
|
||||
/// <https://jestjs.io/docs/configuration#testmatch-arraystring>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@ pub fn parse_jest_fn_call<'a>(
|
|||
return None;
|
||||
}
|
||||
|
||||
if matches!(kind, JestFnKind::General(JestGeneralFnKind::Jest)) {
|
||||
if matches!(kind, JestFnKind::General(JestGeneralFnKind::Jest | JestGeneralFnKind::Vitest))
|
||||
{
|
||||
return parse_jest_jest_fn_call(members, name, resolved.local);
|
||||
}
|
||||
|
||||
|
|
@ -244,12 +245,17 @@ fn parse_jest_jest_fn_call<'a>(
|
|||
name: &'a str,
|
||||
local: &'a str,
|
||||
) -> Option<ParsedJestFnCall<'a>> {
|
||||
if !name.to_ascii_lowercase().eq_ignore_ascii_case("jest") {
|
||||
let lowercase_name = name.to_ascii_lowercase();
|
||||
|
||||
if !(lowercase_name == "jest" || lowercase_name == "vi") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let kind =
|
||||
if lowercase_name == "jest" { JestGeneralFnKind::Jest } else { JestGeneralFnKind::Vitest };
|
||||
|
||||
return Some(ParsedJestFnCall::GeneralJest(ParsedGeneralJestFnCall {
|
||||
kind: JestFnKind::General(JestGeneralFnKind::Jest),
|
||||
kind: JestFnKind::General(kind),
|
||||
members,
|
||||
name: Cow::Borrowed(name),
|
||||
local: Cow::Borrowed(local),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub fn is_jest_rule_adapted_to_vitest(rule_name: &str) -> bool {
|
|||
"no-disabled-tests",
|
||||
"no-focused-tests",
|
||||
"no-identical-title",
|
||||
"no-restricted-jest-methods",
|
||||
"no-test-prefixes",
|
||||
"prefer-hooks-in-order",
|
||||
"valid-describe-callback",
|
||||
|
|
|
|||
Loading…
Reference in a new issue