Skip to content

feat(biome_js_analyze): add useExplicitTestAssertions rule#5995

Open
drwpow wants to merge 17 commits intobiomejs:mainfrom
drwpow:drwpow/use_explicit_test_assertions
Open

feat(biome_js_analyze): add useExplicitTestAssertions rule#5995
drwpow wants to merge 17 commits intobiomejs:mainfrom
drwpow:drwpow/use_explicit_test_assertions

Conversation

@drwpow
Copy link
Contributor

@drwpow drwpow commented May 13, 2025

Summary

Adds expect-expect rule as discussed in #5862. Aims to match eslint-plugin-jest/expect-expect and @vitest/eslint-plugin/expect-expect, but without options to start.

Alternatives

  • Rule could also be named noImplicitTestAssertions if that’s clearer.

Test Plan

  • Tests added

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels May 13, 2025

it('should pass', () => expect(true).toBeDefined());

test('should pass', () => expect(true).toBeDefined());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test cases were pulled from the original expect-expect ESLint rule, so these are all correct. Now to just get them passing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s one test case from the original that may be beyond my abilities to get passing:

it("should pass", myTest);
function myTest() {
  expect(true).toBeDefined();
}

The current logic just does a shallow scan for expect() at the top level, but doesn’t trace references within the same file. Would love help with this, if it’s trivial. Or we could punt on it for now and just wait till someone reports it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can leave it for future oppotunities.

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch 2 times, most recently from b3ddcb8 to 3c475e8 Compare May 13, 2025 03:56
@github-actions github-actions bot added A-CLI Area: CLI A-Project Area: project labels May 13, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented May 13, 2025

CodSpeed Performance Report

Merging #5995 will not alter performance

Comparing drwpow:drwpow/use_explicit_test_assertions (07bae43) with main (b622425)

Summary

✅ 53 untouched
⏩ 85 skipped1

Footnotes

  1. 85 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch 4 times, most recently from 63a602f to a501c07 Compare May 20, 2025 06:23
@drwpow
Copy link
Contributor Author

drwpow commented May 20, 2025

OK It’s getting closer! Some tests (snapshots) are passing, some are failing. I’ll mark it “Ready for review” when the tests seem to be in a better spot

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch from a501c07 to 5aa1a0f Compare May 20, 2025 15:16
@drwpow drwpow marked this pull request as ready for review May 20, 2025 15:17
@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch 2 times, most recently from 0416cad to 2fff644 Compare May 20, 2025 15:27

i Missing assertion in test body.

> 1 │ it('should fail', () => {});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 Please double-check these to make sure they’re correct! I know it’s mostly correct but needs a better eye

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch from 2fff644 to 8db699f Compare May 20, 2025 15:29
@drwpow
Copy link
Contributor Author

drwpow commented May 20, 2025

Hooray! It works! 🎉 And it’s blowing up another test :P.

