@@ -113,7 +113,7 @@ export const getElementFromResponse = (res?: ElementReference) => {
113113 return null
114114}
115115
116- function sanitizeCSS ( value ?: string ) {
116+ function sanitizeCSS ( value ?: string ) {
117117 /* istanbul ignore next */
118118 if ( ! value ) {
119119 return value
@@ -128,7 +128,7 @@ function sanitizeCSS (value?: string) {
128128 * @param {string } cssProperty name of css property to parse
129129 * @return {object } parsed css property
130130 */
131- export function parseCSS ( cssPropertyValue : string , cssProperty ?: string ) {
131+ export function parseCSS ( cssPropertyValue : string , cssProperty ?: string ) {
132132 const parsedValue : ParsedCSSValue = {
133133 property : cssProperty ,
134134 value : cssPropertyValue . toLowerCase ( ) . trim ( ) ,
@@ -185,7 +185,7 @@ export function parseCSS (cssPropertyValue: string, cssProperty?: string) {
185185 * @param {string } value text
186186 * @return {Array } set of characters or unicode symbols
187187 */
188- export function checkUnicode ( value : string ) {
188+ export function checkUnicode ( value : string ) {
189189 /**
190190 * "Ctrl" key is specially handled based on OS in action class
191191 */
@@ -203,7 +203,7 @@ export function checkUnicode (value: string) {
203203 return [ UNICODE_CHARACTERS [ value as keyof typeof UNICODE_CHARACTERS ] ]
204204}
205205
206- function fetchElementByJSFunction (
206+ function fetchElementByJSFunction (
207207 selector : ElementFunction ,
208208 scope : WebdriverIO . Browser | WebdriverIO . Element ,
209209 referenceId ?: string
@@ -225,15 +225,15 @@ function fetchElementByJSFunction (
225225 return getBrowserObject ( scope ) . executeScript ( `return (${ script } ).apply(null, arguments)` , args )
226226}
227227
228- export function isElement ( o : Selector ) {
228+ export function isElement ( o : Selector ) {
229229 return (
230230 typeof HTMLElement === 'object'
231231 ? o instanceof HTMLElement
232- : o && typeof o === 'object' && o !== null && ( o as HTMLElement ) . nodeType === 1 && typeof ( o as HTMLElement ) . nodeName === 'string'
232+ : o && typeof o === 'object' && o !== null && ( o as HTMLElement ) . nodeType === 1 && typeof ( o as HTMLElement ) . nodeName === 'string'
233233 )
234234}
235235
236- export function isStaleElementError ( err : Error ) {
236+ export function isStaleElementError ( err : Error ) {
237237 return (
238238 // Chrome
239239 err . message . includes ( 'stale element reference' ) ||
@@ -255,7 +255,7 @@ export function isStaleElementError (err: Error) {
255255 * @param shadowRootId shadow root id that was inspected
256256 * @returns a function to handle the result of a shadow root inspection
257257 */
258- export function elementPromiseHandler < T extends object > ( handle : string , shadowRootManager : ShadowRootManager , shadowRootId ?: string ) {
258+ export function elementPromiseHandler < T extends object > ( handle : string , shadowRootManager : ShadowRootManager , shadowRootId ?: string ) {
259259 return ( el : T | Error ) => {
260260 const errorString = 'error' in el && typeof el . error === 'string'
261261 ? el . error
@@ -276,7 +276,7 @@ export function elementPromiseHandler <T extends object>(handle: string, shadowR
276276 }
277277}
278278
279- export function transformClassicToBidiSelector ( using: string , value : string) : remote . BrowsingContextCssLocator | remote . BrowsingContextXPathLocator | remote . BrowsingContextInnerTextLocator {
279+ export function transformClassicToBidiSelector ( using: string , value : string) : remote . BrowsingContextCssLocator | remote . BrowsingContextXPathLocator | remote . BrowsingContextInnerTextLocator {
280280 if ( using = == 'css selector' || using = == 'tag name' ) {
281281 return { type : 'css' , value }
282282 }
@@ -317,6 +317,16 @@ export async function findDeepElement(
317317 (this as WebdriverIO.Element).elementId
318318 )
319319 const { using, value } = findStrategy(selector as string, this.isW3C, this.isMobile)
320+
321+ /**
322+ * if we are using a relative xpath selector and we have a parent element
323+ * we need to fall back to the regular WebDriver Classic command as BiDi
324+ * does not support relative xpath selectors with a start node
325+ */
326+ if (using === 'xpath' && (value.startsWith('./') || value.startsWith('..')) && (this as WebdriverIO.Element).elementId) {
327+ return this.findElementFromElement((this as WebdriverIO.Element).elementId, using, value)
328+ }
329+
320330 const locator = transformClassicToBidiSelector(using, value)
321331
322332 /**
@@ -383,6 +393,16 @@ export async function findDeepElements(
383393 (this as WebdriverIO.Element).elementId
384394 )
385395 const { using, value } = findStrategy(selector as string, this.isW3C, this.isMobile)
396+
397+ /**
398+ * if we are using a relative xpath selector and we have a parent element
399+ * we need to fall back to the regular WebDriver Classic command as BiDi
400+ * does not support relative xpath selectors with a start node
401+ */
402+ if (using === 'xpath' && (value.startsWith('./') || value.startsWith('..')) && (this as WebdriverIO.Element).elementId) {
403+ return this.findElementsFromElement((this as WebdriverIO.Element).elementId, using, value)
404+ }
405+
386406 const locator = transformClassicToBidiSelector(using, value)
387407
388408 /**
@@ -598,7 +618,7 @@ export async function findElements(
598618 * Strip element object and return w3c and jsonwp compatible keys
599619 */
600620export function verifyArgsAndStripIfElement ( args : unknown ) {
601- function verify ( arg : unknown ) {
621+ function verify ( arg : unknown ) {
602622 if ( arg && typeof arg === 'object' && arg . constructor . name === 'Element' ) {
603623 const elem = arg as WebdriverIO . Element
604624 if ( ! elem . elementId ) {
@@ -667,7 +687,7 @@ export async function getElementRect(scope: WebdriverIO.Element) {
667687 * @param {Boolean } [retryCheck=false] true if an url was already check and still failed with fix applied
668688 * @return {string } fixed url
669689 */
670- export function validateUrl ( url : string , origError ?: Error ) : string {
690+ export function validateUrl ( url : string , origError ?: Error ) : string {
671691 try {
672692 const urlObject = new URL ( url )
673693 return urlObject . href
@@ -683,7 +703,7 @@ export function validateUrl (url: string, origError?: Error): string {
683703 }
684704}
685705
686- export async function hasElementId ( element : WebdriverIO . Element ) {
706+ export async function hasElementId ( element : WebdriverIO . Element ) {
687707 /*
688708 * This is only necessary as isDisplayed is on the exclusion list for the middleware
689709 */
@@ -799,7 +819,7 @@ export const containsHeaderObject = (
799819 return true
800820}
801821
802- export function createFunctionDeclarationFromString ( userScript : Function | string ) {
822+ export function createFunctionDeclarationFromString ( userScript : Function | string ) {
803823 if ( typeof userScript === 'string' ) {
804824 return `(${ SCRIPT_PREFIX } function () {\n${ userScript . toString ( ) } \n}${ SCRIPT_SUFFIX } ).apply(this, arguments);`
805825 }
0 commit comments