Skip to content

Commit c3097db

Browse files
DavertMikclaude
andcommitted
fix: role locators now use getByRole() when wrapped in Locator object
handleRoleLocator used isRoleLocatorObject() which rejected Locator-wrapped role objects (checking !locator.type). This caused findClickable to fall through to a CSS [role="button"] selector, losing text/exact filters. Now uses new Locator(locator).isRole() to detect role locators regardless of whether they arrive as raw objects or Locator instances, ensuring Playwright's native getByRole() API is always used. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 59c7b25 commit c3097db

File tree

1 file changed

+17
-26
lines changed

1 file changed

+17
-26
lines changed

lib/helper/Playwright.js

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,15 +2700,12 @@ class Playwright extends Helper {
27002700
*
27012701
*/
27022702
async grabTextFrom(locator) {
2703-
// Handle role locators with text/exact options
2704-
if (isRoleLocatorObject(locator)) {
2705-
const elements = await handleRoleLocator(this.page, locator)
2706-
if (elements && elements.length > 0) {
2707-
const text = await elements[0].textContent()
2708-
assertElementExists(text, JSON.stringify(locator))
2709-
this.debugSection('Text', text)
2710-
return text
2711-
}
2703+
const roleElements = await handleRoleLocator(this.page, locator)
2704+
if (roleElements && roleElements.length > 0) {
2705+
const text = await roleElements[0].textContent()
2706+
assertElementExists(text, JSON.stringify(locator))
2707+
this.debugSection('Text', text)
2708+
return text
27122709
}
27132710

27142711
const locatorObj = new Locator(locator, 'css')
@@ -4194,25 +4191,22 @@ export function buildLocatorString(locator) {
41944191
return locator.simplify()
41954192
}
41964193

4197-
/**
4198-
* Checks if a locator is a role locator object (e.g., {role: 'button', text: 'Submit', exact: true})
4199-
*/
4200-
function isRoleLocatorObject(locator) {
4201-
return locator && typeof locator === 'object' && locator.role && !locator.type
4202-
}
4203-
42044194
/**
42054195
* Handles role locator objects by converting them to Playwright's getByRole() API
4196+
* Accepts both raw objects ({role: 'button', text: 'Submit'}) and Locator-wrapped role objects.
42064197
* Returns elements array if role locator, null otherwise
42074198
*/
42084199
async function handleRoleLocator(context, locator) {
4209-
if (!isRoleLocatorObject(locator)) return null
4200+
const loc = new Locator(locator)
4201+
if (!loc.isRole()) return null
42104202

4203+
const roleObj = loc.locator || {}
42114204
const options = {}
4212-
if (locator.text) options.name = locator.text
4213-
if (locator.exact !== undefined) options.exact = locator.exact
4205+
if (roleObj.text) options.name = roleObj.text
4206+
if (roleObj.name) options.name = roleObj.name
4207+
if (roleObj.exact !== undefined) options.exact = roleObj.exact
42144208

4215-
return context.getByRole(locator.role, Object.keys(options).length > 0 ? options : undefined).all()
4209+
return context.getByRole(roleObj.role, Object.keys(options).length > 0 ? options : undefined).all()
42164210
}
42174211

42184212
async function findByRole(context, locator) {
@@ -4426,12 +4420,9 @@ async function findFields(locator, context = null) {
44264420
? loc => findElements.call(this, contextEl, loc)
44274421
: loc => this._locate(loc)
44284422

4429-
// Handle role locators with text/exact options
4430-
if (isRoleLocatorObject(locator)) {
4431-
const matcher = contextEl || (await this.page)
4432-
const roleElements = await handleRoleLocator(matcher, locator)
4433-
if (roleElements) return roleElements
4434-
}
4423+
const matcher = contextEl || (await this.page)
4424+
const roleElements = await handleRoleLocator(matcher, locator)
4425+
if (roleElements) return roleElements
44354426

44364427
const matchedLocator = new Locator(locator)
44374428
if (!matchedLocator.isFuzzy()) {

0 commit comments

Comments
 (0)