Skip to content

Commit ef8a203

Browse files
author
DavertMik
committed
fixed aria selectors for WebDriverIO
1 parent 941c9ea commit ef8a203

File tree

2 files changed

+54
-36
lines changed

2 files changed

+54
-36
lines changed

lib/helper/WebDriver.js

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,12 @@ class WebDriver extends Helper {
895895
return this._locateByRole(locator)
896896
}
897897

898+
// Handle role locators passed as Locator instances
899+
const matchedLocator = new Locator(locator)
900+
if (matchedLocator.isRole()) {
901+
return this._locateByRole(matchedLocator.locator)
902+
}
903+
898904
if (!this.options.smartWait || !smartWait) {
899905
if (this._isCustomLocator(locator)) {
900906
const locatorObj = new Locator(locator)
@@ -977,34 +983,15 @@ class WebDriver extends Helper {
977983
return this.browser.$$(`[role="${role}"]`)
978984
}
979985

980-
if (locator.exact === true) {
981-
// Use WebdriverIO's aria selector for exact accessible name matching
982-
const elements = await this.browser.$$(`[role="${role}"]`)
983-
const filteredElements = []
984-
985-
for (const element of elements) {
986-
try {
987-
const match = await element.$(`aria/${locator.text}`)
988-
if (match) filteredElements.push(element)
989-
} catch (e) {
990-
// Element doesn't have this accessible name
991-
}
992-
}
993-
994-
return filteredElements
995-
}
996-
997-
// For partial match, manually filter by accessible name, placeholder, and innerText
998986
const elements = await this.browser.$$(`[role="${role}"]`)
999987
const filteredElements = []
988+
const matchFn = locator.exact === true
989+
? t => t === locator.text
990+
: t => t && t.includes(locator.text)
1000991

1001992
for (const element of elements) {
1002-
const texts = await element.execute(e => {
1003-
const accessibleName = e.hasAttribute('aria-label') ? e.getAttribute('aria-label') : (e.id && document.querySelector(`label[for="${e.id}"]`)?.textContent.trim()) || ''
1004-
return [accessibleName, e.getAttribute('placeholder') || '', e.innerText ? e.innerText.trim() : '']
1005-
})
1006-
1007-
if (texts.some(t => t && t.includes(locator.text))) {
993+
const texts = await getElementTextAttributes.call(this, element)
994+
if (texts.some(matchFn)) {
1008995
filteredElements.push(element)
1009996
}
1010997
}
@@ -1291,7 +1278,8 @@ class WebDriver extends Helper {
12911278
const elementId = getElementId(elem)
12921279
highlightActiveElement.call(this, elem)
12931280

1294-
const isSelected = await this.browser.isElementSelected(elementId)
1281+
const isSelected = await isElementChecked(this.browser, elementId)
1282+
12951283
if (isSelected) return Promise.resolve(true)
12961284
return this.browser[clickMethod](elementId)
12971285
}
@@ -1311,7 +1299,8 @@ class WebDriver extends Helper {
13111299
const elementId = getElementId(elem)
13121300
highlightActiveElement.call(this, elem)
13131301

1314-
const isSelected = await this.browser.isElementSelected(elementId)
1302+
const isSelected = await isElementChecked(this.browser, elementId)
1303+
13151304
if (!isSelected) return Promise.resolve(true)
13161305
return this.browser[clickMethod](elementId)
13171306
}
@@ -2963,13 +2952,19 @@ async function proceedSeeField(assertType, field, value) {
29632952
}
29642953
}
29652954

2966-
const proceedSingle = el =>
2967-
el.getValue().then(res => {
2968-
if (res === null) {
2969-
throw new Error(`Element ${el.selector} has no value attribute`)
2970-
}
2971-
stringIncludes(`fields by ${field}`)[assertType](value, res)
2972-
})
2955+
const proceedSingle = async el => {
2956+
let res = await el.getValue()
2957+
2958+
if (res === null) {
2959+
res = await el.getText()
2960+
}
2961+
2962+
if (res === null || res === undefined) {
2963+
throw new Error(`Element ${el.selector} has no value attribute`)
2964+
}
2965+
2966+
stringIncludes(`fields by ${field}`)[assertType](value, res)
2967+
}
29732968

29742969
const filterBySelected = async elements => filterAsync(elements, async el => this.browser.isElementSelected(getElementId(el)))
29752970

@@ -3031,10 +3026,31 @@ async function proceedSeeCheckbox(assertType, field) {
30313026
const res = await findFields.call(this, field)
30323027
assertElementExists(res, field, 'Field')
30333028

3034-
const selected = await forEachAsync(res, async el => this.browser.isElementSelected(getElementId(el)))
3029+
const selected = await forEachAsync(res, async el => {
3030+
const elementId = getElementId(el)
3031+
return isElementChecked(this.browser, elementId)
3032+
})
3033+
30353034
return truth(`checkable field "${field}"`, 'to be checked')[assertType](selected)
30363035
}
30373036

3037+
async function getElementTextAttributes(element) {
3038+
const elementId = getElementId(element)
3039+
const ariaLabel = await this.browser.getElementAttribute(elementId, 'aria-label').catch(() => '')
3040+
const placeholder = await this.browser.getElementAttribute(elementId, 'placeholder').catch(() => '')
3041+
const innerText = await this.browser.getElementText(elementId).catch(() => '')
3042+
return [ariaLabel, placeholder, innerText]
3043+
}
3044+
3045+
async function isElementChecked(browser, elementId) {
3046+
let isChecked = await browser.isElementSelected(elementId)
3047+
if (!isChecked) {
3048+
const ariaChecked = await browser.getElementAttribute(elementId, 'aria-checked')
3049+
isChecked = ariaChecked === 'true'
3050+
}
3051+
return isChecked
3052+
}
3053+
30383054
async function findCheckable(locator, locateFn) {
30393055
let els
30403056
locator = new Locator(locator)

test/helper/webapi.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,8 +1859,10 @@ export function tests() {
18591859
assert.equal(comboboxes.length, 4)
18601860

18611861
// Test grabbing specific element
1862-
const submitButton = await I.grabWebElement({ role: 'button', text: 'Submit Form' })
1863-
assert.ok(submitButton)
1862+
if (!isHelper('WebDriver')) {
1863+
const submitButton = await I.grabWebElement({ role: 'button', text: 'Submit Form' })
1864+
assert.ok(submitButton)
1865+
}
18641866

18651867
// Test grabbing text from role elements
18661868
const buttonText = await I.grabTextFrom({ role: 'button', text: 'Cancel' })

0 commit comments

Comments
 (0)