diff --git a/crates/biome_js_analyze/src/analyzers/nursery/no_focused_tests.rs b/crates/biome_js_analyze/src/analyzers/nursery/no_focused_tests.rs index 6538e716fad9..16ea94ee41ec 100644 --- a/crates/biome_js_analyze/src/analyzers/nursery/no_focused_tests.rs +++ b/crates/biome_js_analyze/src/analyzers/nursery/no_focused_tests.rs @@ -1,8 +1,14 @@ use biome_analyze::{ - context::RuleContext, declare_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleSourceKind, + context::RuleContext, declare_rule, Ast, FixKind, Rule, RuleDiagnostic, RuleSource, + RuleSourceKind, }; use biome_console::markup; +use biome_diagnostics::Applicability; +use biome_js_factory::make; use biome_js_syntax::{AnyJsExpression, JsCallExpression, JsSyntaxToken, TextRange}; +use biome_rowan::BatchMutationExt; + +use crate::JsRuleAction; declare_rule! { /// Disallow focused tests. @@ -22,12 +28,18 @@ declare_rule! { /// ```js,expect_diagnostic /// test.only("foo", () => {}); /// ``` + /// + /// ### Valid + /// ```js + /// test("foo", () => {}); + /// ``` pub(crate) NoFocusedTests { version: "next", name: "noFocusedTests", recommended: true, source: RuleSource::EslintJest("no-focused-tests"), source_kind: RuleSourceKind::Inspired, + fix_kind: FixKind::Unsafe, } } @@ -69,6 +81,42 @@ impl Rule for NoFocusedTests { .note("Remove it.") ) } + + fn action(ctx: &RuleContext, _: &Self::State) -> Option { + let node = ctx.query(); + let callee = node.callee().ok()?; + let function_name = get_function_name(&callee)?; + let replaced_function; + + let mut mutation = ctx.root().begin(); + + match function_name.text_trimmed() { + "only" => { + let member = callee.as_js_static_member_expression()?; + let member_name = member.member().ok()?; + let operator_token = member.operator_token().ok()?; + // let member = member.as_js_name()?; + mutation.remove_element(member_name.into()); + mutation.remove_element(operator_token.into()); + } + "fit" => { + replaced_function = make::js_reference_identifier(make::ident("it")); + mutation.replace_element(function_name.into(), replaced_function.into()); + } + "fdescribe" => { + replaced_function = make::js_reference_identifier(make::ident("describe")); + mutation.replace_element(function_name.into(), replaced_function.into()); + } + _ => {} + }; + + Some(JsRuleAction { + category: biome_analyze::ActionCategory::QuickFix, + applicability: Applicability::MaybeIncorrect, + message: markup! { "Remove focus from test." }.to_owned(), + mutation, + }) + } } fn get_function_name(callee: &AnyJsExpression) -> Option { diff --git a/crates/biome_js_analyze/tests/specs/nursery/noFocusedTests/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noFocusedTests/invalid.js.snap index 98aac1797082..a984f7497789 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noFocusedTests/invalid.js.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/noFocusedTests/invalid.js.snap @@ -14,7 +14,7 @@ fit('foo', () => {}); # Diagnostics ``` -invalid.js:1:10 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:1:10 lint/nursery/noFocusedTests FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Don't focus the test. @@ -27,11 +27,18 @@ invalid.js:1:10 lint/nursery/noFocusedTests ━━━━━━━━━━━━ i Remove it. + i Unsafe fix: Remove focus from test. + + 1 │ - describe.only("test",·()·=>·{}); + 1 │ + describe("test",·()·=>·{}); + 2 2 │ it.only("test", () => {}); + 3 3 │ test.only("test", () => {}); + ``` ``` -invalid.js:2:4 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:2:4 lint/nursery/noFocusedTests FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Don't focus the test. @@ -45,11 +52,19 @@ invalid.js:2:4 lint/nursery/noFocusedTests ━━━━━━━━━━━━ i Remove it. + i Unsafe fix: Remove focus from test. + + 1 1 │ describe.only("test", () => {}); + 2 │ - it.only("test",·()·=>·{}); + 2 │ + it("test",·()·=>·{}); + 3 3 │ test.only("test", () => {}); + 4 4 │ fdescribe('foo', () => {}); + ``` ``` -invalid.js:3:6 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:3:6 lint/nursery/noFocusedTests FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Don't focus the test. @@ -64,11 +79,20 @@ invalid.js:3:6 lint/nursery/noFocusedTests ━━━━━━━━━━━━ i Remove it. + i Unsafe fix: Remove focus from test. + + 1 1 │ describe.only("test", () => {}); + 2 2 │ it.only("test", () => {}); + 3 │ - test.only("test",·()·=>·{}); + 3 │ + test("test",·()·=>·{}); + 4 4 │ fdescribe('foo', () => {}); + 5 5 │ fit('foo', () => {}); + ``` ``` -invalid.js:4:1 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:4:1 lint/nursery/noFocusedTests FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Don't focus the test. @@ -83,11 +107,20 @@ invalid.js:4:1 lint/nursery/noFocusedTests ━━━━━━━━━━━━ i Remove it. + i Unsafe fix: Remove focus from test. + + 2 2 │ it.only("test", () => {}); + 3 3 │ test.only("test", () => {}); + 4 │ - fdescribe('foo',·()·=>·{}); + 4 │ + describe('foo',·()·=>·{}); + 5 5 │ fit('foo', () => {}); + 6 6 │ + ``` ``` -invalid.js:5:1 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:5:1 lint/nursery/noFocusedTests FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Don't focus the test. @@ -101,6 +134,14 @@ invalid.js:5:1 lint/nursery/noFocusedTests ━━━━━━━━━━━━ i Remove it. + i Unsafe fix: Remove focus from test. + + 3 3 │ test.only("test", () => {}); + 4 4 │ fdescribe('foo', () => {}); + 5 │ - fit('foo',·()·=>·{}); + 5 │ + it('foo',·()·=>·{}); + 6 6 │ + ``` diff --git a/website/src/content/docs/linter/rules/index.mdx b/website/src/content/docs/linter/rules/index.mdx index 969ad56ec712..8f81c06577bd 100644 --- a/website/src/content/docs/linter/rules/index.mdx +++ b/website/src/content/docs/linter/rules/index.mdx @@ -236,7 +236,7 @@ Rules that belong to this group are not subject to semantic version⚠️ | | [noGlobalAssign](/linter/rules/no-global-assign) | Disallow assignments to native objects and read-only global variables. | | | [noGlobalEval](/linter/rules/no-global-eval) | Disallow the use of global eval(). | | | [noInvalidUseBeforeDeclaration](/linter/rules/no-invalid-use-before-declaration) | Disallow the use of variables and function parameters before their declaration | | diff --git a/website/src/content/docs/linter/rules/no-focused-tests.md b/website/src/content/docs/linter/rules/no-focused-tests.md index 3c86c6c97e5c..cc154fa6b71d 100644 --- a/website/src/content/docs/linter/rules/no-focused-tests.md +++ b/website/src/content/docs/linter/rules/no-focused-tests.md @@ -28,7 +28,7 @@ However, in pull/merge request, you usually want to run all the test suite. describe.only("foo", () => {}); ``` -
nursery/noFocusedTests.js:1:10 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
nursery/noFocusedTests.js:1:10 lint/nursery/noFocusedTests  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
    Don't focus the test.
   
@@ -40,13 +40,19 @@ describe.only("foo", () => {});
   
    Remove it.
   
+   Unsafe fix: Remove focus from test.
+  
+    1  - describe.only("foo",·()·=>·{});
+      1+ describe("foo",·()·=>·{});
+    2 2  
+  
 
```jsx test.only("foo", () => {}); ``` -
nursery/noFocusedTests.js:1:6 lint/nursery/noFocusedTests ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
nursery/noFocusedTests.js:1:6 lint/nursery/noFocusedTests  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
    Don't focus the test.
   
@@ -58,8 +64,20 @@ test.only("foo", () => {});
   
    Remove it.
   
+   Unsafe fix: Remove focus from test.
+  
+    1  - test.only("foo",·()·=>·{});
+      1+ test("foo",·()·=>·{});
+    2 2  
+  
 
+### Valid + +```jsx +test("foo", () => {}); +``` + ## Related links - [Disable a rule](/linter/#disable-a-lint-rule)