---- cases::linter_domains::does_enable_test_rules_and_skip stdout ----
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Snapshot file: crates/biome_cli/tests/snapshots/main_cases_linter_domains/does_enable_test_rules_and_skip.snap
Snapshot: does_enable_test_rules_and_skip
Source: crates/biome_cli/tests/snap_test.rs:432
────────────────────────────────────────────────────────────────────────────────
Expression: redactor(content)
────────────────────────────────────────────────────────────────────────────────
-old snapshot
+new results
────────────┬───────────────────────────────────────────────────────────────────
   32    32 │ 
   33    33 │ # Emitted Messages
   34    34 │ 
   35    35 │ ```block
         36 │+test1.js:1:1 lint/nursery/useExplicitTestAssertions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
         37 │+
         38 │+  i Missing assertion in test body.
         39 │+  
         40 │+  > 1 │ describe.only("bar", () => {});
         41 │+      │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         42 │+    2 │ 
         43 │+  
         44 │+  i This could cause false positives where the test always passes but isn’t testing anything.
         45 │+  
         46 │+  i Add an expect() (Vitest/Jest) or assert() (node:assert) assertion to this test.
         47 │+  
         48 │+
         49 │+```
         50 │+
         51 │+```block
         52 │+test2.js:2:1 lint/nursery/useExplicitTestAssertions 

This seems like it’s moving in the right direction, but not sure what to do here / how to disable this rule in other contexts

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch 2 times, most recently from 318c4e5 to ede0e33 Compare May 24, 2025 00:22
Copy link
Member

@siketyan siketyan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!


it('should pass', () => expect(true).toBeDefined());

test('should pass', () => expect(true).toBeDefined());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can leave it for future oppotunities.

@siketyan
Copy link
Member

For currently failing tests, I think we can just update and accept the snapshots. As this PR introduces a new rule for tests, it also should be enabled in the test domain.

@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch 3 times, most recently from f6e21e5 to bc9341a Compare May 25, 2025 19:38
@drwpow drwpow force-pushed the drwpow/use_explicit_test_assertions branch from b21c318 to 0dcabcf Compare August 6, 2025 06:18
@changeset-bot
Copy link

changeset-bot bot commented Aug 6, 2025

🦋 Changeset detected

Latest commit: 07bae43

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 6, 2025

Walkthrough

Adds a new nursery lint rule, useExplicitTestAssertions, that requires explicit assertions in test callbacks. Integrates the rule into the analyser, nursery group, diagnostics categories, rule options, JSON‑RPC types, and configuration schema. Introduces an empty options struct and corresponding schema/types. Updates the ESLint migration to map jest/expect-expect to this rule when “inspired” and “nursery” categories are enabled. Includes valid/invalid test fixtures.

Suggested reviewers

  • dyc3

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly summarises the main change by indicating that a new useExplicitTestAssertions lint rule is being added to the biome_js_analyze crate, matching the PR’s primary purpose and following conventional style.
Description Check ✅ Passed The description directly relates to adding the new test assertion rule, references its inspiration and the added tests, and therefore aligns with the changeset without being off-topic or misleading.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
crates/biome_js_analyze/tests/specs/nursery/useExplicitTestAssertions/valid.js (1)

7-8: Tiny nit: swap the self-calling array for a noop arrow

['x']() will explode if someone ever runs this JS. A benign self-invoking arrow keeps the intention (“arbitrary call”) without the potential runtime TypeError.

-['x']();
+(() => {})();
crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs (2)

43-43: Consider expanding the assertion function list.

The current list covers common cases, but you might want to add more assertion functions like chai.expect, should, or t.is (for AVA). However, keeping it minimal initially is sensible.


171-190: Complex else-if handling could be simplified.

The nested else-if logic is quite complex and hard to follow. Consider extracting this into a separate function for better readability.

+fn handle_else_clause(else_clause: &JsElseClause) -> bool {
+    if let Ok(else_alternate) = else_clause.alternate() {
+        match else_alternate {
+            AnyJsStatement::JsBlockStatement(else_block) => {
+                statements_contain_expect(&else_block.statements())
+            }
+            AnyJsStatement::JsIfStatement(else_if_statement) => {
+                // Handle else-if recursively
+                statements_contain_expect(&[else_if_statement.into()])
+            }
+            _ => false,
+        }
+    } else {
+        false
+    }
+}

Comment on lines +137 to +144
AnyJsExpression::JsConditionalExpression(conditional_expression) => {
if let Ok(left) = conditional_expression.test() {
return expression_contains_expect(&left);
}
if let Ok(right) = conditional_expression.alternate() {
return expression_contains_expect(&right);
}
false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incomplete conditional expression handling.

You're only checking the test and alternate branches of conditional expressions, but missing the consequent branch. This could miss assertions in ternary operations.

         AnyJsExpression::JsConditionalExpression(conditional_expression) => {
-            if let Ok(left) = conditional_expression.test() {
-                return expression_contains_expect(&left);
-            }
-            if let Ok(right) = conditional_expression.alternate() {
-                return expression_contains_expect(&right);
-            }
+            if let Ok(test) = conditional_expression.test() {
+                if expression_contains_expect(&test) {
+                    return true;
+                }
+            }
+            if let Ok(consequent) = conditional_expression.consequent() {
+                if expression_contains_expect(&consequent) {
+                    return true;
+                }
+            }
+            if let Ok(alternate) = conditional_expression.alternate() {
+                if expression_contains_expect(&alternate) {
+                    return true;
+                }
+            }
             false

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
around lines 137 to 144, the code handles conditional expressions by checking
only the test and alternate branches but omits the consequent branch. To fix
this, add a check for the consequent branch of the conditional expression by
retrieving it and passing it to expression_contains_expect, ensuring all parts
of the ternary operation are covered.

Comment on lines 5049 to 5054
"useExplicitTestAssertions": {
"description": "Require each test function (test(), it()) to have an assertion (expect(), assert(), etc.).",
"anyOf": [
{ "$ref": "#/definitions/RuleConfiguration" },
{ "type": "null" }
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not patch the generated schema directly

This JSON schema is auto-generated; manual tweaks here will be overwritten on the next code-gen run and risk desynchronising the rule name or docs. Please add useExplicitTestAssertions in the generator source (look under crates/biome_configuration compile step) and re-generate the schema instead.

🤖 Prompt for AI Agents
In packages/@biomejs/biome/configuration_schema.json around lines 5049 to 5054,
do not manually edit the generated JSON schema as changes will be overwritten.
Instead, locate the source definition for useExplicitTestAssertions in the
generator source code under crates/biome_configuration, add or update the rule
there, and then re-run the schema generation process to apply the change
correctly.

@github-actions github-actions bot removed the A-Project Area: project label Aug 9, 2025
@github-actions github-actions bot added the A-Project Area: project label Aug 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d158953 and 30a23a2.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitTestAssertions/invalid.js.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • crates/biome_configuration/src/analyzer/linter/rules.rs (13 hunks)
  • crates/biome_js_analyze/src/lint/nursery.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Format code (Rust + TOML) using just format

Format Rust and TOML files using just f (alias for just format).

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
crates/biome_*/**/*

📄 CodeRabbit Inference Engine (CLAUDE.md)

Core crates must be located in /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
**/*.rs

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Update documentation for new features or changes, using inline rustdoc for rules, assists, and their options.

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: You are encouraged to split the work for a new rule into multiple PRs and describe your plan in an issue if unfamiliar with Biome's APIs.
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Test rules using quick tests in the appropriate test file (e.g., `biome_js_analyze/tests/quick_test.rs`) and snapshot tests in `tests/specs/`.
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-05T13:25:32.395Z
Learning: Create new lint rules using `just new-js-lintrule`, `just new-css-lintrule`, `just new-json-lintrule`, or `just new-graphql-lintrule`, and the rule name must be camelCase
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Document and test the effect of rule options as part of the rule's documentation and test suite.
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Update the `language` field in `declare_lint_rule!` to match the language the rule applies to (e.g., `js`, `jsx`, `ts`, `tsx`).
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{use*,no*}_*{vue,react,angular,svelte}*.rs : If a rule overwhelmingly applies to a specific framework, it should be named using the `use<Framework>...` or `no<Framework>...` pattern (e.g., `noVueReservedProps`).
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a lint rule is ported from another ecosystem (e.g., ESLint), add a `sources` metadata field in `declare_lint_rule!` referencing the original rule.
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : New rules must be placed inside the `nursery` group for incubation before promotion.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `declare_lint_rule!` macro must be used to declare an analyzer rule type and implement the RuleMeta trait.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a lint rule is ported from another ecosystem (e.g., ESLint), add a `sources` metadata field in `declare_lint_rule!` referencing the original rule.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `version` field in `declare_lint_rule!` must be set to `next` for new rules.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Update the `language` field in `declare_lint_rule!` to match the language the rule applies to (e.g., `js`, `jsx`, `ts`, `tsx`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When deprecating a rule, specify the reason using the `deprecated:` field in the `declare_lint_rule!` macro.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Assign the `domains` field in `declare_lint_rule!` if the rule belongs to a specific domain (e.g., testing, framework).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Rule documentation must start with a single-line summary, followed by detailed paragraphs, and include `## Examples` with `### Invalid` and `### Valid` sections.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a rule provides a code action, add the `fix_kind` metadata to the `declare_lint_rule!` macro and implement the `action` function.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When banning certain functions or variables, always check if the variable is global using the semantic model to avoid false positives.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use_consistent*_*.rs : Rules that ensure consistency should use the `useConsistent<Concept>` naming convention (e.g., `useConsistentArrayType`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use*_*.rs : Rules that mandate a single concept should be named using the `use<Concept>` prefix (e.g., `useValidLang` for mandating valid HTML `lang` attribute values).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use_shorthand*_*.rs : Rules that promote shorthand syntax should use the `useShorthand<Concept>` naming convention (e.g., `useShorthandAssign`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_redundant*_*.rs : Rules that report redundant code should use the `noRedundant<Concept>` naming convention (e.g., `noRedundantUseStrict`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{use*,no*}_*{vue,react,angular,svelte}*.rs : If a rule overwhelmingly applies to a specific framework, it should be named using the `use<Framework>...` or `no<Framework>...` pattern (e.g., `noVueReservedProps`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no*_*.rs : Rules that forbid a single concept should be named using the `no<Concept>` prefix (e.g., `noDebugger` for disallowing `debugger` statements).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Avoid deep indentation by using combinators like `map`, `filter`, and `and_then` instead of nested `if let` or `match` statements.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Rule options must be documented in the `## Options` section of the rule's documentation, with each option having its own header and example.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `rule_category!` macro should be used in diagnostics to statically inject the category at compile time.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_excessive*_*.rs : Rules that report code exceeding certain limits should use the `noExcessive<Concept>` naming convention (e.g., `noExcessiveNestedTestSuites`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_useless*_*.rs : Rules that report unnecessary code should use the `noUseless<Concept>` naming convention (e.g., `noUselessConstructor`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{no_invalid*,use_valid*}_*.rs : Rules that report invalid code should use the `noInvalid<Concept>` or `useValid<Concept>` naming conventions (e.g., `noInvalidConstructorSuper`, `useValidTypeof`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_misleading*_*.rs : Rules that report misleading code should use the `noMisleading<Concept>` naming convention (e.g., `noMisleadingCharacterClass`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_unknown*_*.rs : Rules that report unknown entities (e.g., CSS units) should use the `noUnknown<Concept>` naming convention (e.g., `noUnknownUnit`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_restricted*_*.rs : Rules that report restricted entities should use the `noRestricted<Concept>` naming convention (e.g., `noRestrictedGlobals`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T13:25:32.395Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-05T13:25:32.395Z
Learning: Move rules from nursery to stable group using `just move-rule stable ruleName`

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : For rules that emit multiple diagnostics or actions, use an iterable type (e.g., `Box<[_]>`) for the `Signals` associated type.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When a rule needs to query multiple node types, use the `declare_node_union!` macro to define a union type.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When implementing the `run` function for a rule, prefer transforming `Result` into `Option` and using the `?` operator for concise code.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:49:35.574Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:49:35.574Z
Learning: Use Rust's `dbg!()` macro for debugging and pass `--show-output` to `cargo` to display debug output during tests.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
🔇 Additional comments (12)
crates/biome_js_analyze/src/lint/nursery.rs (2)

