Skip to content

Commit

Permalink
feat(linter/eslint-plugin-vitest): implement no-restricted-vi-methods (
Browse files Browse the repository at this point in the history
…#4956)

Related to #4656
  • Loading branch information
shulaoda authored Aug 22, 2024
1 parent ddf83ff commit 14bf5d5
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 19 deletions.
63 changes: 52 additions & 11 deletions crates/oxc_linter/src/rules/jest/no_restricted_jest_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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,
));
}
},
);
Expand All @@ -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),
Expand All @@ -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" }]))),
Expand All @@ -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();
}
40 changes: 35 additions & 5 deletions crates/oxc_linter/src/snapshots/no_restricted_jest_methods.snap
Original file line number Diff line number Diff line change
@@ -1,39 +1,69 @@
---
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]
1jest.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]
1jest["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]
1jest.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]
1jest["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]
2import { jest } from '@jest/globals';
3jest.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]
1vi.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]
1vi.mock()
· ────
╰────
help: "Do not use mocks"

eslint-plugin-vitest(no-restricted-jest-methods): Disallow specific `vi.` methods
╭─[no_restricted_jest_methods.tsx:3:12]
2import { vi } from 'vitest';
3vi.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]
1vi["fn"]()
· ────
╰────
help: Use of `"fn"` is disallowed
3 changes: 3 additions & 0 deletions crates/oxc_linter/src/utils/jest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub const JEST_METHOD_NAMES: phf::Set<&'static str> = phf_set![
"fit",
"it",
"jest",
"vi",
"test",
"xdescribe",
"xit",
Expand All @@ -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),
Expand All @@ -75,6 +77,7 @@ pub enum JestGeneralFnKind {
Describe,
Test,
Jest,
Vitest,
}

/// <https://jestjs.io/docs/configuration#testmatch-arraystring>
Expand Down
12 changes: 9 additions & 3 deletions crates/oxc_linter/src/utils/jest/parse_jest_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_linter/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 14bf5d5

Please sign in to comment.