Kapitel 4. Browser-gnostische Funktionen
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
In diesem Kapitel werden die Funktionen von Selenium WebDriver besprochen, die in verschiedenen Webbrowsern interoperabel sind. Ein wichtiges Mehrzweckmerkmal in dieser Gruppe ist die Ausführung von JavaScript. Außerdem ermöglicht die Selenium WebDriver API die Konfiguration von Timeouts für das Laden von Seiten und Skripten. Eine weitere praktische Funktion ist das Erstellen von Screenshots des Browserbildschirms oder nur des Teils, der einem bestimmten Element entspricht. Dann können wir mit WebDriver verschiedene Aspekte des kontrollierten Browsers verwalten, z. B. die Browsergröße und -position, den Verlauf oder die Cookies. Dann stellt WebDriver verschiedene Assets für die Steuerung bestimmter Webelemente zur Verfügung, z. B. Dropdown-Listen (d. h. HTML-Auswahlfelder und Datenlisten), Navigationsziele (d. h. Fenster, Tabs, Frames und Iframes) oder Dialogfelder (d. h. Warnungen, Eingabeaufforderungen, Bestätigungen und modale Dialoge). Zum Schluss erfährst du, wie du lokale und Sitzungsdaten mit Hilfe von Webspeichern verwaltest, Event-Listener implementierst und die Ausnahmen der Selenium WebDriver API nutzt.
Ausführen von JavaScript
JavaScript ist eine High-Level-Programmiersprache, die von allen wichtigen Browsern unterstützt wird. Wir können JavaScript auf der Client-Seite von Webanwendungen für eine Vielzahl von Operationen verwenden, z. B. für DOM-Manipulationen, Benutzerinteraktionen, die Verarbeitung von Anfragen und Antworten von Remote-Servern oder die Arbeit mit regulären Ausdrücken, neben vielen anderen Funktionen. Zum Glück für die Testautomatisierung ermöglicht Selenium WebDriver das Einfügen und Ausführen beliebiger JavaScript-Stücke. Zu diesem Zweck bietet die Selenium WebDriver API die Schnittstelle JavascriptExecutor
. Tabelle 4-1 stellt die verfügbaren öffentlichen Methoden in dieser Schnittstelle vor, die in drei Kategorien unterteilt sind: synchrone, angeheftete und asynchrone Skripte. Die folgenden Unterabschnitte enthalten weitere Details und veranschaulichen ihre Verwendung anhand verschiedener Beispiele.
Jedes Treiberobjekt , das von der Klasse RemoteWebDriver
erbt, implementiert auch die Schnittstelle JavascriptExecutor
. Daher können wir , wenn wir einen Hauptbrowser (z. B. ChromeDriver
, FirefoxDriver
, usw.) verwenden, der über die generische Schnittstelle WebDriver
deklariert wurde, in JavascriptExecutor
umwandeln, wie im folgenden Ausschnitt gezeigt. Dann können wir den Executor (im Beispiel die Variable js
) verwenden, um die in Tabelle 4-1 aufgeführten Methoden aufzurufen.
WebDriver
driver
=
new
ChromeDriver
();
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
Synchrone Skripte
Die Methode executeScript()
eines JavascriptExecutor
Objekts ermöglicht das Ausführen eines Stücks JavaScript im Kontext der aktuellen Webseite in einer WebDriver-Sitzung. Der Aufruf dieser Methode (in Java) blockiert den Kontrollfluss, bis das Skript beendet ist. Daher verwenden wir diese Methode in der Regel für die Ausführung von synchronen Skripten in einer zu testenden Webseite. Die Methode executeScript()
erlaubt zwei Argumente:
String script
-
Obligatorisch JavaScript-Fragment, das ausgeführt werden soll. Dieser Code wird im Body der aktuellen Seite als anonyme Funktion (d. h. eine JavaScript-Funktion ohne Namen) ausgeführt.
Object... args
-
Optionales Argumente Skript. Diese Argumente müssen einem der folgenden Typen entsprechen: Zahl, Boolescher Wert, String,
WebElement
oder eineList
dieser Typen (andernfalls löst WebDriver eine Ausnahme aus). Diese Argumente sind im injizierten Skript über die integrierte JavaScript-Variablearguments
verfügbar.
Wenn das Skript einen Wert zurückgibt (d.h. der Code enthält eine return
Anweisung), gibt die Selenium WebDriver executeScript()
Methode auch einen Wert in Java zurück (andernfalls gibt executeScript()
null
zurück). Die möglichen Rückgabetypen sind:
WebElement
-
Bei der Rückgabe eines HTML-Elements
Double
-
Für Dezimalen
Long
-
Für nicht dezimale Zahlen
Boolean
-
Für boolesche Werte
List<Object>
-
Für Arrays
Map<String, Object>
-
Für Schlüssel-Wert-Sammlungen
String
-
Für alle anderen Fälle
Die Situationen, die die Ausführung von JavaScript mit Selenium WebDriver erfordern, sind sehr heterogen. In den folgenden Unterabschnitten werden zwei Fälle beschrieben, in denen der Selenium WebDriver keine eingebauten Funktionen bietet und wir stattdessen JavaScript verwenden müssen, um sie zu automatisieren: das Scrollen einer Webseite und die Handhabung eines Farbwählers in einem Webformular.
Scrollen
Wie in Kapitel 3 erläutert, ermöglicht Selenium WebDriver das Imitieren verschiedener Mausaktionen, darunter Klick, Rechtsklick oder Doppelklick. Allerdings ist es mit der Selenium WebDriver API nicht möglich, auf einer Webseite nach unten oder oben zu scrollen. Stattdessen können wir diese Automatisierung ganz einfach durch das Ausführen einer einfachen JavaScript-Zeile erreichen. Beispiel 4-1 zeigt ein einfaches Beispiel mit einer Übungswebseite (die URL dieser Seite steht in der ersten Zeile der Testmethode).
Beispiel 4-1. Test zur Ausführung von JavaScript, um einen Pixel nach unten zu scrollen
@Test
void
testScrollBy
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/long-page.html"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
String
script
=
"window.scrollBy(0, 1000);"
;
js
.
executeScript
(
script
)
;
}
Öffne eine Praxisseite mit sehr langem Text (siehe Abbildung 4-1).
Übertrage das Objekt
driver
aufJavascriptExecutor
. Wir werden die Variablejs
verwenden, um JavaScript im Browser auszuführen.Führe einen Teil des JavaScript-Codes aus. In diesem Fall rufen wir die JavaScript-Funktion
scrollBy()
auf, um das Dokument um einen bestimmten Betrag zu scrollen (in diesem Fall um 1.000 px nach unten). Beachte, dass dieses Fragment nichtreturn
verwendet und wir daher kein Objekt in der Java-Logik zurückbekommen. Außerdem übergeben wir dem Skript kein Argument.
Beispiel 4-2 zeigt einen weiteren Test mit Scrollen und der gleichen Beispiel-Webseite wie zuvor. Anstatt eine feste Anzahl von Pixeln zu verschieben, bewegen wir das Dokument bis zum letzten Absatz der Webseite.
Beispiel 4-2. Test zum Ausführen von JavaScript, um zu einem bestimmten Element nach unten zu scrollen
@Test
void
testScrollIntoView
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/long-page.html"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
driver
.
manage
(
)
.
timeouts
(
)
.
implicitlyWait
(
Duration
.
ofSeconds
(
10
)
)
;
WebElement
lastElememt
=
driver
.
findElement
(
By
.
cssSelector
(
"p:last-child"
)
)
;
String
script
=
"arguments[0].scrollIntoView();"
;
js
.
executeScript
(
script
,
lastElememt
)
;
}
Um diesen Test robust zu machen, geben wir ein implizites Timeout an. Andernfalls könnte der Test fehlschlagen, wenn die Seite bei der Ausführung der nachfolgenden Befehle noch nicht vollständig geladen ist.
Wir suchen den letzten Absatz auf der Webseite mithilfe eines CSS-Selektors.
Wir definieren das Skript, das in die Seite eingefügt werden soll. Beachte, dass das Skript keinen Wert zurückgibt, sondern als Neuerung das erste Funktionsargument verwendet, um die JavaScript-Funktion
scrollIntoView()
aufzurufen.Wir führen das vorherige Skript aus und übergeben das gefundene
WebElement
als Argument. Dieses Element wird das erste Argument für das Skript sein (d.h.arguments[0]
).
Das letzte Beispiel für das Scrollen ist das unendliche Scrollen. Diese Technik ermöglicht das dynamische Laden von weiteren Inhalten, wenn der Nutzer das Ende der Webseite erreicht. Die Automatisierung dieser Art von Webseiten ist ein lehrreicher Anwendungsfall, da er verschiedene Aspekte der Selenium WebDriver API umfasst. Du kannst zum Beispiel einen ähnlichen Ansatz verwenden, um Webseiten mit Selenium WebDriver zu crawlen. Beispiel 4-3 zeigt einen Test mit einer unendlich scrollenden Seite.
Beispiel 4-3. Test der Ausführung von JavaScript in einer Seite mit unendlichem Scrollen
@Test
void
testInfiniteScroll
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/infinite-scroll.html"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
10
)
)
;
By
pLocator
=
By
.
tagName
(
"p"
)
;
List
<
WebElement
>
paragraphs
=
wait
.
until
(
ExpectedConditions
.
numberOfElementsToBeMoreThan
(
pLocator
,
0
)
)
;
int
initParagraphsNumber
=
paragraphs
.
size
(
)
;
WebElement
lastParagraph
=
driver
.
findElement
(
By
.
xpath
(
String
.
format
(
"//p[%d]"
,
initParagraphsNumber
)
)
)
;
String
script
=
"arguments[0].scrollIntoView();"
;
js
.
executeScript
(
script
,
lastParagraph
)
;
wait
.
until
(
ExpectedConditions
.
numberOfElementsToBeMoreThan
(
pLocator
,
initParagraphsNumber
)
)
;
}
Farbwähler
Ein Farbwähler in HTML ist ein Eingabetyp, der es den Nutzern ermöglicht, eine Farbe durch Klicken und Ziehen des Cursors über einen grafischen Bereich auszuwählen. Das Praxis-Webformular enthält eines dieser Elemente (siehe Abbildung 4-2).
Der folgende Code zeigt das HTML-Markup für den Farbwähler. Beachte, dass ein anfänglicher Farbwert festgelegt wird (ansonsten ist die Standardfarbe schwarz).
<
input
type
=
"color"
class
=
"form-control form-control-color"
name
=
"my-colors"
value
=
"#563d7c"
>
Beispiel 4-4 zeigt, wie du mit diesem Farbwähler interagieren kannst. Da die Selenium WebDriver API kein Asset zur Steuerung von Farbwählern bereitstellt, verwenden wir JavaScript. Außerdem veranschaulicht dieser Test die Verwendung von Color
, einer in der Selenium WebDriver API verfügbaren Unterstützungsklasse für die Arbeit mit Farben.
Beispiel 4-4. Test der Ausführung von JavaScript zur Interaktion mit einem Farbwähler
@Test
void
testColorPicker
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
WebElement
colorPicker
=
driver
.
findElement
(
By
.
name
(
"my-colors"
)
)
;
String
initColor
=
colorPicker
.
getAttribute
(
"value"
)
;
log
.
debug
(
"The initial color is {}"
,
initColor
)
;
Color
red
=
new
Color
(
255
,
0
,
0
,
1
)
;
String
script
=
String
.
format
(
"arguments[0].setAttribute('value', '%s');"
,
red
.
asHex
(
)
)
;
js
.
executeScript
(
script
,
colorPicker
)
;
String
finalColor
=
colorPicker
.
getAttribute
(
"value"
)
;
log
.
debug
(
"The final color is {}"
,
finalColor
)
;
assertThat
(
finalColor
)
.
isNotEqualTo
(
initColor
)
;
assertThat
(
Color
.
fromString
(
finalColor
)
)
.
isEqualTo
(
red
)
;
}
Wir suchen den Farbwähler nach seinem Namen.
Wir lesen den Anfangswert des Farbwählers ab (er sollte
#563d7c
sein).Wir definieren eine Farbe, mit der wir arbeiten können, indem wir die folgenden RGBA-Komponenten verwenden: rot=255 (maximaler Wert), grün=0 (minimaler Wert), blau=0 (minimaler Wert) und alpha=1 (maximaler Wert, d.h. völlig undurchsichtig).
Wir verwenden JavaScript, um den in der Farbauswahl ausgewählten Wert zu ändern. Alternativ können wir die ausgewählte Farbe ändern, indem wir die Anweisung
colorPicker.sendKeys(red.asHex());
aufrufen.Wir lesen den Ergebniswert des Farbwählers ab (er sollte
#ff0000
sein).Wir stellen fest, dass die Farbe anders ist als der ursprüngliche Wert, aber wie erwartet.
Angepinnte Skripte
Die Selenium WebDriver API ermöglicht es dir, Skripte in Selenium WebDriver 4 anzuheften. Diese Funktion ermöglicht es, JavaScript-Fragmente an eine WebDriver-Sitzung anzuhängen, jedem Snippet einen eindeutigen Schlüssel zuzuweisen und diese Snippets bei Bedarf auszuführen (sogar auf verschiedenen Webseiten). Beispiel 4-5 zeigt einen Test mit angehefteten Skripten.
Beispiel 4-5. Test der Ausführung von JavaScript als angeheftete Skripte
@Test
void
testPinnedScripts
(
)
{
String
initPage
=
"https://bonigarcia.dev/selenium-webdriver-java/"
;
driver
.
get
(
initPage
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
ScriptKey
linkKey
=
js
.
pin
(
"return document.getElementsByTagName('a')[2];"
)
;
ScriptKey
firstArgKey
=
js
.
pin
(
"return arguments[0];"
)
;
Set
<
ScriptKey
>
pinnedScripts
=
js
.
getPinnedScripts
(
)
;
assertThat
(
pinnedScripts
)
.
hasSize
(
2
)
;
WebElement
formLink
=
(
WebElement
)
js
.
executeScript
(
linkKey
)
;
formLink
.
click
(
)
;
assertThat
(
driver
.
getCurrentUrl
(
)
)
.
isNotEqualTo
(
initPage
)
;
String
message
=
"Hello world!"
;
String
executeScript
=
(
String
)
js
.
executeScript
(
firstArgKey
,
message
)
;
assertThat
(
executeScript
)
.
isEqualTo
(
message
)
;
js
.
unpin
(
linkKey
)
;
assertThat
(
js
.
getPinnedScripts
(
)
)
.
hasSize
(
1
)
;
}
Wir hängen ein JavaScript-Fragment an, um ein Element auf der Webseite zu finden. Das Gleiche könnten wir auch mit der Standard-WebDriver-API machen. Dennoch verwenden wir diesen Ansatz zu Demozwecken.
Wir hängen ein weiteres Stück JavaScript an, das das zurückgibt, was wir ihm als ersten Parameter übergeben.
Wir lesen den Satz der angehefteten Skripte.
Wir behaupten, dass die Anzahl der angehefteten Skripte wie erwartet ist (d.h.
2
).Wir führen das erste angeheftete Skript aus. Als Ergebnis erhalten wir den dritten Link auf der Webseite als
WebElement
in Java.Wir klicken auf diesen Link, der dem Praxis-Web-Link entsprechen sollte. Daraufhin sollte der Browser zu dieser Seite navigieren.
Wir behaupten, dass sich die aktuelle URL von der ursprünglichen unterscheidet.
Wir führen das zweite angeheftete Skript aus. Beachte, dass es möglich ist, das angeheftete Skript auszuführen, obwohl sich die Seite im Browser geändert hat (da das Skript an die Sitzung und nicht an eine einzelne Seite gebunden ist).
Wir versichern, dass die zurückgegebene Nachricht wie erwartet ist.
Wir heften eines der Skripte ab.
Wir überprüfen, ob die Anzahl der angehefteten Skripte wie erwartet ist (d.h.
1
zu diesem Zeitpunkt).
Asynchrone Skripte
Die Methode executeAsyncScript()
der Schnittstelle JavascriptExecutor
ermöglicht die Ausführung von JavaScript-Skripten im Kontext einer Webseite mit Selenium WebDriver. Auf die gleiche Weise wie executeScript()
zuvor erklärt, führt executeAsyncScript()
eine anonyme Funktion mit dem angegebenen JavaScript-Code im Body der aktuellen Seite aus. Die Ausführung dieser Funktion blockiert den Kontrollfluss von Selenium WebDriver. Der Unterschied besteht darin, dass wir bei executeAsyncScript()
die Beendigung des Skripts explizit signalisieren müssen, indem wir einen done-Callback aufrufen ( ). Dieser Callback wird in das ausgeführte Skript als letztes Argument (d.h. arguments[arguments.length - 1]
) in der entsprechenden anonymen Funktion eingefügt. Beispiel 4-6 zeigt einen Test, der diesen Mechanismus verwendet.
Beispiel 4-6. Test zur Ausführung von asynchronem JavaScript
@Test
void
testAsyncScript
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
Duration
pause
=
Duration
.
ofSeconds
(
2
)
;
String
script
=
"const callback = arguments[arguments.length - 1];"
+
"window.setTimeout(callback, "
+
pause
.
toMillis
(
)
+
");"
;
long
initMillis
=
System
.
currentTimeMillis
(
)
;
js
.
executeAsyncScript
(
script
)
;
Duration
elapsed
=
Duration
.
ofMillis
(
System
.
currentTimeMillis
(
)
-
initMillis
)
;
log
.
debug
(
"The script took {} ms to be executed"
,
elapsed
.
toMillis
(
)
)
;
assertThat
(
elapsed
)
.
isGreaterThanOrEqualTo
(
pause
)
;
}
Wir legen eine Pausenzeit von
2
Sekunden fest.Wir definieren das Skript, das ausgeführt werden soll. In der ersten Zeile definieren wir eine Konstante für den Rückruf (d. h. das letzte Skriptargument). Danach verwenden wir die JavaScript-Funktion
window.setTimeout()
, um die Skriptausführung für eine bestimmte Zeit zu unterbrechen.Wir erhalten die aktuelle Systemzeit (in Millisekunden).
Wir führen das Skript aus. Wenn alles wie erwartet funktioniert, wird die Testausführung in dieser Zeile für zwei Sekunden blockiert (wie in Schritt 1 definiert).
Wir berechnen die Zeit, die für die Ausführung der vorherigen Zeile benötigt wird.
Wir stellen fest, dass die verstrichene Zeit wie erwartet ist (normalerweise einige Millisekunden über der festgelegten Pausenzeit).
Tipp
Ein weiteres Beispiel, das ein asynchrones Skript ausführt, findest du unter "Benachrichtigungen".
Zeitüberschreitungen
Selenium WebDriver ermöglicht die Angabe von drei Arten von Timeouts. Wir können sie nutzen, indem wir die Methode manage().timeouts()
in der Selenium WebDriver API aufrufen. Die erste Zeitüberschreitung ist das implizite Warten, das bereits in "Implizites Warten" (als Teil der Wartestrategien) erklärt wurde. Die anderen Optionen sind die Timeouts für das Laden von Seiten und das Laden von Skripten, die im Folgenden erklärt werden.
Zeitüberschreitung beim Laden der Seite
Das Timeout für das Laden einer Seite bietet ein Zeitlimit, um einen Navigationsversuch zu unterbrechen. Mit anderen Worten: Diese Zeitüberschreitung begrenzt die Zeit, in der eine Webseite geladen wird. Wenn diese Zeitüberschreitung (der Standardwert ist 30 Sekunden) überschritten wird, wird eine Ausnahme ausgelöst. Beispiel 4-7 zeigt ein Beispiel für diese Zeitüberschreitung. Wie du siehst, ist dieser Code eine Dummy-Implementierung eines negativen Tests. Mit anderen Worten: Er prüft unerwartete Bedingungen im SUT.
Beispiel 4-7. Test mit einer Zeitüberschreitung beim Laden der Seite
@Test
void
testPageLoadTimeout
(
)
{
driver
.
manage
(
)
.
timeouts
(
)
.
pageLoadTimeout
(
Duration
.
ofMillis
(
1
)
)
;
assertThatThrownBy
(
(
)
-
>
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
)
.
isInstanceOf
(
TimeoutException
.
class
)
;
}
Wir geben die kleinstmögliche Zeitspanne zum Laden der Seite an, nämlich eine Millisekunde.
Wir laden eine Webseite. Dieser Aufruf (implementiert als Java-Lambda) wird fehlschlagen, da es unmöglich ist, diese Webseite in weniger als einer Millisekunde zu laden. Aus diesem Grund wird erwartet, dass die Ausnahme
TimeoutException
im Lambda ausgelöst wird, indem die Methode AssertJassertThatThrownBy
verwendet wird.
Hinweis
Du kannst mit diesem Test spielen, indem du die Timeout-Deklaration entfernst (d.h. Schritt 1). Wenn du das tust, schlägt der Test fehl, da eine Ausnahme erwartet, aber nicht ausgelöst wird.
Zeitüberschreitung beim Laden des Skripts
Das Zeitlimit für das Laden von Skripten bietet ein Zeitlimit für die Unterbrechung eines Skripts, das gerade ausgewertet wird. Der Standardwert für diese Zeitüberschreitung beträgt dreihundert Sekunden. Beispiel 4-8 zeigt einen Test mit einem Zeitlimit für das Laden von Skripten.
Beispiel 4-8. Test mit einer Zeitüberschreitung beim Laden eines Skripts
@Test
void
testScriptTimeout
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
JavascriptExecutor
js
=
(
JavascriptExecutor
)
driver
;
driver
.
manage
(
)
.
timeouts
(
)
.
scriptTimeout
(
Duration
.
ofSeconds
(
3
)
)
;
assertThatThrownBy
(
(
)
-
>
{
long
waitMillis
=
Duration
.
ofSeconds
(
5
)
.
toMillis
(
)
;
String
script
=
"const callback = arguments[arguments.length - 1];"
+
"window.setTimeout(callback, "
+
waitMillis
+
");"
;
js
.
executeAsyncScript
(
script
)
;
}
)
.
isInstanceOf
(
ScriptTimeoutException
.
class
)
;
}
Wir definieren eine Skript-Zeitüberschreitung von drei Sekunden. Das bedeutet, dass ein Skript, das länger als diese Zeit dauert, eine Ausnahme auslöst.
Wir führen ein asynchrones Skript aus, das die Ausführung fünf Sekunden lang pausiert.
Die Ausführungszeit des Skripts ist größer als der konfigurierte Skript-Timeout, was zu einer
ScriptTimeoutException
führt. Auch dieses Beispiel ist ein negativer Test, d.h. es wurde so konzipiert, dass diese Ausnahme erwartet wird.
Screenshots
Selenium WebDriver wird hauptsächlich verwendet, um funktionale End-to-End-Tests von Webanwendungen durchzuführen. Mit anderen Worten: Wir verwenden ihn, um zu überprüfen, ob sich Webanwendungen wie erwartet verhalten, wenn wir mit ihrer Benutzeroberfläche (d. h. mit einem Webbrowser) interagieren. Dieser Ansatz ist sehr praktisch, um High-Level-Benutzerszenarien zu automatisieren, aber er birgt auch verschiedene Schwierigkeiten. Eine der größten Herausforderungen bei End-to-End-Tests besteht darin, die Ursache für einen fehlgeschlagenen Test zu ermitteln. Angenommen, der Fehler ist legitim (d. h. er wurde nicht durch einen schlecht implementierten Test verursacht), dann kann die Ursache ganz unterschiedlich sein: auf der Client-Seite (z. B. fehlerhafte JavaScript-Logik), auf der Server-Seite (z. B. eine interne Ausnahme) oder bei der Integration mit anderen Komponenten (z. B. unzureichender Zugriff auf die Datenbank), neben anderen Gründen. Einer der häufigsten Mechanismen, die in Selenium WebDriver zur Fehleranalyse eingesetzt werden, ist das Erstellen von Browser-Screenshots. In diesem Abschnitt werden die von der Selenium WebDriver API bereitgestellten Mechanismen vorgestellt.
Tipp
In"Fehleranalyse" werden die Framework-spezifischen Techniken erläutert, mit denen festgestellt werden kann, wann ein Test fehlgeschlagen ist, um verschiedene Fehleranalysetechniken wie Screenshots, Aufzeichnungen und Logsammlungen durchzuführen.
Selenium WebDriver bietet die Schnittstelle TakesScreenshot
für die Erstellung von Browser-Screenshots. Jedes Treiberobjekt, das von RemoteWebDriver
erbt (siehe Abbildung 2-2), implementiert ebenfalls diese Schnittstelle. Wir können also ein WebDriver
Objekt, das einen der wichtigsten Browser instanziiert (z.B. ChromeDriver
, FirefoxDriver
, etc.), wie folgt casten:
WebDriver
driver
=
new
ChromeDriver
();
TakesScreenshot
ts
=
(
TakesScreenshot
)
driver
;
Die Schnittstelle TakesScreenshot
bietet nur eine Methode namens getScreenshotAs(OutputType<X> target)
, um Screenshots zu erstellen. Der Parameter OutputType<X> target
bestimmt den Screenshot-Typ und den zurückgegebenen Wert. Tabelle 4-2 zeigt die verfügbaren Alternativen für diesen Parameter.
Tipp
Mit der Methode getScreenshotAs()
können Screenshots des Browser-Viewports erstellt werden. Darüber hinaus ermöglicht Selenium WebDriver 4 die Erstellung von Ganzseiten-Screenshots mit verschiedenen Mechanismen (siehe "Ganzseiten-Screenshot").
Beispiel 4-9 zeigt einen Test zur Erstellung eines Browser-Screenshots im PNG-Format. Beispiel 4-10 zeigt einen weiteren Test, um einen Screenshot als Base64-String zu erstellen. Der resultierende Screenshot ist in Abbildung 4-3 zu sehen.
Beispiel 4-9. Einen Screenshot als PNG-Datei erstellen
@Test
void
testScreenshotPng
(
)
throws
IOException
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
TakesScreenshot
ts
=
(
TakesScreenshot
)
driver
;
File
screenshot
=
ts
.
getScreenshotAs
(
OutputType
.
FILE
)
;
log
.
debug
(
"Screenshot created on {}"
,
screenshot
)
;
Path
destination
=
Paths
.
get
(
"screenshot.png"
)
;
Files
.
move
(
screenshot
.
toPath
(
)
,
destination
,
REPLACE_EXISTING
)
;
log
.
debug
(
"Screenshot moved to {}"
,
destination
)
;
assertThat
(
destination
)
.
exists
(
)
;
}
Wir machen den Browser-Bildschirm zu einer PNG-Datei.
Diese Datei befindet sich standardmäßig in einem temporären Ordner, also verschieben wir sie in eine neue Datei namens
screenshot.png
(im Stammordner des Projekts).Wir verwenden Standard-Java, um die Screenshot-Datei an den neuen Ort zu verschieben.
Wir verwenden Assertions, um zu überprüfen, ob die Zieldatei existiert.
Beispiel 4-10. Test, um einen Screenshot als Base64 zu erstellen
@Test
void
testScreenshotBase64
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
TakesScreenshot
ts
=
(
TakesScreenshot
)
driver
;
String
screenshot
=
ts
.
getScreenshotAs
(
OutputType
.
BASE64
)
;
log
.
debug
(
"Screenshot in base64 "
+
"(you can copy and paste it into a browser navigation bar to watch it)\n"
+
"data:image/png;base64,{}"
,
screenshot
)
;
assertThat
(
screenshot
)
.
isNotEmpty
(
)
;
}
Wir machen den Browser-Bildschirm im Base64-Format.
Wir hängen das Präfix
data:image/png;base64,
an den Base64-String an und protokollieren ihn in der Standardausgabe. Du kannst die resultierende Zeichenkette kopieren und in die Navigationsleiste eines Browsers einfügen, um das Bild anzuzeigen.Wir behaupten, dass der Screenshot-String einen Inhalt hat.
Hinweis
Die Protokollierung des Screenshots in Base64 wie im vorherigen Beispiel könnte sehr nützlich sein, um Fehler zu diagnostizieren, wenn wir Tests auf CI-Servern durchführen, bei denen wir keinen Zugriff auf das System haben (z. B. GitHub Actions).
WebElement Screenshots
Die Schnittstelle WebElement
erweitert die Schnittstelle TakesScreenshot
. Auf diese Weise ist es möglich, Teil-Screenshots des sichtbaren Inhalts eines bestimmten Webelements zu erstellen. (Siehe Beispiel 4-11.) Beachte, dass dieser Test dem vorherigen mit PNG-Dateien sehr ähnlich ist, aber in diesem Fall rufen wir die Methode getScreenshotAs()
direkt mit einem Webelement auf. Abbildung 4-4 zeigt den resultierenden Screenshot.
Beispiel 4-11. Testen der Erstellung eines Teilbildschirms als PNG-Datei
@Test
void
testWebElementScreenshot
()
throws
IOException
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
);
WebElement
form
=
driver
.
findElement
(
By
.
tagName
(
"form"
));
File
screenshot
=
form
.
getScreenshotAs
(
OutputType
.
FILE
);
Path
destination
=
Paths
.
get
(
"webelement-screenshot.png"
);
Files
.
move
(
screenshot
.
toPath
(),
destination
,
REPLACE_EXISTING
);
assertThat
(
destination
).
exists
();
}
Größe und Position des Fensters
Die Selenium WebDriver API ermöglicht es, die Größe und Position des Browsers sehr einfach über die Window
Schnittstelle zu manipulieren. Auf diesen Typ kann von einem Treiberobjekt aus mit der folgenden Anweisung zugegriffen werden. Tabelle 4-3 zeigt die verfügbaren Methoden in dieser Schnittstelle. Beispiel 4-12 zeigt einen grundlegenden Test über diese Funktion.
Window
window
=
driver
.
manage
().
window
();
Methode | Rückgabe | Beschreibung |
---|---|---|
|
|
Ermittelt die aktuelle Fenstergröße. Sie gibt die äußere Abmessung des Fensters zurück, nicht nur den Viewport (d. h. den sichtbaren Bereich einer Webseite für Endnutzer). |
|
|
Ändere die aktuelle Fenstergröße (auch hier wieder die äußere Abmessung und nicht das Ansichtsfenster). |
|
|
Ermittelt die aktuelle Fensterposition (relativ zur oberen linken Ecke des Bildschirms). |
|
|
Ändere die aktuelle Fensterposition (wieder relativ zur oberen linken Ecke des Bildschirms). |
|
|
Maximiere das aktuelle Fenster. |
|
|
Minimiere das aktuelle Fenster. |
|
|
Vergrößert den Bildschirm des aktuellen Fensters. |
Beispiel 4-12. Test zum Lesen und Ändern der Browsergröße und -position
@Test
void
testWindow
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
Window
window
=
driver
.
manage
(
)
.
window
(
)
;
Point
initialPosition
=
window
.
getPosition
(
)
;
Dimension
initialSize
=
window
.
getSize
(
)
;
log
.
debug
(
"Initial window: position {} -- size {}"
,
initialPosition
,
initialSize
)
;
window
.
maximize
(
)
;
Point
maximizedPosition
=
window
.
getPosition
(
)
;
Dimension
maximizedSize
=
window
.
getSize
(
)
;
log
.
debug
(
"Maximized window: position {} -- size {}"
,
maximizedPosition
,
maximizedSize
)
;
assertThat
(
initialPosition
)
.
isNotEqualTo
(
maximizedPosition
)
;
assertThat
(
initialSize
)
.
isNotEqualTo
(
maximizedSize
)
;
}
Browser-Verlauf
Selenium WebDriver ermöglicht die Manipulation des Browserverlaufs über die Schnittstelle Navigation
. Die folgende Anweisung veranschaulicht, wie man von einem WebDriver
Objekt auf diese Schnittstelle zugreift. Die Verwendung dieser Schnittstelle ist recht einfach. Tabelle 4-4 zeigt ihre öffentlichen Methoden, und Beispiel 4-13 zeigt ein grundlegendes Beispiel. Beachte, dass dieser Test mit diesen Methoden zu verschiedenen Webseiten navigiert und am Ende des Tests überprüft, ob die URL der Webseite den Erwartungen entspricht.
Navigation
navigation
=
driver
.
navigate
();
Methode | Rückgabe | Beschreibung |
---|---|---|
|
|
Im Browserverlauf zurückgehen |
|
|
Im Browserverlauf vorwärts gehen |
|
|
Eine neue Webseite in das aktuelle Fenster laden |
|
|
Aktualisiere die aktuelle Seite |
Der Schatten DOM
Wie in "The Document Object Model (DOM)" vorgestellt , ist das DOM eine Programmierschnittstelle, die es uns ermöglicht, eine Webseite mithilfe einer Baumstruktur darzustellen und zu manipulieren. Das Shadow-DOM ist eine Funktion dieser Programmierschnittstelle, die die Erstellung von Teilbäumen innerhalb des regulären DOM-Baums ermöglicht. Das Schatten-DOM ermöglicht die Kapselung einer Gruppe von DOM-Teilbäumen ( Schattenbaum genannt, wie in Abbildung 4-5 dargestellt), die andere CSS-Stile als das ursprüngliche DOM festlegen können. Der Knoten im regulären DOM, an den der Schattenbaum angehängt ist, wird als Shadow Host bezeichnet. Der Wurzelknoten des Schattenbaums wird Schattenwurzel genannt. Wie in Abbildung 4-5 dargestellt, wird der Schattenbaum in einem einzigen zusammengesetzten Baum in das ursprüngliche DOM eingefügt, um im Browser gerendert zu werden.
Hinweis
Das Shadow DOM ist Teil des Standardpakets (zusammen mit HTML-Vorlagen oder benutzerdefinierten Elementen), das die Implementierung von Webkomponenten (d. h. wiederverwendbaren benutzerdefinierten Elementen für Webanwendungen) ermöglicht.
Das Schatten-DOM ermöglicht die Erstellung von in sich geschlossenen Komponenten. Mit anderen Worten: Der Schattenbaum ist vom ursprünglichen DOM isoliert. Diese Funktion ist nützlich für Webdesign und Komposition, kann aber für automatisierte Tests mit Selenium WebDriver eine Herausforderung darstellen (da die regulären Lokalisierungsstrategien keine Webelemente innerhalb des Schattenbaums finden können). Glücklicherweise bietet Selenium WebDriver 4 eine WebElement
Methode, die den Zugriff auf das Shadow DOM ermöglicht. Beispiel 4-14 demonstriert diese Anwendung.
Beispiel 4-14. Test zum Lesen des Schatten-DOMs
@Test
void
testShadowDom
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/shadow-dom.html"
)
;
WebElement
content
=
driver
.
findElement
(
By
.
id
(
"content"
)
)
;
SearchContext
shadowRoot
=
content
.
getShadowRoot
(
)
;
WebElement
textElement
=
shadowRoot
.
findElement
(
By
.
cssSelector
(
"p"
)
)
;
assertThat
(
textElement
.
getText
(
)
)
.
contains
(
"Hello Shadow DOM"
)
;
}
Wir öffnen die Übungswebseite, die einen Schattenbaum enthält. Du kannst den Quellcode dieser Seite einsehen, um die JavaScript-Methode zu überprüfen, mit der ein Schattenbaum erstellt wird.
Wir erhalten die Schattenwurzel vom Host-Element. Als Ergebnis erhalten wir eine Instanz von
SearchContext
, einer Schnittstelle, die vonWebDriver
undWebElement
implementiert wird, und die es uns ermöglicht, Elemente mit den MethodenfindElement()
undfindElements()
zu finden.Wir finden das erste Absatzelement im Schattenbaum.
Wir überprüfen, ob der Textinhalt des Schattenelements wie erwartet ist.
Cookies
HTTP 1.x ist ein zustandsloses Protokoll, was bedeutet, dass der Server den Status des Benutzers nicht verfolgt. Mit anderen Worten: Webserver erinnern sich nicht an die Benutzer bei verschiedenen Anfragen. Der Cookie-Mechanismus ist eine Erweiterung von HTTP, die es ermöglicht, Benutzer zu verfolgen, indem sie kleine Textstücke, Cookies genannt, vom Server zum Client sendet. Diese Cookies müssen von den Kunden zurückgeschickt werden, so dass sich die Server an ihre Kunden erinnern. Cookies ermöglichen es unter anderem, Websitzungen aufrechtzuerhalten oder das Nutzererlebnis auf der Website zu personalisieren.
Webbrowser ermöglichen die manuelle Verwaltung der Browser-Cookies. Selenium WebDriver ermöglicht eine äquivalente Manipulation, allerdings programmatisch. Die Selenium WebDriver API bietet dafür die in Tabelle 4-5 aufgeführten Methoden. Sie sind über die Funktion manage()
eines WebDriver
Objekts zugänglich.
Methode | Rückgabe | Beschreibung |
---|---|---|
|
|
Ein neues Cookie hinzufügen |
|
|
Ein bestehendes Cookie nach Namen löschen |
|
|
Ein bestehendes Cookie per Instanz löschen |
|
|
Alle Cookies löschen |
|
|
Alle Cookies erhalten |
|
|
Ein Cookie nach Name abrufen |
Wie diese Tabelle zeigt, bietet die Klasse Cookie
eine Abstraktion für ein einzelnes Cookie in Java. Tabelle 4-6 fasst die in dieser Klasse verfügbaren Methoden zusammen. Außerdem hat diese Klasse mehrere Konstruktoren, die die folgenden Parameter akzeptieren:
String name
-
Cookie-Name (obligatorisch)
String value
-
Cookie-Wert (obligatorisch)
String domain
-
Domain, in der das Cookie sichtbar ist (optional)
String path
-
Pfad, in dem das Cookie sichtbar ist (optional)
Date expiry
-
Ablaufdatum des Cookies (optional)
boolean isSecure
-
Ob das Cookie eine sichere Verbindung erfordert (optional)
boolean isHttpOnly
-
Ob es sich bei diesem Cookie um ein HTTP-Only-Cookie handelt, d. h., das Cookie ist nicht über ein clientseitiges Skript zugänglich (optional)
String sameSite
-
Ob es sich bei diesem Cookie um ein Same-Site-Cookie handelt, d. h., das Cookie ist auf einen First-Party- oder Same-Site-Kontext beschränkt (optional)
Methode | Rückgabe | Beschreibung |
---|---|---|
|
|
Cookie-Name lesen |
|
|
Cookie-Wert lesen |
|
|
Cookie-Domäne lesen |
|
|
Cookie-Pfad lesen |
|
|
Lesen, ob das Cookie eine sichere Verbindung erfordert |
|
|
Lesen, wenn Cookie HTTP-only ist |
|
|
Ablaufdatum des Cookies lesen |
|
|
Cookie-Kontext auf derselben Seite lesen |
|
|
Überprüfe die verschiedenen Felder des Cookies und werfe ein |
|
|
Cookie-Werte als Key-Value-Map abbilden |
Die folgenden Beispiele zeigen verschiedene Tests, die Web-Cookies mit der Selenium WebDriver API verwalten. Diese Beispiele verwenden eine Übungswebseite, die die Website-Cookies auf der GUI anzeigt (siehe Abbildung 4-6):
-
Beispiel 4-15 zeigt, wie du die vorhandenen Cookies einer Website auslesen kannst.
-
Beispiel 4-16 zeigt, wie du neue Cookies hinzufügst.
-
Beispiel 4-17 erklärt, wie du bestehende Cookies bearbeitest.
-
Beispiel 4-18 zeigt, wie du Cookies löschen kannst.
Wir erhalten das
Options
Objekt, das zur Verwaltung von Cookies verwendet wird.Wir lesen alle verfügbaren Cookies auf dieser Seite. Sie sollte zwei Cookies enthalten.
Wir lesen den Cookie mit dem Namen
username
.Der Wert des vorherigen Cookies sollte
John Doe
sein.Die letzte Anweisung hat keine Auswirkungen auf den Test. Wir rufen diesen Befehl auf, um die Cookies in der Browser-GUI zu prüfen.
Wir erstellen ein neues Cookie.
Wir fügen den Cookie zur aktuellen Seite hinzu.
Wir lesen den Wert des gerade hinzugefügten Cookies.
Wir überprüfen, ob dieser Wert den Erwartungen entspricht.
Dropdown-Listen
Ein typisches Element in Webformularen sind Dropdown-Listen. Diese Felder ermöglichen es den Nutzern, ein oder mehrere Elemente innerhalb einer Optionsliste auszuwählen. Die klassischen HTML-Tags, die zur Darstellung dieser Felder verwendet werden, sind <select>
und <options>
. Wie üblich enthält das Praxis-Webformular eines dieser Elemente (siehe Abbildung 4-7), das in HTML wie folgt definiert ist:
<
select
class
=
"form-select"
name
=
"my-select"
>
<
option
selected
>
Open this select menu</
option
>
<
option
value
=
"1"
>
One</
option
>
<
option
value
=
"2"
>
Two</
option
>
<
option
value
=
"3"
>
Three</
option
>
</
select
>
Diese Elemente sind in Webformularen sehr weit verbreitet. Aus diesem Grund bietet Selenium WebDriver eine Hilfsklasse namens Select
, um ihre Handhabung zu vereinfachen. Diese Klasse umhüllt eine Auswahl WebElement
und bietet eine Vielzahl von Funktionen. Tabelle 4-7 fasst die öffentlichen Methoden von zusammen, die in der Klasse Select
verfügbar sind. Beispiel 4-19 zeigt einen einfachen Test mit dieser Klasse.
Beispiel 4-19. Test der Interaktion mit einem Auswahlfeld
@Test
void
test
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
)
;
Select
select
=
new
Select
(
driver
.
findElement
(
By
.
name
(
"my-select"
)
)
)
;
String
optionLabel
=
"Three"
;
select
.
selectByVisibleText
(
optionLabel
)
;
assertThat
(
select
.
getFirstSelectedOption
(
)
.
getText
(
)
)
.
isEqualTo
(
optionLabel
)
;
}
Wir suchen das Select-Element anhand seines Namens und verwenden die resultierende
WebElement
, um einSelect
Objekt zu instanziieren.Wir wählen eine der Optionen aus, die in dieser Auswahl zur Verfügung stehen, indem wir eine By-Text-Strategie anwenden.
Wir überprüfen, ob der ausgewählte Optionstext den Erwartungen entspricht.
Elemente der Datenliste
Eine andere Möglichkeit, Dropdown-Listen in HTML zu implementieren, ist die Verwendung von Datenlisten. Obwohl Datenlisten aus grafischer Sicht den Auswahlelementen sehr ähnlich sind, gibt es einen klaren Unterschied zwischen ihnen. Einerseits zeigen Auswahlfelder eine Optionsliste an, und die Benutzer/innen wählen eine (oder mehrere) der verfügbaren Optionen aus. Andererseits zeigen Datenlisten eine Liste mit vorgeschlagenen Optionen an, die mit einem Eingabefeld (Textfeld) verbunden sind, und die Nutzer können einen dieser vorgeschlagenen Werte auswählen oder einen eigenen Wert eingeben. Das Praxis-Webformular enthält eine dieser Datenlisten. Das Markup findest du im folgenden Snippet und einen Screenshot in Abbildung 4-8.
<
input
class
=
"form-control"
list
=
"my-options"
name
=
"my-datalist"
placeholder
=
"Type to search..."
>
<
datalist
id
=
"my-options"
>
<
option
value
=
"San Francisco"
>
<
option
value
=
"New York"
>
<
option
value
=
"Seattle"
>
<
option
value
=
"Los Angeles"
>
<
option
value
=
"Chicago"
>
</
datalist
>
Selenium WebDriver bietet keine benutzerdefinierte Hilfsklasse für die Bearbeitung von Datenlisten. Stattdessen müssen wir mit ihnen wie mit Standard-Eingabetexten interagieren, mit dem Unterschied, dass ihre Optionen beim Klicken auf das Eingabefeld angezeigt werden. Beispiel 4-20 zeigt einen Test, der dies veranschaulicht.
Beispiel 4-20. Test der Interaktion mit einem Datenlistenfeld
@Test
void
testDatalist
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
)
;
WebElement
datalist
=
driver
.
findElement
(
By
.
name
(
"my-datalist"
)
)
;
datalist
.
click
(
)
;
WebElement
option
=
driver
.
findElement
(
By
.
xpath
(
"//datalist/option[2]"
)
)
;
String
optionValue
=
option
.
getAttribute
(
"value"
)
;
datalist
.
sendKeys
(
optionValue
)
;
assertThat
(
optionValue
)
.
isEqualTo
(
"New York"
)
;
}
Navigation Ziele
Wenn wir mit einem Browser durch Webseiten navigieren, verwenden wir standardmäßig eine einzelne Seite, die der URL in der Navigationsleiste entspricht. Dann können wir eine weitere Seite in einem neuen Browser-Tab öffnen. Dieser zweite Tab kann explizit geöffnet werden, wenn ein Link das Attribut target
definiert, oder der Nutzer kann die Navigation zu einem neuen Tab erzwingen, indem er die Modifikatortaste Strg (oder Cmd in macOS) zusammen mit dem Mausklick in einen Weblink verwendet. Eine weitere Möglichkeit ist , Webseiten in neuen Fenstern zu öffnen. Dazu verwenden Webseiten normalerweise den JavaScript-Befehl window.open(url)
. Eine andere Möglichkeit, verschiedene Seiten gleichzeitig anzuzeigen, ist die Verwendung von Frames und iframes. Ein Frame ist ein HTML-Elementtyp, der einen bestimmten Bereich (in einem sogenannten Frameset) definiert, in dem eine Webseite angezeigt werden kann. Ein iframe ist ein weiteres HTML-Element, das die Einbettung einer HTML-Seite in die aktuelle Seite ermöglicht.
Warnung
Die Verwendung von Frames wird nicht empfohlen, da diese Elemente viele Nachteile haben, wie z. B. Probleme mit der Leistung und der Barrierefreiheit. Ich erkläre, wie du sie aus Kompatibilitätsgründen mit Selenium WebDriver verwenden kannst. Dennoch empfehle ich dringend, Frames bei brandneuen Webanwendungen zu vermeiden.
Die Selenium WebDriver API bietet die Schnittstelle TargetLocator
zum Umgang mit den zuvor genannten Zielen (d.h. Tabs, Fenster, Frames und Iframes). Diese Schnittstelle ermöglicht es, den Fokus der zukünftigen Befehle eines WebDriver
Objekts zu ändern (auf einen neuen Tab, ein neues Fenster usw.). Auf diese Schnittstelle kann man zugreifen, indem man die Methode switchTo()
in einem WebDriver
Objekt aufruft.Tabelle 4-8 beschreibt die öffentlichen Methoden.
Methode | Rückgabe | Beschreibung |
---|---|---|
|
|
Wechsle den Fokus auf einen Frame (oder Iframe) nach Indexnummer. |
|
|
Ändere den Fokus auf einen Frame (oder iframe) nach Name oder id. |
|
|
Ändere den Fokus auf einen Frame (oder iframe), der sich zuvor als WebElement befand. |
|
|
Wechsle den Fokus auf den übergeordneten Kontext. |
|
|
Wechsle den Fokus auf zu einem anderen Fenster, nach Name oder Handle. Ein Fensterhandle ist eine hexadezimale Zeichenfolge, die ein Fenster oder eine Registerkarte eindeutig identifiziert. |
|
|
Erstellt ein neues Browserfenster (mit |
|
|
Wähle das Hauptdokument (bei Verwendung von Iframes) oder den ersten Frame auf der Seite (bei Verwendung eines Framesets). |
|
|
Ermittelt das aktuell ausgewählte Element. |
|
|
Ändere den Fokus auf eine Fenstermeldung (siehe "Dialogfelder" für weitere Informationen). |
Registerkarten und Fenster
Beispiel 4-21 zeigt einen Test, bei dem wir einen neuen Tab für die Navigation auf einer zweiten Webseite öffnen. Beispiel 4-22 zeigt einen ähnlichen Fall, bei dem ein neues Fenster für die zweite Webseite geöffnet wird. Beachte, dass der Unterschied zwischen diesen Beispielen nur in den Parametern WindowType.TAB
und WindowType.WINDOW
besteht.
Beispiel 4-21. Test zum Öffnen einer neuen Registerkarte
@Test
void
testNewTab
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
String
initHandle
=
driver
.
getWindowHandle
(
)
;
driver
.
switchTo
(
)
.
newWindow
(
WindowType
.
TAB
)
;
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
)
;
assertThat
(
driver
.
getWindowHandles
(
)
.
size
(
)
)
.
isEqualTo
(
2
)
;
driver
.
switchTo
(
)
.
window
(
initHandle
)
;
driver
.
close
(
)
;
assertThat
(
driver
.
getWindowHandles
(
)
.
size
(
)
)
.
isEqualTo
(
1
)
;
}
Wir navigieren zu einer Webseite.
Wir erhalten das aktuelle Fensterhandle.
Wir öffnen eine neue Registerkarte und ändern den Fokus auf diese.
Wir öffnen eine weitere Webseite (da der Fokus im zweiten Tab liegt, wird die Seite im zweiten Tab geöffnet).
Wir überprüfen, dass die Anzahl der Fenstergriffe an dieser Stelle 2 beträgt.
Wir ändern den Fokus von auf das ursprüngliche Fenster (mithilfe seines Handles).
Wir schließen nur das aktuelle Fenster. Die zweite Registerkarte bleibt geöffnet.
Wir überprüfen, dass die Anzahl der Fenstergriffe jetzt 1 ist.
Beispiel 4-22. Test zum Öffnen eines neuen Fensters
@Test
void
testNewWindow
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
String
initHandle
=
driver
.
getWindowHandle
(
)
;
driver
.
switchTo
(
)
.
newWindow
(
WindowType
.
WINDOW
)
;
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-form.html"
)
;
assertThat
(
driver
.
getWindowHandles
(
)
.
size
(
)
)
.
isEqualTo
(
2
)
;
driver
.
switchTo
(
)
.
window
(
initHandle
)
;
driver
.
close
(
)
;
assertThat
(
driver
.
getWindowHandles
(
)
.
size
(
)
)
.
isEqualTo
(
1
)
;
}
Rahmen und Iframes
Beispiel 4-23 zeigt einen Test, bei dem die zu testende Webseite einen iframe enthält. Beispiel 4-24 zeigt den gleichen Fall auf , allerdings mit einem Frameset.
Beispiel 4-23. Test zum Umgang mit iframes
@Test
void
testIFrames
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/iframes.html"
)
;
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
10
)
)
;
wait
.
until
(
ExpectedConditions
.
frameToBeAvailableAndSwitchToIt
(
"my-iframe"
)
)
;
By
pName
=
By
.
tagName
(
"p"
)
;
wait
.
until
(
ExpectedConditions
.
numberOfElementsToBeMoreThan
(
pName
,
0
)
)
;
List
<
WebElement
>
paragraphs
=
driver
.
findElements
(
pName
)
;
assertThat
(
paragraphs
)
.
hasSize
(
20
)
;
}
Wir öffnen eine Webseite, die einen Iframe enthält (siehe Abbildung 4-9).
Wir verwenden ein explizites Warten, um auf den Frame zu warten und zu ihm zu wechseln.
Wir verwenden eine weitere explizite Wartezeit, um zu warten, bis die im iframe enthaltenen Absätze verfügbar sind.
Wir behaupten, dass die Anzahl der Absätze wie erwartet ist.
Beispiel 4-24. Test Umgang mit Frames
@Test
void
testFrames
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/frames.html"
)
;
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
10
)
)
;
String
frameName
=
"frame-body"
;
wait
.
until
(
ExpectedConditions
.
presenceOfElementLocated
(
By
.
name
(
frameName
)
)
)
;
driver
.
switchTo
(
)
.
frame
(
frameName
)
;
By
pName
=
By
.
tagName
(
"p"
)
;
wait
.
until
(
ExpectedConditions
.
numberOfElementsToBeMoreThan
(
pName
,
0
)
)
;
List
<
WebElement
>
paragraphs
=
driver
.
findElements
(
pName
)
;
assertThat
(
paragraphs
)
.
hasSize
(
20
)
;
}
Wir öffnen eine Webseite , die ein Frameset enthält (siehe Abbildung 4-10).
Wir warten, bis der Rahmen verfügbar ist. Beachte, dass die Schritte 2 und 3 in Beispiel 4-23 mit diesem Schritt gleichzusetzen sind.
Wir ändern den Fokus auf diesen Rahmen.
Dialogboxen
JavaScript bietet verschiedene Dialogfelder (manchmal auch Pop-ups genannt), um mit dem Benutzer zu interagieren, nämlich:
- Alert
-
Um eine Nachricht anzuzeigen und darauf zu warten, dass der Benutzer die Schaltfläche OK drückt (einzige Auswahlmöglichkeit im Dialog). Der folgende Code öffnet zum Beispiel einen Dialog, der "Hallo Welt!" anzeigt und darauf wartet, dass der Benutzer die Schaltfläche OK drückt.
alert
(
"Hello world!"
);
- Bestätige
-
Um ein Dialogfeld mit einer Frage und zwei Schaltflächen anzuzeigen: OK und Abbrechen. Der folgende Code öffnet z. B. ein Dialogfeld mit der Meldung "Ist das richtig?" und der Eingabeaufforderung, auf OK oder Abbrechen zu klicken.
let
correct
=
confirm
(
"Is this correct?"
);
- Eingabeaufforderung
-
So zeigst du ein Dialogfeld mit einer Textnachricht, einem Eingabetextfeld und den Schaltflächen OK und Abbrechen an. Der folgende Code zeigt zum Beispiel ein Pop-up mit der Meldung "Bitte geben Sie Ihren Namen ein", ein Dialogfeld, in dem der Benutzer etwas eingeben kann, und zwei Schaltflächen (OK und Abbrechen).
let
username
=
prompt
(
"Please enter your name"
);
Außerdem kann mit CSS eine andere Art von Dialogfeld, das sogenannte modale Fenster, implementiert werden. Dieses Dialogfeld deaktiviert das Hauptfenster (lässt es aber sichtbar) und überlagert ein untergeordnetes Pop-up-Fenster, das normalerweise eine Nachricht und einige Schaltflächen anzeigt. Auf der Praxis-Webseite findest du eine Beispielseite mit all diesen Dialogfeldern (Warnung, Bestätigung, Eingabeaufforderung und modales Fenster). Abbildung 4-11 zeigt einen Screenshot dieser Seite, wenn das modale Dialogfeld aktiv ist.
Warnungen, Bestätigungen und Eingabeaufforderungen
Die Selenium WebDriver API bietet die Schnittstelle Alert
zur Bearbeitung von JavaScript-Dialogen (d.h. Warnungen, Bestätigungen und Eingabeaufforderungen). Tabelle 4-9 beschreibt die Methoden, die von dieser Schnittstelle bereitgestellt werden. Beispiel 4-25 zeigt einen einfachen Test, der mit einem Alert interagiert.
Beispiel 4-25. Test der Handhabung eines Warndialogs
@Test
void
testAlert
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/dialog-boxes.html"
)
;
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
5
)
)
;
driver
.
findElement
(
By
.
id
(
"my-alert"
)
)
.
click
(
)
;
wait
.
until
(
ExpectedConditions
.
alertIsPresent
(
)
)
;
Alert
alert
=
driver
.
switchTo
(
)
.
alert
(
)
;
assertThat
(
alert
.
getText
(
)
)
.
isEqualTo
(
"Hello world!"
)
;
alert
.
accept
(
)
;
}
Wir öffnen die Praxis-Webseite, auf der Dialogfelder geöffnet werden.
Wir klicken auf die linke Schaltfläche, um einen JavaScript-Alarm zu starten.
Wir warten, bis der Warndialog auf dem Bildschirm angezeigt wird.
Wir ändern den Fokus auf das Alarm-Pop-up.
Wir überprüfen, ob der Alarmtext den Erwartungen entspricht.
Wir klicken auf die Schaltfläche "OK" im Warndialog.
Wir können die Schritte 3 und 4 durch eine einzige explizite Warteanweisung ersetzen, wie folgt (du findest sie in einem zweiten Test in derselben Klasse im Repository für Beispiele):
Alert
alert
=
wait
.
until
(
ExpectedConditions
.
alertIsPresent
());
Der nächste Test(Beispiel 4-26) veranschaulicht , wie man mit einem Bestätigungsdialog umgeht. Dieses Beispiel ist dem vorherigen sehr ähnlich, aber in diesem Fall können wir die Methode dismiss()
aufrufen, um auf die Schaltfläche Abbrechen zu klicken, die im Bestätigungsdialog verfügbar ist. Beispiel 4-27 schließlich zeigt , wie man eine Eingabeaufforderung verwaltet. In diesem Fall können wir eine Zeichenfolge in den Eingabetext eingeben.
Beispiel 4-26. Test der Handhabung eines Bestätigungsdialogs
@Test
void
testConfirm
()
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/dialog-boxes.html"
);
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
5
));
driver
.
findElement
(
By
.
id
(
"my-confirm"
)).
click
();
wait
.
until
(
ExpectedConditions
.
alertIsPresent
());
Alert
confirm
=
driver
.
switchTo
().
alert
();
assertThat
(
confirm
.
getText
()).
isEqualTo
(
"Is this correct?"
);
confirm
.
dismiss
();
}
Beispiel 4-27. Test der Handhabung einer Eingabeaufforderung
@Test
void
testPrompt
()
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/dialog-boxes.html"
);
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
5
));
driver
.
findElement
(
By
.
id
(
"my-prompt"
)).
click
();
wait
.
until
(
ExpectedConditions
.
alertIsPresent
());
Alert
prompt
=
driver
.
switchTo
().
alert
();
prompt
.
sendKeys
(
"John Doe"
);
assertThat
(
prompt
.
getText
()).
isEqualTo
(
"Please enter your name"
);
prompt
.
accept
();
}
Modale Fenster
Modale Fenster sind Dialogfelder, die mit einfachen CSS- und HTML-Funktionen erstellt werden. Aus diesem Grund bietet Selenium WebDriver kein spezielles Dienstprogramm für die Bearbeitung von modalen Fenstern. Stattdessen verwenden wir die Standard-WebDriver-API (Locators, Waits usw.), um mit modalen Fenstern zu interagieren. Beispiel 4-28 zeigt einen einfachen Test mit der Übungswebseite, die Dialogfenster enthält.
Beispiel 4-28. Test der Handhabung eines modalen Dialogs
@Test
void
testModal
()
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/dialog-boxes.html"
);
WebDriverWait
wait
=
new
WebDriverWait
(
driver
,
Duration
.
ofSeconds
(
5
));
driver
.
findElement
(
By
.
id
(
"my-modal"
)).
click
();
WebElement
close
=
driver
.
findElement
(
By
.
xpath
(
"//button[text() = 'Close']"
));
assertThat
(
close
.
getTagName
()).
isEqualTo
(
"button"
);
wait
.
until
(
ExpectedConditions
.
elementToBeClickable
(
close
));
close
.
click
();
}
Webspeicherung
Die Web Storage API ermöglicht es Webanwendungen , Daten lokal im Dateisystem des Clients zu speichern. Diese API bietet zwei JavaScript-Objekte:
window.localStorage
window.sessionStorage
-
Zum Speichern von Daten während der Sitzungszeit (Daten werden gelöscht, wenn der Browser-Tab geschlossen wird)
Selenium WebDriver bietet die Schnittstelle WebStorage
für die Handhabung der Web Storage API. Die meisten der WebDriver
Typen, die von Selenium WebDriver unterstützt werden, erben diese Schnittstelle: ChromeDriver
, EdgeDriver
, FirefoxDriver
, OperaDriver
und SafariDriver
. Auf diese Weise können wir diese Funktion dieser Browser nutzen. Beispiel 4-29 demonstriert diese Verwendung in Chrome. In diesem Test werden beide Arten der Webspeicherung (lokal und Sitzung) verwendet.
Beispiel 4-29. Test mit der Webspeicherung
@Test
void
testWebStorage
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/web-storage.html"
)
;
WebStorage
webStorage
=
(
WebStorage
)
driver
;
LocalStorage
localStorage
=
webStorage
.
getLocalStorage
(
)
;
log
.
debug
(
"Local storage elements: {}"
,
localStorage
.
size
(
)
)
;
SessionStorage
sessionStorage
=
webStorage
.
getSessionStorage
(
)
;
sessionStorage
.
keySet
(
)
.
forEach
(
key
-
>
log
.
debug
(
"Session storage: {}={}"
,
key
,
sessionStorage
.
getItem
(
key
)
)
)
;
assertThat
(
sessionStorage
.
size
(
)
)
.
isEqualTo
(
2
)
;
sessionStorage
.
setItem
(
"new element"
,
"new value"
)
;
assertThat
(
sessionStorage
.
size
(
)
)
.
isEqualTo
(
3
)
;
driver
.
findElement
(
By
.
id
(
"display-session"
)
)
.
click
(
)
;
}
Wir übergeben das Treiberobjekt an
WebStorage
.Wir protokollieren die Anzahl der Elemente der lokalen Speicherung.
Wir protokollieren die Speicherung der Sitzung (sie sollte zwei Elemente enthalten).
Nach dem Hinzufügen eines neuen Elements sollten sich drei Elemente in der Speicherung der Sitzung befinden.
Ereignis-Listener
Die Selenium WebDriver API ermöglicht das Erstellen von Listenern, die Ereignisse in WebDriver
und abgeleiteten Objekten melden. In früheren Versionen von Selenium WebDriver war diese Funktion über die Klasse EventFiringWebDriver
zugänglich. Diese Klasse ist seit Selenium WebDriver 4 veraltet, und stattdessen sollten wir die folgende Klasse verwenden:
EventFiringDecorator
-
Wrapper Klasse für
WebDriver
und abgeleitete Objekte (z.B.WebElement
,TargetLocator
, etc.). Sie ermöglicht die Registrierung von einem oder mehreren Listenern (d.h.WebDriverListener
Instanzen). WebDriverListener
-
Schnittstelle, die die im Dekorator registrierten Listener implementieren sollte. Sie unterstützt drei Arten von Ereignissen:
- Vor Veranstaltungen
-
Logik, die kurz vor Beginn eines Ereignisses eingefügt wird
- Nach Veranstaltungen
-
Logik, die kurz nach Beendigung eines Ereignisses eingefügt wird
- Fehlerereignisse
-
Logik eingefügt, bevor eine Ausnahme ausgelöst wird
Um einen Ereignis-Listener zu implementieren, sollten wir zunächst eine Listener-Klasse erstellen. Mit anderen Worten: Wir müssen eine Klasse erstellen, die die WebDriverListener
implementiert. Diese Schnittstelle definiert alle ihre Methoden mit dem Schlüsselwort default
und daher ist es optional, ihre Methoden zu überschreiben. Dank dieser Funktion (verfügbar ab Java 8) sollte unsere Klasse nur die Methode implementieren, die wir brauchen. Es gibt viele Listener-Methoden, z. B. afterGet()
(wird nach dem Aufruf der Methode get()
in einer WebDriver
-Instanz ausgeführt) oder beforeQuit()
(wird vor dem Aufruf der Methode quit()
in einer WebDriver
-Instanz ausgeführt), um nur einige zu nennen. Um all diese Listener zu überprüfen, empfehle ich dir, deine bevorzugte IDE zu verwenden, um die möglichen Methoden zu entdecken, die überschrieben/implementiert werden müssen. Abbildung 4-12 zeigt den Assistenten für diese Aufgabe in Eclipse.
Sobald wir unseren Listener implementiert haben, müssen wir die Dekoratorklasse erstellen. Es gibt zwei Möglichkeiten, das zu tun. Wenn wir ein WebDriver
Objekt dekorieren wollen, können wir eine Instanz von EventFiringDecorator
erstellen (und den Listener als Argument an den Konstruktor übergeben) und dann die Methode decorate()
aufrufen, um das WebDriver
Objekt zu übergeben. Zum Beispiel:
WebDriver
decoratedDriver
=
new
EventFiringDecorator
(
myListener
)
.
decorate
(
originalDriver
);
Die zweite Möglichkeit ist, andere Objekte der Selenium WebDriver API zu dekorieren, nämlich WebElement
, TargetLocator
, Navigation
, Options
, Timeouts
, Window
, Alert
oder VirtualAuthenticator
. In diesem Fall müssen wir die Methode createDecorated()
in einem EventFiringDecorator
Objekt aufrufen, um eine generische Klasse Decorated<T>
zu erhalten. Der folgende Ausschnitt zeigt ein Beispiel mit einem WebElement
als Parameter:
Decorated
<
WebElement
>
decoratedWebElement
=
new
EventFiringDecorator
(
listener
).
createDecorated
(
myWebElement
);
Schauen wir uns ein fertiges Beispiel an. Beispiel 4-30 zeigt zunächst die Klasse, die die Schnittstelle WebDriverListener
implementiert. Beachte diese Klasse implementiert zwei Methoden: afterGet()
und beforeQuit()
. Beide Methoden rufen takeScreenshot()
auf, um einen Browser-Screenshot zu machen. Alles in allem sammeln wir Browser-Screenshots kurz nach dem Laden einer Webseite (typischerweise zu Beginn des Tests) und vor dem Beenden (typischerweise am Ende des Tests). Beispiel 4-31 zeigt den Test, der diesen Listener verwendet.
Beispiel 4-30. Ereignis-Listener, der die Methoden afterGet() und beforeQuit() implementiert
public
class
MyEventListener
implements
WebDriverListener
{
static
final
Logger
log
=
getLogger
(
lookup
(
)
.
lookupClass
(
)
)
;
@Override
public
void
afterGet
(
WebDriver
driver
,
String
url
)
{
WebDriverListener
.
super
.
afterGet
(
driver
,
url
)
;
takeScreenshot
(
driver
)
;
}
@Override
public
void
beforeQuit
(
WebDriver
driver
)
{
takeScreenshot
(
driver
)
;
}
private
void
takeScreenshot
(
WebDriver
driver
)
{
TakesScreenshot
ts
=
(
TakesScreenshot
)
driver
;
File
screenshot
=
ts
.
getScreenshotAs
(
OutputType
.
FILE
)
;
SessionId
sessionId
=
(
(
RemoteWebDriver
)
driver
)
.
getSessionId
(
)
;
Date
today
=
new
Date
(
)
;
SimpleDateFormat
dateFormat
=
new
SimpleDateFormat
(
"yyyy.MM.dd_HH.mm.ss.SSS"
)
;
String
screenshotFileName
=
String
.
format
(
"%s-%s.png"
,
dateFormat
.
format
(
today
)
,
sessionId
.
toString
(
)
)
;
Path
destination
=
Paths
.
get
(
screenshotFileName
)
;
try
{
Files
.
move
(
screenshot
.
toPath
(
)
,
destination
)
;
}
catch
(
IOException
e
)
{
log
.
error
(
"Exception moving screenshot from {} to {}"
,
screenshot
,
destination
,
e
)
;
}
}
}
Wir überschreiben diese Methode, um nach dem Laden von Webseiten mit dem
WebDriver
Objekt eine eigene Logik auszuführen.Wir überschreiben diese Methode, um eine eigene Logik auszuführen , bevor wir das
WebDriver
Objekt verlassen.Wir verwenden einen eindeutigen Namen für die PNG-Screenshots. Dafür erhalten wir das Systemdatum (Datum und Uhrzeit) plus die Sitzungskennung .
Beispiel 4-31. Test mit EventFiringDecorator und dem vorherigen Listener
class
EventListenerJupiterTest
{
WebDriver
driver
;
@BeforeEach
void
setup
(
)
{
MyEventListener
listener
=
new
MyEventListener
(
)
;
WebDriver
originalDriver
=
WebDriverManager
.
chromedriver
(
)
.
create
(
)
;
driver
=
new
EventFiringDecorator
(
listener
)
.
decorate
(
originalDriver
)
;
}
@AfterEach
void
teardown
(
)
{
driver
.
quit
(
)
;
}
@Test
void
testEventListener
(
)
{
driver
.
get
(
"https://bonigarcia.dev/selenium-webdriver-java/"
)
;
assertThat
(
driver
.
getTitle
(
)
)
.
isEqualTo
(
"Hands-On Selenium WebDriver with Java"
)
;
driver
.
findElement
(
By
.
linkText
(
"Web form"
)
)
.
click
(
)
;
}
}
Wir erstellen ein dekoriertes
WebDriver
Objekt mit einer Instanz aufMyEventListener
. Wir verwenden das resultierendedriver
, um den Browser in der@Test
Logik zu steuern.Wir klicken auf einen Weblink, um die Seite zu wechseln. Die daraus resultierenden zwei Screenshots, die im Zuhörer aufgenommen wurden, sollten unterschiedlich sein.
WebDriver Ausnahmen
Alle von der WebDriver-API bereitgestellten Ausnahmen erben von der Klasse WebDriverException
und sind ungeprüft (siehe die folgende Seitenleiste, wenn du mit dieser Terminologie nicht vertraut bist). Abbildung 4-13 zeigt diese Ausnahmen in Selenium WebDriver 4. Wie diese Abbildung zeigt, gibt es viele verschiedene Ausnahmetypen. Tabelle 4-10 fasst einige der häufigsten Ursachen zusammen.
Zusammenfassung und Ausblick
In diesem Kapitel hast du auf einen umfassenden Überblick über die WebDriver-API-Funktionen erhalten, die mit verschiedenen Webbrowsern kompatibel sind. Unter anderem hast du erfahren, wie du JavaScript mit Selenium WebDriver ausführen kannst, und zwar mit synchronen, angehefteten (d.h. an eine WebDriver-Sitzung angehängten) und asynchronen Skripten. Dann hast du etwas über Timeouts gelernt, mit denen du ein Zeitlimit für das Laden von Seiten und die Ausführung von Skripten festlegen kannst. Außerdem hast du gesehen, wie du verschiedene Browseraspekte wie Größe und Position, Navigationsverlauf, das Schatten-DOM und Cookies verwalten kannst. Als Nächstes hast du erfahren, wie du mit bestimmten Webelementen interagieren kannst, z. B. mit Dropdown-Listen (Auswahl- und Datenlisten), Navigationszielen (Fenster, Tabs, Frames und Iframes) und Dialogfeldern (Warnungen, Eingabeaufforderungen, Bestätigungen und Modals). Abschließend haben wir uns den Mechanismus zur Implementierung von Webspeicherung und Ereignis-Listenern in Selenium WebDriver 4 sowie die wichtigsten WebDriver-Ausnahmen (und ihre häufigsten Ursachen) angesehen.
Im nächsten Kapitel werden die Funktionen der Selenium WebDriver API weiter erläutert. Das Kapitel erklärt die Aspekte, die für einen bestimmten Browser (z. B. Chrome, Firefox usw.) spezifisch sind, wie z. B. die Browserfunktionen (z. B. ChromeOptions
, FirefoxOptions
usw.), das Chrome DevTools Protocol (CDP), das Abfangen von Netzwerken, das Mocking von Geolocation-Koordinaten, das WebDriver BiDirectional (BiDi)-Protokoll, Authentifizierungsmechanismen oder das Drucken von Webseiten als PDF und andere Funktionen.
Get Hands-On Selenium WebDriver mit Java now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.