44-44: Module added and named correctly.

Good call on use_explicit_test_assertions; matches Biome’s use<Concept> convention and belongs in nursery.


65-65: Rule wired into Nursery group — looks good.

The rule is present in the group. Nice and tidy.

crates/biome_configuration/src/analyzer/linter/rules.rs (10)

360-360: New rule is correctly registered (enum, name strings, and parsing).

Variant, as_str, and FromStr entries for useExplicitTestAssertions look consistent with naming conventions.

Also applies to: 715-716, 1426-1426


1066-1066: Group mapping is correct.

useExplicitTestAssertions belongs to the Nursery group. All good.


4313-4313: Nursery option wire-up for useExplicitTestAssertions is sound.

Field, serde casing, and options type are correct. Docstring reads well.


4358-4361: Alphabetical placement in GROUP_RULES is correct.

"useExplicitTestAssertions" sits between useExhaustiveSwitchCases and useExplicitType as expected.


4459-4460: ALL_RULES_AS_FILTERS updated for new tail index.

Good catch adding index 63 after extending the group rules.


4676-4684: Enabled rules wiring for useExplicitTestAssertions looks right.

Index 41 matches its position in GROUP_RULES; logic mirrors surrounding entries.


5000-5008: Disabled rules wiring for useExplicitTestAssertions is consistent.

