-
-
Notifications
You must be signed in to change notification settings - Fork 725
feat(lint): migrate first batch of Playwright rules from eslint-plugin-playwright #7775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 9911849 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 13 Playwright lint rules to the nursery (ported from eslint-plugin-playwright), introduces Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.$$eval
variants, 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
/describe
automatically 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
frame
or 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
JsStaticMemberExpression
is 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
JsComputedMemberExpression
and 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
frame
ormyPage
; 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
JsStaticMemberExpression
missespage?.$eval
and 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
/describe
originate from@playwright/test
viactx.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.rs
is excluded by!**/categories.rs
and included by**
crates/biome_js_analyze/src/lint/nursery.rs
is excluded by!**/nursery.rs
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js.snap
is excluded by!**/*.snap
and 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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js
crates/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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js
crates/biome_analyze/src/rule.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js
crates/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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js
crates/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 f
which 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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_analyze/src/rule.rs
crates/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
await
keywords. This correctly demonstrates valid usage for thenoPlaywrightUselessAwait
rule.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js (1)
1-1
: LGTM! Correct invalid test case.Properly demonstrates the useless
await
pattern 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
networkidle
wait 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.step
called withoutawait
on 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
waitForTimeout
usage 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.skip
usage 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: true
option 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
missingPlaywrightAwait
rule 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: true
option pattern.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js (1)
1-1
: LGTM!Correct invalid case—
toBe()
is synchronous, so theawait
is indeed useless.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js (1)
1-1
: LGTM!Proper demonstration of the discouraged
networkidle
option.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.all
is 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
waitForSelector
that 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
waitForTimeout
that 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-callback
rule 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.poll
before 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 flaggingreturn
inside 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
return
statements 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 identifierforce
keys.
- Without receiver checks, any
.click({ force: true })
is flagged (false positives).has_force_true
only 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
frame
or 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_object
is 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_frame
helper 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
: Includefilter
inLOCATOR_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_frame
to a shared module and reuse in other rules.This helper exists here but similar logic is duplicated elsewhere. Extract to a small
playwright_utils
module 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.rs
is excluded by!**/migrate/eslint_any_rule_to_biome.rs
and included by**
crates/biome_configuration/src/analyzer/linter/rules.rs
is excluded by!**/rules.rs
and included by**
crates/biome_js_analyze/src/lint/nursery.rs
is excluded by!**/nursery.rs
and included by**
packages/@biomejs/backend-jsonrpc/src/workspace.ts
is excluded by!**/backend-jsonrpc/src/workspace.ts
and included by**
packages/@biomejs/biome/configuration_schema.json
is excluded by!**/configuration_schema.json
and 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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_rule_options/src/lib.rs
crates/biome_rule_options/src/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_rule_options/src/no_playwright_force_option.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs
crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/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 f
which formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_rule_options/src/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_rule_options/src/lib.rs
crates/biome_rule_options/src/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_rule_options/src/no_playwright_force_option.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs
crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_focused_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/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.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_useless_await.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_rule_options/src/no_playwright_focused_test.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_rule_options/src/no_playwright_force_option.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_rule_options/src/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs
crates/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.rs
crates/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
.skip
annotation only, so your implementation is already aligned..fixme
falls 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
CodSpeed Performance ReportMerging #7775 will not alter performanceComparing Summary
Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 thewaitForLoadState
branch (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_true
misses 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
: PreferTokenText
overto_string()
to avoid allocations.The
.to_string()
calls at lines 78-79 and 88-89 allocate unnecessarily. UseTokenText
for 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
: PreferTokenText
overto_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), useTokenText
instead.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.rs
is excluded by!**/migrate/eslint_any_rule_to_biome.rs
and included by**
crates/biome_configuration/src/analyzer/linter/rules.rs
is excluded by!**/rules.rs
and included by**
crates/biome_js_analyze/src/lint/nursery.rs
is excluded by!**/nursery.rs
and 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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_analyze/src/rule.rs
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_rule_options/src/lib.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs
: Format Rust files before committing (e.g., viajust f
which formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_analyze/src/rule.rs
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
crates/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
RuleSource
variant follows the established pattern for ESLint plugins.
218-218
: LGTM! Display and as_rule_name implementations correct.Both additions properly handle the new
EslintPlaywright
variant.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, d FCC0 iagnostics, 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_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.
@dyc3 Thanks for all of the thoughtful feedback on my first PR :-) I believe I've addressed it all, but do check again and let me know if anything else needs to be adjusted. Cheers! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
104-104
: Make the diagnostic message generic.The rule matches
frame.waitForSelector()
and other receivers (lines 86-89), but the message hard-codespage.
. Use the generic form instead.- "Unexpected use of "<Emphasis>"page.waitForSelector()"</Emphasis>"." + "Unexpected use of "<Emphasis>"waitForSelector()"</Emphasis>"."crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
119-124
: Generalise diagnostics: drop hard‑coded “page.” prefix.Keep guidance receiver‑agnostic so it’s correct for
frame
,this.page
, etc. Apply:- .note(markup! { - "Element handles like "<Emphasis>"page."{{state_text}}"()"</Emphasis>" are discouraged." - }) + .note(markup! { + "Element handles like "<Emphasis>"{{state_text}}"()"</Emphasis>" are discouraged." + }) - .note(markup! { - "Use "<Emphasis>"page.locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." - }) + .note(markup! { + "Use "<Emphasis>"locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." + })
🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (3)
63-80
: Also handle bracket access and optional chaining.Calls like
page['$']('a')
andpage?.$('a')
won’t be caught. Consider matchingJsComputedMemberExpression
(string literal "$" or "$$") and optional‑chained members too, with tests.Add tests for:
await page['$']('#id')
await page?.$('button')
9-9
: Tweak rule summary to be receiver‑agnostic.Minor copy edit to match the generalised notes:
- /// Disallow usage of element handles (`page.$()` and `page.$$()`). + /// Disallow usage of element handles (e.g. `.$()` and `. $$()`), commonly seen as `page.$()/page.$$()` or `frame.$()`.
81-105
: De‑duplicate “page‑like receiver” detection across Playwright rules.
no_playwright_eval
implements near‑identical object/member extraction. Extract a tiny helper (e.g.is_page_like(&AnyJsExpression) -> bool
) in a shared module and reuse here and there to keep fixes in one place.Also applies to: 63-75
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts
is excluded by!**/backend-jsonrpc/src/workspace.ts
and included by**
📒 Files selected for processing (7)
.changeset/common-lizards-sniff.md
(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_page_pause.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)
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
- crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.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/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/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/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs
: Format Rust files before committing (e.g., viajust f
which formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.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
🧠 Learnings (1)
📚 Learning: 2025-10-15T09:19:01.347Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:19:01.347Z
Learning: Applies to .changeset/*.md : End every sentence in a changeset with a period
Applied to files:
.changeset/common-lizards-sniff.md
🧬 Code graph analysis (4)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain
(904-913)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run
(63-106)diagnostic
(108-129)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run
(55-99)diagnostic
(101-118)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (3)
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_eval.rs (2)
run
(52-94)diagnostic
(96-116)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.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_element_handle.rs (2)
run
(63-106)diagnostic
(108-129)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run
(55-99)diagnostic
(101-118)
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 (5)
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_selector.rs (2)
run
(58-95)diagnostic
(97-114)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref
(142-151)
🪛 LanguageTool
.changeset/common-lizards-sniff.md
[uncategorized] ~9-~9: Loose punctuation mark.
Context: .../linter/rules/missing-playwright-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: ...inter/rules/no-playwright-skipped-test/): Disallow skipped tests with `test.skip(...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nter/rules/no-playwright-useless-await/): Disallow unnecessary await
on synchro...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~17-~17: Loose punctuation mark.
Context: .../no-playwright-valid-describe-callback/): Validate describe callback signatures a...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~18-~18: Loose punctuation mark.
Context: ...ules/no-playwright-wait-for-navigation/): Prefer modern navigation APIs over depr...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~19-~19: Loose punctuation mark.
Context: .../rules/no-playwright-wait-for-selector/): Prefer locators over deprecated `waitFo...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...r/rules/no-playwright-wait-for-timeout/): Disallow hard-coded timeouts with `wait...
(UNLIKELY_OPENING_PUNCTUATION)
🔇 Additional comments (6)
.changeset/common-lizards-sniff.md (1)
1-22
: ✓ Changeset looks excellent.The previous feedback has been addressed. Header format is correct, all sentences end with periods, rule links and descriptions are included, and the content is clearly user-facing. The tense usage is spot-on (past tense for the action, present tense for what the rules do).
The static analysis flags are false positives—markdown link syntax is expected here.
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
58-95
: Implementation follows established pattern.The logic correctly identifies
waitForSelector
calls on page, frame, or Page/Frame-suffixed objects. Well done.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs (2)
57-94
: Clean implementation.The pattern matching correctly handles all targeted receiver types.
103-103
: Spot on – generic diagnostic message.Unlike the other two files, this correctly uses the generic
"waitForTimeout()"
instead of hard-coding the receiver. Nicely done.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (1)
57-94
: Solid pattern matching.The implementation correctly identifies
waitForNavigation
calls across all targeted receiver types.crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
96-105
: Current implementation is already in parity with eslint-plugin-playwright.The upstream rule flags calls that create ElementHandles (page.$/page.$$ and Frame equivalents), but not calls on existing ElementHandles (elementHandle.$/elementHandle.$$). Your code does exactly that—it checks for page/frame/*Page/*Frame receivers. No broadening needed.
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
♻️ Duplicate comments (8)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs (1)
101-105
: Use receiver‑agnostic primary message.The rule fires for
frame
and other receivers; message still hard‑codespage.
.- "Unexpected use of "<Emphasis>"page.waitForNavigation()"</Emphasis>"." + "Unexpected use of "<Emphasis>"waitForNavigation()"</Emphasis>"."crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs (1)
104-108
: Make the message object‑agnostic.Avoid hard‑coding
page.
; the rule also targets frames/custom pages.- "Unexpected use of "<Emphasis>"page."{{state_text}}"()"</Emphasis>"." + "Unexpected use of "<Emphasis>"{{state_text}}"()</Emphasis>"."crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (2)
243-274
:expect.poll()
with synchronous matchers is still not detected.The early return at line 256 prevents detection of
expect.poll(...).toBe(...)
wheretoBe
isn't inASYNC_PLAYWRIGHT_MATCHERS
. Check forpoll
before validating the matcher.Apply this diff:
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()?; + + // Walk up the chain first + let object = member_expr.object().ok()?; + + // Check for expect.poll (must come before matcher validation) + 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.token_text_trimmed(); // 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); - } - // Check if the chain starts with expect if has_expect_in_chain(&object) { return Some(MissingAwaitType::ExpectMatcher(matcher_name)); } None }
437-439
: Expand to coverPromise.allSettled()
,Promise.any()
, andPromise.race()
.Awaited calls inside
Promise.allSettled([...])
,Promise.any([...])
, orPromise.race([...])
currently escape detection.Apply this diff:
fn is_promise_all(call: &JsCallExpression) -> bool { - is_member_call_pattern(call, "Promise", "all") + if let Ok(callee) = call.callee() { + if let Some(member) = callee.as_js_static_member_expression() { + if let Ok(member_name) = member.member() { + if let Some(name) = member_name.as_js_name() { + if let Ok(token) = name.value_token() { + let method = token.text_trimmed(); + if matches!(method, "all" | "allSettled" | "any" | "race") { + if let Ok(object) = member.object() { + if let AnyJsExpression::JsIdentifierExpression(id) = object { + if let Ok(obj_name) = id.name() { + if let Ok(obj_token) = obj_name.value_token() { + return obj_token.text_trimmed() == "Promise"; + } + } + } + } + } + } + } + } + } + } + false }crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs (1)
1-6
: Add rustdoc comment to the struct.Per coding guidelines, inline rustdoc is required. Document what this options type configures.
+/// Options for the `noPlaywrightWaitForNavigation` rule. +/// Currently empty; reserved for future configuration. #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]As per coding guidelines.
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (1)
55-87
: Add receiver guard to prevent false positives.The rule matches
waitForLoadState("networkidle")
on any receiver, not just Playwright page/frame objects. Add the same page/frame guard used in the other Playwright rules.Apply this diff:
let member_expr = JsStaticMemberExpression::cast_ref(callee.syntax())?; let member_name = member_expr.member().ok()?; let member_text = member_name.as_js_name()?.value_token().ok()?; let method_name = member_text.text_trimmed(); + // Ensure 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()?.token_text_trimmed() + } + AnyJsExpression::JsStaticMemberExpression(member) => { + member.member().ok()?.as_js_name()?.value_token().ok()?.token_text_trimmed() + } + _ => 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; + } + // Check if it's one of the navigation methods let is_navigation_method = matches!(crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
97-114
: Generalise diagnostic messages.The messages hardcode
page.
which is incorrect for other receivers likeframe.waitForSelector()
. Remove the receiver prefix.Apply this diff:
RuleDiagnostic::new( rule_category!(), node.range(), markup! { - "Unexpected use of "<Emphasis>"page.waitForSelector()"</Emphasis>"." + "Unexpected use of "<Emphasis>"waitForSelector()"</Emphasis>"." }, ) .note(markup! { - "Use locator-based "<Emphasis>"page.locator()"</Emphasis>" or "<Emphasis>"page.getByRole()"</Emphasis>" APIs instead." + "Use locator-based "<Emphasis>"locator()"</Emphasis>" or "<Emphasis>"getByRole()"</Emphasis>" APIs instead." })crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
108-129
: Generalise diagnostic notes.The notes hardcode
page.
which is incorrect for other receivers. Remove the receiver prefix to make guidance applicable to any Playwright actor.Apply this diff:
.note(markup! { - "Element handles like "<Emphasis>"page."{{state_text}}"()"</Emphasis>" are discouraged." + "Element handles like "<Emphasis>{{state_text}}"()"</Emphasis>" are discouraged." }) .note(markup! { - "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." })
🧹 Nitpick comments (8)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js (1)
1-4
: Good invalid fixture forwaitForTimeout
.Covers the canonical misuse. For extra bite, consider a sibling case using aliases or other targets:
- const p = page; await p.waitForTimeout(1000)
- await frame.waitForTimeout(1000)
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js (1)
1-1
: Forceful, in the right way.Nice invalid for
{ force: true }
on a locator click. If not elsewhere, add twins for:
- await page.click('button', { force: true })
- await page.locator('btn').click({ force: !!1 }) // truthy variant
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js (1)
1-1
: Crisp “useless await” example.getByRole returns a Locator; awaiting it should be flagged. Consider adding a guard case elsewhere to ensure no false positives on chains like
await page.getByRole('button').click()
(await applies to click, not the locator creation).crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js (1)
1-3
: Solid valid samples.These ensure we don’t penalise synchronous locator retrieval. Optional: add an assignment form to widen coverage:
- const btn = page.getByRole('button');
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js (1)
1-1
: Right on target for ElementHandle APIs.Good catch on
$$
. To fully mirror eslint-plugin-playwright parity, consider siblings for:
- const el = await page.$('#id')
- const kids = await handle.$$('.child')
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs (1)
70-96
: Broaden detection: returns/generators andtest.describe.parallel/serial
.
- Add a check that the callback body contains no
return
statements.- Treat generator functions (
function*
) as invalid.- Recognise
test.describe.parallel(...)
/test.describe.serial(...)
(callee chain where final member isn’tdescribe
but the parent is).Happy to sketch these out if you want this in the first batch.
Also applies to: 102-128
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js (1)
1-2
: Add one more invalid forframe.waitForNavigation()
.Helps prove the rule isn’t page‑only (and guards against regressions). Happy to add it if you like.
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (1)
74-101
: Scope to Playwright receivers to avoid false positives.Limit matches to
page
/frame
/*Page
/*Frame
or locator/getBy* chains.@@ - // Check the arguments for { force: true } + // Narrow to Playwright receivers to avoid false positives + let object = member_expr.object().ok()?; + if !is_playwright_receiver(&object) { + return None; + } + + // Check the arguments for { force: true } let args = call_expr.arguments().ok()?; @@ None } @@ +fn is_playwright_receiver(expr: &AnyJsExpression) -> bool { + match expr { + AnyJsExpression::JsIdentifierExpression(id) => { + let t = id.name().ok()?.value_token().ok()?.text_trimmed(); + t == "page" || t == "frame" || t.ends_with("Page") || t.ends_with("Frame") + } + AnyJsExpression::JsStaticMemberExpression(member) => { + let t = member.member().ok()?.as_js_name()?.value_token().ok()?.text_trimmed(); + t == "page" || t == "frame" || t.ends_with("Page") || t.ends_with("Frame") + } + AnyJsExpression::JsCallExpression(call) => { + // e.g. page.locator(...).click(...) + let callee = call.callee().ok()?; + let m = JsStaticMemberExpression::cast_ref(callee.syntax())?; + let name = m.member().ok()?.as_js_name()?.value_token().ok()?.text_trimmed(); + matches!(name.as_str(), "locator" | "getByRole" | "getByText" | "getByLabel" | "getByTitle" | "getByAltText" | "getByPlaceholder" | "getByTestId") + } + _ => false, + } +}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (57)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
is excluded by!**/migrate/eslint_any_rule_to_biome.rs
and included by**
crates/biome_configuration/src/analyzer/linter/rules.rs
is excluded by!**/rules.rs
and included by**
crates/biome_diagnostics_categories/src/categories.rs
is excluded by!**/categories.rs
and included by**
crates/biome_js_analyze/src/lint/nursery.rs
is excluded by!**/nursery.rs
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/non-async-context.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js.snap
is excluded by!**/*.snap
and included by**
packages/@biomejs/backend-jsonrpc/src/workspace.ts
is excluded by!**/backend-jsonrpc/src/workspace.ts
and included by**
packages/@biomejs/biome/configuration_schema.json
is excluded by!**/configuration_schema.json
and included by**
📒 Files selected for processing (79)
.changeset/common-lizards-sniff.md
(1 hunks)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_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_j F00 s_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)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_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)
🚧 Files skipped from review as they are similar to previous changes (46)
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval.js
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/module-level.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/wait-for-load-state.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/valid/locators.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/valid/click.js
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrigh FCC0 tAwait/invalid/non-async-context.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/fill.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/other-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/invalid/goto.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/valid/correct.js
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/promise-all-not-awaited.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/simple.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-sync.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/valid/alternatives.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/test-skip.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/valid/other-methods.js
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/awaited.js
- crates/biome_rule_options/src/no_playwright_valid_describe_callback.rs
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/locator.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/valid/locator.js
- crates/biome_rule_options/src/no_playwright_useless_await.rs
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/invalid/eval-all.js
- crates/biome_rule_options/src/no_playwright_wait_for_selector.rs
- crates/biome_js_analyze/src/lint/nursery/no_playwright_skipped_test.rs
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/test-only.js
- crates/biome_analyze/src/rule.rs
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightSkippedTest/invalid/describe-skip.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/simple.js
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-async-matcher.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/page-frame.js
- crates/biome_rule_options/src/lib.rs
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/has-params.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-parallel-only.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/async.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/in-test.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/with-options.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightEval/valid/locator-evaluate.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightFocusedTest/invalid/describe-only.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/pause-function.js
- crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_timeout.rs
- crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/returned.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/async-methods.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js
- crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/frame.js
- crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
🧰 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/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js
crates/biome_rule_options/src/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_rule_options/src/no_playwright_skipped_test.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_rule_options/src/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/noPlaywrightElementHandle/invalid/dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/test-step.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/getByRole.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightElementHandle/invalid/dollar-dollar.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/invalid/expect-poll.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForNavigation/invalid/simple.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightNetworkidle/valid/load.js
crates/biome_js_analyze/tests/specs/nursery/missingPlaywrightAwait/valid/promise-all.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/sync-no-await.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightForceOption/invalid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForSelector/invalid/with-state.js
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs
: Format Rust files before committing (e.g., viajust f
which formats Rust)
Document rules, assists, and options with inline rustdoc in source
Files:
crates/biome_rule_options/src/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_rule_options/src/no_playwright_skipped_test.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_navigation.rs
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_rule_options/src/no_playwright_wait_for_navigation.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
🧠 Learnings (5)
📚 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_force_option.rs
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs
crates/biome_rule_options/src/no_playwright_eval.rs
crates/biome_rule_options/src/no_playwright_networkidle.rs
crates/biome_rule_options/src/no_playwright_page_pause.rs
crates/biome_rule_options/src/no_playwright_skipped_test.rs
crates/biome_rule_options/src/no_playwright_element_handle.rs
crates/biome_rule_options/src/missing_playwright_await.rs
crates/biome_rule_options/src/no_playwright_wait_for_navigation.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_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs
📚 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
📚 Learning: 2025-10-15T09:19:01.347Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:19:01.347Z
Learning: Applies to .changeset/*.md : End every sentence in a changeset with a period
Applied to files:
.changeset/common-lizards-sniff.md
📚 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 : If a lint rule is ported or inspired by another linter, add sources metadata in declare_lint_rule! with RuleSource (use .same() or .inspired())
Applied to files:
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs
🧬 Code graph analysis (19)
crates/biome_rule_options/src/no_playwright_force_option.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightForceOptionOptions
(8467-8467)
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
RuleDomain
(904-913)crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (2)
run
(63-106)diagnostic
(108-129)crates/biome_rowan/src/ast/mod.rs (1)
cast_ref
(142-151)
crates/biome_rule_options/src/no_playwright_wait_for_timeout.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightWaitForTimeoutOptions
(8475-8475)
crates/biome_js_analyze/src/lint/nursery/no_playwright_eval.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_element_handle.rs (2)
run
(63-106)diagnostic
(108-129)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
(8465-8465)
crates/biome_js_analyze/src/lint/nursery/no_playwright_force_option.rs (3)
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_rowan/src/ast/mod.rs (1)
cast_ref
(142-151)
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs (2)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (3)
FixKind
(8167-8167)RuleDomain
(904-913)Applicability
(9964-9964)crates/biome_analyze/src/rule.rs (12)
language
(592-595)sources
(587-590)same
(247-252)recommended
(572-575)fix_kind
(582-585)domains
(602-605)run
(1033-1033)diagnostic
(1120-1122)new
(552-570)new
(1316-1327)new
(1441-1453)action
(1128-1134)
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (3)
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_rowan/src/ast/mod.rs (1)
cast_ref
(142-151)
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 (11)
language
(592-595)sources
(587-590)same
(247-252)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_rule_options/src/no_playwright_networkidle.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightNetworkidleOptions
(8468-8468)
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (3)
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_eval.rs (2)
run
(52-94)diagnostic
(96-116)
crates/biome_rule_options/src/no_playwright_page_pause.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightPagePauseOptions
(8469-8469)
crates/biome_rule_options/src/no_playwright_skipped_test.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightSkippedTestOptions
(8470-8470)
crates/biome_rule_options/src/no_playwright_element_handle.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightElementHandleOptions
(8464-8464)
crates/biome_js_analyze/src/lint/nursery/missing_playwright_await.rs (3)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (3)
FixKind
(8167-8167)RuleDomain
(904-913)Applicability
(9964-9964)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_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_wait_for_navigation.rs (4)
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-106)diagnostic
(108-129)crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs (2)
run
(55-99)diagnostic
(101-118)crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (2)
run
(58-95)diagnostic
(97-114)
crates/biome_rule_options/src/missing_playwright_await.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
MissingPlaywrightAwaitOptions
(8431-8431)
crates/biome_rule_options/src/no_playwright_wait_for_navigation.rs (1)
packages/@biomejs/backend-jsonrpc/src/workspace.ts (1)
NoPlaywrightWaitForNavigationOptions
(8473-8473)
🪛 LanguageTool
.changeset/common-lizards-sniff.md
[uncategorized] ~9-~9: Loose punctuation mark.
Context: .../linter/rules/missing-playwright-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: ...inter/rules/no-playwright-skipped-test/): Disallow skipped tests with `test.skip(...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nter/rules/no-playwright-useless-await/): Disallow unnecessary await
on synchro...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~17-~17: Loose punctuation mark.
Context: .../no-playwright-valid-describe-callback/): Validate describe callback signatures a...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~18-~18: Loose punctuation mark.
Context: ...ules/no-playwright-wait-for-navigation/): Prefer modern navigation APIs over depr...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~19-~19: Loose punctuation mark.
Context: .../rules/no-playwright-wait-for-selector/): Prefer locators over deprecated `waitFo...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...r/rules/no-playwright-wait-for-timeout/): Disallow hard-coded timeouts with `wait...
(UNLIKELY_OPENING_PUNCTUATION)
🔇 Additional comments (8)
crates/biome_js_analyze/src/lint/suspicious/no_focused_tests.rs (1)
53-53
: Rule name is correct.The eslint-plugin-playwright rule is indeed configured as
"playwright/no-focused-test"
(singular), so the code change is accurate. The naming difference from the Jest and Vitest sources is intentional.crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/valid/click.js (1)
1-5
: Valid test case looks good.This correctly demonstrates Playwright code that should pass the
noPlaywrightPagePause
rule—nopage.pause()
call present, standard async/await pattern, proper use of page methods.Note: While
page.waitForSelector()
may be flagged by other Playwright rules in this batch, that's intentional for this specific test fixture..changeset/common-lizards-sniff.md (1)
1-22
: Changeset looks solid.The documentation is clear, comprehensive, and follows the project's conventions. The LanguageTool hints about punctuation are false positives from the markdown link syntax.
crates/biome_rule_options/src/no_playwright_networkidle.rs (1)
1-6
: LGTM!Options struct follows the coding guidelines precisely: correct derives, serde attributes, and schema feature gating.
crates/biome_js_analyze/src/lint/nursery/no_playwright_networkidle.rs (2)
107-124
: LGTM!Diagnostic messages are clear and avoid hardcoded receiver names, making them applicable to any receiver.
127-150
: LGTM!Helper function correctly identifies
waitUntil: "networkidle"
in object expressions.crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs (1)
58-95
: LGTM!Proper receiver guard in place to avoid false positives on non-Playwright objects.
crates/biome_js_analyze/src/lint/nursery/no_playwright_element_handle.rs (1)
63-106
: LGTM!Proper receiver validation and correct state capture for the diagnostic.
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
Show resolved
Hide resolved
…pdate tests This commit improves the `missingPlaywrightAwait` lint rule by adding checks for Promise combinators and ensuring that they are awaited when necessary. The logic now correctly identifies when a Promise combinator is not awaited and suggests adding an `await` to preserve concurrency semantics. Additionally, the rule's test cases have been updated to reflect these changes, including new diagnostics for invalid usages of `expect.poll` and `Promise.all`. Obsolete test snapshots related to focused tests have also been removed, streamlining the test suite. These enhancements aim to improve linting accuracy and maintainability for Playwright-specific code.
This commit updates the indices of various lint rules in the `rules.rs` file to ensure proper alignment with the intended rule group structure. The changes involve shifting the indices for multiple rules related to Playwright and Vue, correcting their positions to maintain consistency in rule filtering. This fix aims to enhance the accuracy of the linter's functionality and ensure that all rules are correctly referenced.
…te RuleDomain This commit removes the `noPlaywrightFocusedTest` rule and its associated configurations from the JSON schema and TypeScript definitions, streamlining the linting rules for Playwright. Additionally, the `RuleDomain` type has been updated to include `playwright`, enhancing the categorization of Playwright-specific rules. These changes aim to improve the clarity and maintainability of the codebase.
…Text for state This commit modifies several Playwright lint rules to utilize `TokenText` as the state type instead of a unit type. The changes enhance the diagnostic messages by including the specific receiver in the output, improving clarity for users. The affected rules include `noPlaywrightPagePause`, `noPlaywrightWaitForNavigation`, `noPlaywrightWaitForSelector`, and `noPlaywrightWaitForTimeout`. Additionally, the `noPlaywrightValidDescribeCallback` rule has been updated to handle new invalid reasons for missing or non-function callbacks. These improvements aim to provide more informative feedback during linting.
…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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_modifier
walks 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.rs
and no_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 like is_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() > 0
whilst 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 see TokenText
being 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
, and no_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 run
method 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.rs
and no_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.
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.rs
andno_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() > 0
whilst 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 seeTokenText
being 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
run
method 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.rs
andno_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.rs
is excluded by!**/rules.rs
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightPagePause/invalid/frame.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/valid/expect-with-async-modifiers.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/not-function.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/in-test.js.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightWaitForTimeout/invalid/simple.js.snap
is excluded by!**/*.snap
and included by**
packages/@biomejs/backend-jsonrpc/src/workspace.ts
is excluded by!**/backend-jsonrpc/src/workspace.ts
and included by**
packages/@biomejs/biome/configuration_schema.json
is excluded by!**/configuration_schema.json
and 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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js
crates/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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js
crates/biome_js_analyze/src/lint/nursery/no_playwright_valid_describe_callback.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightValidDescribeCallback/invalid/missing-callback.js
crates/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.js
crates/biome_js_analyze/tests/specs/nursery/noPlaywrightUselessAwait/invalid/expect-mixed-chains.js
crates/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 f
which 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.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_useless_await.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_wait_for_selector.rs
crates/biome_js_analyze/src/lint/nursery/no_playwright_page_pause.rs
crates/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
NotFunction
variant 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
TokenText
which 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
TokenText
as 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()
) whereawait
is 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 returnstrue
from async modifier checkThe valid test cases in
expect-with-async-modifiers.js
should 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
await
usage with synchronous expect matchers, including theexpect.soft
variant. 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rules are looking much more clean now. But it doesn't look like the implementations are flagging all the invalid cases.
/// | ||
pub MissingPlaywrightAwait { | ||
version: "next", | ||
name: "missingPlaywrightAwait", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rule name doesn't follow our naming convention. Rules must begin with either use
or no
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think "usePlaywrightAwait" sounds weird? Maybe it's just me :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could also be noPlaywrightMissingAwait
, i do think having "missing" in there is useful
/// | ||
pub NoPlaywrightSkippedTest { | ||
version: "next", | ||
name: "noPlaywrightSkippedTest", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, I must have missed this in my last review. We already have noSkippedTests
.
/// | ||
pub NoPlaywrightValidDescribeCallback { | ||
version: "next", | ||
name: "noPlaywrightValidDescribeCallback", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name should be either:
usePlaywrightValidDescribeCallback
noPlaywrightInvalidDescribeCallback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid test files must always start with the comment:
/* should generate diagnostics */
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly, all valid test files should start with:
/* should not generate diagnostics */
# Input | ||
```js | ||
// Test bracket notation for element handles | ||
const handle1 = await page["$"]("button"); | ||
|
||
const handle2 = await page[`$`]("button"); | ||
|
||
const handles1 = await page["$$"]("a"); | ||
|
||
const handles2 = await page[`$$`]("a"); | ||
|
||
await this.page["$"]("input"); | ||
|
||
await this.page[`$$`]("div"); | ||
|
||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
having those comments would have caught this invalid case having no diagnostics.
.note(markup! { | ||
"Add "<Emphasis>"await"</Emphasis>" before the test.step call or return the promise." | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a rule has an action, we should put the "how to fix it" part in the action's message instead.
1 1 │ test('example', async ({ page }) => { | ||
2 │ - ····expect(page.locator('body')).toBeVisible(); | ||
2 │ + ····await | ||
3 │ + ····expect(page.locator('body')).toBeVisible(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we try to have our fixes match what the formatter would output (on a best effort basis, sometimes it's not reasonably possible). The await
should be on the same line as the expect
.
markup! { | ||
"Unexpected use of element handles." | ||
}, | ||
) | ||
.note(markup! { | ||
"Element handles like "<Emphasis>"page."{{state_text}}"()"</Emphasis>" are discouraged." | ||
}) | ||
.note(markup! { | ||
"Use "<Emphasis>"page.locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." | ||
}) | ||
.note(markup! { | ||
"Locators auto-wait and are more reliable than element handles." | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
markup! { | |
"Unexpected use of element handles." | |
}, | |
) | |
.note(markup! { | |
"Element handles like "<Emphasis>"page."{{state_text}}"()"</Emphasis>" are discouraged." | |
}) | |
.note(markup! { | |
"Use "<Emphasis>"page.locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." | |
}) | |
.note(markup! { | |
"Locators auto-wait and are more reliable than element handles." | |
}), | |
markup! { | |
"Element handles like "<Emphasis>"page."{{state_text}}"()"</Emphasis>" are discouraged." | |
}, | |
) | |
.note(markup! { | |
"Use "<Emphasis>"page.locator()"</Emphasis>" or other locator methods like "<Emphasis>"getByRole()"</Emphasis>" instead." | |
}) | |
.note(markup! { | |
"Locators auto-wait and are more reliable than element handles." | |
}), |
sources: &[ | ||
RuleSource::EslintJest("no-focused-tests").inspired(), | ||
RuleSource::EslintVitest("no-focused-tests").inspired(), | ||
RuleSource::EslintPlaywright("no-focused-test").same(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen this format used in other tests:
test.describe.only(() => ...)
Does this rule cover that? There should be some test we can point to in order to confirm.
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
missingPlaywrightAwait
- Rule - TestnoPlaywrightElementHandle
- Rule - TestnoPlaywrightEval
- Rule - Testpage.$eval
andpage.$$eval
are discouraged, uselocator.evaluate
orlocator.evaluateAll
instead.noPlaywrightForceOption
- Rule - Test{ force: true }
option.noPlaywrightNetworkidle
- Rule - TestnoPlaywrightPagePause
- Rule - TestnoPlaywrightSkippedTest
- Rule - Test.skip()
skip test annotation.noPlaywrightUselessAwait
- Rule - TestvalidPlaywrightDescribeCallback
- Rule - Testdescribe()
callback.noPlaywrightWaitForSelector
- 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!)