diff --git a/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs b/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs index 2d4909c54b30e..badf51bb613bc 100644 --- a/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs +++ b/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs @@ -31,6 +31,9 @@ declare_oxc_lint!( /// ### Why is this bad? /// /// Having duplicate hooks in a describe block can lead to confusion and unexpected behavior. + /// When multiple hooks of the same type exist, they all execute in order, which can make it + /// difficult to understand the test setup flow and may result in redundant or conflicting + /// operations. This makes tests harder to maintain and debug. /// /// ### Examples /// diff --git a/crates/oxc_linter/src/rules/jest/no_jasmine_globals.rs b/crates/oxc_linter/src/rules/jest/no_jasmine_globals.rs index c2cd38a3395d9..0b1b93059c843 100644 --- a/crates/oxc_linter/src/rules/jest/no_jasmine_globals.rs +++ b/crates/oxc_linter/src/rules/jest/no_jasmine_globals.rs @@ -21,7 +21,14 @@ pub struct NoJasmineGlobals; declare_oxc_lint!( /// ### What it does /// - /// This rule reports on any usage of Jasmine globals, which is not ported to Jest, and suggests alternatives from Jest's own API. + /// This rule reports on any usage of Jasmine globals, which is not ported to + /// Jest, and suggests alternatives from Jest's own API. + /// + /// ### Why is this bad? + /// + /// When migrating from Jasmine to Jest, relying on Jasmine-specific globals + /// creates compatibility issues and prevents taking advantage of Jest's + /// improved testing features and better error reporting. /// /// ### Examples /// @@ -29,10 +36,24 @@ declare_oxc_lint!( /// ```javascript /// jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; /// test('my test', () => { - /// pending(); + /// pending(); + /// }); + /// test('my test', () => { + /// jasmine.createSpy(); + /// }); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```javascript + /// jest.setTimeout(5000); + /// test('my test', () => { + /// // Use test.skip() instead of pending() + /// }); + /// test.skip('my test', () => { + /// // Skipped test /// }); /// test('my test', () => { - /// jasmine.createSpy(); + /// jest.fn(); // Use jest.fn() instead of jasmine.createSpy() /// }); /// ``` NoJasmineGlobals, 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 c61c14a53c036..7a388aedd4ade 100644 --- a/crates/oxc_linter/src/rules/jest/no_mocks_import.rs +++ b/crates/oxc_linter/src/rules/jest/no_mocks_import.rs @@ -24,7 +24,11 @@ declare_oxc_lint!( /// /// ### Why is this bad? /// - /// Manually importing mocks from a `__mocks__` directory can lead to unexpected behavior. + /// Manually importing mocks from a `__mocks__` directory can lead to unexpected behavior + /// and breaks Jest's automatic mocking system. Jest is designed to automatically resolve + /// and use mocks from `__mocks__` directories when `jest.mock()` is called. Directly + /// importing from these directories bypasses Jest's module resolution system and can cause + /// inconsistencies between test and production environments. /// /// ### Examples /// diff --git a/crates/oxc_linter/src/rules/jest/no_restricted_matchers.rs b/crates/oxc_linter/src/rules/jest/no_restricted_matchers.rs index 315458a9c7fc7..fa2233f0124e5 100644 --- a/crates/oxc_linter/src/rules/jest/no_restricted_matchers.rs +++ b/crates/oxc_linter/src/rules/jest/no_restricted_matchers.rs @@ -46,6 +46,14 @@ declare_oxc_lint!( /// /// Ban specific matchers & modifiers from being used, and can suggest alternatives. /// + /// ### Why is this bad? + /// + /// Some matchers or modifiers might be discouraged in your codebase for various reasons: + /// they might be deprecated, cause confusion, have performance implications, or there + /// might be better alternatives available. This rule allows you to enforce consistent + /// testing patterns by restricting certain Jest matchers and providing guidance on + /// preferred alternatives. + /// /// ### Examples /// /// Bans are expressed in the form of a map, with the value being either a string message to be shown, diff --git a/crates/oxc_linter/src/rules/jest/no_standalone_expect/mod.rs b/crates/oxc_linter/src/rules/jest/no_standalone_expect/mod.rs index a61de4a70c126..f6b3b93d5a98e 100644 --- a/crates/oxc_linter/src/rules/jest/no_standalone_expect/mod.rs +++ b/crates/oxc_linter/src/rules/jest/no_standalone_expect/mod.rs @@ -49,6 +49,13 @@ declare_oxc_lint!( /// Statements like `expect.hasAssertions()` will NOT trigger this rule since these /// calls will execute if they are not in a test block. /// + /// ### Why is this bad? + /// + /// `expect` statements outside of test blocks will not be executed by the Jest + /// test runner, which means they won't actually test anything. This can lead to + /// false confidence in test coverage and may hide bugs that would otherwise be + /// caught by proper testing. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_called_with.rs b/crates/oxc_linter/src/rules/jest/prefer_called_with.rs index 4a4a27eb82cfd..f9968bc6d81df 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_called_with.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_called_with.rs @@ -29,6 +29,14 @@ declare_oxc_lint!( /// /// Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` /// + /// ### Why is this bad? + /// + /// When testing function calls, it's often more valuable to assert both + /// that a function was called AND what arguments it was called with. + /// Using `toBeCalled()` or `toHaveBeenCalled()` only verifies the function + /// was invoked, but doesn't validate the arguments, potentially missing + /// bugs where functions are called with incorrect parameters. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_comparison_matcher.rs b/crates/oxc_linter/src/rules/jest/prefer_comparison_matcher.rs index dd7c2372c24f2..0954520548475 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_comparison_matcher.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_comparison_matcher.rs @@ -36,6 +36,13 @@ declare_oxc_lint!( /// - `toBeLessThan` /// - `toBeLessThanOrEqual` /// + /// ### Why is this bad? + /// + /// Using generic matchers like `toBe(true)` with comparison expressions + /// makes tests less readable and provides less helpful error messages when + /// they fail. Jest's specific comparison matchers offer clearer intent and + /// better error output that shows the actual values being compared. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_equality_matcher.rs b/crates/oxc_linter/src/rules/jest/prefer_equality_matcher.rs index d38e0dabdf016..105c3077d3284 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_equality_matcher.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_equality_matcher.rs @@ -28,6 +28,14 @@ declare_oxc_lint!( /// Jest has built-in matchers for expecting equality, which allow for more readable /// tests and error messages if an expectation fails. /// + /// ### Why is this bad? + /// + /// Testing equality expressions with generic matchers like `toBe(true)` + /// makes tests harder to read and understand. When tests fail, the error + /// messages are less helpful because they don't show what the actual values + /// were. Using specific equality matchers provides clearer test intent and + /// better debugging information. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_hooks_on_top.rs b/crates/oxc_linter/src/rules/jest/prefer_hooks_on_top.rs index 2ae27e19d89e1..48ac1b91062b6 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_hooks_on_top.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_hooks_on_top.rs @@ -30,6 +30,14 @@ declare_oxc_lint!( /// specific order, which means it can be confusing if they're intermixed with test /// cases. /// + /// ### Why is this bad? + /// + /// When hooks are mixed with test cases, it becomes harder to understand + /// the test setup and execution order. This can lead to confusion about + /// which hooks apply to which tests and when they run. Grouping hooks at + /// the top of each `describe` block makes the test structure clearer and + /// more maintainable. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_jest_mocked.rs b/crates/oxc_linter/src/rules/jest/prefer_jest_mocked.rs index 3b8c1698a6bcb..53f8d51cfc019 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_jest_mocked.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_jest_mocked.rs @@ -30,6 +30,14 @@ declare_oxc_lint!( /// - `jest.MockedClass` /// - `jest.MockedObject` /// + /// ### Why is this bad? + /// + /// Using type assertions like `fn as jest.Mock` is a less safe approach + /// than using `jest.mocked()`. The `jest.mocked()` helper provides better + /// type safety by preserving the original function signature while adding + /// mock capabilities. It also makes the code more readable and explicit + /// about mocking intentions. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_mock_promise_shorthand.rs b/crates/oxc_linter/src/rules/jest/prefer_mock_promise_shorthand.rs index d2ad97dbc581a..2c8b895ab8ed0 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_mock_promise_shorthand.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_mock_promise_shorthand.rs @@ -24,6 +24,14 @@ declare_oxc_lint!( /// API sugar functions to reduce the amount of boilerplate you have to write. /// These methods should be preferred when possible. /// + /// ### Why is this bad? + /// + /// Using generic mock functions like `mockImplementation(() => Promise.resolve())` + /// or `mockReturnValue(Promise.reject())` is more verbose and less readable than + /// Jest's specialized promise shorthands. The shorthand methods like + /// `mockResolvedValue()` and `mockRejectedValue()` are more expressive and + /// make the test intent clearer. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_spy_on.rs b/crates/oxc_linter/src/rules/jest/prefer_spy_on.rs index 60f204a601bec..3431452e4f753 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_spy_on.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_spy_on.rs @@ -40,6 +40,14 @@ declare_oxc_lint!( /// `mockFn.mockImplementation()` or by some of the /// [other mock functions](https://jestjs.io/docs/en/mock-function-api). /// + /// ### Why is this bad? + /// + /// Directly overwriting properties with mock functions can lead to cleanup issues + /// and test isolation problems. When you manually assign a mock to a property, + /// you're responsible for restoring the original implementation, which is easy to + /// forget and can cause tests to interfere with each other. Using `jest.spyOn()` + /// provides automatic cleanup capabilities and makes your tests more reliable. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/prefer_strict_equal.rs b/crates/oxc_linter/src/rules/jest/prefer_strict_equal.rs index de5adfafbea8c..5ea69665688c1 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_strict_equal.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_strict_equal.rs @@ -22,6 +22,13 @@ declare_oxc_lint!( /// /// This rule triggers a warning if `toEqual()` is used to assert equality. /// + /// ### Why is this bad? + /// + /// The `toEqual()` matcher performs a deep equality check but ignores + /// `undefined` values in objects and arrays. This can lead to false + /// positives where tests pass when they should fail. `toStrictEqual()` + /// provides more accurate comparison by checking for `undefined` values. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/require_hook.rs b/crates/oxc_linter/src/rules/jest/require_hook.rs index 04e902ae7e6e1..254cb4addc139 100644 --- a/crates/oxc_linter/src/rules/jest/require_hook.rs +++ b/crates/oxc_linter/src/rules/jest/require_hook.rs @@ -52,6 +52,15 @@ declare_oxc_lint!( /// - Types /// - Calls to the standard Jest globals /// + /// ### Why is this bad? + /// + /// Having setup and teardown code outside of hooks can lead to unpredictable test + /// behavior. Code that runs at the top level executes when the test file is loaded, + /// not when tests run, which can cause issues with test isolation and make tests + /// dependent on execution order. Using proper hooks like `beforeEach`, `beforeAll`, + /// `afterEach`, and `afterAll` ensures that setup and teardown code runs at the + /// correct time and maintains test isolation. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jest/require_to_throw_message.rs b/crates/oxc_linter/src/rules/jest/require_to_throw_message.rs index b5ea6b52729e0..31335c53c8f4e 100644 --- a/crates/oxc_linter/src/rules/jest/require_to_throw_message.rs +++ b/crates/oxc_linter/src/rules/jest/require_to_throw_message.rs @@ -23,6 +23,14 @@ declare_oxc_lint!( /// /// This rule triggers a warning if `toThrow()` or `toThrowError()` is used without an error message. /// + /// ### Why is this bad? + /// + /// Using `toThrow()` or `toThrowError()` without specifying an expected error message + /// makes tests less specific and harder to debug. When a test only checks that an + /// error was thrown but not what kind of error, it can pass even when the wrong + /// error is thrown, potentially hiding bugs. Providing an expected error message + /// or error type makes tests more precise and helps catch regressions more effectively. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/jsdoc/check_access.rs b/crates/oxc_linter/src/rules/jsdoc/check_access.rs index eccc2875c620b..ba24611c27c05 100644 --- a/crates/oxc_linter/src/rules/jsdoc/check_access.rs +++ b/crates/oxc_linter/src/rules/jsdoc/check_access.rs @@ -34,7 +34,11 @@ declare_oxc_lint!( /// /// ### Why is this bad? /// - /// It is important to have a consistent way of specifying access levels. + /// It is important to have a consistent way of specifying access levels in JSDoc + /// comments. Using invalid or multiple access level tags creates confusion about + /// the intended visibility of documented elements and can lead to inconsistencies + /// in API documentation generation. Mixing different access tags or using invalid + /// values makes the documentation unclear and potentially misleading. /// /// ### Examples /// diff --git a/crates/oxc_linter/src/rules/jsx_a11y/aria_activedescendant_has_tabindex.rs b/crates/oxc_linter/src/rules/jsx_a11y/aria_activedescendant_has_tabindex.rs index 60b4186cd384e..25c0596389d7e 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/aria_activedescendant_has_tabindex.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/aria_activedescendant_has_tabindex.rs @@ -28,6 +28,13 @@ declare_oxc_lint!( /// /// Enforce elements with aria-activedescendant are tabbable. /// + /// ### Why is this bad? + /// + /// Elements with `aria-activedescendant` must be tabbable for users to + /// navigate to them using keyboard input. Without proper tabindex, screen + /// reader users cannot access the element through keyboard navigation, + /// making the functionality inaccessible. + /// /// ### Examples /// /// Examples of **incorrect** code for this rule: diff --git a/crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs b/crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs index 81fcec88873c5..baf78ee5a83a5 100644 --- a/crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs +++ b/crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs @@ -30,10 +30,47 @@ declare_oxc_lint!( /// /// Examples of **incorrect** code for this rule: /// ```javascript + /// // pages/_document.js + /// import Document, { Html, Head, Main, NextScript } from 'next/document' + /// + /// class MyDocument extends Document { + /// render() { + /// return ( + /// + ///
+ /// + ///