From 3e56b2bd165ed8bcc41d1936569a4387d38267b0 Mon Sep 17 00:00:00 2001 From: cinchen Date: Fri, 12 Jul 2024 11:03:39 +0800 Subject: [PATCH] feat(linter): support eslint-plugin-vitest/no-test-prefixes (#4182) Rule detail: [link](https://github.com/veritem/eslint-plugin-vitest/blob/main/src/rules/no-test-prefixes.ts) --- .../src/rules/jest/no_test_prefixes.rs | 65 +++++++++++++++---- .../src/snapshots/no_test_prefixes.snap | 61 +++++++++++++++++ crates/oxc_linter/src/utils/mod.rs | 9 ++- 3 files changed, 122 insertions(+), 13 deletions(-) diff --git a/crates/oxc_linter/src/rules/jest/no_test_prefixes.rs b/crates/oxc_linter/src/rules/jest/no_test_prefixes.rs index ea101026f6bbe..cb9247131954a 100644 --- a/crates/oxc_linter/src/rules/jest/no_test_prefixes.rs +++ b/crates/oxc_linter/src/rules/jest/no_test_prefixes.rs @@ -7,14 +7,14 @@ use crate::{ context::LintContext, rule::Rule, utils::{ - collect_possible_jest_call_node, parse_general_jest_fn_call, JestGeneralFnKind, - KnownMemberExpressionProperty, ParsedGeneralJestFnCall, PossibleJestNode, + collect_possible_jest_call_node, get_test_plugin_name, parse_general_jest_fn_call, + JestGeneralFnKind, KnownMemberExpressionProperty, ParsedGeneralJestFnCall, + PossibleJestNode, TestPluginName, }, }; -fn no_test_prefixes_diagnostic(x0: &str, span1: Span) -> OxcDiagnostic { - OxcDiagnostic::warn(format!("eslint-plugin-jest(no-test-prefixes): Use {x0:?} instead.")) - .with_label(span1) +fn no_test_prefixes_diagnostic(x0: TestPluginName, x1: &str, span2: Span) -> OxcDiagnostic { + OxcDiagnostic::warn(format!("{x0}(no-test-prefixes): Use {x1:?} instead.")).with_label(span2) } #[derive(Debug, Default, Clone)] @@ -42,6 +42,17 @@ declare_oxc_lint!( /// xtest('foo'); // invalid /// xdescribe('foo'); // invalid /// ``` + /// + /// This rule is compatible with [eslint-plugin-vitest](https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-test-prefixes.md), + /// to use it, add the following configuration to your `.eslintrc.json`: + /// + /// ```json + /// { + /// "rules": { + /// "vitest/no-test-prefixes": "error" + /// } + /// } + /// ``` NoTestPrefixes, style ); @@ -84,10 +95,12 @@ fn run<'a>(possible_jest_node: &PossibleJestNode<'a, '_>, ctx: &LintContext<'a>) }; let preferred_node_name = get_preferred_node_names(&jest_fn_call); + let plugin_name = get_test_plugin_name(ctx); - ctx.diagnostic_with_fix(no_test_prefixes_diagnostic(&preferred_node_name, span), |fixer| { - fixer.replace(span, preferred_node_name) - }); + ctx.diagnostic_with_fix( + no_test_prefixes_diagnostic(plugin_name, &preferred_node_name, span), + |fixer| fixer.replace(span, preferred_node_name), + ); } fn get_preferred_node_names(jest_fn_call: &ParsedGeneralJestFnCall) -> String { @@ -112,7 +125,7 @@ fn get_preferred_node_names(jest_fn_call: &ParsedGeneralJestFnCall) -> String { fn test() { use crate::tester::Tester; - let pass = vec![ + let mut pass = vec![ ("describe('foo', function () {})", None), ("it('foo', function () {})", None), ("it.concurrent('foo', function () {})", None), @@ -132,7 +145,7 @@ fn test() { ("[1,2,3].forEach()", None), ]; - let fail = vec![ + let mut fail = vec![ ("fdescribe('foo', function () {})", None), ("xdescribe.each([])('foo', function () {})", None), ("fit('foo', function () {})", None), @@ -166,5 +179,35 @@ fn test() { ), ]; - Tester::new(NoTestPrefixes::NAME, pass, fail).with_jest_plugin(true).test_and_snapshot(); + let pass_vitest = vec![ + ("describe(\"foo\", function () {})", None), + ("it(\"foo\", function () {})", None), + ("it.concurrent(\"foo\", function () {})", None), + ("test(\"foo\", function () {})", None), + ("test.concurrent(\"foo\", function () {})", None), + ("describe.only(\"foo\", function () {})", None), + ("it.only(\"foo\", function () {})", None), + ("it.each()(\"foo\", function () {})", None), + ]; + + let fail_vitest = vec![ + ("fdescribe(\"foo\", function () {})", None), + ("xdescribe.each([])(\"foo\", function () {})", None), + ("fit(\"foo\", function () {})", None), + ("xdescribe(\"foo\", function () {})", None), + ("xit(\"foo\", function () {})", None), + ("xtest(\"foo\", function () {})", None), + ("xit.each``(\"foo\", function () {})", None), + ("xtest.each``(\"foo\", function () {})", None), + ("xit.each([])(\"foo\", function () {})", None), + ("xtest.each([])(\"foo\", function () {})", None), + ]; + + pass.extend(pass_vitest); + fail.extend(fail_vitest); + + Tester::new(NoTestPrefixes::NAME, pass, fail) + .with_jest_plugin(true) + .with_vitest_plugin(true) + .test_and_snapshot(); } diff --git a/crates/oxc_linter/src/snapshots/no_test_prefixes.snap b/crates/oxc_linter/src/snapshots/no_test_prefixes.snap index c7125788ed2b7..f2369626b8078 100644 --- a/crates/oxc_linter/src/snapshots/no_test_prefixes.snap +++ b/crates/oxc_linter/src/snapshots/no_test_prefixes.snap @@ -1,5 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs +assertion_line: 216 --- ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.only" instead. ╭─[no_test_prefixes.tsx:1:1] @@ -84,3 +85,63 @@ source: crates/oxc_linter/src/tester.rs · ──────── 4 │ ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.only" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ fdescribe("foo", function () {}) + · ───────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip.each" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xdescribe.each([])("foo", function () {}) + · ────────────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.only" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ fit("foo", function () {}) + · ─── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xdescribe("foo", function () {}) + · ───────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xit("foo", function () {}) + · ─── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xtest("foo", function () {}) + · ───── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xit.each``("foo", function () {}) + · ──────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xtest.each``("foo", function () {}) + · ────────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xit.each([])("foo", function () {}) + · ──────── + ╰──── + + ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. + ╭─[no_test_prefixes.tsx:1:1] + 1 │ xtest.each([])("foo", function () {}) + · ────────── + ╰──── diff --git a/crates/oxc_linter/src/utils/mod.rs b/crates/oxc_linter/src/utils/mod.rs index 3ebd2f7c8b73b..542fb48a0fa14 100644 --- a/crates/oxc_linter/src/utils/mod.rs +++ b/crates/oxc_linter/src/utils/mod.rs @@ -16,8 +16,13 @@ pub use self::{ /// Many Vitest rule are essentially ports of Jest plugin rules with minor modifications. /// For these rules, we use the corresponding jest rules with some adjustments for compatibility. pub fn is_jest_rule_adapted_to_vitest(rule_name: &str) -> bool { - let jest_rules: &[&str] = - &["consistent-test-it", "no-disabled-tests", "no-focused-tests", "prefer-hooks-in-order"]; + let jest_rules: &[&str] = &[ + "consistent-test-it", + "no-disabled-tests", + "no-focused-tests", + "no-test-prefixes", + "prefer-hooks-in-order", + ]; jest_rules.contains(&rule_name) }