fix(locator): prevent click(text, container) from matching the container itself#5532
Merged
fix(locator): prevent click(text, container) from matching the container itself#5532
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
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.Locator.clickable.selfused./self::*[contains(normalize-space(string(.)), literal) …]. A container's concatenated string-value always contains every child's text, so the scope element itself matched.selfto prefer the deepest descendant whose string-value contains the literal, and only match self when self is that deepest element (or when@valuematches — preserves the<input value="…">case).Locator.clickable.widewith 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.selfunchanged, so they inherit the fix.Test plan
npm run test:unit— 597 passed, 0 failed (incl. 5 newclickable.self/clickable.widexpath tests).npx mocha test/helper/Playwright_test.js --grep "#click"— 15/15 passing (9 pre-existing +#clickXY3 + invisible 1 + 2 new regressions).npx mocha test/helper/Puppeteer_test.js --grep "#click"— 12/12 passing (sharesLocator.clickable.self).#makeApiRequest(network) andVideo & Trace & HAR(Playwright tracing), both unrelated to the click/locator paths.#click - tablist regressiontest fails, confirming the reproduction.Scenarios covered
History,Description,Runs,Code templateeach verified via#selected-tab.<a><span>Buy Chocolate Bar</span></a>clicked with'a'as context: still works (handled first bygetByRole('link'),selffallback never reached).<div>Submit</div>and<input value="Submit">with context-is-the-target:selfbranch still matches.[role="tab"]/[role="menuitem"]directly matched bywide— semantic click target, no reliance on event bubbling.🤖 Generated with Claude Code