@@ -1314,11 +1314,11 @@ class WebDriver extends Helper {
13141314
13151315 // Fuzzy: try combobox
13161316 this . debugSection ( 'SelectOption' , `Fuzzy: "${ matchedLocator . value } "` )
1317- let els = await this . _locateByRole ( { role : 'combobox' , name : matchedLocator . value } )
1317+ let els = await this . _locateByRole ( { role : 'combobox' , text : matchedLocator . value } )
13181318 if ( els ?. length ) return proceedSelectOption . call ( this , usingFirstElement ( els ) , option )
13191319
13201320 // Fuzzy: try listbox
1321- els = await this . _locateByRole ( { role : 'listbox' , name : matchedLocator . value } )
1321+ els = await this . _locateByRole ( { role : 'listbox' , text : matchedLocator . value } )
13221322 if ( els ?. length ) return proceedSelectOption . call ( this , usingFirstElement ( els ) , option )
13231323
13241324 // Fuzzy: try native select
@@ -3124,7 +3124,23 @@ async function getElementTextAttributes(element) {
31243124 const ariaLabel = await this . browser . getElementAttribute ( elementId , 'aria-label' ) . catch ( ( ) => '' )
31253125 const placeholder = await this . browser . getElementAttribute ( elementId , 'placeholder' ) . catch ( ( ) => '' )
31263126 const innerText = await this . browser . getElementText ( elementId ) . catch ( ( ) => '' )
3127- return [ ariaLabel , placeholder , innerText ]
3127+
3128+ // Handle aria-labelledby
3129+ const labelledBy = await this . browser . getElementAttribute ( elementId , 'aria-labelledby' ) . catch ( ( ) => '' )
3130+ let labelText = ''
3131+ if ( labelledBy ) {
3132+ try {
3133+ const labelId = labelledBy . split ( ' ' ) [ 0 ]
3134+ const labelEls = await this . browser . $$ ( `#${ labelId } ` )
3135+ if ( labelEls ?. length ) {
3136+ labelText = await this . browser . getElementText ( getElementId ( labelEls [ 0 ] ) ) . catch ( ( ) => '' )
3137+ }
3138+ } catch ( e ) {
3139+ // Ignore errors when resolving aria-labelledby
3140+ }
3141+ }
3142+
3143+ return [ ariaLabel , placeholder , innerText , labelText ]
31283144}
31293145
31303146async function isElementChecked ( browser , elementId ) {
@@ -3382,38 +3398,56 @@ async function proceedSelectOption(elem, option) {
33823398 highlightActiveElement . call ( this , elem )
33833399 const ariaOwns = await this . browser . getElementAttribute ( elementId , 'aria-owns' ) . catch ( ( ) => null )
33843400 const ariaControls = await this . browser . getElementAttribute ( elementId , 'aria-controls' ) . catch ( ( ) => null )
3401+ const ariaLabelledBy = await this . browser . getElementAttribute ( elementId , 'aria-labelledby' ) . catch ( ( ) => null )
33853402 await this . browser . elementClick ( elementId )
3386- await this . _waitForAction ( )
33873403
33883404 const listboxId = ariaOwns || ariaControls
33893405 let listbox = null
33903406 if ( listboxId ) {
33913407 const listboxEls = await this . browser . $$ ( `#${ listboxId } ` )
33923408 if ( listboxEls ?. length ) listbox = listboxEls [ 0 ]
33933409 }
3394- if ( ! listbox ) {
3395- const listboxEls = await this . _locateByRole ( { role : 'listbox' } )
3410+ if ( ! listbox && ariaLabelledBy ) {
3411+ // Find listbox with the same aria-labelledby
3412+ const listboxEls = await this . browser . $$ ( `[role="listbox"][aria-labelledby="${ ariaLabelledBy } "]` )
33963413 if ( listboxEls ?. length ) listbox = listboxEls [ 0 ]
33973414 }
3415+ if ( ! listbox ) {
3416+ // Fallback: find any listbox with the same label
3417+ const allListboxes = await this . browser . $$ ( `[role="listbox"]` )
3418+ for ( const lb of allListboxes ) {
3419+ const lbLabelledBy = await this . browser . getElementAttribute ( getElementId ( lb ) , 'aria-labelledby' ) . catch ( ( ) => '' )
3420+ if ( lbLabelledBy === ariaLabelledBy ) {
3421+ listbox = lb
3422+ break
3423+ }
3424+ }
3425+ }
33983426
33993427 if ( listbox ) {
34003428 const listboxElementId = getElementId ( listbox )
34013429 for ( const opt of options ) {
3402- const optEls = await this . _locateByRole ( { role : 'option ', text : opt } )
3430+ const optEls = await this . browser . findElementsFromElement ( listboxElementId , 'xpath ', `.//*[@role="option"]` )
34033431 if ( optEls ?. length ) {
3404- const optEl = optEls [ 0 ]
3405- this . debugSection ( 'SelectOption' , `Clicking: "${ opt } "` )
3406- highlightActiveElement . call ( this , optEl )
3407- await this . browser . elementClick ( getElementId ( optEl ) )
3432+ for ( const optEl of optEls ) {
3433+ const optElId = getElementId ( optEl )
3434+ const text = await this . browser . getElementText ( optElId ) . catch ( ( ) => '' )
3435+ if ( text && text . includes ( opt ) ) {
3436+ this . debugSection ( 'SelectOption' , `Clicking: "${ opt } "` )
3437+ highlightActiveElement . call ( this , optEl )
3438+ await this . browser . elementClick ( optElId )
3439+ break
3440+ }
3441+ }
34083442 }
34093443 }
34103444 }
3411- return this . _waitForAction ( )
3445+ return
34123446 }
34133447
34143448 if ( role === 'listbox' ) {
34153449 for ( const opt of options ) {
3416- const optEls = await this . browser . findElementsFromElement ( elementId , 'css ' , `[ role="option"]` )
3450+ const optEls = await this . browser . findElementsFromElement ( elementId , 'xpath ' , `.//*[@ role="option"]` )
34173451 if ( optEls ?. length ) {
34183452 for ( const optEl of optEls ) {
34193453 const optElId = getElementId ( optEl )
@@ -3427,7 +3461,7 @@ async function proceedSelectOption(elem, option) {
34273461 }
34283462 }
34293463 }
3430- return this . _waitForAction ( )
3464+ return
34313465 }
34323466
34333467 // Native <select> element
0 commit comments