Matches the enabled branch index usage; no issues.


5309-5313: Configuration retrieval arm added correctly.

Key matches "useExplicitTestAssertions"; returns (level, options) as expected.


5450-5454: From initialiser includes the new rule.

Keeps defaulting behaviour consistent with other Nursery rules.


4391-4394: Indices sanity-checked and correct

The Nursery::GROUP_RULES entries at the specified offsets match the intended rules:

  • Index 47 → useIndexOf
  • Index 48 → useIterableCallbackReturn
  • Index 51 → useNamedOperation
  • Index 55 → useParseIntRadix

No changes required.

Comment on lines 1103 to 1104
Self::UseNamingConvention => RuleGroup::Style,
Self::UseNodeAssertStrict => RuleGroup::Style,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

useNamingConvention is duplicated across Nursery and Style; please remove it from Nursery.

RuleName::group maps UseNamingConvention to Style, but Nursery still declares and wires it (field, GROUP_RULES, enabled/disabled/config arms). This causes conflicting configuration and filters for the same rule name.

As this file is generated, please update the codegen to:

  • Drop useNamingConvention from Nursery::GROUP_RULES, struct fields, get_enabled_rules/get_disabled_rules/get_rule_configuration, From, and related filters.
  • Keep it only in Style (as currently mapped in RuleName::group).

This will avoid ambiguous configuration and rule lookups.

Also applies to: 4358-4371, 4676-4684, 4729-4735, 5000-5008, 5053-5059, 5309-5313, 5450-5462

🤖 Prompt for AI Agents
In crates/biome_configuration/src/analyzer/linter/rules.rs around lines 1103 to
1104 and also in the specified ranges (4358-4371, 4676-4684, 4729-4735,
5000-5008, 5053-5059, 5309-5313, 5450-5462), remove all references to
useNamingConvention from the Nursery group including struct fields, GROUP_RULES,
get_enabled_rules, get_disabled_rules, get_rule_configuration,
From<GroupPlainConfiguration>, and any related filters. Ensure
useNamingConvention remains only in the Style group as mapped in RuleName::group
to prevent conflicting configurations and ambiguous rule lookups. Update the
code generation logic accordingly to reflect this change.

pub mod use_unified_type_signature;
pub mod use_unique_element_ids;
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_await_in_loop :: NoAwaitInLoop , self :: no_bitwise_operators :: NoBitwiseOperators , self :: no_constant_binary_expression :: NoConstantBinaryExpression , self :: no_destructured_props :: NoDestructuredProps , self :: no_excessive_lines_per_function :: NoExcessiveLinesPerFunction , self :: no_floating_promises :: NoFloatingPromises , self :: no_global_dirname_filename :: NoGlobalDirnameFilename , self :: no_implicit_coercion :: NoImplicitCoercion , self :: no_import_cycles :: NoImportCycles , self :: no_magic_numbers :: NoMagicNumbers , self :: no_misused_promises :: NoMisusedPromises , self :: no_nested_component_definitions :: NoNestedComponentDefinitions , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_non_null_asserted_optional_chain :: NoNonNullAssertedOptionalChain , self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions , self :: no_process_global :: NoProcessGlobal , self :: no_qwik_use_visible_task :: NoQwikUseVisibleTask , self :: no_react_prop_assign :: NoReactPropAssign , self :: no_restricted_elements :: NoRestrictedElements , self :: no_secrets :: NoSecrets , self :: no_shadow :: NoShadow , self :: no_ts_ignore :: NoTsIgnore , self :: no_unassigned_variables :: NoUnassignedVariables , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unwanted_polyfillio :: NoUnwantedPolyfillio , self :: no_useless_backref_in_regex :: NoUselessBackrefInRegex , self :: no_useless_escape_in_string :: NoUselessEscapeInString , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: use_adjacent_getter_setter :: UseAdjacentGetterSetter , self :: use_anchor_href :: UseAnchorHref , self :: use_consistent_object_definition :: UseConsistentObjectDefinition , self :: use_consistent_response :: UseConsistentResponse , self :: use_consistent_type_definitions :: UseConsistentTypeDefinitions , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_exports_last :: UseExportsLast , self :: use_for_component :: UseForComponent , self :: use_google_font_preconnect :: UseGoogleFontPreconnect , self :: use_image_size :: UseImageSize , self :: use_index_of :: UseIndexOf , self :: use_iterable_callback_return :: UseIterableCallbackReturn , self :: use_json_import_attribute :: UseJsonImportAttribute , self :: use_max_params :: UseMaxParams , self :: use_numeric_separators :: UseNumericSeparators , self :: use_object_spread :: UseObjectSpread , self :: use_parse_int_radix :: UseParseIntRadix , self :: use_qwik_classlist :: UseQwikClasslist , self :: use_react_function_components :: UseReactFunctionComponents , self :: use_readonly_class_properties :: UseReadonlyClassProperties , self :: use_single_js_doc_asterisk :: UseSingleJsDocAsterisk , self :: use_sorted_classes :: UseSortedClasses , self :: use_symbol_description :: UseSymbolDescription , self :: use_unified_type_signature :: UseUnifiedTypeSignature , self :: use_unique_element_ids :: UseUniqueElementIds ,] } }
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_await_in_loop :: NoAwaitInLoop , self :: no_bitwise_operators :: NoBitwiseOperators , self :: no_constant_binary_expression :: NoConstantBinaryExpression , self :: no_destructured_props :: NoDestructuredProps , self :: no_excessive_lines_per_function :: NoExcessiveLinesPerFunction , self :: no_floating_promises :: NoFloatingPromises , self :: no_global_dirname_filename :: NoGlobalDirnameFilename , self :: no_implicit_coercion :: NoImplicitCoercion , self :: no_import_cycles :: NoImportCycles , self :: no_magic_numbers :: NoMagicNumbers , self :: no_misused_promises :: NoMisusedPromises , self :: no_nested_component_definitions :: NoNestedComponentDefinitions , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_non_null_asserted_optional_chain :: NoNonNullAssertedOptionalChain , self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions , self :: no_process_global :: NoProcessGlobal , self :: no_qwik_use_visible_task :: NoQwikUseVisibleTask , self :: no_react_prop_assign :: NoReactPropAssign , self :: no_restricted_elements :: NoRestrictedElements , self :: no_secrets :: NoSecrets , self :: no_shadow :: NoShadow , self :: no_ts_ignore :: NoTsIgnore , self :: no_unassigned_variables :: NoUnassignedVariables , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unwanted_polyfillio :: NoUnwantedPolyfillio , self :: no_useless_backref_in_regex :: NoUselessBackrefInRegex , self :: no_useless_escape_in_string :: NoUselessEscapeInString , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: use_adjacent_getter_setter :: UseAdjacentGetterSetter , self :: use_anchor_href :: UseAnchorHref , self :: use_consistent_object_definition :: UseConsistentObjectDefinition , self :: use_consistent_response :: UseConsistentResponse , self :: use_consistent_type_definitions :: UseConsistentTypeDefinitions , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_test_assertions :: UseExplicitTestAssertions , self :: use_explicit_type :: UseExplicitType , self :: use_exports_last :: UseExportsLast , self :: use_for_component :: UseForComponent , self :: use_google_font_preconnect :: UseGoogleFontPreconnect , self :: use_image_size :: UseImageSize , self :: use_index_of :: UseIndexOf , self :: use_iterable_callback_return :: UseIterableCallbackReturn , self :: use_json_import_attribute :: UseJsonImportAttribute , self :: use_max_params :: UseMaxParams , self :: use_numeric_separators :: UseNumericSeparators , self :: use_object_spread :: UseObjectSpread , self :: use_parse_int_radix :: UseParseIntRadix , self :: use_qwik_classlist :: UseQwikClasslist , self :: use_react_function_components :: UseReactFunctionComponents , self :: use_readonly_class_properties :: UseReadonlyClassProperties , self :: use_single_js_doc_asterisk :: UseSingleJsDocAsterisk , self :: use_sorted_classes :: UseSortedClasses , self :: use_symbol_description :: UseSymbolDescription , self :: use_unified_type_signature :: UseUnifiedTypeSignature , self :: use_unique_element_ids :: UseUniqueElementIds ,] } }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Sanity-check rule metadata, registration, and tests across the repo.

Please verify the new rule has:

  • version set to "next"
  • language set for JS/TS variants (js, jsx, ts, tsx as applicable)
  • domains includes "testing"
  • sources attribute referencing eslint-plugin-jest/expect-expect and @vitest/eslint-plugin/expect-expect
  • registration in diagnostics categories, configuration schema, CLI migrate mapping, and docs with Valid/Invalid examples
  • quick and snapshot tests for edge-cases (loops, conditionals, callback indirections noted in the PR)

Run this to confirm:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate rule file =="
fd -a -t f 'use_explicit_test_assertions.rs' || true

echo "== Check rule macro and meta =="
rg -n -S 'declare_lint_rule!\s*\{\s*pub\s+UseExplicitTestAssertions' -U || true
rg -n -S 'name\s*:\s*"useExplicitTestAssertions"' || true
rg -n -S 'version\s*:\s*"next"' || true
rg -n -Si 'domains\s*:\s*\[.*testing.*\]' || true
rg -n -Si 'language\s*:' || true
rg -n -Si 'sources\s*:' || true
rg -n -Si 'jest/expect-expect|@vitest/.*/expect-expect' || true

echo "== Check categories and config schema =="
rg -n -S 'UseExplicitTestAssertions|useExplicitTestAssertions' crates/biome_diagnostics_categories || true
rg -n -S 'useExplicitTestAssertions' packages/@biomejs/biome/configuration_schema.json || true

