Skip to content

fix(locator): prevent click(text, container) from matching the container itself#5532

Merged
DavertMik merged 1 commit into4.xfrom
fix/click-tablist-container-match
Apr 23, 2026
Merged

fix(locator): prevent click(text, container) from matching the container itself#5532
DavertMik merged 1 commit into4.xfrom
fix/click-tablist-container-match

Conversation

@DavertMik
Copy link
Copy Markdown
Contributor

Summary

  • Bug: I.click("Description", 'ul[role="tablist"]') clicked the <ul> itself instead of the intended <li role="tab">. Playwright landed the click on whatever child sat at the container's geometric center, so the wrong tab activated while the step still passed — a silent misleading failure.
  • Root cause: Locator.clickable.self used ./self::*[contains(normalize-space(string(.)), literal) …]. A container's concatenated string-value always contains every child's text, so the scope element itself matched.
  • Fix: narrow self to prefer the deepest descendant whose string-value contains the literal, and only match self when self is that deepest element (or when @value matches — preserves the <input value="…"> case).
  • Bonus: extend Locator.clickable.wide with ARIA widget roles (tab, link, menuitem, menuitemcheckbox, menuitemradio, option, treeitem) so clicks hit the semantic element directly rather than relying on bubble-up.

Shared with Puppeteer and WebDriver helpers — both consume Locator.clickable.self unchanged, so they inherit the fix.

Test plan

  • Unit suite: npm run test:unit597 passed, 0 failed (incl. 5 new clickable.self / clickable.wide xpath tests).
  • Playwright helper: npx mocha test/helper/Playwright_test.js --grep "#click"15/15 passing (9 pre-existing + #clickXY 3 + invisible 1 + 2 new regressions).
  • Puppeteer helper: npx mocha test/helper/Puppeteer_test.js --grep "#click"12/12 passing (shares Locator.clickable.self).
  • Full Playwright helper suite: 424 passed, 4 failing — the 4 failures are #makeApiRequest (network) and Video & Trace & HAR (Playwright tracing), both unrelated to the click/locator paths.
  • Reproduced the bug on this branch before applying the fix: the new #click - tablist regression test fails, confirming the reproduction.

Scenarios covered

  • Container with many text-bearing children (the tablist): click now lands on the correct tab — History, Description, Runs, Code template each verified via #selected-tab.
  • <a><span>Buy Chocolate Bar</span></a> clicked with 'a' as context: still works (handled first by getByRole('link'), self fallback never reached).
  • <div>Submit</div> and <input value="Submit"> with context-is-the-target: self branch still matches.
  • [role="tab"] / [role="menuitem"] directly matched by wide — semantic click target, no reliance on event bubbling.

🤖 Generated with Claude Code

…ner itself

`I.click("Description", 'ul[role="tablist"]')` was clicking the <ul> itself
instead of the intended <li role="tab">. The fallback xpath
`./self::*[contains(normalize-space(string(.)), literal)]` matched the scope
element whenever its concatenated string-value contained the literal — and a
container with text-bearing children (tab labels, menu items) always will.
Playwright then clicked the container's geometric center, landing on whatever
child sat there.

Fix: narrow `Locator.clickable.self` to prefer the deepest descendant whose
string-value contains the literal, and only match self when self *is* that
deepest element (or its @value matches, preserving the input case).

Also extend `Locator.clickable.wide` with ARIA widget roles so clicks hit
the semantic element directly rather than relying on bubble-up:
tab, link, menuitem (+ checkbox/radio variants), option, treeitem.

Tests:
- test/data/app/view/form/tablist.php — ember-like 5-tab fixture with
  a #selected-tab marker driven by click handlers.
- test/helper/Playwright_test.js — regression scenario clicks History →
  Description → Runs → Code template against ul[role="tablist"] and
  asserts the correct tab fired. Plus an explicit <a>+span case scoped
  by tag 'a' to document that behavior.
- test/unit/locator_test.js — three xpath-level tests for clickable.self
  (tablist narrowest-match, <div>Submit</div> self-match, <input value>
  self-match) and two for clickable.wide (role="tab", role="menuitem").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@DavertMik DavertMik merged commit 6ca126f into 4.x Apr 23, 2026
10 checks passed
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