feat(lint): migrate first batch of Playwright rules from eslint-plugin-playwright#7775
feat(lint): migrate first batch of Playwright rules from eslint-plugin-playwright#7775voxxit wants to merge 25 commits intobiomejs:mainfrom
Conversation
🦋 Changeset detectedLatest commit: ae23713 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
WalkthroughAdds Playwright support and 11 new Playwright nursery lint rules (sourced from eslint-plugin-playwright). Introduces a new Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (17)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js (1)
2-3: Optional: Consider one trailing blank line for consistency.Most other test files in this batch have a single trailing blank line rather than two.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js (1)
2-3: Optional: Consider one trailing blank line for consistency.Most other test files in this batch have a single trailing blank line rather than two.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js (1)
1-3: Good invalid case for parameterised describe().This neatly exercises the “no params in describe callback” branch.
If not already covered elsewhere, add a sibling invalid case for an async describe callback to hit that path too.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js (1)
1-1: Covers the $eval pitfall; consider broadening.Solid invalid sample. To harden coverage, also include:
page.$$eval,frame.$eval, andframe.$$evalvariants, plus a note in docs pointing tolocator.evaluate()/evaluateAll().crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js (1)
1-2: Nice invalid fixture; show the preferred pattern too?This triggers the rule as intended. Consider adding a nearby valid counterpart demonstrating:
await expect(page.locator('#dialog')).toBeVisible();await page.locator('#dialog .button').click();crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js (1)
1-3: Good showcase of timeout-free synchronisation.These are sensible alternatives. Optional: add
await expect(page).toHaveURL('/home');to mirror the URL case with assertions.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (3)
41-47: Add the Test domain so this rule self-enables in test contextsInclude the testing domain to pick up globals like
test/describeautomatically and avoid surprising activation in non-test code.- pub NoPlaywrightWaitForNavigation { + pub NoPlaywrightWaitForNavigation { version: "next", name: "noPlaywrightWaitForNavigation", language: "js", sources: &[RuleSource::EslintPlaywright("no-wait-for-navigation").same()], + domains: &[RuleDomain::Test], recommended: false, }Also add the import:
-use biome_analyze::{ - context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, -}; +use biome_analyze::{ + context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleDomain, +};
96-104: Mark as deprecated and avoid hard-coding “page.” in the messageTagging the diagnostic as deprecated improves UX in editors. The message should be generic since the receiver could be
frameor a variable likemyPage.- markup! { - "Unexpected use of "<Emphasis>"page.waitForNavigation()"</Emphasis>"." - }, + markup! { + "Unexpected use of "<Emphasis>"waitForNavigation()"</Emphasis>"." + }, ) + .deprecated()
60-77: Broaden callee detection (optional chaining/computed members are missed)Currently only
JsStaticMemberExpressionis handled; calls likepage?.waitForNavigation()orpage["waitForNavigation"]()won’t be flagged. Not a blocker, but worth a follow-up for parity with ESLint.Would you like me to open a follow-up to add
JsComputedMemberExpressionand optional-chaining support?crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
47-53: Add the Test domain to scope this rule correctlyHelps auto-enable where Playwright tests live and keeps noise out of app code.
pub NoPlaywrightValidDescribeCallback { version: "next", name: "noPlaywrightValidDescribeCallback", language: "js", sources: &[RuleSource::EslintPlaywright("valid-describe-callback").same()], + domains: &[RuleDomain::Test], recommended: false, }And import:
-use biome_analyze::{ - context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, -}; +use biome_analyze::{ + context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleDomain, +};crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
39-45: Add the Test domain to scope activationKeeps this lint where Playwright lives.
pub NoPlaywrightNetworkidle { version: "next", name: "noPlaywrightNetworkidle", language: "js", sources: &[RuleSource::EslintPlaywright("no-networkidle").same()], + domains: &[RuleDomain::Test], recommended: false, }And update imports:
-use biome_analyze::{ - context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, -}; +use biome_analyze::{ + context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleDomain, +};crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (3)
41-47: Add the Test domainSame rationale as the other Playwright lints.
pub NoPlaywrightWaitForTimeout { version: "next", name: "noPlaywrightWaitForTimeout", language: "js", sources: &[RuleSource::EslintPlaywright("no-wait-for-timeout").same()], + domains: &[RuleDomain::Test], recommended: false, }Plus import:
-use biome_analyze::{ - context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, -}; +use biome_analyze::{ + context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleDomain, +};
96-104: Make the message receiver‑agnosticThe callee may be
frameormyPage; keep the copy generic.- markup! { - "Unexpected use of "<Emphasis>"page.waitForTimeout()"</Emphasis>"." - }, + markup! { + "Unexpected use of "<Emphasis>"waitForTimeout()"</Emphasis>"." + },
60-77: Optional: support optional chaining/computed membersAs with the navigation rule,
page?.waitForTimeout()orpage["waitForTimeout"]()won’t match. Worth a follow-up if you aim for full parity with ESLint.crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
55-65: Broaden member handling (optional chaining/computed) later.Casting only to
JsStaticMemberExpressionmissespage?.$evaland computed forms. Consider using a member‑union (e.g.AnyJsMemberExpression) and normalising the name.crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (1)
55-109: Reduce false positives by verifying the identifier binding.This will also flag Jest/Mocha’s
test.skip/describe.skip. Prefer a semantic query and confirmtest/describeoriginate from@playwright/testviactx.model().Happy to draft a
Semantic<JsCallExpression>variant that resolves the import and keeps your recursive chain logic.crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (1)
459-492: Async-context helper scopeThis helper is local-only; if other rules need it, consider
pub(crate)and moving it to a shared utils module to avoid drift with similar logic elsewhere.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (53)
crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (66)
.changeset/common-lizards-sniff.md(1 hunks)crates/biome_analyze/src/rule.rs(5 hunks)crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
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/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.jscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.jscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.jscrates/biome_analyze/src/rule.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js
**/tests/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place test files under a tests/ directory in each crate
Files:
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.jscrates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Format Rust files before committing (e.g., viajust fwhich formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_analyze/src/rule.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.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/common-lizards-sniff.md
🧬 Code graph analysis (14)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js (1)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js (1)
frame(1-1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (2)
crates/biome_analyze/src/rule.rs (2)
sources(582-585)same(247-252)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (3)
crates/biome_js_analyze/src/ast_utils.rs (1)
is_in_async_function(336-350)crates/biome_js_factory/src/generated/node_factory.rs (1)
js_await_expression(207-218)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
crates/biome_analyze/src/rule.rs (2)
sources(582-585)same(247-252)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)
🔇 Additional comments (54)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js (1)
1-3: LGTM! Correct valid test case.All three calls are properly synchronous without unnecessary
awaitkeywords. This correctly demonstrates valid usage for thenoPlaywrightUselessAwaitrule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js (1)
1-1: LGTM! Correct invalid test case.Properly demonstrates the useless
awaitpattern on a synchronouspage.locator()call that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js (1)
1-3: LGTM! Correct alternatives demonstrated.Properly shows the recommended alternatives to the deprecated
waitForNavigation()method:waitForURL(),waitForLoadState(), andgoto().crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js (1)
1-2: LGTM! Correct invalid pattern.Properly demonstrates the deprecated
waitForNavigation()usage with options that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js (1)
1-4: LGTM! Correct focused test pattern.Properly demonstrates the
test.describe.parallel.only()focused test pattern that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js (1)
1-4: LGTM! Correct focused suite pattern.Properly demonstrates the
test.describe.only()focused suite pattern that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js (1)
1-1: LGTM! Correct focused test pattern.Properly demonstrates the
test.only()focused test pattern that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js (1)
1-1: LGTM! Correct deprecated pattern.Properly demonstrates the simple deprecated
waitForNavigation()usage that the rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js (1)
1-1: LGTM! Valid test case for networkidle detection.The test correctly demonstrates the
networkidlewait strategy that the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js (1)
1-1: LGTM! Appropriate test case.Correctly demonstrates
page.pause()usage that should be flagged by the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js (1)
1-1: LGTM! Correct demonstration of unnecessary await.The test properly shows an awaited Locator method (getByRole), which the lint rule should flag as the Locator API is synchronous.
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js (1)
1-5: LGTM! Properly demonstrates missing await on test.step.The test correctly shows
test.stepcalled withoutawaiton line 2, which is the pattern the lint rule should catch.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js (1)
1-4: LGTM! Valid test case for hardcoded timeout detection.Correctly demonstrates
waitForTimeoutusage that the lint rule should flag as a hardcoded wait anti-pattern.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js (1)
1-1: LGTM! Appropriate test for skipped test detection.Correctly demonstrates
test.skipusage that should be flagged by the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js (1)
1-4: LGTM! Appropriate test case.Correctly demonstrates
page.pause()usage within a test that the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js (1)
1-1: LGTM! Valid test case for force option detection.The test correctly demonstrates the
force: trueoption that the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js (1)
1-3: Test fixture correctly demonstrates the missing await pattern.The async matcher
toBeVisible()returns a promise that should be awaited, making this a proper invalid case for the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js (1)
1-1: Correct invalid pattern for element handle detection.Properly demonstrates the discouraged
page.$$()API that the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js (1)
1-1: Good coverage of element handles on frame objects.Correctly demonstrates that the rule should catch
frame.$()in addition topage.$().crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js (1)
1-4: Appropriate test case for skipped test detection.Demonstrates the
test.describe.skip()pattern that should be flagged by the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js (1)
1-4: Valid test case without debugging utilities.Correctly demonstrates normal test flow without
page.pause(), which the rule should allow.crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js (1)
1-6: Correct valid pattern for parallel async matchers.Properly demonstrates awaiting
Promise.all()with async matchers inside, which is the recommended approach for parallel assertions.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js (1)
1-2: Demonstrates recommended locator-based evaluation.Correctly shows the preferred
locator.evaluate()andlocator.evaluateAll()patterns that the rule should allow.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js (1)
1-1: Proper invalid case for deprecated eval API.Correctly demonstrates
page.$$eval()usage that should be flagged in favour of the locator-based approach.crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js (1)
1-3: LGTM!This test case correctly demonstrates a synchronous test callback using Playwright's async matchers—exactly the pattern the
missingPlaywrightAwaitrule should catch.crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js (1)
1-3: LGTM!Proper invalid test case—
expect.poll()returns a promise and must be awaited.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js (1)
1-1: LGTM!Correctly demonstrates the discouraged
force: trueoption pattern.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js (1)
1-1: LGTM!Correct invalid case—
toBe()is synchronous, so theawaitis indeed useless.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js (1)
1-1: LGTM!Proper demonstration of the discouraged
networkidleoption.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js (1)
1-2: LGTM!Correctly demonstrates
frame.pause()usage that should be flagged as a debugging artefact.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js (1)
1-3: LGTM!Clean example of sequential Playwright actions without force options—exactly what the rule wants to see.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js (1)
1-4: LGTM! Proper use of modern Playwright locators.This correctly demonstrates the recommended pattern using locators instead of
waitForSelector.crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js (1)
1-6: LGTM! Correctly demonstrates missing await on Promise.all.This accurately captures the anti-pattern where
Promise.allis constructed but not awaited, which the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js (1)
1-7: LGTM! Valid locator-based interactions.This correctly demonstrates the recommended pattern using locators instead of element handles.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js (1)
1-1: LGTM! Correctly demonstrates deprecated element handle pattern.This accurately captures the use of
page.$()that should be flagged by the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js (1)
1-1: LGTM! Correctly demonstrates deprecated waitForSelector pattern.This accurately captures the use of
waitForSelectorthat the lint rule should flag.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js (1)
1-6: LGTM! Correctly distinguishes user-defined function from page.pause().This properly tests that a user-defined
pause()function is not flagged by the rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js (1)
1-3: LGTM! Valid page methods that should not be flagged.This correctly demonstrates legitimate page interactions that are not pause-related.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js (1)
1-1: LGTM! Correctly demonstrates hardcoded timeout anti-pattern.This accurately captures the use of
waitForTimeoutthat should be flagged by the lint rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js (1)
1-4: Valid sample looks spot on.All awaits target async Playwright APIs (click/goto/assert/poll). No useless await lurking here—ship it.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js (1)
1-9: LGTM!Valid test specimen demonstrating proper describe callback usage with synchronous callbacks.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js (1)
1-3: LGTM!Valid specimen showing proper load state usage instead of networkidle.
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js (1)
1-2: LGTM!Invalid specimen correctly demonstrates missing await on async Playwright matcher at module level.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js (1)
1-3: LGTM!Invalid specimen correctly demonstrates useless awaits on synchronous Playwright methods.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js (1)
1-3: LGTM!Invalid specimen correctly demonstrates async describe callback anti-pattern.
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js (1)
1-5: LGTM!Valid specimen demonstrating that returning async Playwright calls is acceptable (the promise is implicitly awaited by the test runner).
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js (1)
1-5: LGTM!Valid specimen demonstrating proper await usage on async Playwright APIs.
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (3)
8-46: LGTM!Rule declaration and documentation are clear and well-structured. The examples effectively demonstrate the anti-pattern.
48-91: Detection logic looks sound.The implementation correctly identifies
page.pause()andframe.pause()patterns, including nested cases likecontext.page.pause(). The case-sensitive checks for identifiers ending with "Page" or "Frame" (lines 82-86) may miss some edge cases (e.g.,PAGE.pause()), but this is acceptable for a nursery rule.
93-110: LGTM!Diagnostic message is clear, contextual, and actionable. Well done.
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
103-109: Code is correct; no handling needed for single-argument form.The verification confirms that Playwright's
valid-describe-callbackrule requiresdescribe("title", () => {})format—the callback must be the second argument. Single-argument form without a title isn't valid, so the code doesn't need to handle it.crates/biome_analyze/src/rule.rs (1)
166-168: Docs URL verified—all solidThe canonical docs URL base is correct:
https://github.com/playwright-community/eslint-plugin-playwright/blob/main/docs/rules/{rule_name}.md, and the implementation at line 385 matches precisely. Namespacing at 218-219, rule-id format at 344-345, and variant definition at 166-168 are all consistent. No issues found.crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (1)
8-51: Thedeclare_lint_rule!macro is defined and properly exported.The macro is defined in
crates/biome_analyze/src/rule.rs(line 648) and is widely used across the codebase (JS, JSON, GraphQL, and CSS analyzers all use it). Your code will compile without issues. The version is also correctly set to"next"per the nursery rule guidelines.crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs (1)
8-48: Solid, concise detection of focused testsPattern matching and diagnostics look correct; happy path. No autofix is sensible here.
Also applies to: 56-110, 112-130
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (8)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (2)
220-251: Bug:expect.poll(...).toBe(...)slips through due to detection order.Detect
expect.pollbefore gating on async matchers; otherwise sync matchers (e.g.toBe) short-circuit and poll is missed.fn get_async_expect_matcher(call_expr: &JsCallExpression) -> Option<MissingAwaitType> { let callee = call_expr.callee().ok()?; - // Must be a member expression (matcher call) - let member_expr = callee.as_js_static_member_expression()?; - - // Get the matcher name - let member = member_expr.member().ok()?; - let name = member.as_js_name()?; - let token = name.value_token().ok()?; - let matcher_name = token.text_trimmed().to_string(); - - // Check if it's an async Playwright matcher - if !ASYNC_PLAYWRIGHT_MATCHERS.contains(&matcher_name.as_str()) { - return None; - } - - // Walk up the chain to find if this is an expect() call - let object = member_expr.object().ok()?; - - // Check for expect.poll - if has_poll_in_chain(&object) { - return Some(MissingAwaitType::ExpectPoll); - } + // Must be a member expression (matcher call) + let member_expr = callee.as_js_static_member_expression()?; + + // Walk up the chain first and catch `expect.poll(...)` + let object = member_expr.object().ok()?; + if has_poll_in_chain(&object) { + return Some(MissingAwaitType::ExpectPoll); + } + + // Get the matcher name + let member = member_expr.member().ok()?; + let name = member.as_js_name()?; + let token = name.value_token().ok()?; + let matcher_name = token.text_trimmed().to_string(); + + // Check if it's an async Playwright matcher + if !ASYNC_PLAYWRIGHT_MATCHERS.contains(&matcher_name.as_str()) { + return None; + } // Check if the chain starts with expect - if has_expect_in_chain(&object) { + if has_expect_in_chain(&object) { return Some(MissingAwaitType::ExpectMatcher(matcher_name)); }
164-189: Auto-fix may serialisePromise.all([...]); prefer awaiting the outer call.When an offending call is inside a non‑awaited/returned
Promise.all, awaiting the inner call changes semantics. Wrap the enclosingPromise.all(...)instead.fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> { let call_expr = ctx.query(); @@ if !is_in_async_context(call_expr.syntax()) { return None; } - let mut mutation = ctx.root().begin(); + // If inside Promise.all([...]) that itself isn’t awaited/returned, fix the outer call. + if let Some(promise_all) = find_enclosing_promise_all(call_expr) { + if !is_call_awaited_or_returned(&promise_all) { + let mut mutation = ctx.root().begin(); + let await_expr = make::js_await_expression(make::token(T![await]), promise_all.clone().into()); + mutation.replace_element(promise_all.into_syntax().into(), await_expr.into_syntax().into()); + return Some(JsRuleAction::new( + ctx.metadata().action_category(ctx.category(), ctx.group()), + Applicability::MaybeIncorrect, + markup! { "Add await to Promise.all" }.to_owned(), + mutation, + )); + } + } + + let mut mutation = ctx.root().begin(); @@ Some(JsRuleAction::new( ctx.metadata().action_category(ctx.category(), ctx.group()), Applicability::MaybeIncorrect, markup! { "Add await" }.to_owned(), mutation, )) }crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
54-57: Report non‑function callbacks; align with ESLint.Right now non‑function callbacks like
describe('x', 42)return None (Line 142), so they slip through. ESLint flags these. Add a NotFunction reason and diagnose it. Also consider flaggingreturninside the callback for closer parity.pub enum InvalidReason { Async, HasParameters, + NotFunction, } @@ match callback_expr { AnyJsExpression::JsArrowFunctionExpression(arrow) => { @@ } AnyJsExpression::JsFunctionExpression(func) => { @@ } - _ => return None, // Not a function, but we won't report this + _ => return Some(InvalidReason::NotFunction), } @@ fn diagnostic(ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> { @@ - let (message, note) = match state { + let (message, note) = match state { InvalidReason::Async => ( @@ ), InvalidReason::HasParameters => ( @@ ), + InvalidReason::NotFunction => ( + markup! { "Second argument to "<Emphasis>"describe()"</Emphasis>" must be a function." }, + markup! { "Pass a synchronous callback function with no parameters." }, + ), };Optional parity improvement (brief sketch): after validating arrow/function, scan the body for
returnstatements and report another reason (e.g., ReturnsFromCallback). Happy to wire this if you want it in this batch.Also applies to: 108-145, 151-160
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (1)
5-5: Two fixes: (1) scope to Playwright receivers; (2) detect identifierforcekeys.
- Without receiver checks, any
.click({ force: true })is flagged (false positives).has_force_trueonly matches string-literal keys, missing the common{ force: true }identifier form.- use biome_js_syntax::{AnyJsExpression, JsCallExpression, JsObjectExpression}; + use biome_js_syntax::{AnyJsExpression, AnyJsObjectMemberName, JsCallExpression, JsObjectExpression}; @@ if !METHODS_WITH_FORCE.contains(&method_name) { return None; } + // Narrow to likely Playwright receivers (page/frame/... or locator/getBy* chain) + let object = member_expr.object().ok()?; + let object_text = match object { + AnyJsExpression::JsIdentifierExpression(id) => { + id.name().ok()?.value_token().ok()?.text_trimmed().to_string() + } + AnyJsExpression::JsStaticMemberExpression(member) => { + member.member().ok()?.as_js_name()?.value_token().ok()?.text_trimmed().to_string() + } + AnyJsExpression::JsCallExpression(call) => { + // e.g. page.locator(...).click(...) + let callee = call.callee().ok()?; + if let Some(m) = biome_js_syntax::JsStaticMemberExpression::cast_ref(callee.syntax()) { + let name = m.member().ok()?.as_js_name()?.value_token().ok()?.text_trimmed(); + if ["locator","getByRole","getByText","getByLabel","getByTitle","getByAltText","getByPlaceholder","getByTestId"].contains(&name) { + "__pw_locator__".to_string() + } else { + return None; + } + } else { + return None; + } + } + _ => return None, + }; + if !(object_text == "page" + || object_text == "frame" + || object_text.ends_with("Page") + || object_text.ends_with("Frame") + || object_text == "__pw_locator__") + { + return None; + } + @@ fn has_force_true(obj_expr: &JsObjectExpression) -> bool { for member in obj_expr.members().into_iter().flatten() { if let Some(prop) = member.as_js_property_object_member() { - // Check if property name is 'force' - if let Ok(name) = prop.name() { - if let Some(name_node) = name.as_js_literal_member_name() { - if let Ok(name_token) = name_node.value() { - if name_token.text_trimmed() == "force" { - // Check if value is true - if let Ok(value) = prop.value() { - if let Some(literal) = value.as_any_js_literal_expression() { - if let Some(bool_lit) = - literal.as_js_boolean_literal_expression() - { - if let Ok(value_token) = bool_lit.value_token() { - if value_token.text_trimmed() == "true" { - return true; - } - } - } - } - } - } - } - } - } + if let Ok(name) = prop.name() { + let is_force_key = match name { + AnyJsObjectMemberName::JsName(n) => { + n.value_token().ok().map_or(false, |t| t.text_trimmed() == "force") + } + AnyJsObjectMemberName::JsLiteralMemberName(lit) => { + lit.value().ok().map_or(false, |t| { + let txt = t.text_trimmed(); + txt == "force" || txt.trim_matches(['"', '\'']).eq("force") + }) + } + }; + if is_force_key { + if let Ok(value) = prop.value() { + if let Some(literal) = value.as_any_js_literal_expression() { + if let Some(bool_lit) = literal.as_js_boolean_literal_expression() { + if let Ok(value_token) = bool_lit.value_token() { + if value_token.text_trimmed() == "true" { + return true; + } + } + } + } + } + } + } } } false }I can add snapshot tests for identifier keys and non‑PW receivers to keep this tight.
Also applies to: 77-87, 88-102, 124-154
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
58-68: Add a page/frame receiver guard to avoid false positives.Right now any
waitForLoadState/navigation-like call is flagged regardless of receiver. This will trip on non‑Playwright APIs. Mirror the receiver guard used in sibling rules (page/frame or names ending with Page/Frame) before method checks.Apply this diff after computing
method_name:let method_name = member_text.text_trimmed(); + // Ensure the receiver is page/frame-like to avoid false positives + let object = member_expr.object().ok()?; + let object_text = match object { + AnyJsExpression::JsIdentifierExpression(id) => { + id.name().ok()?.value_token().ok()?.text_trimmed().to_string() + } + AnyJsExpression::JsStaticMemberExpression(member) => { + member.member().ok()?.as_js_name()?.value_token().ok()?.text_trimmed().to_string() + } + _ => return None, + }; + let is_page_like = object_text == "page" + || object_text == "frame" + || object_text.ends_with("Page") + || object_text.ends_with("Frame"); + if !is_page_like { + return None; + }Also applies to: 69-87, 89-103
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
105-107: Make the diagnostic object‑agnostic (don’t hard‑codepage.).This rule also triggers on frames/custom page vars; message should not pin the receiver.
- "Unexpected use of "<Emphasis>"page."{{state}}"()"</Emphasis>"." + "Unexpected use of "<Emphasis>"{{state}}()"</Emphasis>"."crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
119-127: Note text assumespage.; generalise it.Apply the earlier suggestion so guidance fits frame/variables too.
- "Element handles like "<Emphasis>"page."{{state}}"()"</Emphasis>" are discouraged." + "Element handles like "<Emphasis>"{{state}}()"</Emphasis>" are discouraged."- "Use "<Emphasis>"page.locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." + "Use "<Emphasis>"locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead."crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
108-116: Message assumespage.; make it generic.Drop the receiver name to avoid misleading users when it’s
frameor a variable.- "Unexpected use of "<Emphasis>"page.waitForSelector()"</Emphasis>"." + "Unexpected use of "<Emphasis>"waitForSelector()"</Emphasis>"."
🧹 Nitpick comments (15)
crates/biome_rule_options/src/no_playwright_force_option.rs (1)
1-6: Solid; add a short rustdoc for consistency.Pattern matches other options. Add a brief comment to aid generated docs and future readers.
+/// Options for the `noPlaywrightForceOption` rule. +/// Empty placeholder, kept for compatibility with future configuration. +/// Mirrors `eslint-plugin-playwright/no-force-option`. #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]Based on learnings.
crates/biome_rule_options/src/no_playwright_eval.rs (1)
1-6: All good; add rustdoc for discoverability.Consistent derives/serde. Please add a brief doc comment so it shows up in generated docs.
+/// Options for the `noPlaywrightEval` rule. +/// Empty; reserved for future flags and schema generation. +/// Mirrors `eslint-plugin-playwright/no-eval`. #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]Based on learnings.
crates/biome_rule_options/src/no_playwright_wait_for_selector.rs (1)
1-6: Nice one; tiny follow-up: add rustdoc.The struct is correct; add a short doc describing the rule and why the options are empty.
+/// Options for the `noPlaywrightWaitForSelector` rule. +/// Empty placeholder kept for forwards compatibility and schema generation. +/// Mirrors `eslint-plugin-playwright/no-wait-for-selector`. #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]Based on learnings.
crates/biome_rule_options/src/missing_playwright_await.rs (1)
3-6: Add rustdoc for the options type.Tiny nit: document the options struct to meet the crate’s “document rules/options” guideline.
#[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields, default)] -pub struct MissingPlaywrightAwaitOptions {} +/// Options for the `missingPlaywrightAwait` rule. Currently no configuration. +pub struct MissingPlaywrightAwaitOptions {}Based on learnings.
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (1)
111-120: Message mentions onlypage.pause()but rule also matchesframe.pause().Widen the phrasing to avoid confusion (or compute the receiver and format dynamically).
- markup! { - "Unexpected use of "<Emphasis>"page.pause()"</Emphasis>"." - }, + markup! { + "Unexpected use of "<Emphasis>"pause()"</Emphasis>" on Playwright Page/Frame." + }, @@ - <Emphasis>"page.pause()"</Emphasis>" is a debugging utility and should not be committed to version control." + <Emphasis>"pause()"</Emphasis>" is a debugging utility and should not be committed to version control."crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
128-151: Handle quoted property keys forwaitUntil.
name_token.text_trimmed() == "waitUntil"misses{ 'waitUntil': 'networkidle' }. Trim quotes to support both forms.- if let Ok(name_token) = name_node.value() { - if name_token.text_trimmed() == "waitUntil" { + if let Ok(name_token) = name_node.value() { + let key = name_token.text_trimmed().trim_matches(&['\'', '"'][..]); + if key == "waitUntil" {crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
66-94: Consider extracting a shared “is page/frame‑like” helper.This receiver check logic is duplicated across Playwright rules (eval/element-handle/etc.). Extract to a small internal helper to keep behaviour consistent.
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (1)
73-102: Deduplicate chain-detection with the focused-test rule.
is_test_or_describe_objectis effectively the same in focused/skip rules. Extract to a shared helper to avoid divergence.crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs (1)
74-103: Share the test/describe chain matcher with sibling rules.Same helper exists in the skipped-test rule; centralise it for consistency and easier maintenance.
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (2)
107-115: Make the primary message receiver‑agnostic.Don’t assume the callee is named page; keep it generic.
- "Unexpected use of "<Emphasis>"page.waitForTimeout()"</Emphasis>"." + "Unexpected use of "<Emphasis>"waitForTimeout()"</Emphasis>"."
60-88: DRY the page/frame detection and consider optional chaining/computed members.The object extraction repeats across rules and ignores patterns like
page?.waitForTimeout(...)orpage['waitForTimeout'](...). Extract a shared helper (e.g., nursery::playwright_utils::is_page_or_frame) and broaden callee handling to cover optional/computed members. Keeps rules consistent and reduces false negatives.Add tests for:
await page?.waitForTimeout(1000)await ctx.page.waitForTimeout(1000)await (page)['waitForTimeout'](1000)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
77-96: Consolidate page/frame detection into a shared utility.Same object‑resolution logic appears in multiple rules; extract once (e.g., playwright_utils::is_page_or_frame) and reuse. Easier to extend (optional chaining, aliases) in one place.
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
70-88: Reuse a sharedis_page_or_framehelper and support optional/computed callee shapes.Mirror the approach across Playwright rules to avoid drift and catch
page?.waitForSelector()/page['waitForSelector']().Please add tests for the optional/computed cases and
context.page.waitForSelector(...).crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (2)
63-79: IncludefilterinLOCATOR_METHODS.
locator.filter()returns a Locator; awaiting it is equally useless.const LOCATOR_METHODS: &[&str] = &[ "and", + "filter", "first", "getByAltText", "getByLabel",
210-240: Promoteis_page_or_frameto a shared module and reuse in other rules.This helper exists here but similar logic is duplicated elsewhere. Extract to a small
playwright_utilsmodule in nursery and import from rules to keep behaviour aligned.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_js_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (27)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)crates/biome_rule_options/src/missing_playwright_await.rs(1 hunks)crates/biome_rule_options/src/no_playwright_element_handle.rs(1 hunks)crates/biome_rule_options/src/no_playwright_eval.rs(1 hunks)crates/biome_rule_options/src/no_playwright_focused_test.rs(1 hunks)crates/biome_rule_options/src/no_playwright_force_option.rs(1 hunks)crates/biome_rule_options/src/no_playwright_networkidle.rs(1 hunks)crates/biome_rule_options/src/no_playwright_page_pause.rs(1 hunks)crates/biome_rule_options/src/no_playwright_skipped_test.rs(1 hunks)crates/biome_rule_options/src/no_playwright_useless_await.rs(1 hunks)crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs(1 hunks)crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs(1 hunks)crates/biome_rule_options/src/no_playwright_wait_for_selector.rs(1 hunks)crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_rule_options/src/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_rule_options/src/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_rule_options/src/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_rule_options/src/no_playwright_element_handle.rscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_rule_options/src/no_playwright_wait_for_timeout.rscrates/biome_rule_options/src/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_rule_options/src/no_playwright_force_option.rscrates/biome_rule_options/src/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_rule_options/src/missing_playwright_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_rule_options/src/no_playwright_wait_for_selector.rscrates/biome_rule_options/src/no_playwright_wait_for_navigation.rscrates/biome_rule_options/src/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Format Rust files before committing (e.g., viajust fwhich formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_rule_options/src/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_rule_options/src/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_rule_options/src/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_rule_options/src/no_playwright_element_handle.rscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_rule_options/src/no_playwright_wait_for_timeout.rscrates/biome_rule_options/src/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_rule_options/src/no_playwright_force_option.rscrates/biome_rule_options/src/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_rule_options/src/missing_playwright_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_rule_options/src/no_playwright_wait_for_selector.rscrates/biome_rule_options/src/no_playwright_wait_for_navigation.rscrates/biome_rule_options/src/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
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/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
🧠 Learnings (3)
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
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_rule_options/src/no_playwright_skipped_test.rscrates/biome_rule_options/src/no_playwright_eval.rscrates/biome_rule_options/src/no_playwright_useless_await.rscrates/biome_rule_options/src/no_playwright_element_handle.rscrates/biome_rule_options/src/no_playwright_focused_test.rscrates/biome_rule_options/src/no_playwright_wait_for_timeout.rscrates/biome_rule_options/src/no_playwright_page_pause.rscrates/biome_rule_options/src/no_playwright_force_option.rscrates/biome_rule_options/src/no_playwright_networkidle.rscrates/biome_rule_options/src/missing_playwright_await.rscrates/biome_rule_options/src/no_playwright_wait_for_selector.rscrates/biome_rule_options/src/no_playwright_wait_for_navigation.rscrates/biome_rule_options/src/no_playwright_valid_describe_callback.rs
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/**/lib/src/{lint,assist}/**/*.rs : Use declare_lint_rule! with version set to "next" for every rule definition
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/**/tests/quick_test.rs : Use the quick test at biome_js_analyze/tests/quick_test.rs by un-ignoring and adjusting SOURCE and RuleFilter for ad-hoc checks
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
🧬 Code graph analysis (26)
crates/biome_rule_options/src/no_playwright_skipped_test.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightSkippedTestOptions(8469-8469)
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (3)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (1)
run(73-102)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_playwright_eval.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightEvalOptions(8464-8464)
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (3)
crates/biome_analyze/src/rule.rs (2)
sources(582-585)same(247-252)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
run(62-107)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_playwright_useless_await.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightUselessAwaitOptions(8470-8470)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (3)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run(57-99)diagnostic(101-118)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_playwright_element_handle.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightElementHandleOptions(8463-8463)
crates/biome_rule_options/src/no_playwright_focused_test.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightFocusedTestOptions(8465-8465)
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightWaitForTimeoutOptions(8474-8474)
crates/biome_rule_options/src/no_playwright_page_pause.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightPagePauseOptions(8468-8468)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (5)
crates/biome_analyze/src/rule.rs (2)
sources(582-585)same(247-252)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(62-107)diagnostic(109-129)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run(54-103)diagnostic(105-122)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
run(56-98)diagnostic(100-117)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (3)
crates/biome_analyze/src/rule.rs (2)
sources(582-585)same(247-252)crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs (3)
run(56-110)is_test_or_describe_object(74-103)diagnostic(112-129)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_playwright_force_option.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightForceOptionOptions(8466-8466)
crates/biome_rule_options/src/no_playwright_networkidle.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightNetworkidleOptions(8467-8467)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (3)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (2)
run(51-95)diagnostic(97-116)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/missing_playwright_await.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
MissingPlaywrightAwaitOptions(8430-8430)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (4)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
FixKind(8166-8166)Applicability(9963-9963)crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (2)
run(110-129)action(164-189)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
run(62-107)
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs (3)
crates/biome_analyze/src/rule.rs (1)
same(247-252)crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (3)
run(55-109)is_test_or_describe_object(73-102)diagnostic(111-128)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (4)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(62-107)diagnostic(109-129)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
run(56-98)diagnostic(100-117)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_rule_options/src/no_playwright_wait_for_selector.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightWaitForSelectorOptions(8473-8473)
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightWaitForNavigationOptions(8472-8472)
crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightValidDescribeCallbackOptions(8471-8471)
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (3)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(62-107)diagnostic(109-129)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (4)
crates/biome_analyze/src/rule.rs (3)
sources(582-585)same(247-252)recommended(567-570)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
run(62-107)crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
run(54-106)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (2)
FixKind(8166-8166)Applicability(9963-9963)crates/biome_js_analyze/src/ast_utils.rs (1)
is_in_async_function(336-350)crates/biome_js_factory/src/generated/node_factory.rs (1)
js_await_expression(207-218)
🔇 Additional comments (10)
crates/biome_rule_options/src/no_playwright_focused_test.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_useless_await.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_page_pause.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_skipped_test.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_networkidle.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/no_playwright_element_handle.rs (1)
1-6: LGTM!Correctly follows the options type pattern with appropriate derives and serde attributes.
crates/biome_rule_options/src/lib.rs (1)
5-5: LGTM: options modules exposed consistently.Entries are in the expected alphabetical region; no concerns.
Also applies to: 144-155
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (1)
62-69: Parity confirmed—no changes needed.ESLint's plugin targets the
.skipannotation only, so your implementation is already aligned..fixmefalls outside scope for that rule, so the current check is correct.
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
Show resolved
Hide resolved
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs
Outdated
Show resolved
Hide resolved
CodSpeed Performance ReportMerging #7775 will not alter performanceComparing Summary
Footnotes
|
dyc3
left a comment
There was a problem hiding this comment.
Wow! Huge! Thanks for the hard work. Great job sticking to the rule pillars for the diagnostics for the most part.
I'd like to encourage you to make smaller PRs in the future though, as github's UX for reviewing huge PRs is terrible. 😅
I think it would make sense to add a playwright domain for all these rules.
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (9)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (1)
107-108: Use generic "waitForNavigation()" in diagnostic message.The diagnostic hard-codes "page.waitForNavigation()" but the rule matches
frame.waitForNavigation()and other receivers (lines 90-93). The message should use the generic form to avoid misleading output.crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
55-105: Missing receiver guard causes potential false positives.The rule matches any call to
goto,reload,waitForLoadState, etc., regardless of the receiver. This risks flagging unrelated APIs. Add a page/frame guard (as suggested in past reviews) for both thewaitForLoadStatebranch (lines 71-87) and navigation methods branch (lines 90-102).crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (2)
74-102: Missing receiver guard risks false positives.The rule matches any call to
click,fill, etc., regardless of receiver. This could flag non-Playwright code. Add a page/frame/locator guard as suggested in past reviews.
124-147: Critical:has_force_truemisses identifier keys.The function only checks
as_js_literal_member_name(), so it won't detect the common{ force: true }form with an identifier key. This severely limits the rule's effectiveness in real code.crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (1)
72-91: PreferTokenTextoverto_string()to avoid allocations.The
.to_string()calls at lines 78-79 and 88-89 allocate unnecessarily. UseTokenTextfor comparisons as suggested in past reviews.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
108-109: Use generic "waitForSelector()" in diagnostic message.The diagnostic hard-codes "page.waitForSelector()" but the rule matches
frame.waitForSelector()and other receivers (lines 91-94). Use the generic form to avoid misleading output.crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (1)
243-306: False negatives for expect(...).resolves/rejects/poll chainsWalking parent nodes misses async modifiers embedded in the callee/object chain (e.g. expect.soft.resolves.toBe). Walk the callee/object chain instead.
- // Check if this is an expect().matcher() pattern - // The call should be a member expression where the object is expect() + // Check if this is an expect().matcher() pattern let member_expr = match callee { Some(AnyJsExpression::JsStaticMemberExpression(member)) => member, _ => return false, }; @@ - // Check if the object is an expect() call - let object = member_expr.object().ok(); - if let Some(AnyJsExpression::JsCallExpression(expect_call)) = object { - let expect_callee = expect_call.callee().ok(); - match expect_callee { - Some(AnyJsExpression::JsIdentifierExpression(id)) => { - if let Ok(name) = id.name() - && let Ok(token) = name.value_token() - && token.text_trimmed() == "expect" - { - // Make sure there's no "poll", "resolves", or "rejects" in the chain - return !has_async_modifier(&expect_call, call_expr); - } - } - Some(AnyJsExpression::JsStaticMemberExpression(expect_member)) => { - // Check for expect.soft, but not expect.poll - if let Ok(member) = expect_member.member() - && let Some(name) = member.as_js_name() - && let Ok(token) = name.value_token() - { - let member_text = token.text_trimmed(); - // soft is OK, poll makes it async - if member_text == "soft" { - return !has_async_modifier(&expect_call, call_expr); - } - } - } - _ => {} - } - } + // Ensure base is expect(...) and there is no async modifier in the chain + if let Ok(obj) = member_expr.object() { + if is_expect_call_chain(&obj) && !has_async_modifier_in_chain(&obj) { + return true; + } + } @@ -fn has_async_modifier(expect_call: &JsCallExpression, final_call: &JsCallExpression) -> bool { - // Walk the chain from expect_call to final_call looking for "poll", "resolves", "rejects" - let mut current = final_call.syntax().clone(); - let expect_syntax = expect_call.syntax(); - - while current != *expect_syntax { - if let Some(member) = JsStaticMemberExpression::cast_ref(¤t) { - if let Ok(member_name) = member.member() - && let Some(name) = member_name.as_js_name() - && let Ok(token) = name.value_token() - { - let text = token.text_trimmed(); - if text == "poll" || text == "resolves" || text == "rejects" { - return true; - } - } - if let Some(parent) = member.syntax().parent() { - current = parent; - } else { - break; - } - } else if let Some(call) = JsCallExpression::cast_ref(¤t) { - if let Some(parent) = call.syntax().parent() { - current = parent; - } else { - break; - } - } else { - break; - } - } - - false -} +fn has_async_modifier_in_chain(expr: &AnyJsExpression) -> bool { + match expr { + AnyJsExpression::JsStaticMemberExpression(member) => { + if let Ok(m) = member.member() + && let Some(n) = m.as_js_name() + && let Ok(t) = n.value_token() + { + let text = t.text_trimmed(); + if text == "poll" || text == "resolves" || text == "rejects" { + return true; + } + } + if let Ok(obj) = member.object() { + return has_async_modifier_in_chain(&obj); + } + false + } + AnyJsExpression::JsCallExpression(call) => { + if let Ok(callee) = call.callee() { + return has_async_modifier_in_chain(&callee); + } + false + } + _ => false, + } +} + +fn is_expect_call_chain(expr: &AnyJsExpression) -> bool { + match expr { + AnyJsExpression::JsCallExpression(call) => { + if let Ok(callee) = call.callee() { + return matches!(callee, + AnyJsExpression::JsIdentifierExpression(id) + if id.name().ok().and_then(|n| n.value_token().ok()).map(|t| t.text_trimmed()=="expect").unwrap_or(false) + ) || is_expect_call_chain(&callee); + } + false + } + AnyJsExpression::JsStaticMemberExpression(member) => { + member.object().ok().map(|o| is_expect_call_chain(&o)).unwrap_or(false) + } + _ => false, + } +}Also add valid tests for:
- await expect(promise).resolves.toBe(1)
- await expect(promise).rejects.toThrow()
- await expect(locator).poll().toHaveText('x')
Also applies to: 308-341
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (2)
243-274: Bug: expect.poll(...).toBe(...) is gated behind async matcher checkYou return early when matcher isn’t in ASYNC_PLAYWRIGHT_MATCHERS, so poll with sync matchers is missed. Detect poll first, then gate on matchers.
- // Get the matcher name + // Get the matcher name let member = member_expr.member().ok()?; @@ - // Check if it's an async Playwright matcher - if !ASYNC_PLAYWRIGHT_MATCHERS.contains(&matcher_name.text()) { - return None; - } - - // Walk up the chain to find if this is an expect() call - let object = member_expr.object().ok()?; - - // Check for expect.poll - if has_poll_in_chain(&object) { - return Some(MissingAwaitType::ExpectPoll); - } + // Walk up the chain first: `expect.poll(...)` is always async regardless of matcher + let object = member_expr.object().ok()?; + if has_poll_in_chain(&object) { + return Some(MissingAwaitType::ExpectPoll); + } + + // Now gate by Playwright async matchers + if !ASYNC_PLAYWRIGHT_MATCHERS.contains(&matcher_name.text()) { + return None; + }
179-205: Auto-fix inside Promise.all currently serialises; prefer awaiting the outer PromiseWhen the call lives inside Promise.all([...]) that itself isn’t awaited/returned, adding await to each inner call changes semantics. Wrap the enclosing Promise.* instead.
fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> { let call_expr = ctx.query(); // Check if we're in an async context if !is_in_async_context(call_expr.syntax()) { return None; } + + // If inside Promise.*([...]) that isn’t awaited/returned, fix the outer call. + if let Some(promise_call) = find_enclosing_promise_all(call_expr) { + if !is_call_awaited_or_returned(&promise_call) { + let mut mutation = ctx.root().begin(); + let await_expr = make::js_await_expression(make::token(T![await]), promise_call.clone().into()); + mutation.replace_element(promise_call.into_syntax().into(), await_expr.into_syntax().into()); + return Some(JsRuleAction::new( + ctx.metadata().action_category(ctx.category(), ctx.group()), + Applicability::MaybeIncorrect, + markup! { "Add await to Promise.*" }.to_owned(), + mutation, + )); + } + } let mut mutation = ctx.root().begin(); @@ } @@ -fn find_enclosing_promise_all(call_expr: &JsCallExpression) -> Option<JsCallExpression> { +fn find_enclosing_promise_all(call_expr: &JsCallExpression) -> Option<JsCallExpression> { @@ - && is_promise_all(&call) + && is_promise_combinator(&call) @@ } -fn is_promise_all(call: &JsCallExpression) -> bool { - is_member_call_pattern(call, "Promise", "all") +fn is_promise_combinator(call: &JsCallExpression) -> bool { + // Promise.all / allSettled / any / race + if let Ok(callee) = call.callee() { + if let Some(member) = callee.as_js_static_member_expression() { + if let Ok(member_name) = member.member() + && let Some(name) = member_name.as_js_name() + && let Ok(tok) = name.value_token() + { + let m = tok.text_trimmed(); + if (m == "all" || m == "allSettled" || m == "any" || m == "race") + && let Ok(object) = member.object() + && let AnyJsExpression::JsIdentifierExpression(id) = object + && id.name().ok().and_then(|n| n.value_token().ok()).map(|t| t.text_trimmed()=="Promise").unwrap_or(false) + { + return true; + } + } + } + } + false }Please add invalid/valid specs for allSettled/any/race mirroring the existing Promise.all cases. Based on learnings.
Also applies to: 385-401, 403-439
🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (1)
70-88: PreferTokenTextoverto_string()to avoid allocations.The
.to_string()calls at lines 78 and 86 allocate unnecessarily. Since you're only comparing the text (lines 90-94), useTokenTextinstead.crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (1)
60-66: Also match computed members (test['skip'], describe['skip'])The rule only considers JsStaticMemberExpression; computed property access won’t be flagged. Add JsComputedMemberExpression handling for parity with ESLint.
- let member_expr = JsStaticMemberExpression::cast_ref(callee.syntax())?; + let member_expr = JsStaticMemberExpression::cast_ref(callee.syntax()); + let computed_expr = biome_js_syntax::JsComputedMemberExpression::cast_ref(callee.syntax()); + let (member_name, object) = if let Some(m) = member_expr { + (m.member().ok()?, m.object().ok()?) + } else if let Some(m) = computed_expr { + let prop = m.member().ok()?; + let name = prop.as_any_js_expression()?.as_js_identifier_expression()? + .name().ok()?.value_token().ok()?; + (biome_js_syntax::AnyJsName::JsName(name.token().clone().into()), m.object().ok()?) + } else { + return None; + }; - let member_name = member_expr.member().ok()?; - let member_text = member_name.as_js_name()?.value_token().ok()?; + let member_text = member_name.as_js_name()?.value_token().ok()?; - let object = member_expr.object().ok()?; + let object = object;Also applies to: 85-99
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (1)
441-474: Minor: consider de-duplicating is_in_async_contextYou already import ast_utils::is_in_async_function; this helper appears in multiple rules. Factor it into a shared util to keep one source of truth.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_js_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**
📒 Files selected for processing (15)
crates/biome_analyze/src/rule.rs(9 hunks)crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs(1 hunks)crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
- crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
- crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
🧰 Additional context used
📓 Path-based instructions (3)
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/suspicious/no_focused_tests.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_analyze/src/rule.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rscrates/biome_rule_options/src/lib.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Format Rust files before committing (e.g., viajust fwhich formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_analyze/src/rule.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rscrates/biome_rule_options/src/lib.rs
🧠 Learnings (2)
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/**/lib/src/{lint,assist}/**/*.rs : Use declare_lint_rule! with version set to "next" for every rule definition
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rscrates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
📚 Learning: 2025-10-15T09:20:19.139Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:20:19.139Z
Learning: Applies to crates/biome_analyze/**/tests/quick_test.rs : Use the quick test at biome_js_analyze/tests/quick_test.rs by un-ignoring and adjusting SOURCE and RuleFilter for ad-hoc checks
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
🧬 Code graph analysis (11)
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs (1)
crates/biome_analyze/src/rule.rs (1)
same(247-252)
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (5)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-912)crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(63-108)diagnostic(110-130)crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (2)
run(74-102)diagnostic(104-121)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (5)
crates/biome_analyze/src/rule.rs (9)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
run(63-108)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
run(58-100)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (1)
run(57-99)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (2)
crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (3)
crates/biome_analyze/src/rule.rs (7)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(63-108)diagnostic(110-130)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (2)
crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(63-108)diagnostic(110-130)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (3)
FixKind(8166-8166)RuleDomain(904-912)Applicability(9963-9963)crates/biome_analyze/src/rule.rs (6)
run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)action(1128-1134)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-912)crates/biome_analyze/src/rule.rs (7)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run(63-108)diagnostic(110-130)
crates/biome_analyze/src/rule.rs (1)
crates/biome_service/src/documentation/mod.rs (2)
fmt(125-205)fmt(211-278)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (4)
crates/biome_js_analyze/src/ast_utils.rs (1)
is_in_async_function(336-350)crates/biome_analyze/src/rule.rs (3)
new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_factory/src/generated/node_factory.rs (1)
js_await_expression(207-218)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
⏰ 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). (1)
- GitHub Check: triage
🔇 Additional comments (10)
crates/biome_rule_options/src/lib.rs (1)
5-5: LGTM! Verify codegen was executed.The new Playwright rule option modules are correctly placed in alphabetical order and follow the existing naming convention. Since this is a generated file, ensure that the codegen commands (
cargo codegen-configuration,cargo codegen-bindings,cargo codegen-schema) have been executed successfully.Based on coding guidelines.
Also applies to: 144-154
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs (1)
50-54: LGTM! Playwright source added correctly.The addition of
EslintPlaywright("no-focused-test").same()properly extends the rule to cover Playwright test frameworks. Note that the singular "no-focused-test" naming matches the upstream ESLint plugin.crates/biome_analyze/src/rule.rs (4)
166-167: LGTM! EslintPlaywright variant added correctly.The new
RuleSourcevariant follows the established pattern for ESLint plugins.
218-218: LGTM! Display and as_rule_name implementations correct.Both additions properly handle the new
EslintPlaywrightvariant.Also applies to: 274-274
344-344: Namespace and URL format look correct.The
playwright/{rule_name}namespace and GitHub docs URL follow the established patterns for ESLint plugins.Also applies to: 385-385
456-457: LGTM! RuleDomain::Playwright additions are correct.The new domain variant is properly integrated:
- Display impl uses lowercase "playwright"
- Manifest dependencies correctly reference
@playwright/test- Globals
["test", "expect"]match Playwright's standard globalsAlso applies to: 476-476, 513-513, 542-542
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs (1)
8-47: Nice rule meta and docsVersion "next", source mapping to ESLint, examples look good. Ship it.
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (1)
54-63: Good rule shape and safe fixMetadata, diagnostics, and “remove await” mutation look sound. Nice.
Also applies to: 173-209
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (2)
56-64: Rule meta and matcher list look solidGood use of FixKind::Unsafe and clear diagnostics. Nicely done.
Also applies to: 67-99
100-105: State plumbing and signal filtering read cleanlyEnum variants are precise; run() short-circuits sensibly. 👍
Also applies to: 112-131
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
Outdated
Show resolved
Hide resolved
Add comprehensive Playwright testing framework support with 13 new lint rules
converted from eslint-plugin-playwright. All rules are placed in the nursery
category with proper namespacing (noPlaywright* prefix).
Rules implemented:
- missingPlaywrightAwait: Enforce async Playwright APIs are awaited/returned
- noPlaywrightUselessAwait: Disallow unnecessary await on sync methods
- noPlaywrightPagePause: Disallow page.pause() debugging calls
- noPlaywrightFocusedTest: Disallow .only test annotations
- noPlaywrightSkippedTest: Disallow .skip test annotations
- noPlaywrightWaitForTimeout: Disallow hardcoded timeouts
- noPlaywrightWaitForNavigation: Disallow deprecated waitForNavigation
- noPlaywrightWaitForSelector: Disallow waitForSelector in favor of locators
- noPlaywrightElementHandle: Disallow element handles (page.$, page.26692)
- noPlaywrightEval: Disallow page.$eval and page.$$eval
- noPlaywrightForceOption: Disallow { force: true } option
- noPlaywrightNetworkidle: Disallow networkidle option
- noPlaywrightValidDescribeCallback: Enforce valid describe callbacks
Infrastructure changes:
- Added EslintPlaywright variant to RuleSource enum
- Registered all rules in nursery lint group
- Added diagnostic categories for all rules
- Comprehensive test coverage with 1813 passing tests
Auto-fixes available for:
- missingPlaywrightAwait (unsafe)
- noPlaywrightUselessAwait (safe)
Source: https://github.com/playwright-community/eslint-plugin-playwright
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ait.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…dd tests Refactor the missingPlaywrightAwait lint rule to improve its logic for checking if call expressions are properly awaited or returned. The function is_properly_handled now verifies both direct awaits and Promise.all usage. Additionally, introduce a new test case to validate the behavior of the rule when encountering Promise.all without awaits, ensuring accurate diagnostics are provided. New test file: - promise-all-not-awaited.js - promise-all-not-awaited.js.snap This update enhances the linting capabilities for Playwright async APIs.
…for describe calls
Add functionality to the missingPlaywrightAwait lint rule to enforce that "describe" calls are awaited or returned. Introduce a new type for handling "describe" in the MissingAwaitType enum.
Update test cases to reflect changes in the rule, ensuring that both valid and invalid usages of "describe" are properly tested. Adjust existing test cases to use `page.locator('body')` for consistency.
New test cases include:
- invalid/expect-async-matcher.js
- valid/awaited.js
- valid/returned.js
This update improves linting accuracy for Playwright async APIs.
…pdate tests Enhance the missingPlaywrightAwait lint rule to ensure that arrow function calls are only considered awaited if they match the exact body of the function. This change improves the accuracy of the linting process for Playwright async APIs. Additionally, update test cases to reflect the new logic, including modifications to the valid alternatives for waitForLoadState in the Playwright navigation tests. This update aims to provide more precise diagnostics and improve the overall linting experience.
…ssingPlaywrightAwait rule Eliminate the check for "describe"-like calls in the missingPlaywrightAwait lint rule to streamline its logic. This change focuses the rule on enforcing that Playwright async APIs are awaited or returned without the additional complexity of handling describe calls. No changes to test cases were necessary as a result of this refactor, maintaining the existing linting functionality for Playwright async APIs.
…gPlaywrightAwait rule Eliminate the handling of "describe" calls in the missingPlaywrightAwait lint rule to simplify its logic. This change focuses the rule on ensuring that Playwright async APIs are awaited or returned, enhancing clarity and maintainability. No modifications to test cases were required, preserving existing linting functionality.
…ses for missingPlaywrightAwait rule Delete obsolete test cases related to "describe" calls in the missingPlaywrightAwait rule. This cleanup aligns with recent refactors that focus on ensuring Playwright async APIs are awaited or returned, enhancing the clarity and maintainability of the test suite. No functional changes to the linting logic were made.
…eck async context Update the missingPlaywrightAwait lint rule to include a check for async contexts, ensuring that Playwright async APIs are only considered awaited when within an async function or module. This change improves the accuracy of the linting process. Additionally, remove obsolete test snapshots related to the noPlaywrightForceOption rule, streamlining the test suite.
…test rule This commit introduces a new `Playwright` domain to the linting rules, allowing for better categorization of Playwright-specific rules. The `NoPlaywrightFocusedTest` rule has been removed, as its functionality is covered under the `suspicious` rules. Additionally, the Playwright rules have been updated to include the `Playwright` domain. Ran `just l` and fixed any remaining issues.
This commit introduces 13 new lint rules for Playwright, enhancing the linting capabilities for Playwright-specific code. The new rules include checks for awaiting async APIs, usage of element handles, and deprecated methods. Additionally, the existing `noFocusedTests` rule has been updated to detect Playwright's `test.only()` pattern. The following rules have been added: - `missingPlaywrightAwait` - `noPlaywrightElementHandle` - `noPlaywrightEval` - `noPlaywrightForceOption` - `noPlaywrightNetworkidle` - `noPlaywrightPagePause` - `noPlaywrightSkippedTest` - `noPlaywrightUselessAwait` - `noPlaywrightValidDescribeCallback` - `noPlaywrightWaitForNavigation` - `noPlaywrightWaitForSelector` - `noPlaywrightWaitForTimeout` These additions aim to improve code quality and adherence to best practices in Playwright usage.
…rule This commit refactors the `missingPlaywrightAwait` lint rule to streamline the logic for checking if a Promise combinator is awaited. The conditional check has been simplified using a single `if let` statement, enhancing code readability while maintaining the same functionality. This change aims to improve the maintainability of the lint rule.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (1)
270-304: Critical: async modifier detection is broken (see earlier reviews).The previous reviewers correctly identified that
has_async_modifierwalks the syntax tree upwards (parent nodes) but async modifiers like.resolves,.rejects, and.poll()live in the object/callee chain going down from the final call. This means patterns likeawait expect(promise).resolves.toBe(1)will incorrectly trigger the rule.The suggested fix in earlier reviews—recursively walking the object/callee chain—is architecturally correct. Please apply the refactor as outlined in the previous review comments.
🧹 Nitpick comments (4)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (1)
57-94: Consider extracting shared receiver-checking logic.The pattern here (lines 57–94) is almost identical to
no_playwright_wait_for_selector.rsandno_playwright_page_pause.rs. All three rules extract the same receiver validation (page/frame/ending-with-Page-or-Frame) and method-name check. A helper likeis_playwright_page_or_frame_method_call(call_expr, method_name) -> Option<TokenText>would eliminate ~40 duplicated lines across the three rules.crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
126-136: Inconsistent emptiness check.Line 130 uses
p.items().len() > 0whilst line 146 uses the more idiomatic!params.items().is_empty(). Please standardise on!is_empty().Apply this diff:
let has_params = match params { biome_js_syntax::AnyJsArrowFunctionParameters::AnyJsBinding(_) => true, biome_js_syntax::AnyJsArrowFunctionParameters::JsParameters(p) => { - p.items().len() > 0 + !p.items().is_empty() } };crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (1)
55-99: Logic is sound; TokenText usage follows past feedback.The implementation correctly detects
page.pause(),frame.pause(), and related patterns. Good to seeTokenTextbeing used throughout, which avoids unnecessary heap allocations as suggested in the previous review.However, lines 72-87 (object extraction logic) are duplicated across
no_playwright_wait_for_navigation,no_playwright_wait_for_selector, andno_playwright_wait_for_timeout. Consider extracting this into a shared helper function to improve maintainability.For example, a helper like:
// In a shared module (e.g., utils.rs) pub(crate) fn extract_playwright_receiver_text( member_expr: &JsStaticMemberExpression, ) -> Option<TokenText> { let object = member_expr.object().ok()?; match object { biome_js_syntax::AnyJsExpression::JsIdentifierExpression(id) => { Some(id.name().ok()?.value_token().ok()?.token_text_trimmed()) } biome_js_syntax::AnyJsExpression::JsStaticMemberExpression(member) => { Some(member.member().ok()?.as_js_name()?.value_token().ok()?.token_text_trimmed()) } _ => None, } } pub(crate) fn is_playwright_page_or_frame(text: &TokenText) -> bool { text == "page" || text == "frame" || text.ends_with("Page") || text.ends_with("Frame") }Then simplify the
runmethod to:let object_text = extract_playwright_receiver_text(&member_expr)?; if is_playwright_page_or_frame(&object_text) { Some(object_text) } else { None }crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
58-95: Consider extracting the common pattern into a helper.This method's logic is nearly identical to
no_playwright_page_pause.rsandno_playwright_wait_for_navigation.rs, differing only in the method name checked. A shared helper accepting the method name as a parameter would reduce duplication.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/not-function.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (11)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/not-function.js(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/not-function.js
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
- crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
🧰 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/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.jscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
**/tests/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place test files under a tests/ directory in each crate
Files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Format Rust files before committing (e.g., viajust fwhich formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
🧠 Learnings (1)
📚 Learning: 2025-10-15T09:21:24.116Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:21:24.116Z
Learning: A diagnostic must explain why something went wrong, using log advices and links to documentation when helpful
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
🧬 Code graph analysis (5)
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (2)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-913)crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)note(1381-1383)new(552-570)new(1316-1327)new(1441-1453)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (3)
FixKind(8150-8150)RuleDomain(904-913)Applicability(9946-9946)crates/biome_service/src/workspace.rs (1)
markup(1130-1132)crates/biome_analyze/src/rule.rs (3)
new(552-570)new(1316-1327)new(1441-1453)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (4)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-913)crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run(55-99)diagnostic(101-119)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
run(57-94)diagnostic(96-114)
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (6)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-913)crates/biome_analyze/src/rule.rs (10)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)new(552-570)new(1316-1327)new(1441-1453)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
run(57-94)diagnostic(96-114)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run(58-95)diagnostic(97-115)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (2)
run(57-94)diagnostic(96-114)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (4)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain(904-913)crates/biome_analyze/src/rule.rs (7)
language(592-595)sources(587-590)same(247-252)recommended(572-575)domains(602-605)run(1033-1033)diagnostic(1120-1122)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run(55-99)diagnostic(101-119)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run(58-95)diagnostic(97-115)
🔇 Additional comments (15)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (1)
96-114: Diagnostic messages correctly use dynamic receiver.Past review concerns about hardcoded "page.waitForNavigation()" have been addressed—lines 104 and 108 now interpolate
{receiver}, soframe.waitForNavigation()will produce the correct message.crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (4)
8-53: Rule declaration looks solid.Metadata is complete, documentation provides clear examples, and the ESLint source is properly attributed.
55-60: Comprehensive coverage of invalid cases.The
NotFunctionvariant properly addresses previous feedback about reporting non-function callbacks.
68-102: Describe call identification is thorough.Correctly handles both
describe()andtest.describe()patterns.
157-188: Excellent diagnostic messages.Each case provides clear guidance: what's wrong, why it's wrong, and how to fix it. The "why" explanations address previous feedback effectively.
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js (1)
1-4: Appropriate test coverage for missing callbacks.Tests both
describe()andtest.describe()forms without callbacks, ensuring the rule catches both patterns.crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (4)
1-7: LGTM! Imports are appropriate.The imports are well-chosen for this rule implementation, including
TokenTextwhich aligns with the previous feedback about avoiding heap allocations.
8-47: LGTM! Rule declaration is well-structured.The rule metadata and documentation are properly configured. The examples clearly demonstrate the invalid patterns and valid alternatives, which will help users understand why
page.pause()should be avoided in production code.
49-54: LGTM! Rule trait setup is correct.The choice of
TokenTextas the state type is efficient and follows best practices for avoiding unnecessary heap allocations.
101-119: LGTM! Diagnostic message is clear and helpful.The diagnostic provides excellent guidance, explaining both why
pause()is problematic and what developers should do instead. The use ofmarkup!with<Emphasis>makes the key information stand out appropriately.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
1-50: LGTM! Clear documentation and correct metadata.The rule declaration follows established conventions, and the documentation provides helpful examples contrasting invalid patterns with locator-based alternatives.
97-115: Dynamic receiver correctly addresses past feedback.The diagnostic uses
{receiver}to show the actual object name (e.g.,page,testPage), making the message specific and helpful. This addresses the previous concern about hard-coding"page."whilst remaining more informative than a generic message.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js (1)
1-18: LGTM! Comprehensive coverage of valid async expect patterns.These test cases correctly cover all the async modifier scenarios (
.resolves,.rejects,.poll()) whereawaitis necessary. Well done.crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (1)
306-365: Async modifier detection appears correct—verify against test cases.The earlier reviews flagged parent-walking logic, but the current implementation walks the object/callee chain downward (lines 317, 333, 354-355), which is the correct approach for detecting
.resolves,.rejects, and.poll()modifiers.Traced examples:
expect(promise).resolves.toBe(1)→ correctly identifies "resolves" at line 328expect.soft(promise).resolves.toBe(1)→ correctly returnstruefrom async modifier checkThe valid test cases in
expect-with-async-modifiers.jsshould confirm this handles all async modifier patterns correctly.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js (1)
1-9: LGTM! Invalid cases appropriately cover sync expect patterns.These test cases correctly demonstrate unnecessary
awaitusage with synchronous expect matchers, including theexpect.softvariant. Well structured.
|
Hi @voxxit Thank you for the contribution! In order to not miss on things, could you please do the following:
|
|
@ematipico Done! #7796 was created, and updated this description, too. |
dyc3
left a comment
There was a problem hiding this comment.
Rules are looking much more clean now. But it doesn't look like the implementations are flagging all the invalid cases.
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
Outdated
Show resolved
Hide resolved
...s/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/bracket-notation.js
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
Show resolved
Hide resolved
...me_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/bracket-notation.js.snap
Outdated
Show resolved
Hide resolved
...e_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js.snap
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
Show resolved
Hide resolved
- Resolved conflicts in crates/biome_analyze/src/rule.rs by keeping both HEAD's EslintPlaywright and upstream's GraphqlSchemaLinter/Stylelint - Added RuleDomain::Playwright to as_str and from_str implementations - Renamed missingPlaywrightAwait to noPlaywrightMissingAwait per project conventions - Regenerated code with just gen-analyzer - Updated snapshots for renamed rule
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/biome_analyze/src/rule.rs (1)
533-556: Playwright globals are minimal but pragmaticExposing just
testandexpectas globals for the Playwright domain seems like a good balance; it avoids overreach while covering the common API surface. If you later see false positives around fixtures, you can always extend this list.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**
📒 Files selected for processing (1)
crates/biome_analyze/src/rule.rs(11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use thedbg!()macro for debugging output during testing, and pass the--show-outputflag tocargoto view debug output
Usecargo torcargo testto run tests; for a single test, pass the test name after thetestcommand
Use snapshot testing with theinstacrate; runcargo insta accept,cargo insta reject, orcargo insta reviewto manage snapshot changes
Write doctests as doc comments with code blocks; the code inside code blocks will be run during the testing phase
Usejust f(alias forjust format) to format Rust and TOML files before committing
Files:
crates/biome_analyze/src/rule.rs
🧠 Learnings (15)
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : For rules ported from other ecosystems like ESLint or Clippy, add a `sources` field with `RuleSource` metadata using `.same()` for identical behavior or `.inspired()` for different behavior
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Deprecate rules by adding a `deprecated` field to the `declare_lint_rule!` macro with a message explaining the reason for deprecation (e.g., 'Use the rule noAnotherVar')
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `declare_lint_rule!` macro must include metadata fields: `version` (set to 'next'), `name` (rule identifier), `language` (applicable language), `recommended` (boolean), and optional fields like `severity`, `fix_kind`, `sources`, `domains`, and `deprecated`
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnknown` prefix for rules that report mistyped entities in CSS (e.g., `noUnknownUnit`)
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Set the `language` field in `declare_lint_rule!` to the primary language (js for JavaScript, jsx for JSX, ts for TypeScript, tsx for TSX) that the rule applies to
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Document rules with a one-line brief description in the first paragraph of the doc comment, followed by detailed paragraphs, `## Examples` section with `### Invalid` and `### Valid` subsections, and optional `## Options` section
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Set rule severity to `error` for correctness/security/a11y rules, `warn` for suspicious/performance rules, `info` for style/complexity rules, and `info` for actions
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Implement custom `Queryable` types and `Visitor` traits for rules requiring deep AST inspection to avoid redundant traversal passes
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Rule options must be defined in the `biome_rule_options` crate and implement traits: `Deserializable`, `Merge`, `Serialize`, `Deserialize`, and `JsonSchema`
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use `rule_category!()` macro instead of dynamic string parsing to refer to rule diagnostic categories for compile-time validation
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Framework-specific rules should be named using the `use` or `no` prefix followed by the framework name (e.g., `noVueReservedProps`)
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `action` function must return a `JsRuleAction` (or equivalent language-specific action type) with category `ctx.action_category(ctx.category(), ctx.group())` and applicability from `ctx.metadata().applicability()`
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Parse rule functions must be prefixed with `parse_` and use the name defined in the grammar file, e.g., `parse_for_statement` or `parse_expression`
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`
Applied to files:
crates/biome_analyze/src/rule.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Use quick testing via `tests/quick_test.rs` by removing the `#[ignore]` macro and modifying the `SOURCE` variable to rapidly validate rule behavior during development
Applied to files:
crates/biome_analyze/src/rule.rs
🧬 Code graph analysis (1)
crates/biome_analyze/src/rule.rs (1)
crates/biome_configuration/src/analyzer/mod.rs (6)
fmt(596-598)fmt(602-607)fmt(666-668)fmt(672-677)fmt(878-880)fmt(884-886)
🔇 Additional comments (10)
crates/biome_analyze/src/rule.rs (10)
164-170: Playwright rule source variant looks consistentThe new
EslintPlaywright(&'static str)variant and its doc comment align with the existing ESLint plugin variants and naming scheme. No issues spotted here.
178-221: Display mapping for Playwright source is correctRendering
"eslint-plugin-playwright"matches the plugin’s package name and is consistent with other ESLint plugin labels in this match.
264-302: Inclusion inas_rule_nameis correctAdding
Self::EslintPlaywright(rule_name)into the shared arm keepsas_rule_namebehaviour uniform for all ESLint-derived sources.
305-347: Namespaced Playwright rule name is spot on
"playwright/{rule_name}"matches the upstream rule namespace convention and fits the rest ofto_namespaced_rule_name.
350-388: Playwright rule URL matches the plugin docs layoutThe GitHub URL format for Playwright rules mirrors how other plugin docs are wired here and matches the plugin’s documented path structure.
456-475: NewRuleDomain::Playwrightis well-integratedThe Playwright domain variant and its doc comment follow the existing pattern for framework/test domains; placement and naming look good.
477-491: Display for Playwright domain aligns with configuration namingReturning
"playwright"here keeps it consistent with how domains are referenced in configuration and other modules.
507-531: Auto-enabling Playwright domain via manifest dependency is sensibleHooking
Playwrightto@playwright/test >= 1.0.0mirrors how other domains are activated off key dependencies and should make DX nice and predictable.
559-571:as_strfor Playwright keeps the domain API coherentReturning
"playwright"here is consistent withDisplayand other domains; nothing to tweak.
577-590:FromStrsupport for Playwright completes the round-tripParsing
"playwright"intoRuleDomain::Playwrightkeeps serialisation/deserialisation symmetric with other domains. Nicely wired.
…edback) - Updated `noFocusedTests` rule to detect Playwright's `test.only()` pattern. - Enhanced `noSkippedTests` to handle Playwright's `test.skip()` pattern. - Introduced new tests for various Playwright linting scenarios, including valid and invalid cases for `usePlaywrightValidDescribeCallback`. - Removed outdated tests related to `noPlaywrightSkippedTest` and `noPlaywrightMissingAwait`. - Added new test cases for `noPlaywrightWaitForTimeout` and other related rules. - Regenerated snapshots for updated tests and rules.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js (1)
2-21: Use realistic Playwright assertions for more representative test cases.The test cases use
expect(page).toBeVisible()andexpect(page).toHaveText('foo'), but these aren't valid Playwright API calls. Assertions liketoBeVisible()andtoHaveText()are called on locators, not page objects.Consider using more realistic patterns:
-test('Promise.allSettled', async ({ page }) => { - Promise.allSettled([ - expect(page).toBeVisible(), - expect(page).toHaveText('foo') - ]); -}); +test('Promise.allSettled', async ({ page }) => { + Promise.allSettled([ + expect(page.locator('.foo')).toBeVisible(), + expect(page.locator('.bar')).toHaveText('foo') + ]); +}); -test('Promise.race', async ({ page }) => { - Promise.race([ - expect(page).toBeVisible(), - expect(page).toHaveText('foo') - ]); -}); +test('Promise.race', async ({ page }) => { + Promise.race([ + expect(page.locator('.foo')).toBeVisible(), + expect(page.locator('.bar')).toHaveText('foo') + ]); +}); -test('Promise.any', async ({ page }) => { - Promise.any([ - expect(page).toBeVisible(), - expect(page).toHaveText('foo') - ]); -}); +test('Promise.any', async ({ page }) => { + Promise.any([ + expect(page.locator('.foo')).toBeVisible(), + expect(page.locator('.bar')).toHaveText('foo') + ]); +});crates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/invalid.js (1)
31-34: Good coverage of Playwright-focused describe patternsNice addition of both simple and
.eachtest.describe.onlycases; this lines up well with the existing Jest/Vitest patterns and should keep the rule behaviour consistent across test frameworks. If the implementation is also meant to catch bracket notation for Playwright (liketest.describe["only"]), you might consider mirroring thedescribe["only"]examples here—but that’s strictly optional.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js (1)
1-10: File name and scenarios don’t quite matchThe cases here are all single sync matchers (plus
expect.soft), so the “mixed-chains” name feels a bit broader than what’s actually covered. If you meant to exercise chains mixing async and sync matchers, consider adding one such example; otherwise, renaming the file to something likeexpect-sync-matchers.jsmight be clearer. Tests themselves look solid either way, so this is just a naming nit.crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs (1)
127-132: Minor style inconsistency.Line 130 uses
len() > 0whilst line 146 uses!is_empty()for the same purpose. Consider using!is_empty()consistently.Apply this diff:
biome_js_syntax::AnyJsArrowFunctionParameters::AnyJsBinding(_) => true, biome_js_syntax::AnyJsArrowFunctionParameters::JsParameters(p) => { - p.items().len() > 0 + !p.items().is_empty() }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (70)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_configuration/src/generated/domain_selector.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/nested-calls.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/multiple-arguments.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/force-string-literal.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/select-option-force.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll-sync-matchers.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/nested-expects.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/test-step.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/awaited.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/bracket-notation-valid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-all.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/returned.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/all-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/other-wait-options.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/async.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/has-params.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/missing-callback.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/not-function.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/valid/correct.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/valid.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (68)
.changeset/common-lizards-sniff.md(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/nested-calls.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/multiple-arguments.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/force-string-literal.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/select-option-force.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll-sync-matchers.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/nested-expects.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/test-step.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/awaited.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/bracket-notation-valid.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-all.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/returned.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/all-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/other-wait-options.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/async.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/has-params.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/missing-callback.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/not-function.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/valid/correct.js(1 hunks)crates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/invalid.js(1 hunks)crates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/valid.js(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)crates/biome_rule_options/src/use_playwright_valid_describe_callback.rs(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/returned.js
🚧 Files skipped from review as they are similar to previous changes (23)
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/force-string-literal.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/all-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/nested-calls.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/multiple-arguments.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use thedbg!()macro for debugging output during testing, and pass the--show-outputflag tocargoto view debug output
Usecargo torcargo testto run tests; for a single test, pass the test name after thetestcommand
Use snapshot testing with theinstacrate; runcargo insta accept,cargo insta reject, orcargo insta reviewto manage snapshot changes
Write doctests as doc comments with code blocks; the code inside code blocks will be run during the testing phase
Usejust f(alias forjust format) to format Rust and TOML files before committing
Files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_rule_options/src/lib.rs
.changeset/**/*.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
.changeset/**/*.md: Create changesets for user-facing changes usingjust new-changeset; use headers with####or#####only; keep descriptions concise (1-3 sentences) and focus on user-facing changes
Use past tense when describing what was done ('Added new feature'), present tense when describing Biome behavior ('Biome now supports'); end sentences with a full stop
For new lint rules, show an example of an invalid case in an inline code snippet or code block; for rule changes, demonstrate what is now invalid or valid; for formatter changes, use adiffcode block
Files:
.changeset/common-lizards-sniff.md
🧠 Learnings (40)
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/*.{js,ts,tsx,jsx,json,css} : Test rules using snapshot tests via the `insta` library with test cases in `tests/specs/<group>/<rule_name>/` directories prefixed by `invalid` or `valid`
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/bracket-notation-valid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/valid/correct.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/has-params.jscrates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/valid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/select-option-force.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/test-step.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll-sync-matchers.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll.jscrates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/nested-expects.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/async.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/not-function.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/awaited.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/missing-callback.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/*.jsonc : Use `.jsonc` files in test specs with code snippets as array of strings to test rules in script environment (no import/export syntax)
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-all.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/bracket-notation-valid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/valid/correct.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/has-params.jscrates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/valid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll-sync-matchers.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll.jscrates/biome_js_analyze/tests/specs/suspicious/noFocusedTests/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/nested-expects.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/async.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/not-function.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/missing-callback.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : In rule documentation code blocks, mark invalid examples with the `expect_diagnostic` property and valid examples without it; each invalid example must emit exactly one diagnostic
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.jscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.jscrates/biome_js_analyze/tests/specs/nursery/usePlaywrightValidDescribeCallback/invalid/missing-callback.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.jscrates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use language tags in documentation code blocks (js, ts, tsx, json, css) and order properties consistently as: language, then `expect_diagnostic`, then options modifiers, then `ignore`, then `file=path`
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
📚 Learning: 2025-11-28T09:08:10.077Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-28T09:08:10.077Z
Learning: Applies to **/*.tsx : For Node.js package development, build WebAssembly bindings and JSON-RPC bindings; run tests against compiled files after implementing features or bug fixes
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
📚 Learning: 2025-11-28T09:08:10.077Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-28T09:08:10.077Z
Learning: Applies to **/*.ts : For Node.js package development, build WebAssembly bindings and JSON-RPC bindings; run tests against compiled files after implementing features or bug fixes
Applied to files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Rule options struct fields should use `#[serde(rename_all = "camelCase")]`, `#[serde(deny_unknown_fields)]`, and `#[serde(default)]` attributes for proper JSON serialization
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Rule options must be defined in the `biome_rule_options` crate and implement traits: `Deserializable`, `Merge`, `Serialize`, `Deserialize`, and `JsonSchema`
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Wrap optional rule option fields in `Option<_>` to properly track set vs unset options during configuration merging
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Implement the `Merge` trait for rule options to define how options from extended configuration merge with user configuration (usually reset instead of extend)
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `useValid` prefix for rules that report code that always evaluates to a constant (e.g., `useValidTypeof`)
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-21T01:10:53.059Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/src/**/*.rs : Use `Box<[T]>` instead of `Vec<T>` for rule options array fields to save memory (boxed slices and boxed str use 2 words instead of three words)
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Document rules with a one-line brief description in the first paragraph of the doc comment, followed by detailed paragraphs, `## Examples` section with `### Invalid` and `### Valid` subsections, and optional `## Options` section
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUseless` prefix for rules that report unnecessary code that could be removed or simplified (e.g., `noUselessConstructor`)
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `use` prefix naming convention when the sole intention is to mandate a single concept (e.g., `useValidLang` to enforce valid HTML lang attribute values)
Applied to files:
crates/biome_rule_options/src/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rule diagnostics must explain to the user what the error is, why it is triggered, and what should be done to fix it following the three pillars: (1) what the error is, (2) why the error is triggered, (3) what the user should do
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `diagnostic` function must return a `RuleDiagnostic` that defines the message reported to the user using the `markup!` macro
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `declare_lint_rule!` macro must include metadata fields: `version` (set to 'next'), `name` (rule identifier), `language` (applicable language), `recommended` (boolean), and optional fields like `severity`, `fix_kind`, `sources`, `domains`, and `deprecated`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Deprecate rules by adding a `deprecated` field to the `declare_lint_rule!` macro with a message explaining the reason for deprecation (e.g., 'Use the rule noAnotherVar')
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noInvalid` prefix for rules that report runtime errors from mistyping (e.g., `noInvalidConstructorSuper`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `action` function must return a `JsRuleAction` (or equivalent language-specific action type) with category `ctx.action_category(ctx.category(), ctx.group())` and applicability from `ctx.metadata().applicability()`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use `rule_category!()` macro instead of dynamic string parsing to refer to rule diagnostic categories for compile-time validation
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : For rules ported from other ecosystems like ESLint or Clippy, add a `sources` field with `RuleSource` metadata using `.same()` for identical behavior or `.inspired()` for different behavior
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `run` function of a lint rule should return `Option<Self::State>` or an iterable like `Vec<Self::State>` or `Box<[Self::State]>` to signal zero or more diagnostics
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules must be implemented using the `Rule` trait with type parameters: `Query` (node type to analyze), `State` (information for signals), `Signals` (return type from run function), and `Options` (rule configuration)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Framework-specific rules should be named using the `use` or `no` prefix followed by the framework name (e.g., `noVueReservedProps`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUndeclared` prefix for rules that report undefined entities (e.g., `noUndeclaredVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnsafe` prefix for rules that report code leading to runtime failures (e.g., `noUnsafeOptionalChaining`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noEmpty` prefix for rules that report empty code (e.g., `noEmptyBlockStatements`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnused` prefix for rules that report unused entities (e.g., `noUnusedVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noRestricted` prefix for rules that report user-banned entities (e.g., `noRestrictedGlobals`)
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnknown` prefix for rules that report mistyped entities in CSS (e.g., `noUnknownUnit`)
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `no` prefix naming convention when the sole intention is to forbid a single concept (e.g., `noDebugger` to disallow debugger statements)
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noRedundant` prefix for rules that report redundant code (e.g., `noRedundantUseStrict`)
Applied to files:
crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-28T09:08:10.077Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-28T09:08:10.077Z
Learning: Applies to .changeset/**/*.md : For new lint rules, show an example of an invalid case in an inline code snippet or code block; for rule changes, demonstrate what is now invalid or valid; for formatter changes, use a `diff` code block
Applied to files:
.changeset/common-lizards-sniff.md
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : New rules must be placed inside the `nursery` group as an incubation space exempt from semantic versioning, with promotion to appropriate groups done during minor/major releases
Applied to files:
.changeset/common-lizards-sniff.md
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Commit rule changes with message format: `feat(biome_<crate>): <ruleName>` to follow Biome's conventional commit style
Applied to files:
.changeset/common-lizards-sniff.md
📚 Learning: 2025-11-28T09:08:10.077Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-28T09:08:10.077Z
Learning: Applies to .changeset/**/*.md : Create changesets for user-facing changes using `just new-changeset`; use headers with `####` or `#####` only; keep descriptions concise (1-3 sentences) and focus on user-facing changes
Applied to files:
.changeset/common-lizards-sniff.md
📚 Learning: 2025-11-28T09:08:10.077Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-28T09:08:10.077Z
Learning: Applies to .changeset/**/*.md : Use past tense when describing what was done ('Added new feature'), present tense when describing Biome behavior ('Biome now supports'); end sentences with a full stop
Applied to files:
.changeset/common-lizards-sniff.md
🧬 Code graph analysis (4)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js (3)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js (1)
button(2-2)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js (1)
button(4-4)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js (1)
buttons(2-2)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js (2)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js (1)
button(2-2)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js (1)
button(2-2)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js (1)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js (1)
frame(2-2)
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs (3)
crates/biome_service/src/workspace.rs (1)
markup(1176-1178)crates/biome_js_syntax/src/expr_ext.rs (1)
callee(33-38)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(143-152)
🪛 LanguageTool
.changeset/common-lizards-sniff.md
[uncategorized] ~9-~9: Loose punctuation mark.
Context: ...nter/rules/no-playwright-missing-await/): Enforce awaiting async Playwright APIs....
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~10-~10: Loose punctuation mark.
Context: ...ter/rules/no-playwright-element-handle/): Prefer locators over element handles (`...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~10-~10: Consider using “to” with “prefer”.
Context: ...r/rules/no-playwright-element-handle/): Prefer locators over element handles (page.$() and page.$$()). -...
(PREFER_OVER_TO)
[uncategorized] ~11-~11: Loose punctuation mark.
Context: ...js.dev/linter/rules/no-playwright-eval/): Disallow page.$eval() and `page.$$eva...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~12-~12: Loose punctuation mark.
Context: ...inter/rules/no-playwright-force-option/): Disallow the force option on user int...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...linter/rules/no-playwright-networkidle/): Disallow deprecated networkidle wait ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~14-~14: Loose punctuation mark.
Context: .../linter/rules/no-playwright-page-pause/): Disallow page.pause() debugging calls...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...nter/rules/no-playwright-useless-await/): Disallow unnecessary await on synchro...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...use-playwright-valid-describe-callback/): Validate describe callback signatures a...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~17-~17: Loose punctuation mark.
Context: ...ules/no-playwright-wait-for-navigation/): Prefer modern navigation APIs over depr...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~18-~18: Loose punctuation mark.
Context: .../rules/no-playwright-wait-for-selector/): Prefer locators over deprecated `waitFo...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...r/rules/no-playwright-wait-for-timeout/): Disallow hard-coded timeouts with `wait...
(UNLIKELY_OPENING_PUNCTUATION)
…seless awaits - Removed redundant notes suggesting to add "await" or return promises in diagnostic messages for `noPlaywrightMissingAwait` and `noPlaywrightUselessAwait` rules. - Updated snapshots to reflect changes in diagnostic output for various test cases.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (1)
238-362: Async‑modifier handling forexpectchains looks correct; please ensure tests cover.resolves/.rejects/.pollThe
is_sync_expect_call+has_async_modifiercombo now walks the callee/object chain rather than climbing parents, which should avoid the earlier false positives on patterns like:
await expect(promise).resolves.toBe(1);await expect(promise).rejects.toThrow();await expect(locator).poll().toHaveText('x');and only flag
awaitwhen:
- the final matcher is one of the synchronous matchers, and
- there’s no
poll/resolves/rejectssegment between the baseexpect/expect.softcall and that matcher.From a quick mental AST walk, this looks correct, but it’s a subtle area. I’d strongly recommend making sure your specs include the above three patterns as valid (no diagnostics) alongside the basic
await expect(1).toBe(1)invalid case, to lock this behaviour in.If you’d like, I can suggest concrete test cases mirroring the upstream
eslint-plugin-playwrightrule docs to double‑check parity.
🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs (1)
427-466: Minor naming nit:find_enclosing_promise_allnow covers all combinatorsThe helper correctly detects
Promise.all,allSettled,race, andany, so the namefind_enclosing_promise_allis a tiny bit misleading. If you touch this code again, consider renaming to something likefind_enclosing_promise_combinatorfor clarity; the implementation itself looks good.crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (2)
63-126: Locator/page/expect matcher lists look reasonable; consider future de‑duplicationThe LOCATOR_METHODS, SYNC_PAGE_METHODS, and SYNC_EXPECT_MATCHERS sets match what I’d expect from the upstream rule and keep lookups O(1) via slice
contains. If more Playwright rules start needing the same method lists, it might be worth centralising them in a shared Playwright helper module to avoid drift between rules, but that can be a follow‑up.
207-236:is_page_or_framemirrors other Playwright rules; potential shared helper
is_page_or_framematches the same “page/frame or *Page/*Frame suffix” heuristic used in the other Playwright rules (e.g. wait‑for‑selector/navigation), and correctly usestext_trimmed()/TokenTextinstead of allocatingStrings. If you find yourself copying this into more rules, a small shared helper in a Playwright utils module would keep everything in sync, but it’s fine as‑is for this PR.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (14)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-async-matcher.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll-sync-matchers.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/expect-poll.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/module-level.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/nested-expects.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/non-async-context.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-all-not-awaited.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/test-step.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (2)
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use thedbg!()macro for debugging output during testing, and pass the--show-outputflag tocargoto view debug output
Usecargo torcargo testto run tests; for a single test, pass the test name after thetestcommand
Use snapshot testing with theinstacrate; runcargo insta accept,cargo insta reject, orcargo insta reviewto manage snapshot changes
Write doctests as doc comments with code blocks; the code inside code blocks will be run during the testing phase
Usejust f(alias forjust format) to format Rust and TOML files before committing
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
🧠 Learnings (19)
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `action` function must return a `JsRuleAction` (or equivalent language-specific action type) with category `ctx.action_category(ctx.category(), ctx.group())` and applicability from `ctx.metadata().applicability()`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Framework-specific rules should be named using the `use` or `no` prefix followed by the framework name (e.g., `noVueReservedProps`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : For rules ported from other ecosystems like ESLint or Clippy, add a `sources` field with `RuleSource` metadata using `.same()` for identical behavior or `.inspired()` for different behavior
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules must be implemented using the `Rule` trait with type parameters: `Query` (node type to analyze), `State` (information for signals), `Signals` (return type from run function), and `Options` (rule configuration)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnsafe` prefix for rules that report code leading to runtime failures (e.g., `noUnsafeOptionalChaining`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noEmpty` prefix for rules that report empty code (e.g., `noEmptyBlockStatements`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Code actions must specify a `fix_kind` field in the `declare_lint_rule!` macro as either `FixKind::Safe` or `FixKind::Unsafe` to indicate whether fixes always preserve program behavior
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Set the `language` field in `declare_lint_rule!` to the primary language (js for JavaScript, jsx for JSX, ts for TypeScript, tsx for TSX) that the rule applies to
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUndeclared` prefix for rules that report undefined entities (e.g., `noUndeclaredVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Implement custom `Queryable` types and `Visitor` traits for rules requiring deep AST inspection to avoid redundant traversal passes
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUseless` prefix for rules that report unnecessary code that could be removed or simplified (e.g., `noUselessConstructor`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnused` prefix for rules that report unused entities (e.g., `noUnusedVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noRedundant` prefix for rules that report redundant code (e.g., `noRedundantUseStrict`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Deprecate rules by adding a `deprecated` field to the `declare_lint_rule!` macro with a message explaining the reason for deprecation (e.g., 'Use the rule noAnotherVar')
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noInvalid` prefix for rules that report runtime errors from mistyping (e.g., `noInvalidConstructorSuper`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Avoid unnecessary string allocations by comparing against `&str` or `TokenText` instead of calling `to_string()` which allocates heap memory
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : In rule documentation code blocks, mark invalid examples with the `expect_diagnostic` property and valid examples without it; each invalid example must emit exactly one diagnostic
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `no` prefix naming convention when the sole intention is to forbid a single concept (e.g., `noDebugger` to disallow debugger statements)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noMisleading` prefix for rules that report valid but potentially misleading code (e.g., `noMisleadingCharacterClass`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (4)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (2)
run(57-94)diagnostic(96-114)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run(58-95)diagnostic(97-115)crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (2)
run(55-105)diagnostic(107-124)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (2)
run(52-94)diagnostic(96-116)
🔇 Additional comments (6)
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs (4)
15-66: Rule declaration & metadata look spot onDocs, examples, rule name,
language: "js",sourcespointing atmissing-playwright-await,fix_kind: FixKind::Unsafe, anddomains: &[RuleDomain::Playwright]all line up nicely with the intended behaviour and the CONTRIBUTING guidance for ported framework rules.
69-107: Async matcher detection is thorough and mirrors Playwright semanticsThe
ASYNC_PLAYWRIGHT_MATCHERSlist plusget_async_expect_matcher/has_poll_in_chain/has_expect_in_chainlogic gives good coverage ofexpect(...)chains, includingexpect.pollandexpect.soft/.notstyle chains. The control flow is defensive (short‑circuiting on poll first, then matcher membership, thenexpectat the root), which should keep false positives low.Also applies to: 266-298
468-501: Async‑context guard for fixes is a nice safety net
is_in_async_contextcombiningis_in_async_functionwith module‑level TLA detection is a good guardrail so the fixer only offersawaitwhere it’s syntactically valid, and falls back to diagnostics‑only elsewhere. Nicely balances helpfulness with not rewriting users into a syntax error.
176-227: AlignJsRuleActionconstruction with rule metadata helpers, but fix the method callBoth branches of
actionhard‑codeApplicability::MaybeIncorrectand usectx.metadata().action_category(...). The suggestion to usectx.metadata().applicability()instead of hard-coded applicability is correct and matches patterns in other rules, but the proposed change to the category call is incorrect.The correct pattern used across the codebase is:
- Use
ctx.metadata().action_category(ctx.category(), ctx.group())for the category (notctx.action_category()).- Use
ctx.metadata().applicability()for applicability.- Drop the now‑unused
Applicabilityimport.Apply this corrected pattern:
- return Some(JsRuleAction::new( - ctx.metadata().action_category(ctx.category(), ctx.group()), - Applicability::MaybeIncorrect, + return Some(JsRuleAction::new( + ctx.metadata().action_category(ctx.category(), ctx.group()), + ctx.metadata().applicability(), markup! { "Add "<Emphasis>"await"</Emphasis>" before the Promise combinator." } .to_owned(), mutation, )); @@ - Some(JsRuleAction::new( - ctx.metadata().action_category(ctx.category(), ctx.group()), - Applicability::MaybeIncorrect, + Some(JsRuleAction::new( + ctx.metadata().action_category(ctx.category(), ctx.group()), + ctx.metadata().applicability(), markup! { "Add "<Emphasis>"await"</Emphasis>" before the call." }.to_owned(), mutation, ))and at the top:
-use biome_diagnostics::Applicability;This centralizes rule metadata as the single source of truth.
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (2)
1-11: Imports and wiring look consistent with the rest of the lint infraThe imports are tight, used, and match the standard pattern for new JS rules in this crate. Nothing to change here.
12-61: Rule metadata & docs align with Biome and upstream namingNice job on the metadata:
NoPlaywrightUselessAwaitfollows theno+ framework naming guidance, usesRuleSource::EslintPlaywright("no-useless-await"), and scopes toRuleDomain::Playwright. The doc examples correctly mark invalid snippets withexpect_diagnosticand valid ones without.
| impl Rule for NoPlaywrightUselessAwait { | ||
| type Query = Ast<JsAwaitExpression>; | ||
| type State = (); | ||
| type Signals = Option<Self::State>; | ||
| type Options = (); | ||
|
|
||
| fn run(ctx: &RuleContext<Self>) -> Self::Signals { | ||
| let await_expr = ctx.query(); | ||
| let argument = await_expr.argument().ok()?; | ||
|
|
||
| // Check if the awaited expression is a call expression | ||
| let call_expr = argument.as_js_call_expression()?; | ||
| let callee = call_expr.callee().ok()?; | ||
|
|
||
| // Check for member expressions (method calls) | ||
| if let Some(member_expr) = callee.as_js_static_member_expression() { | ||
| let member_name = member_expr.member().ok()?; | ||
| let member_token = member_name.as_js_name()?.value_token().ok()?; | ||
| let method_name = member_token.text_trimmed(); | ||
|
|
||
| // Check if it's a locator method | ||
| if LOCATOR_METHODS.contains(&method_name) { | ||
| return Some(()); | ||
| } | ||
|
|
||
| // Check if it's a sync page method | ||
| if SYNC_PAGE_METHODS.contains(&method_name) { | ||
| // Verify it's called on page/frame | ||
| let object = member_expr.object().ok()?; | ||
| if is_page_or_frame(&object) { | ||
| return Some(()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Check for expect calls with sync matchers | ||
| if is_sync_expect_call(call_expr) { | ||
| return Some(()); | ||
| } | ||
|
|
||
| None | ||
| } | ||
|
|
||
| fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> { | ||
| let node = ctx.query(); | ||
| Some( | ||
| RuleDiagnostic::new( | ||
| rule_category!(), | ||
| node.range(), | ||
| markup! { | ||
| "Unnecessary "<Emphasis>"await"</Emphasis>" expression." | ||
| }, | ||
| ) | ||
| .note(markup! { | ||
| "This method does not return a Promise." | ||
| }), | ||
| ) | ||
| } | ||
|
|
||
| fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> { | ||
| let await_expr = ctx.query(); | ||
| let argument = await_expr.argument().ok()?; | ||
|
|
||
| let mut mutation = ctx.root().begin(); | ||
| // Replace the entire await expression with just its argument | ||
| mutation.replace_element( | ||
| await_expr.clone().into_syntax().into(), | ||
| argument.into_syntax().into(), | ||
| ); | ||
|
|
||
| Some(JsRuleAction::new( | ||
| ctx.metadata().action_category(ctx.category(), ctx.group()), | ||
| Applicability::Always, | ||
| markup! { "Remove unnecessary await" }.to_owned(), | ||
| mutation, | ||
| )) | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use ctx.metadata().applicability() instead of hard‑coding Applicability::Always
The main rule logic in run and the diagnostic text look solid, and the fix (replace the whole await expression with its argument) is indeed safe for the methods you’re matching.
One small but important consistency point: the action currently hard‑codes Applicability::Always, instead of deferring to the rule metadata:
Some(JsRuleAction::new(
ctx.metadata().action_category(ctx.category(), ctx.group()),
- Applicability::Always,
+ ctx.metadata().applicability(),
markup! { "Remove unnecessary await" }.to_owned(),
mutation,
))Using ctx.metadata().applicability() keeps this rule aligned with how applicability is configured centrally for lint actions.
🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
around lines 128 to 205, the JsRuleAction is using a hard-coded
Applicability::Always; change it to use ctx.metadata().applicability() instead:
update the JsRuleAction::new call to pass ctx.metadata().applicability() as the
applicability argument so the rule respects centrally configured applicability.
- Modified examples in `no_playwright_missing_await` to use `page.getByRole('button')` instead of `page` directly for better clarity.
- Adjusted the `use_playwright_valid_describe_callback` rule to check for non-empty parameter lists more clearly.
- Updated test cases and snapshots to reflect changes in the usage of locators for better accuracy in diagnostics.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs (3)
62-67: Consider wiring through the dedicated options type instead of()AI context mentions a
UsePlaywrightValidDescribeCallbackOptionsinbiome_rule_options; if that exists, it would be more consistent with other rules to import and use it astype Options = UsePlaywrightValidDescribeCallbackOptions, or else drop the unused options struct. That keeps configuration, docs, and type-level wiring in sync for future tweaks.
72-102: Broaden describe detection to match more Playwright call shapes
is_describecurrently recognises only baredescribe(...)andtest.describe(...), so patterns liketest.describe.only(...)/test.describe.skip(...)/test.describe.parallel(...)will not be linted, whereas the upstream ESLint rule typically handles the “describe-ish” variants too. If you’re aiming for behavioural parity witheslint-plugin-playwright, consider peeling one level ofJsStaticMemberExpression(or reusing a shared helper) so calls where the inner member isdescribeontestare also treated as describes; otherwise it might be more accurate to mark the rule source as.inspired()rather than.same().
157-188: Diagnostics read well and follow the three‑pillars guidanceEach
InvalidReasonmaps to a clear primary message plus two notes that cover why it’s a problem and how to fix it, and you’re usingmarkup!withrule_category!()as expected; this is exactly the style the lint docs call for. If you ever fancy micro-polish, you could target the callback expression’s range instead of the whole call, but it’s definitely shippable as is. Based on learnings, this ticks the diagnostic requirements.crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs (1)
102-106: Consider adding derive macros for better ergonomics.Adding
#[derive(Debug)]would be helpful for debugging during development. Not strictly required since the type is only passed by reference, but a nice-to-have.+#[derive(Debug)] pub enum MissingAwaitType { ExpectMatcher(TokenText), ExpectPoll, TestStep, }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (4)
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js(1 hunks)crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/invalid/promise-combinators.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightMissingAwait/valid/promise-combinators-valid.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use thedbg!()macro for debugging output during testing, and pass the--show-outputflag tocargoto view debug output
Usecargo torcargo testto run tests; for a single test, pass the test name after thetestcommand
Use snapshot testing with theinstacrate; runcargo insta accept,cargo insta reject, orcargo insta reviewto manage snapshot changes
Write doctests as doc comments with code blocks; the code inside code blocks will be run during the testing phase
Usejust f(alias forjust format) to format Rust and TOML files before committing
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
🧠 Learnings (19)
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `declare_lint_rule!` macro must include metadata fields: `version` (set to 'next'), `name` (rule identifier), `language` (applicable language), `recommended` (boolean), and optional fields like `severity`, `fix_kind`, `sources`, `domains`, and `deprecated`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUndeclared` prefix for rules that report undefined entities (e.g., `noUndeclaredVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `action` function must return a `JsRuleAction` (or equivalent language-specific action type) with category `ctx.action_category(ctx.category(), ctx.group())` and applicability from `ctx.metadata().applicability()`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : For rules ported from other ecosystems like ESLint or Clippy, add a `sources` field with `RuleSource` metadata using `.same()` for identical behavior or `.inspired()` for different behavior
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnused` prefix for rules that report unused entities (e.g., `noUnusedVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : New rules must be placed inside the `nursery` group as an incubation space exempt from semantic versioning, with promotion to appropriate groups done during minor/major releases
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Framework-specific rules should be named using the `use` or `no` prefix followed by the framework name (e.g., `noVueReservedProps`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnknown` prefix for rules that report mistyped entities in CSS (e.g., `noUnknownUnit`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules must be implemented using the `Rule` trait with type parameters: `Query` (node type to analyze), `State` (information for signals), `Signals` (return type from run function), and `Options` (rule configuration)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rscrates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noEmpty` prefix for rules that report empty code (e.g., `noEmptyBlockStatements`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : In rule documentation code blocks, mark invalid examples with the `expect_diagnostic` property and valid examples without it; each invalid example must emit exactly one diagnostic
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rule diagnostics must explain to the user what the error is, why it is triggered, and what should be done to fix it following the three pillars: (1) what the error is, (2) why the error is triggered, (3) what the user should do
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `diagnostic` function must return a `RuleDiagnostic` that defines the message reported to the user using the `markup!` macro
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Deprecate rules by adding a `deprecated` field to the `declare_lint_rule!` macro with a message explaining the reason for deprecation (e.g., 'Use the rule noAnotherVar')
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noInvalid` prefix for rules that report runtime errors from mistyping (e.g., `noInvalidConstructorSuper`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use `rule_category!()` macro instead of dynamic string parsing to refer to rule diagnostic categories for compile-time validation
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `useValid` prefix for rules that report code that always evaluates to a constant (e.g., `useValidTypeof`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `run` function of a lint rule should return `Option<Self::State>` or an iterable like `Vec<Self::State>` or `Box<[Self::State]>` to signal zero or more diagnostics
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `use` prefix naming convention when the sole intention is to mandate a single concept (e.g., `useValidLang` to enforce valid HTML lang attribute values)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs
🔇 Additional comments (9)
crates/biome_js_analyze/src/lint/nursery/use_playwright_valid_describe_callback.rs (1)
8-52: Rule declaration and docs look solidDocs, examples (with
expect_diagnosticon invalid cases), and metadata (version,language,sources,domains,recommended) all line up with the Playwright rule you’re porting; nothing blocking here. Based on learnings, this matches the expected lint-rule boilerplate.crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs (8)
15-67: Well-structured rule declaration with clear documentation.The examples nicely illustrate both the problematic pattern and the corrected version. Good inclusion of the
returncase as a valid alternative toawait.
114-133: Clean early-return pattern in the run function.The separation of
test.step()detection fromexpectmatcher detection is well-organised. Theis_properly_handledabstraction keeps this function readable.
135-174: Informative diagnostics with appropriate context.The notes for
ExpectPollandTestStepvariants add useful context. Including the specific matcher name in theExpectMatcherdiagnostic is a nice touch for clarity.
176-227: Thoughtful handling of Promise combinators.The logic to fix the enclosing
Promise.all/Promise.raceetc. rather than individual array elements preserves concurrency semantics — a detail that's easy to overlook. Well done.
230-260: Neat helper with clean control flow.The inner closure pattern with
?operator keeps the code readable whilst handling all theResult/Optionunwrapping gracefully.
300-365: Solid chain traversal logic.The recursive approach handles arbitrarily deep chains like
expect.poll(...).not.toBeVisible()andexpect.soft(...)variants correctly.
385-399: Pragmatic arrow function body detection.Using
text_trimmed_range()comparison is a reasonable approach to check if the call expression is exactly the arrow body (implicit return). The immediatebreakcorrectly prevents matching calls nested deeper inside the arrow body.
468-501: Correct handling of top-level await context.The function properly distinguishes between ES modules (where TLA is valid) and code nested inside synchronous functions (where being in a module doesn't permit
await). The boundary check at lines 487-497 ensures we don't incorrectly assume async context.
| // Playwright async matchers (web-first assertions) | ||
| const ASYNC_PLAYWRIGHT_MATCHERS: &[&str] = &[ | ||
| "toBeAttached", | ||
| "toBeChecked", | ||
| "toBeDisabled", | ||
| "toBeEditable", | ||
| "toBeEmpty", | ||
| "toBeEnabled", | ||
| "toBeFocused", | ||
| "toBeHidden", | ||
| "toBeInViewport", | ||
| "toBeOK", | ||
| "toBeVisible", | ||
| "toContainText", | ||
| "toHaveAccessibleDescription", | ||
| "toHaveAccessibleErrorMessage", | ||
| "toHaveAccessibleName", | ||
| "toHaveAttribute", | ||
| "toHaveClass", | ||
| "toHaveCount", | ||
| "toHaveCSS", | ||
| "toHaveId", | ||
| "toHaveJSProperty", | ||
| "toHaveScreenshot", | ||
| "toHaveText", | ||
| "toHaveTitle", | ||
| "toHaveURL", | ||
| "toHaveValue", | ||
| "toHaveValues", | ||
| "toContainClass", | ||
| "toPass", | ||
| ]; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Playwright async expect matchers complete list 2025 documentation
💡 Result:
Here’s the up‑to‑date (2025) list of Playwright’s async (auto‑retrying) expect matchers, per the Playwright docs:
Element/Locator matchers
- toBeAttached
- toBeChecked
- toBeDisabled
- toBeEditable
- toBeEmpty
- toBeEnabled
- toBeFocused
- toBeHidden
- toBeInViewport
- toBeVisible
- toContainText
- toHaveAccessibleDescription
- toHaveAccessibleName
- toHaveAttribute
- toHaveClass / toContainClass
- toHaveCount
- toHaveCSS
- toHaveId
- toHaveJSProperty
- toHaveRole
- toHaveScreenshot
- toHaveText
- toHaveValue
- toHaveValues
Page matchers
- toHaveScreenshot (page)
- toHaveTitle
- toHaveURL
Network/response matcher
- toBeOK (response)
(Playwright also provides many synchronous generic Jest‑style matchers — toEqual, toContain, toBeTruthy, etc. — which are not auto‑retrying.)
Sources: Playwright assertions and locator/assertions API docs. [1][2]
References
[1] Playwright — Assertions / Test assertions (Playwright docs).
[2] Playwright — LocatorAssertions / API (Playwright docs).
🌐 Web query:
Playwright toHaveAccessibleErrorMessage async matcher
💡 Result:
Short answer: Playwright provides an async locator matcher expect(locator).toHaveAccessibleErrorMessage(...) (added in v1.50) that waits/retries until the element's aria-errormessage text matches the expected string/RegExp. Use it with await and you can pass options { ignoreCase, timeout }.
Example:
const input = page.getByTestId('username-input');
// waits up to expect timeout (or override with options.timeout)
await expect(input).toHaveAccessibleErrorMessage('Username is required.');
// case-insensitive / regex / timeout
await expect(input).toHaveAccessibleErrorMessage(/required/i, { timeout: 3000 });
References:
[1] Playwright LocatorAssertions (toHaveAccessibleErrorMessage).
[2] Playwright test assertions — async matchers wait/retry.
[3] Playwright v1.50 release notes (added toHaveAccessibleErrorMessage).
🌐 Web query:
Playwright toPass async matcher
💡 Result:
Short answer
- expect(...).toPass() retries an async block until all assertions inside it pass (or until timeout). Use it to wrap flaky async checks (network, UI, emails). [1][2]
Example
- Basic:
await expect(async () => {
const r = await page.request.get('https://api.example.com');
expect(r.status()).toBe(200);
}).toPass(); - With options:
await expect(async () => { /* ... */ }).toPass({ intervals: [1000,2000,10000], timeout: 60000 });
Key notes
- toPass retries the entire block if any assertion fails (unlike expect.poll which polls a value). [2]
- Default toPass timeout is 0 (no retries) unless you pass options or configure it in config (e.g., expect: { toPass: { timeout: 60000 } }). [1][2]
Sources
- Playwright docs — Assertions (expect.toPass). [1]
- Comparison / examples (community notes on toPass vs poll). [2]
Add the missing toHaveRole async matcher to the list.
The constant is missing toHaveRole, which is a documented Playwright async matcher for locators. The list should include it alongside the other element matchers to ensure complete coverage of auto-retrying assertions.
🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery/no_playwright_missing_await.rs
around lines 69 to 100, the ASYNC_PLAYWRIGHT_MATCHERS array is missing the
Playwright async matcher "toHaveRole"; add "toHaveRole" to the list alongside
the other element matchers so it is treated as an async auto-retrying assertion.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
46-49:EvalMethodCallcan be private to this module.The struct doesn’t appear to be used outside this file, so you can drop the
pubon the struct and its fields to keep the surface area minimal.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (2)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs(1 hunks)crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use thedbg!()macro for debugging output during testing, and pass the--show-outputflag tocargoto view debug output
Usecargo torcargo testto run tests; for a single test, pass the test name after thetestcommand
Use snapshot testing with theinstacrate; runcargo insta accept,cargo insta reject, orcargo insta reviewto manage snapshot changes
Write doctests as doc comments with code blocks; the code inside code blocks will be run during the testing phase
Usejust f(alias forjust format) to format Rust and TOML files before committing
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
🧠 Learnings (19)
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnsafe` prefix for rules that report code leading to runtime failures (e.g., `noUnsafeOptionalChaining`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `no` prefix naming convention when the sole intention is to forbid a single concept (e.g., `noDebugger` to disallow debugger statements)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules must be implemented using the `Rule` trait with type parameters: `Query` (node type to analyze), `State` (information for signals), `Signals` (return type from run function), and `Options` (rule configuration)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Framework-specific rules should be named using the `use` or `no` prefix followed by the framework name (e.g., `noVueReservedProps`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noRestricted` prefix for rules that report user-banned entities (e.g., `noRestrictedGlobals`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Deprecate rules by adding a `deprecated` field to the `declare_lint_rule!` macro with a message explaining the reason for deprecation (e.g., 'Use the rule noAnotherVar')
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noConstant` prefix for rules that report computations always evaluated to the same value (e.g., `noConstantMathMinMaxClamp`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUndeclared` prefix for rules that report undefined entities (e.g., `noUndeclaredVariables`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : New rules must be placed inside the `nursery` group as an incubation space exempt from semantic versioning, with promotion to appropriate groups done during minor/major releases
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use `rule_category!()` macro instead of dynamic string parsing to refer to rule diagnostic categories for compile-time validation
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `diagnostic` function must return a `RuleDiagnostic` that defines the message reported to the user using the `markup!` macro
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noInvalid` prefix for rules that report runtime errors from mistyping (e.g., `noInvalidConstructorSuper`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : In rule documentation code blocks, mark invalid examples with the `expect_diagnostic` property and valid examples without it; each invalid example must emit exactly one diagnostic
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `useValid` prefix for rules that report code that always evaluates to a constant (e.g., `useValidTypeof`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `action` function must return a `JsRuleAction` (or equivalent language-specific action type) with category `ctx.action_category(ctx.category(), ctx.group())` and applicability from `ctx.metadata().applicability()`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rscrates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `declare_lint_rule!` macro must include metadata fields: `version` (set to 'next'), `name` (rule identifier), `language` (applicable language), `recommended` (boolean), and optional fields like `severity`, `fix_kind`, `sources`, `domains`, and `deprecated`
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use the `noUnknown` prefix for rules that report mistyped entities in CSS (e.g., `noUnknownUnit`)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `run` function of a lint rule should return `Option<Self::State>` or an iterable like `Vec<Self::State>` or `Box<[Self::State]>` to signal zero or more diagnostics
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Rules should use the `use` prefix naming convention when the sole intention is to mandate a single concept (e.g., `useValidLang` to enforce valid HTML lang attribute values)
Applied to files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (6)
crates/biome_service/src/workspace.rs (1)
markup(1176-1178)crates/biome_analyze/src/rule.rs (10)
language(634-637)sources(629-632)same(249-254)recommended(614-617)domains(644-647)run(1075-1075)diagnostic(1162-1164)new(594-612)new(1396-1408)new(1518-1530)crates/biome_service/src/workspace_types.rs (1)
Self(748-748)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run(58-95)diagnostic(97-115)crates/biome_js_syntax/src/expr_ext.rs (1)
callee(33-38)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref(143-152)
🔇 Additional comments (5)
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
8-43: Rule logic and diagnostics look solid and match the stated intent.Detection is nicely constrained to
$eval/$$evalon page/frame‑like receivers, and the diagnostic (including the updated receiver/method wording) steers users cleanly towards locator APIs. Docs, naming (noPlaywright…), nursery placement, and use ofrule_category!/markup!are all in line with the CONTRIBUTING guidance.Based on learnings, this follows the rule‑authoring conventions for nursery rules.
Also applies to: 51-125
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (4)
1-6: LGTM!Imports are correct and complete for this rule implementation.
8-55: LGTM!Rule declaration follows Biome conventions correctly. The documentation is clear and includes helpful examples that cover the main use cases.
57-60: LGTM!State struct is clean and captures the necessary information for the diagnostic.
68-114: LGTM!The detection logic is solid and consistent with other Playwright rules in the codebase. The pattern matching correctly handles both direct identifiers and member expressions for the receiver.
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
Show resolved
Hide resolved
There was a problem hiding this comment.
A few changes are needed:
- create a changeset for each rule
- for each rule, please provide a small summary (seems like you already do so) and optionally a small snippet of invalid code
- Avoid mentioning the batch thing, it's not needed to the user
| // Locator methods that return Locator (synchronous) | ||
| const LOCATOR_METHODS: &[&str] = &[ | ||
| "and", | ||
| "first", | ||
| "getByAltText", | ||
| "getByLabel", | ||
| "getByPlaceholder", | ||
| "getByRole", | ||
| "getByTestId", | ||
| "getByText", | ||
| "getByTitle", | ||
| "last", | ||
| "locator", | ||
| "nth", | ||
| "or", | ||
| ]; | ||
|
|
||
| // Page/Frame methods that are synchronous | ||
| const SYNC_PAGE_METHODS: &[&str] = &[ | ||
| "childFrames", | ||
| "frame", | ||
| "frameLocator", | ||
| "frames", | ||
| "isClosed", | ||
| "isDetached", | ||
| "mainFrame", | ||
| "name", | ||
| "on", | ||
| "page", | ||
| "parentFrame", | ||
| "setDefaultNavigationTimeout", | ||
| "setDefaultTimeout", | ||
| "url", | ||
| "video", | ||
| "viewportSize", | ||
| "workers", | ||
| ]; | ||
|
|
||
| // Synchronous expect matchers (not Playwright-specific web-first assertions) | ||
| const SYNC_EXPECT_MATCHERS: &[&str] = &[ | ||
| "toBe", | ||
| "toBeCloseTo", | ||
| "toBeDefined", | ||
| "toBeFalsy", | ||
| "toBeGreaterThan", | ||
| "toBeGreaterThanOrEqual", | ||
| "toBeInstanceOf", | ||
| "toBeLessThan", | ||
| "toBeLessThanOrEqual", | ||
| "toBeNaN", | ||
| "toBeNull", | ||
| "toBeTruthy", | ||
| "toBeUndefined", | ||
| "toContain", | ||
| "toContainEqual", | ||
| "toEqual", | ||
| "toHaveLength", | ||
| "toHaveProperty", | ||
| "toMatch", | ||
| "toMatchObject", | ||
| "toStrictEqual", | ||
| "toThrow", | ||
| "toThrowError", | ||
| ]; |
There was a problem hiding this comment.
Please make these lists ordered, and use binary_seach instead of contains. The former is faster than the latter.
To avoid regressions, we have tests to keep them ordered. We have similar tests throughout the linter code base
| type Query = Ast<JsAwaitExpression>; | ||
| type State = (); | ||
| type Signals = Option<Self::State>; | ||
| type Options = (); |
There was a problem hiding this comment.
It seems the PR got old. You should add a file named like the file rule inside the crate biome_rules_options, and use that struct here. Refer to the existing code. It must be applied to all rules
| impl Rule for NoPlaywrightUselessAwait { | ||
| type Query = Ast<JsAwaitExpression>; | ||
| type State = (); | ||
| type Signals = Option<Self::State>; | ||
| type Options = (); | ||
|
|
||
| fn run(ctx: &RuleContext<Self>) -> Self::Signals { | ||
| let await_expr = ctx.query(); | ||
| let argument = await_expr.argument().ok()?; | ||
|
|
||
| // Check if the awaited expression is a call expression | ||
| let call_expr = argument.as_js_call_expression()?; | ||
| let callee = call_expr.callee().ok()?; | ||
|
|
||
| // Check for member expressions (method calls) | ||
| if let Some(member_expr) = callee.as_js_static_member_expression() { | ||
| let member_name = member_expr.member().ok()?; | ||
| let member_token = member_name.as_js_name()?.value_token().ok()?; | ||
| let method_name = member_token.text_trimmed(); | ||
|
|
||
| // Check if it's a locator method | ||
| if LOCATOR_METHODS.contains(&method_name) { | ||
| return Some(()); | ||
| } | ||
|
|
||
| // Check if it's a sync page method | ||
| if SYNC_PAGE_METHODS.contains(&method_name) { | ||
| // Verify it's called on page/frame | ||
| let object = member_expr.object().ok()?; | ||
| if is_page_or_frame(&object) { | ||
| return Some(()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Check for expect calls with sync matchers | ||
| if is_sync_expect_call(call_expr) { | ||
| return Some(()); | ||
| } | ||
|
|
||
| None | ||
| } | ||
|
|
||
| fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> { | ||
| let node = ctx.query(); | ||
| Some( | ||
| RuleDiagnostic::new( | ||
| rule_category!(), | ||
| node.range(), | ||
| markup! { | ||
| "Unnecessary "<Emphasis>"await"</Emphasis>" expression." | ||
| }, | ||
| ) | ||
| .note(markup! { | ||
| "This method does not return a Promise." | ||
| }), | ||
| ) | ||
| } | ||
|
|
||
| fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> { | ||
| let await_expr = ctx.query(); | ||
| let argument = await_expr.argument().ok()?; | ||
|
|
||
| let mut mutation = ctx.root().begin(); | ||
| // Replace the entire await expression with just its argument | ||
| mutation.replace_element( | ||
| await_expr.clone().into_syntax().into(), | ||
| argument.into_syntax().into(), | ||
| ); | ||
|
|
||
| Some(JsRuleAction::new( | ||
| ctx.metadata().action_category(ctx.category(), ctx.group()), | ||
| Applicability::Always, | ||
| markup! { "Remove unnecessary await" }.to_owned(), | ||
| mutation, | ||
| )) | ||
| } | ||
| } |
| } | ||
| } | ||
|
|
||
| fn is_page_or_frame(expr: &AnyJsExpression) -> bool { |
There was a problem hiding this comment.
Return a SyntaxResult<bool> so you can simplify a lot of code
| } | ||
| } | ||
|
|
||
| fn is_sync_expect_call(call_expr: &JsCallExpression) -> bool { |
| false | ||
| } | ||
|
|
||
| fn has_async_modifier(expect_call: &JsCallExpression, final_call: &JsCallExpression) -> bool { |
| if object_text == "page" | ||
| || object_text == "frame" | ||
| || object_text.ends_with("Page") | ||
| || object_text.ends_with("Frame") | ||
| { | ||
| Some(object_text) | ||
| } else { | ||
| None | ||
| } |
There was a problem hiding this comment.
Many rules have this code. Please consider a share function
|
Hey @voxxit, still interested in this PR? |
Yep! But earliest I can get back to it is this Friday PM. Apologies - it's a busy week. |
|
@voxxit if you are occupied with something can I contribute here? |
Yeah go for it. I have some other priorities that I'm working on right now that are taking up almost all of my time so I won't have much time for a couple of weeks or even a month or so. |
|
Hi @voxxit! 👋 Thank you for your foundational work on this PR - it's a great start to bringing Playwright linting to Biome! I noticed this PR had been open for a while without recent activity, and since I need these Playwright rules for my own projects, I decided to pick it up and move it forward. I hope that's okay - I completely understand if you've been busy with other priorities! I've taken your implementation and created a new PR (#8960) that:
Key fixes made:
I've also created issue #8961 to track the overall eslint-plugin-playwright migration progress (12/57 rules now implemented). All tests pass and lint checks are green. Once #8960 is merged, this PR can be closed. Thanks again for getting this started! 🙏 cc @ematipico @dyc3 |
|
I believe we can close this. Thank you @voxxit for starting this, and thank you @abossenbroek for bringing this to the finishing line |
Summary
This PR helps to start bringing the first batch of eslint-plugin-playwright lints into Biome. I chose to write this PR in order to start being able to fully lint my API and E2E tests.
Rules
noPlaywrightMissingAwait- Rule - TestnoPlaywrightElementHandle- Rule - TestnoPlaywrightEval- Rule - Testpage.$evalandpage.$$evalare discouraged, uselocator.evaluateorlocator.evaluateAllinstead.noPlaywrightForceOption- Rule - Test{ force: true }option.noPlaywrightNetworkidle- Rule - TestnoPlaywrightPagePause- Rule - TestnoPlaywrightUselessAwait- Rule - TestusePlaywrightValidDescribeCallback- Rule - Testdescribe()callback.noPlaywrightWaitForNavigation- Rule - TestnoPlaywrightWaitForSelector- Rule - TestnoPlaywrightWaitForTimeout- Rule - TestTest Plan
Docs
Examples are part of the code (old, ESLint rules URL is linked - if that needs to be updated to point to biomejs.dev, please let me know how. Thanks!)
Recent Changes
Dynamic Receiver in Diagnostic Messages
Fixed
noPlaywrightEvalandnoPlaywrightElementHandleto use dynamic receiver names in diagnostic messages instead of hardcodingpage.. This ensures accurate diagnostics when the receiver isframe,myPage,myFrame, etc.Before:
"Unexpected use of page.$eval()"(even when called onframe)After:
"Unexpected use of frame.$eval()"(correctly shows actual receiver)This aligns with the behavior of the other Playwright rules which already use dynamic receivers.