echo "== Check CLI migrate mapping =="
rg -n -S 'jest/expect-expect' crates/biome_cli/src/execute/migrate || true

echo "== Check tests exist =="
rg -n -S 'useExplicitTestAssertions' crates/biome_js_analyze/tests || true
fd -a 'useExplicitTestAssertions' crates/biome_js_analyze/tests/specs || true

Length of output: 128230


Add missing domains, Vitest source, and quick tests for useExplicitTestAssertions

  • In crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs, update the declare_lint_rule! metadata to include
    • domains: ["testing"]
    • both sources:
      sources: &[
        RuleSource::EslintJest("expect-expect").inspired(),
        RuleSource::EslintVitest("expect-expect").same(),
      ],
  • In crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs, add a branch for "@vitest/eslint-plugin/expect-expect" alongside the existing Jest mapping.
  • Add a quick‐test in crates/biome_js_analyze/tests/quick_test.rs that covers loops, conditionals and callback indirections for invalid cases.
🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery.rs at line 65, update the
useExplicitTestAssertions lint rule metadata to include the missing domains and
sources by adding domains: ["testing"] and sources with both
RuleSource::EslintJest("expect-expect").inspired() and
RuleSource::EslintVitest("expect-expect").same(). Then, in
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs, add a new
branch to handle the "@vitest/eslint-plugin/expect-expect" rule alongside the
existing Jest mapping. Finally, add a quick test in
crates/biome_js_analyze/tests/quick_test.rs that covers invalid cases involving
loops, conditionals, and callback indirections for the useExplicitTestAssertions
rule.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
crates/biome_configuration/src/analyzer/linter/rules.rs (1)

4313-4313: Follow-ups outside this file: set rule domain and sources metadata

Since this is a testing-specific rule, ensure declare_lint_rule! sets domains to include testing and adds sources pointing to eslint-plugin-jest/expect-expect and @vitest/eslint-plugin/expect-expect in the rule file. Shout if you want a patch.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d158953 and 30a23a2.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitTestAssertions/invalid.js.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • crates/biome_configuration/src/analyzer/linter/rules.rs (13 hunks)
  • crates/biome_js_analyze/src/lint/nursery.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Format code (Rust + TOML) using just format

Format Rust and TOML files using just f (alias for just format).

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
crates/biome_*/**/*

📄 CodeRabbit Inference Engine (CLAUDE.md)

