Skip to content

feat(locator): add withClass, negation, and raw-predicate helpers#5524

Open
DavertMik wants to merge 2 commits into4.xfrom
feat/locator-builder-class-negation
Open

feat(locator): add withClass, negation, and raw-predicate helpers#5524
DavertMik wants to merge 2 commits into4.xfrom
feat/locator-builder-class-negation

Conversation

@DavertMik
Copy link
Copy Markdown
Contributor

Summary

  • Adds a richer fluent DSL on locate() so complex XPath can be written as readable JavaScript
  • New positive/negative filters: withClass(...classes) (variadic, word-exact), withoutClass, withoutText, withoutAttr, withoutChild, withoutDescendant
  • New raw-predicate escape hatches: and(expr) / andNot(expr) for cases the DSL doesn't cover
  • Documents previously undocumented methods: or, withAttrStartsWith, withAttrEndsWith, withAttrContains, as
  • withClassAttr is kept for backward compatibility and marked @deprecated — prefer withClass (word-exact, matches CSS .foo semantics) or withAttrContains('class', …) for substring matching

Motivation

Verbose XPath like

//*[self::button
    and contains(@class,"red-btn")
    and contains(@class,"btn-text-and-icon")
    and contains(@class,"btn-lg")
    and contains(@class,"btn-selected")
    and normalize-space(.)="Button selected"
    and not(.//svg)]

now becomes:

locate('button')
  .withClass('red-btn', 'btn-text-and-icon', 'btn-lg', 'btn-selected')
  .withText('Button selected')
  .withoutDescendant('svg')

Naming note — why withClass over withClassAttr

withClassAttr emits contains(@class, 'foo'), i.e. substring match, so withClassAttr('btn') unintentionally matches elements with class="btn-lg". withClass uses word-exact matching (same semantics as CSS .foo) and is variadic.

Test plan

  • npx mocha test/unit/locator_test.js — 59 passing, including 10 new tests covering each new method
  • Manual smoke with a CodeceptJS test run against a real page once reviewers get a chance
  • Confirm docs render correctly on the site build

🤖 Generated with Claude Code

…builder DSL

Adds withClass (variadic, word-exact), withoutClass, withoutText,
withoutAttr, withoutChild, withoutDescendant, and raw and()/andNot()
escape hatches. Lets users express complex XPath like
`not(.//svg)` and multi-class matches through the fluent builder
instead of writing raw XPath. Also documents previously undocumented
methods (or, withAttrStartsWith/EndsWith/Contains, as).

withClassAttr is kept for backward compatibility and marked
@deprecated in favor of withClass (word-exact) or
withAttrContains('class', …) for substring matching.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@DavertMik DavertMik requested a review from DenysKuchma April 17, 2026 21:37
…lass-negation

# Conflicts:
#	docs/locators.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant