From 76b360dcc36307771dd9d932a878ed1e370de9dc Mon Sep 17 00:00:00 2001 From: Said Atrahouch Date: Thu, 4 Dec 2025 19:15:37 +0100 Subject: [PATCH 1/4] feat(linter/eslint-plugin-vitest): reuse the jest linter rule --- crates/oxc_linter/src/rules/jest/no_mocks_import.rs | 1 + crates/oxc_linter/src/utils/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs index 939c0e8dfbf79..906acdf3a932e 100644 --- a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs +++ b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs @@ -118,5 +118,6 @@ fn test() { Tester::new(NoMocksImport::NAME, NoMocksImport::PLUGIN, pass, fail) .with_jest_plugin(true) + .with_vitest_plugin(true) .test_and_snapshot(); } diff --git a/crates/oxc_linter/src/utils/mod.rs b/crates/oxc_linter/src/utils/mod.rs index 005a82538855e..abfd32a3980c5 100644 --- a/crates/oxc_linter/src/utils/mod.rs +++ b/crates/oxc_linter/src/utils/mod.rs @@ -33,7 +33,7 @@ pub use self::{ /// List of Jest rules that have Vitest equivalents. // When adding a new rule to this list, please ensure oxlint-migrate is also updated. // See https://github.com/oxc-project/oxlint-migrate/blob/2c336c67d75adb09a402ae66fb3099f1dedbe516/scripts/constants.ts -const VITEST_COMPATIBLE_JEST_RULES: [&str; 35] = [ +const VITEST_COMPATIBLE_JEST_RULES: [&str; 36] = [ "consistent-test-it", "expect-expect", "max-expects", @@ -48,6 +48,7 @@ const VITEST_COMPATIBLE_JEST_RULES: [&str; 35] = [ "no-hooks", "no-identical-title", "no-interpolation-in-snapshots", + "no-mocks-import", "no-restricted-jest-methods", "no-restricted-matchers", "no-standalone-expect", From cc4f827fdd9f3b96a748adc0ea20c6602c759dcf Mon Sep 17 00:00:00 2001 From: Said Atrahouch Date: Sun, 7 Dec 2025 08:35:21 +0100 Subject: [PATCH 2/4] feat(linter/eslint-plugin-vitest): Mention that this rule can be reuse with vitest --- crates/oxc_linter/src/rules/jest/no_mocks_import.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs index 906acdf3a932e..5e2a41f41f65c 100644 --- a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs +++ b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs @@ -43,6 +43,17 @@ declare_oxc_lint!( /// import thing from 'thing'; /// require('thing'); /// ``` + /// + /// This rule is compatible with [eslint-plugin-vitest](https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-mocks-import.md), + /// to use it, add the following configuration to your `.oxlintrc.json`: + /// + /// ```json + /// { + /// "rules": { + /// "vitest/no-mocks-import": "error" + /// } + /// } + /// ``` NoMocksImport, jest, style From 9f7f75a563efa9fa223618e3ee99d19b2d8310d9 Mon Sep 17 00:00:00 2001 From: Said Atrahouch Date: Wed, 10 Dec 2025 14:59:01 +0100 Subject: [PATCH 3/4] feat(linter/eslint-plugin-vitest): Extend test with vitest test cases and message based on framework --- .../src/rules/jest/no_mocks_import.rs | 58 +++++++++++++++++-- .../src/snapshots/jest_no_mocks_import.snap | 49 ++++++++++++++++ 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs index 5e2a41f41f65c..06f0652d2d6d6 100644 --- a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs +++ b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs @@ -7,12 +7,18 @@ use oxc_span::Span; use crate::{context::LintContext, rule::Rule}; -fn no_mocks_import_diagnostic(span: Span) -> OxcDiagnostic { +fn no_mocks_jest_import_diagnostic(span: Span) -> OxcDiagnostic { OxcDiagnostic::warn("Mocks should not be manually imported from a `__mocks__` directory.") .with_help("Instead use `jest.mock` and import from the original module path.") .with_label(span) } +fn no_mocks_vitest_import_diagnostic(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Mocks should not be manually imported from a `__mocks__` directory.") + .with_help("Instead use `vi.mock` and import from the original module path.") + .with_label(span) +} + // #[derive(Debug, Default, Clone)] pub struct NoMocksImport; @@ -66,7 +72,17 @@ impl Rule for NoMocksImport { for import_entry in &module_records.import_entries { let module_specifier = import_entry.module_request.name(); if contains_mocks_dir(module_specifier) { - ctx.diagnostic(no_mocks_import_diagnostic(import_entry.module_request.span)); + if ctx.frameworks().is_vitest() { + ctx.diagnostic(no_mocks_vitest_import_diagnostic( + import_entry.module_request.span, + )); + } + + if ctx.frameworks().is_jest() { + ctx.diagnostic(no_mocks_jest_import_diagnostic( + import_entry.module_request.span, + )); + } } } @@ -87,7 +103,13 @@ impl Rule for NoMocksImport { }; if contains_mocks_dir(&string_literal.value) { - ctx.diagnostic(no_mocks_import_diagnostic(string_literal.span)); + if ctx.frameworks().is_vitest() { + ctx.diagnostic(no_mocks_vitest_import_diagnostic(string_literal.span)); + } + + if ctx.frameworks().is_jest() { + ctx.diagnostic(no_mocks_jest_import_diagnostic(string_literal.span)); + } } } } @@ -104,7 +126,7 @@ fn contains_mocks_dir(value: &str) -> bool { fn test() { use crate::tester::Tester; - let pass = vec![ + let mut pass = vec![ ("import something from 'something'", None), ("require('somethingElse')", None), ("require('./__mocks__.js')", None), @@ -117,7 +139,7 @@ fn test() { ("entirelyDifferent(fn)", None), ]; - let fail = vec![ + let mut fail = vec![ ("require('./__mocks__')", None), ("require('./__mocks__/')", None), ("require('./__mocks__/index')", None), @@ -127,6 +149,32 @@ fn test() { ("import thing from './__mocks__/index'", None), ]; + let pass_vitest = vec![ + ("import something from 'something'", None), + ("require('somethingElse')", None), + ("require('./__mocks__.js')", None), + ("require('./__mocks__x')", None), + ("require('./__mocks__x/x')", None), + ("require('./x__mocks__')", None), + ("require('./x__mocks__/x')", None), + ("require()", None), + ("var path = './__mocks__.js'; require(path)", None), + ("entirelyDifferent(fn)", None), + ]; + + let fail_vitest = vec![ + ("require('./__mocks__')", None), + ("require('./__mocks__/')", None), + ("require('./__mocks__/index')", None), + ("require('__mocks__')", None), + ("require('__mocks__/')", None), + ("require('__mocks__/index')", None), + ("import thing from './__mocks__/index'", None), + ]; + + pass.extend(pass_vitest); + fail.extend(fail_vitest); + Tester::new(NoMocksImport::NAME, NoMocksImport::PLUGIN, pass, fail) .with_jest_plugin(true) .with_vitest_plugin(true) diff --git a/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap b/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap index 2bf7fc02b1907..0313f27848124 100644 --- a/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap +++ b/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap @@ -49,3 +49,52 @@ source: crates/oxc_linter/src/tester.rs · ─────────────────── ╰──── help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('./__mocks__') + · ───────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('./__mocks__/') + · ────────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('./__mocks__/index') + · ─────────────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('__mocks__') + · ─────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('__mocks__/') + · ──────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:9] + 1 │ require('__mocks__/index') + · ───────────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. + + ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. + ╭─[no_mocks_import.tsx:1:19] + 1 │ import thing from './__mocks__/index' + · ─────────────────── + ╰──── + help: Instead use `jest.mock` and import from the original module path. From 9734366bb9b33a655af5ff0f3d731099824d7f5b Mon Sep 17 00:00:00 2001 From: Cameron Clark Date: Wed, 10 Dec 2025 14:08:23 +0000 Subject: [PATCH 4/4] u framwork flags can sometime be unreliable, so merge the two help messages into one, and update the help text --- .../src/rules/jest/no_mocks_import.rs | 30 +++---------------- .../src/snapshots/jest_no_mocks_import.snap | 28 ++++++++--------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs index 06f0652d2d6d6..71cd1926dfaf8 100644 --- a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs +++ b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs @@ -7,15 +7,9 @@ use oxc_span::Span; use crate::{context::LintContext, rule::Rule}; -fn no_mocks_jest_import_diagnostic(span: Span) -> OxcDiagnostic { +fn no_mocks_import_diagnostic(span: Span) -> OxcDiagnostic { OxcDiagnostic::warn("Mocks should not be manually imported from a `__mocks__` directory.") - .with_help("Instead use `jest.mock` and import from the original module path.") - .with_label(span) -} - -fn no_mocks_vitest_import_diagnostic(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("Mocks should not be manually imported from a `__mocks__` directory.") - .with_help("Instead use `vi.mock` and import from the original module path.") + .with_help("Instead use `jest.mock` or `vi.mock` and import from the original module path.") .with_label(span) } @@ -72,17 +66,7 @@ impl Rule for NoMocksImport { for import_entry in &module_records.import_entries { let module_specifier = import_entry.module_request.name(); if contains_mocks_dir(module_specifier) { - if ctx.frameworks().is_vitest() { - ctx.diagnostic(no_mocks_vitest_import_diagnostic( - import_entry.module_request.span, - )); - } - - if ctx.frameworks().is_jest() { - ctx.diagnostic(no_mocks_jest_import_diagnostic( - import_entry.module_request.span, - )); - } + ctx.diagnostic(no_mocks_import_diagnostic(import_entry.module_request.span)); } } @@ -103,13 +87,7 @@ impl Rule for NoMocksImport { }; if contains_mocks_dir(&string_literal.value) { - if ctx.frameworks().is_vitest() { - ctx.diagnostic(no_mocks_vitest_import_diagnostic(string_literal.span)); - } - - if ctx.frameworks().is_jest() { - ctx.diagnostic(no_mocks_jest_import_diagnostic(string_literal.span)); - } + ctx.diagnostic(no_mocks_import_diagnostic(string_literal.span)); } } } diff --git a/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap b/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap index 0313f27848124..8ba3285b34996 100644 --- a/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap +++ b/crates/oxc_linter/src/snapshots/jest_no_mocks_import.snap @@ -6,95 +6,95 @@ source: crates/oxc_linter/src/tester.rs 1 │ require('./__mocks__') · ───────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('./__mocks__/') · ────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('./__mocks__/index') · ─────────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__') · ─────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__/') · ──────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__/index') · ───────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:19] 1 │ import thing from './__mocks__/index' · ─────────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('./__mocks__') · ───────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('./__mocks__/') · ────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('./__mocks__/index') · ─────────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__') · ─────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__/') · ──────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:9] 1 │ require('__mocks__/index') · ───────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path. ⚠ eslint-plugin-jest(no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory. ╭─[no_mocks_import.tsx:1:19] 1 │ import thing from './__mocks__/index' · ─────────────────── ╰──── - help: Instead use `jest.mock` and import from the original module path. + help: Instead use `jest.mock` or `vi.mock` and import from the original module path.