(webdriverio): expose WebdriverIO.ElementArray properly (#11671)

This commit is contained in:
Christian Bromann 2023-11-14 10:48:19 -08:00 committed by GitHub
parent 28f02d71b4
commit 6ef2bd3a6c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 55 additions and 23 deletions

View file

@ -2,7 +2,7 @@ import type { ElementReference } from '@wdio/protocols'
import { findElements, enhanceElementsArray, isElement, findElement } from '../../utils/index.js'
import { getElements } from '../../utils/getElementObject.js'
import type { Selector, ElementArray } from '../../types.js'
import type { Selector } from '../../types.js'
/**
* The `$$` command is a short and handy way in order to fetch multiple elements on the page.
@ -63,5 +63,5 @@ export async function $$ (
}
const elements = await getElements.call(this, selector as Selector, res)
return enhanceElementsArray(elements, this, selector as Selector) as ElementArray
return enhanceElementsArray(elements, this, selector as Selector) as WebdriverIO.ElementArray
}

View file

@ -1,7 +1,7 @@
import { enhanceElementsArray } from '../../utils/index.js'
import { getElements } from '../../utils/getElementObject.js'
import { ELEMENT_KEY } from '../../constants.js'
import type { ElementArray, CustomStrategyFunction, CustomStrategyReference } from '../../types.js'
import type { CustomStrategyFunction, CustomStrategyReference } from '../../types.js'
/**
*
@ -25,13 +25,13 @@ import type { ElementArray, CustomStrategyFunction, CustomStrategyReference } fr
* @alias custom$$
* @param {string} strategyName
* @param {*} strategyArguments
* @return {ElementArray}
* @return {WebdriverIO.ElementArray}
*/
export async function custom$$ (
this: WebdriverIO.Browser,
strategyName: string,
...strategyArguments: any[]
): Promise<ElementArray> {
): Promise<WebdriverIO.ElementArray> {
const strategy = this.strategies.get(strategyName) as CustomStrategyFunction
if (!strategy) {
@ -52,6 +52,6 @@ export async function custom$$ (
res = res.filter(el => !!el && typeof el[ELEMENT_KEY] === 'string')
const elements = res.length ? await getElements.call(this, strategyRef, res) : [] as any as ElementArray
const elements = res.length ? await getElements.call(this, strategyRef, res) : [] as any as WebdriverIO.ElementArray
return enhanceElementsArray(elements, this, strategyName, 'custom$$', strategyArguments)
}

View file

@ -7,7 +7,7 @@ import type { ElementReference } from '@wdio/protocols'
import { enhanceElementsArray } from '../../utils/index.js'
import { getElements } from '../../utils/getElementObject.js'
import { waitToLoadReact, react$$ as react$$Script } from '../../scripts/resq.js'
import type { ReactSelectorOptions, ElementArray } from '../../types.js'
import type { ReactSelectorOptions } from '../../types.js'
let resqScript: string
@ -60,6 +60,6 @@ export async function react$$ (
react$$Script as any, selector, props, state
) as ElementReference[]
const elements: ElementArray = await getElements.call(this, selector, res, { isReactElement: true })
const elements: WebdriverIO.ElementArray = await getElements.call(this, selector, res, { isReactElement: true })
return enhanceElementsArray(elements, this, selector, 'react$$', [props, state])
}

View file

@ -1,7 +1,7 @@
import { getElements } from '../../utils/getElementObject.js'
import { getBrowserObject, enhanceElementsArray } from '../../utils/index.js'
import { ELEMENT_KEY } from '../../constants.js'
import type { ElementArray, CustomStrategyFunction } from '../../types.js'
import type { CustomStrategyFunction } from '../../types.js'
/**
*
@ -32,7 +32,7 @@ export async function custom$$ (
this: WebdriverIO.Element,
strategyName: string,
...strategyArguments: any[]
): Promise<ElementArray> {
): Promise<WebdriverIO.ElementArray> {
const browserObject = getBrowserObject(this)
const strategy = browserObject.strategies.get(strategyName) as CustomStrategyFunction
@ -64,6 +64,6 @@ export async function custom$$ (
res = res.filter((el) => !!el && typeof el[ELEMENT_KEY] === 'string')
const elements = res.length ? await getElements.call(this, strategyRef, res) : [] as any as ElementArray
const elements = res.length ? await getElements.call(this, strategyRef, res) : [] as any as WebdriverIO.ElementArray
return enhanceElementsArray(elements, this, strategyName, 'custom$$', strategyArguments)
}

View file

@ -5,7 +5,7 @@ import { getElements } from '../../utils/getElementObject.js'
import { getBrowserObject, enhanceElementsArray } from '../../utils/index.js'
import { findStrategy } from '../../utils/findStrategy.js'
import { SHADOW_ELEMENT_KEY } from '../../constants.js'
import type { Selector, ElementArray } from '../../types.js'
import type { Selector } from '../../types.js'
const log = logger('webdriverio')
@ -40,7 +40,7 @@ export async function shadow$$ (
const { using, value } = findStrategy(selector as string, this.isW3C, this.isMobile)
const res = await browser.findElementsFromShadowRoot(shadowRoot[SHADOW_ELEMENT_KEY], using, value)
const elements = await getElements.call(this, selector as Selector, res, { isShadowElement: true })
return enhanceElementsArray(elements, this, selector as Selector) as ElementArray
return enhanceElementsArray(elements, this, selector as Selector) as WebdriverIO.ElementArray
} catch (err: unknown) {
log.warn(
`Failed to fetch element within shadow DOM using WebDriver command: ${(err as Error).message}!\n` +

View file

@ -126,7 +126,7 @@ export type MultiRemoteProtocolCommandsType = {
[K in keyof ProtocolCommands]: (...args: Parameters<ProtocolCommands[K]>) => Promise<ThenArg<ReturnType<ProtocolCommands[K]>>[]>
}
export interface ElementArray extends Array<WebdriverIO.Element> {
interface ElementArrayExport extends Array<WebdriverIO.Element> {
selector: Selector
parent: WebdriverIO.Element | WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
foundWith: string
@ -502,9 +502,41 @@ export interface AttachOptions extends Omit<WebDriverAttachOptions, 'capabilitie
declare global {
namespace WebdriverIO {
/**
* WebdriverIO browser object
* @see https://webdriver.io/docs/api/browser
*/
interface Browser extends Omit<BrowserBase, 'on' | 'once'>, BidiEventHandler, BidiHandler, ProtocolCommands, BrowserCommandsType {}
/**
* WebdriverIO element object
* @see https://webdriver.io/docs/api/element
*/
interface Element extends ElementBase, ProtocolCommands, ElementCommandsType {}
/**
* WebdriverIO element array
* When fetching elements via `$$`, `custom$$` or `shadow$$` commands an array of elements
* is returns. This array has extended prototype properties to provide information about
* the parent element, selector and properties of the fetched elements. This is useful to
* e.g. re-fetch the set in case no elements got returned.
*/
interface ElementArray extends ElementArrayExport {}
/**
* WebdriverIO multiremote browser object
* A multiremote browser instance is a property on the global WebdriverIO browser object that
* allows to control multiple browser instances at once. It can be represented as `Record<string, WebdriverIO.Browser>`
* where `string` is the capability name defined in the WebdriverIO options.
*
* @see https://webdriver.io/docs/multiremote/
*/
interface MultiRemoteBrowser extends MultiRemoteBrowserType {}
/**
* WebdriverIO multiremote browser object
* A multiremote browser instance is a property on the global WebdriverIO browser object that
* allows to control multiple browser instances at once. It can be represented as `Record<string, WebdriverIO.Element>`
* where `string` is the capability name defined in the WebdriverIO options.
*
* @see https://webdriver.io/docs/multiremote/
*/
interface MultiRemoteElement extends MultiRemoteElementType {}
}
}

View file

@ -6,7 +6,7 @@ import { getBrowserObject, getPrototype as getWDIOPrototype, getElementFromRespo
import { elementErrorHandler } from '../middlewares.js'
import { ELEMENT_KEY } from '../constants.js'
import * as browserCommands from '../commands/browser.js'
import type { Selector, ElementArray } from '../types.js'
import type { Selector } from '../types.js'
interface GetElementProps {
isReactElement?: boolean
@ -113,7 +113,7 @@ export const getElements = function getElements(
selector: Selector | ElementReference[] | WebdriverIO.Element[],
elemResponse: (ElementReference | Error | WebDriverError)[],
props: GetElementProps = { isReactElement: false, isShadowElement: false }
): ElementArray {
): WebdriverIO.ElementArray {
const browser = getBrowserObject(this as WebdriverIO.Element)
const browserCommandKeys = Object.keys(browserCommands)
const propertiesObject = {
@ -179,5 +179,5 @@ export const getElements = function getElements(
return elementInstance
})
return elements as ElementArray
return elements as WebdriverIO.ElementArray
}

View file

@ -15,7 +15,7 @@ import * as elementCommands from '../commands/element.js'
import querySelectorAllDeep from './thirdParty/querySelectorShadowDom.js'
import { ELEMENT_KEY, DEEP_SELECTOR, Key } from '../constants.js'
import { findStrategy } from './findStrategy.js'
import type { ElementArray, ElementFunction, Selector, ParsedCSSValue, CustomLocatorReturnValue } from '../types.js'
import type { ElementFunction, Selector, ParsedCSSValue, CustomLocatorReturnValue } from '../types.js'
import type { CustomStrategyReference } from '../types.js'
const log = logger('webdriverio')
@ -503,7 +503,7 @@ export function addLocatorStrategyHandler(scope: WebdriverIO.Browser | Webdriver
* @returns {object[]} elements
*/
export const enhanceElementsArray = (
elements: ElementArray,
elements: WebdriverIO.ElementArray,
parent: WebdriverIO.Browser | WebdriverIO.Element,
selector: Selector | ElementReference[] | WebdriverIO.Element[],
foundWith = '$$',

View file

@ -4,7 +4,7 @@ import allure from '@wdio/allure-reporter'
import { remote, multiremote, SevereServiceError } from 'webdriverio'
import type { DetailedContext } from '@wdio/protocols'
import type { MockOverwriteFunction } from '../../../packages/webdriverio/src/utils/interception/types.ts'
import type { ClickOptions, TouchAction, Selector, Action, ElementArray } from '../../../packages/webdriverio/build/types'
import type { ClickOptions, TouchAction, Selector, Action } from '../../../packages/webdriverio/build/types'
import { Key } from 'webdriverio'
declare global {
@ -83,7 +83,7 @@ async function bar() {
const elemA = await remoteBrowser.$('')
const elemB = await remoteBrowser.$('')
const multipleElems = await $$([elemA, elemB])
expectType<ElementArray>(multipleElems)
expectType<WebdriverIO.ElementArray>(multipleElems)
////////////////////////////////////////////////////////////////////////////////
@ -150,7 +150,7 @@ async function bar() {
}
return elems
})
expectType<ElementArray>(waitUntilElems)
expectType<WebdriverIO.ElementArray>(waitUntilElems)
await browser.getCookies()
await browser.getCookies('foobar')
@ -507,7 +507,7 @@ async function bar() {
}, {} as Random)
)
const elemArrayTest: ElementArray = {} as any
const elemArrayTest: WebdriverIO.ElementArray = {} as any
expectType<string>(elemArrayTest.foundWith)
expectType<WebdriverIO.Element>(elemArrayTest[123])
}