Core crates must be located in /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
**/*.rs

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Update documentation for new features or changes, using inline rustdoc for rules, assists, and their options.

Files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: You are encouraged to split the work for a new rule into multiple PRs and describe your plan in an issue if unfamiliar with Biome's APIs.
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Test rules using quick tests in the appropriate test file (e.g., `biome_js_analyze/tests/quick_test.rs`) and snapshot tests in `tests/specs/`.
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-05T13:25:32.395Z
Learning: Create new lint rules using `just new-js-lintrule`, `just new-css-lintrule`, `just new-json-lintrule`, or `just new-graphql-lintrule`, and the rule name must be camelCase
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Document and test the effect of rule options as part of the rule's documentation and test suite.
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Update the `language` field in `declare_lint_rule!` to match the language the rule applies to (e.g., `js`, `jsx`, `ts`, `tsx`).
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{use*,no*}_*{vue,react,angular,svelte}*.rs : If a rule overwhelmingly applies to a specific framework, it should be named using the `use<Framework>...` or `no<Framework>...` pattern (e.g., `noVueReservedProps`).
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a lint rule is ported from another ecosystem (e.g., ESLint), add a `sources` metadata field in `declare_lint_rule!` referencing the original rule.
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : New rules must be placed inside the `nursery` group for incubation before promotion.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `declare_lint_rule!` macro must be used to declare an analyzer rule type and implement the RuleMeta trait.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a lint rule is ported from another ecosystem (e.g., ESLint), add a `sources` metadata field in `declare_lint_rule!` referencing the original rule.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `version` field in `declare_lint_rule!` must be set to `next` for new rules.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Update the `language` field in `declare_lint_rule!` to match the language the rule applies to (e.g., `js`, `jsx`, `ts`, `tsx`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When deprecating a rule, specify the reason using the `deprecated:` field in the `declare_lint_rule!` macro.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Assign the `domains` field in `declare_lint_rule!` if the rule belongs to a specific domain (e.g., testing, framework).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Rule documentation must start with a single-line summary, followed by detailed paragraphs, and include `## Examples` with `### Invalid` and `### Valid` sections.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When banning certain functions or variables, always check if the variable is global using the semantic model to avoid false positives.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : If a rule provides a code action, add the `fix_kind` metadata to the `declare_lint_rule!` macro and implement the `action` function.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use_consistent*_*.rs : Rules that ensure consistency should use the `useConsistent<Concept>` naming convention (e.g., `useConsistentArrayType`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use*_*.rs : Rules that mandate a single concept should be named using the `use<Concept>` prefix (e.g., `useValidLang` for mandating valid HTML `lang` attribute values).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/use_shorthand*_*.rs : Rules that promote shorthand syntax should use the `useShorthand<Concept>` naming convention (e.g., `useShorthandAssign`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_redundant*_*.rs : Rules that report redundant code should use the `noRedundant<Concept>` naming convention (e.g., `noRedundantUseStrict`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{use*,no*}_*{vue,react,angular,svelte}*.rs : If a rule overwhelmingly applies to a specific framework, it should be named using the `use<Framework>...` or `no<Framework>...` pattern (e.g., `noVueReservedProps`).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no*_*.rs : Rules that forbid a single concept should be named using the `no<Concept>` prefix (e.g., `noDebugger` for disallowing `debugger` statements).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Avoid deep indentation by using combinators like `map`, `filter`, and `and_then` instead of nested `if let` or `match` statements.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Rule options must be documented in the `## Options` section of the rule's documentation, with each option having its own header and example.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : Set the `severity` field in `declare_lint_rule!` to `Severity::Warning` or `Severity::Error` as appropriate for the rule.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : The `rule_category!` macro should be used in diagnostics to statically inject the category at compile time.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_excessive*_*.rs : Rules that report code exceeding certain limits should use the `noExcessive<Concept>` naming convention (e.g., `noExcessiveNestedTestSuites`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_useless*_*.rs : Rules that report unnecessary code should use the `noUseless<Concept>` naming convention (e.g., `noUselessConstructor`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/{no_invalid*,use_valid*}_*.rs : Rules that report invalid code should use the `noInvalid<Concept>` or `useValid<Concept>` naming conventions (e.g., `noInvalidConstructorSuper`, `useValidTypeof`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_misleading*_*.rs : Rules that report misleading code should use the `noMisleading<Concept>` naming convention (e.g., `noMisleadingCharacterClass`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_unknown*_*.rs : Rules that report unknown entities (e.g., CSS units) should use the `noUnknown<Concept>` naming convention (e.g., `noUnknownUnit`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/no_restricted*_*.rs : Rules that report restricted entities should use the `noRestricted<Concept>` naming convention (e.g., `noRestrictedGlobals`).

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T13:25:32.395Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-05T13:25:32.395Z
Learning: Move rules from nursery to stable group using `just move-rule stable ruleName`

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : For rules that emit multiple diagnostics or actions, use an iterable type (e.g., `Box<[_]>`) for the `Signals` associated type.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When a rule needs to query multiple node types, use the `declare_node_union!` macro to define a union type.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:50:18.454Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:50:18.454Z
Learning: Applies to crates/biome_analyze/biome_*/lib/src/lint/nursery/*.rs : When implementing the `run` function for a rule, prefer transforming `Result` into `Option` and using the `?` operator for concise code.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
📚 Learning: 2025-08-05T14:49:35.574Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-08-05T14:49:35.574Z
Learning: Use Rust's `dbg!()` macro for debugging and pass `--show-output` to `cargo` to display debug output during tests.

Applied to files:

  • crates/biome_configuration/src/analyzer/linter/rules.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Lint project (depot-windows-2022)
🔇 Additional comments (12)
crates/biome_js_analyze/src/lint/nursery.rs (2)

44-44: Module registered for the new rule — looks right.

Name and placement are consistent with existing rules. Good to see it landing in Nursery first.


65-65: Nursery rule wiring and metadata are all good—no action needed

  • declare_lint_rule! in use_explicit_test_assertions.rs includes version: "next", language: "js", domains: [Test], sources: RuleSource::EslintJest("expect-expect").inspired().
  • Rule name is camelCase (useExplicitTestAssertions) everywhere: tests/specs, configuration_schema.json, workspace.ts, diagnostics categories, migration mapping.
  • Tests live under crates/biome_js_analyze/tests/specs/nursery/useExplicitTestAssertions.
  • Config/schema and CLI migration for “jest/expect-expect” → useExplicitTestAssertions are wired.
  • Ordering in declare_lint_group! is already correct (snake_case alphabetical: exhaustive before explicit).
crates/biome_configuration/src/analyzer/linter/rules.rs (10)

360-361: Rule name wiring is complete and consistent

Enum variant, as_str, group mapping, and FromStr entry for UseExplicitTestAssertions are all correctly added and in sync with "useExplicitTestAssertions".

Also applies to: 715-716, 1066-1067, 1426-1427


4313-4313: Nursery config surface added correctly

Field use_explicit_test_assertions with RuleConfiguration and a clear doc comment looks good. CamelCase serialisation will expose "useExplicitTestAssertions" as expected.


4358-4359: Included in Nursery::GROUP_RULES in the right spot

Placed after useExhaustiveSwitchCases and before useExplicitType, preserving alphabetical order enforced by test_order.


4391-4394: Recommended indices updated appropriately

Index shifts in RECOMMENDED_RULES_AS_FILTERS line up with the new insertion; nothing sneaky here.


4460-4460: ALL_RULES_AS_FILTERS coverage intact

Array tail updated to include the last entry (index 63). Looks tidy.


4676-4680: Enabled rules getter covers the new rule

get_enabled_rules now emits the correct filter at index 41 when enabled. Matches GROUP_RULES.


5000-5004: Disabled rules getter covers the new rule

get_disabled_rules mirrors the enabled path for index 41. All good.


5309-5313: Config lookup added

get_rule_configuration match arm for "useExplicitTestAssertions" is present and consistent with other entries.


5450-5451: Group default initialisation wired

From initialises use_explicit_test_assertions like its peers. No nits.


4313-4313: Sanity-check rule registration

I ran the grep/fd checks and didn’t spot any references to use_explicit_test_assertions. Please confirm that the rule is wired up everywhere:

  • Declared in the enums/mappings config
  • Implementation file present in the biome_analyze crate
  • Registered in the JS analyse nursery group (crates/biome_js_analyze)
  • Mapped in the CLI migrations (for ESLint’s jest/expect-expect)
  • Included in diagnostics categories (biome_diagnostics_categories)
  • Exposed in the configuration schema (packages folder)

@github-actions github-actions bot removed the A-Project Area: project label Oct 15, 2025
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30a23a2 and 360fe82.

⛔ Files ignored due to path filters (2)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
📒 Files selected for processing (1)
  • .changeset/tasty-moose-mix.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changesets, only use #### or ##### headers; other header levels are not allowed
Changesets should cover user-facing changes only; internal changes do not need changesets
Use past tense for what you did and present tense for current Biome behavior in changesets
When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)
When referencing a rule or assist in a changeset, include a link to its page on the website
Include code blocks in changesets when applicable to illustrate changes
End every sentence in a changeset with a period

Files:

  • .changeset/tasty-moose-mix.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Check JS Files
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)

@github-actions github-actions bot added the A-Project Area: project label Oct 15, 2025
ematipico and others added 2 commits October 15, 2025 10:33
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 360fe82 and 07bae43.

⛔ Files ignored due to path filters (1)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
📒 Files selected for processing (2)
  • .changeset/tasty-moose-mix.md (1 hunks)
  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changesets, only use #### or ##### headers; other header levels are not allowed
Changesets should cover user-facing changes only; internal changes do not need changesets
Use past tense for what you did and present tense for current Biome behavior in changesets
When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)
When referencing a rule or assist in a changeset, include a link to its page on the website
Include code blocks in changesets when applicable to illustrate changes
End every sentence in a changeset with a period

Files:

  • .changeset/tasty-moose-mix.md
🧠 Learnings (2)
📚 Learning: 2025-10-15T09:22:45.991Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:45.991Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import and use the `FormatNode` trait for AST nodes

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
📚 Learning: 2025-10-15T09:20:19.126Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.126Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : For options types, derive Serialize, Deserialize, Deserializable (and JsonSchema under the schema feature) and use #[serde(rename_all="camelCase", deny_unknown_fields, default)] with skip_serializing_if where appropriate

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
  • RuleDomain (904-912)
crates/biome_analyze/src/rule.rs (4)
  • sources (576-579)
  • inspired (252-257)
  • recommended (561-564)
  • domains (591-594)
crates/biome_js_syntax/src/generated/nodes.rs (1)
  • else_clause (3427-3429)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Check JS Files
  • GitHub Check: Test Node.js API
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: autofix
🔇 Additional comments (8)
.changeset/tasty-moose-mix.md (1)

1-26: Excellent work on the changeset!

The changeset follows all guidelines, incorporates all past feedback, and clearly documents the new rule with proper examples.

crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs (7)

1-7: Imports look good.

Proper use of AstNodeList trait as discussed in past feedback.


8-41: Rule declaration is well-structured.

Metadata, documentation, and examples are clear and follow conventions.


43-43: Note on assertion function names.

As discussed in past comments, this set covers the common cases. Additional assertion functions can be added in future iterations based on user feedback.


45-92: Rule implementation logic is sound.

The flow correctly identifies test calls, extracts the callback, and checks for assertions.


94-118: Assertion detection handles common patterns.

Correctly handles both direct identifier calls and chained member expressions. The explicit returns are fine for clarity.


160-223: Statement traversal logic is thorough.

Handles expression statements, conditionals, and various loop types correctly. The use of any() is appropriate here.


225-231: Clean helper function.

Simple and effective for checking block statements.

Comment on lines +141 to +149
AnyJsExpression::JsConditionalExpression(conditional_expression) => {
if let Ok(left) = conditional_expression.test() {
return expression_contains_expect(&left);
}
if let Ok(right) = conditional_expression.alternate() {
return expression_contains_expect(&right);
}
false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Missing consequent branch in conditional expression.

You're checking the test and alternate branches but omitting the consequent (the middle part of a ternary). This causes the rule to miss assertions like:

test('foo', () => {
  const x = condition ? expect(true) : false;
});

Apply this diff to check all three branches:

 AnyJsExpression::JsConditionalExpression(conditional_expression) => {
-    if let Ok(left) = conditional_expression.test() {
-        return expression_contains_expect(&left);
+    if let Ok(test) = conditional_expression.test() {
+        if expression_contains_expect(&test) {
+            return true;
+        }
     }
-    if let Ok(right) = conditional_expression.alternate() {
-        return expression_contains_expect(&right);
+    if let Ok(consequent) = conditional_expression.consequent() {
+        if expression_contains_expect(&consequent) {
+            return true;
+        }
+    }
+    if let Ok(alternate) = conditional_expression.alternate() {
+        if expression_contains_expect(&alternate) {
+            return true;
+        }
     }
     false
 }
🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery/use_explicit_test_assertions.rs
around lines 141 to 149, the conditional branch handling only checks the test
and alternate of a JsConditionalExpression and omits the consequent (middle)
branch; update the code to also attempt to get and check the consequent (e.g.,
conditional_expression.consequent()) and call expression_contains_expect on it,
returning true if any of test, consequent, or alternate contain an expect, with
the same Ok handling pattern used for the other branches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants