Selektoren
Das WebDriver Protocol bietet mehrere Auswahlstrategien zum Abfragen eines Elements an. WebdriverIO vereinfacht sie, um die Auswahl von Elementen einfach zu halten. Bitte beachten Sie, dass die Befehle zum Abfragen von Elementen zwar $
und $$
heißen, aber nichts mit jQuery oder der Sizzle Selector Engine zu tun haben.
Obwohl so viele verschiedene Selektoren verfügbar sind, bieten nur wenige von ihnen eine verlässliche Möglichkeit, das richtige Element zu finden. Zum Beispiel mit der folgenden Schaltfläche:
<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-testid="submit"
>
Submit
</button>
Empfehlen wir (oder nicht) die folgenden Selektoren:
Selektor | Empfehlung | Anmerkungen |
---|---|---|
$('button') | 🚨 Niemals | Am schlimmsten - zu allgemein, kein Kontext. |
$('.btn.btn-large') | 🚨 Niemals | Weniger Gut. Verbunden mit Styling. Fehler durch Style-Änderungen möglich. |
$('#main') | ⚠️ Sparsam | Besser. Aber immer noch an Styling oder JS-Event-Listener gekoppelt. |
$(() => document.queryElement('button')) | ⚠️ Sparsam | Ermöglicht effektive Abfragen, allerdings komplex zu schreiben. |
$('button[name="submission"]') | ⚠️ Sparsam | Gekoppelt an das Attribut name , das HTML-Semantik hat. |
$('button[data-testid="submit"]') | ✅ Gut | Erfordert zusätzliches Attribut, das keine weitere Funktion hat. |
$('aria/Submit') or $('button=Submit') | ✅ Immer | Am besten geeignet. Ähnelt, wie der Benutzer mit der Seite interagiert. |
CSS-Selektoren
Wenn nicht anders angegeben, fragt WebdriverIO Elemente mit dem CSS Selektor ab, z. B.:
loading...
Link-Text
Um ein Link-Element mit einem bestimmtem Text zu bekommen, fragen Sie den Text beginnend mit einem Gleichheitszeichen (=
) ab.
Zum Beispiel:
loading...
Sie können dieses Element abfragen, indem Sie Folgendes aufrufen:
loading...
Teillinktext
Um ein Link-Element zu finden, dessen sichtbarer Text teilweise mit Ihrem Suchwert übereinstimmt, fragen Sie es ab, indem Sie *=
vor die Abfragezeichenfolge setzen (z. B. *=driver
).
Sie können das Element aus dem obigen Beispiel abfragen, indem Sie auch Folgendes aufrufen:
loading...
Hinweis: Sie können nicht mehrere Selektorstrategien in einem Selektor mischen. Verwenden Sie mehrere verkettete Elementabfragen, um dasselbe Ziel zu erreichen, z. B.:
const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('*=driver')
Element mit bestimmtem Text
Die gleiche Technik kann auch auf Elemente angewendet werden.
Hier ist zum Beispiel eine Abfrage für eine Überschrift der Ebene 1 mit dem Text „Welcome to my page“:
loading...
Sie können dieses Element abfragen, indem Sie Folgendes aufrufen:
loading...
Oder verwenden Sie die Teiltext-Abfrage:
loading...
Das gleiche funktioniert für id
und class
Namen:
loading...
Sie können dieses Element abfragen, indem Sie Folgendes aufrufen:
loading...
Hinweis: Sie können nicht mehrere Selektorstrategien in einem Selektor mischen. Verwenden Sie mehrere verkettete Elementabfragen, um dasselbe Ziel zu erreichen, z. B.:
const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('h1*=Welcome')
Tag-Name
Um ein Element mit einem bestimmten Tag-Namen abzufragen, verwenden Sie <tag>
oder <tag />
.
loading...
Sie können dieses Element abfragen, indem Sie Folgendes aufrufen:
loading...
Namensattribut
Zum Abfragen von Elementen mit einem bestimmten Namensattribut können Sie entweder einen normalen CSS3-Selektor verwenden oder die bereitgestellte Namensstrategie aus dem JSONWireProtocol verwenden, indem Sie etwas wie [name="some-name"] als Selektorparameter übergeben:
loading...
loading...
Hinweis: Diese Auswahlstrategie ist veraltet und funktioniert nur in alten Browsern, die vom JSONWireProtocol-Protokoll oder von Appium ausgeführt werden.
xPath
Es ist auch möglich, Elemente über einen bestimmten xPathabzufragen.
Ein xPath-Selektor hat ein Format wie //body/div[6]/div[1]/span[1]
.
loading...
Sie können den zweiten `
` Tag abfragen, indem Sie Folgendes aufrufen:
loading...
Sie können xPath auch verwenden, um den DOM-Baum nach oben und unten zu durchlaufen:
loading...
Accessibility Name Selektor
Fragen Sie Elemente nach ihrem Accessibility Namen ab. Der Accessibility Name wird von einem Screenreader angesagt, wenn dieses Element den Fokus erhält. Der Accessibility Name kann sowohl visueller Inhalt als auch versteckte Textalternativen darstellen.
Weitere Informationen zu diesem Selektor finden Sie in unserem Release-Blogbeitrag
Finden von Elementen via Aria-Label
loading...
loading...
Finden von Elementen via aria-labelledby
loading...
loading...
Finden von Elementen via dessen Inhalt
loading...
loading...
Finden von Elementen durch ein "titel" Attribut
loading...
loading...
Finden von Elementen durch ein alt
Attribut
loading...
loading...
ARIA - Rollen-Attribut
Um Elemente basierend auf ARIA-Rollen zu finden, können Sie die Rolle des Elements direkt angeben, z. B. [role=button]
als Selektor:
loading...
loading...
ID Attribut
Die Locator-Strategie „id“ wird im WebDriver-Protokoll nicht unterstützt, man sollte stattdessen entweder CSS- oder xPath-Selector-Strategien verwenden, um Elemente mit ID zu finden.
Einige Treiber (z.B. Appium You.i Engine Driver) unterstützen diesen Selektor jedoch möglicherweise immer noch.
Aktuell unterstützte Selektor-Syntax für ID sind:
//css locator
const button = await $('#someid')
//xpath locator
const button = await $('//*[@id="someid"]')
//id strategy
// Note: works only in Appium or similar frameworks which supports locator strategy "ID"
const button = await $('id=resource-id/iosname')
Elemente finden via JavaScript-Funktion
Sie können auch JavaScript-Funktionen verwenden, um Elemente mithilfe web-nativer APIs zu abzufragen. Natürlich können Sie dies nur innerhalb eines Webkontexts tun (z. B. browser
oder im Web-Kontext auf Mobilgeräten).
Bei folgender HTML-Struktur:
loading...
können Sie das Geschwisterelement von #elem
wie folgt abfragen:
loading...
Tiefe Selektoren
Viele Frontend-Anwendungen verlassen sich stark auf Elemente mit Shadow DOM. Es ist technisch nicht möglich, Elemente innerhalb des Shadow-DOM ohne Workarounds abzufragen. Die shadow$
und shadow$$
waren Möglichkeiten, die ihre Einschränkungen hatten. Mit dem Tiefenselektor können Sie jetzt alle Elemente in jedem Schatten-DOM mit dem allgemeinen Abfragebefehl abfragen.
Angenommen, wir haben eine Anwendung mit der folgenden Struktur:
Mit diesem Selektor können Sie das <button />
Element abfragen, das in einem anderen Schatten-DOM verschachtelt ist, z.B.:
loading...
Mobile Selektoren
Für hybride mobile Tests ist es wichtig, dass sich der Automatisierungsserver im richtigen context befindet, bevor Befehle ausgeführt werden. Für die Automatisierung von Gesten sollte der Treiber idealerweise auf nativen Kontext eingestellt werden. Um jedoch Elemente aus dem DOM auszuwählen, muss der Treiber auf den Webview-Kontext der Plattform eingestellt werden. Erst dann können die oben genannten Methoden verwendet werden.
Beim nativen mobilen Testen gibt es keinen Wechsel zwischen Kontexten, da Sie mobile Strategien verwenden und die zugrunde liegende Geräteautomatisierungstechnologie direkt verwenden müssen. Dies ist besonders nützlich, wenn ein Test eine feinkörnige Kontrolle über das Finden von Elementen erfordert.
Android UiAutomator
Das UI Automator-Framework von Android bietet eine Reihe von Möglichkeiten zum Suchen von Elementen. Sie können die UI Automator API, insbesondere die UiSelector-Klasse verwenden, um Elemente zu lokalisieren. In Appium können Sie den Java-Code als Zeichenfolge an den Server senden, der in der Umgebung der Anwendung ausgeführt wird und das Element oder die Elemente zurückgibt.
const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()
Android DataMatcher und ViewMatcher (nur Espresso)
Die View-Tag-Strategie bietet eine bequeme Möglichkeit, Elemente anhand ihres -Tagszu finden.
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"]
})
await menuItem.click()
Die DataMatcher-Strategie von Android bietet eine Möglichkeit, Elemente mit DataMatcherzu finden.
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"],
"class": "androidx.test.espresso.matcher.ViewMatchers"
})
await menuItem.click()
Android View Tag (nur Espresso)
Und ähnlich View Matcher
const elem = await $('-android viewtag:tag_identifier')
await elem.click()
iOS UIAutomation
Bei der Automatisierung einer iOS-Anwendung kann Apples UI Automation Framework verwendet werden, um Elemente zu finden.
Diese JavaScript API verfügt über Methoden für den Zugriff auf die View und alles darin enthaltene.
const selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
const button = await $(`ios=${selector}`)
await button.click()
Sie können auch das "Predicate Searching" innerhalb der iOS-UI-Automatisierung in Appium verwenden, um die Elementauswahl noch weiter zu verfeinern. Siehe iOS Predicate für weitere Details.
iOS XCUITest Prädikatzeichenfolgen und Klassenketten
Und Klassenketten:
const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()
Mit iOS 10 und höher (unter Verwendung des XCUITest
Treibers) können Sie Prädikatzeichenfolgen verwenden:
const selector = '**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton'
const button = await $(`-ios class chain:${selector}`)
await button.click()
Accessibility ID
Die Locator-Strategie Accessibility ID
wurde entwickelt, um eine eindeutige Kennung für ein UI-Element zu bekommen. Dies hat den Vorteil, dass sich durch Übersetzungen oder andere Umstände, die den Text ändern könnte, der Selektor stabil bleibt. Außerdem kann es hilfreich sein, plattformübergreifende Tests zu erstellen, wenn funktional gleiche Elemente dieselbe Accessibility-ID haben.
- Für iOS ist es der
accessibility identifier
und ist von Apple hier festgelegt. - Für Android wird die
Accessibility-ID
dercontent-description
für das Element zugeordnet, wie hier beschrieben.
Für beide Plattformen ist es normalerweise die beste Methode, ein Element (oder mehrere Elemente) anhand ihrer Accessibility-ID
zu erhalten. Es ist auch der bevorzugte Weg gegenüber der veralteten Name-
Strategie.
const elem = await $('~my_accessibility_identifier')
await elem.click()
Klassenname
Die Klassenname-
Strategie ist eine Zeichenfolge
, die ein UI-Element in der aktuellen Ansicht darstellt.
- Für iOS ist es der vollständige Name einer UIAutomation-Klasseund beginnt mit
UIA-
, z. B.UIATextField
für ein Textfeld. Eine vollständige Referenz finden Sie hier. - Für Android ist es der vollständig qualifizierte Name eines UI Automator class, z. B.
android.widget.EditText
für ein Textfeld. Eine vollständige Referenz finden Sie hier. - Für Youi.tv ist es der vollständige Name einer Youi.tv-Klasse und wird mit
CYI-
sein, z. B.CYIPushButtonView
für ein Button Element. Eine vollständige Referenz finden Sie auf GitHub Seite auf den Dokumentationsseiten des You.i Engine Driver
// iOS example
await $('UIATextField').click()
// Android example
await $('android.widget.DatePicker').click()
// Youi.tv example
await $('CYIPushButtonView').click()
Ketten-Selektoren
Wenn Sie in Ihrer Abfrage spezifischer sein möchten, können Sie Selektoren verketten, bis Sie das richtige Element gefunden haben. Befehle der Element API nutzen immer den Kontext des vorhergegangen Query Befehls.
Wenn Sie beispielsweise eine DOM-Struktur haben, die wie folgt aussieht:
<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>
Und Sie möchten Produkt B in den Warenkorb legen, so wäre es schwierig, dies nur mit dem CSS-Selektor zu tun.
Mit der Selektorverkettung ist es viel einfacher. Einfach Schritt für Schritt das gewünschte Element eingrenzen:
await $('.row .entry:nth-child(2)').$('button*=Add').click()
Appium Bild Selektoren
Mit der -image-
Selektor ist es möglich, Appium eine Bilddatei zu senden, die ein Element darstellt, auf das Sie zugreifen möchten.
Unterstützte Dateiformate jpg,png,gif,bmp,svg
Eine vollständige Referenz finden Sie hier
const elem = await $('./file/path/of/image/test.jpg')
await elem.click()
Hinweis: Die Art und Weise, wie Appium mit diesem Selektor arbeitet, ist, dass es intern einen (App-)Screenshot erstellt und den bereitgestellten Bildselektor verwendet, um zu überprüfen, ob das Element in diesem (App-)Screenshot gefunden werden kann.
Beachten Sie, dass Appium die Größe des aufgenommenen (App-) möglicherweise an die CSS-Größe Ihres (App-)Bildschirms anpasst (dies geschieht auf iPhones, aber auch auf Mac-Computern mit einem Retina-Display, da der DPR größer ist als 1). Dies führt dazu dass keine Übereinstimmung gefunden wird, da die bereitgestellte Bildauswahl möglicherweise aus dem ursprünglichen Screenshot stammt. Sie können dies beheben, indem Sie die Appium Server-Einstellungen aktualisieren, siehe die Appium-Dokumentation für die Einstellungen und diesen Kommentar für eine detaillierte Erklärung.
React Selektoren
WebdriverIO bietet eine Möglichkeit, React-Komponenten basierend auf dem Komponentennamen auszuwählen. Dazu stehen Ihnen zwei Befehle zur Auswahl: react$
und react$$
.
Mit diesen Befehlen können Sie Komponenten aus dem React VirtualDOM auswählen und entweder ein einzelnes WebdriverIO-Element oder ein Array von Elementen zurückgeben (je nachdem, welche Funktion verwendet wird).
Hinweis: Die Befehle react$
und react$$
sind in ihrer Funktionalität ähnlich, außer dass react$$
alle übereinstimmenden Instanzen als ein Array von WebdriverIO-Elementen zurückgibt und react$
nur die erste gefundene Instanz.
Einfaches Beispiel
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<div>
MyComponent
</div>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
Mit dem Befehl browser.react$
können Sie eine Instanz von MyComponent
auswählen:
Im obigen Code gibt es eine einfache MyComponent
-Instanz innerhalb der Anwendung, die React innerhalb eines HTML-Elements mit id="root"
rendert.
const myCmp = await browser.react$('MyComponent')
Nachdem Sie nun das WebdriverIO-Element in der Variablen myCmp
gespeichert haben, können Sie Elementbefehle dafür ausführen.
Komponenten filtern
Die Bibliothek, die WebdriverIO intern verwendet, ermöglicht es, Ihre Auswahl nach Props und/oder Zustand der Komponente zu filtern. Dazu müssen Sie dem Browser-Befehl ein zweites Argument für Props und/oder ein drittes Argument für State übergeben.
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent(props) {
return (
<div>
Hello { props.name || 'World' }!
</div>
)
}
function App() {
return (
<div>
<MyComponent name="WebdriverIO" />
<MyComponent />
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#root'))
Wenn Sie die Instanz von MyComponent
mit einem Prop name
als WebdriverIO
auswählen möchten, können Sie den Befehl wie folgt ausführen:
const myCmp = await browser.react$('MyComponent', {
props: { name: 'WebdriverIO' }
})
Wenn Sie unsere Auswahl nach Status filtern möchten, sieht der Befehl browser
ungefähr so aus:
const myCmp = await browser.react$('MyComponent', {
state: { myState: 'some value' }
})
Umgang mit React.Fragment
Wenn Sie den Befehl react$
verwenden, um React fragments auszuwählen, gibt WebdriverIO das erste untergeordnete Element dieser Komponente als Knoten der Komponente zurück. Wenn Sie react$$
verwenden, erhalten Sie ein Array mit allen HTML-Knoten innerhalb der Fragmente, die mit dem Selektor übereinstimmen.
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<React.Fragment>
<div>
MyComponent
</div>
<div>
MyComponent
</div>
</React.Fragment>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
In Anbetracht des obigen Beispiels würden die Befehle so funktionieren:
await browser.react$('MyComponent') // returns the WebdriverIO Element for the first <div />
await browser.react$$('MyComponent') // returns the WebdriverIO Elements for the array [<div />, <div />]
Hinweis: Wenn Sie mehrere Instanzen von MyComponent
haben und react$$
verwenden, um diese Fragmentkomponenten auszuwählen, erhalten Sie ein eindimensionales Array aller Knoten zurück. Mit anderen Worten, wenn Sie 3 <MyComponent />
Instanzen haben, erhalten Sie ein Array mit sechs WebdriverIO-Elementen zurück.
Benutzerdefinierte Selektoren
Wenn Ihre App eine bestimmte Methode zum Abrufen von Elementen erfordert, können Sie sich selbst eine benutzerdefinierte Selektorstrategie definieren, die Sie mit custom$
und custom$$
verwenden können. Registrieren Sie dazu Ihre Strategie einmalig zu Beginn des Tests:
loading...
Bei folgender HTML-Struktur:
loading...
Verwenden Sie Ihren benutzerdefinierten Selektor wie folgt::
loading...
Hinweis: Dies funktioniert nur in einer Webumgebung, in der der Befehl execute
ausgeführt werden kann.