• Selenium Video Tutorials

Selenium WebDriver - DevTools



Selenium Webdriver 的最新版本是 4.x 版本。Selenium 4 帶來了許多改進,包括 Chrome DevTools (CDP) 上的新 API。它提供了對要執行測試的瀏覽器的更多控制。

什麼是 Chrome DevTools?

Chrome DevTools 是一套用於 Chromium 瀏覽器(即 Chrome、Edge 和 Opera)的工具。它們有助於啟用除錯並獲取有關被測應用程式的更多資訊。CDP 的優勢如下所示:

  • 獲取控制檯日誌
  • 執行和除錯 JavaScript
  • 模擬地理位置
  • 在文件物件模型 (DOM) 中檢查 Web 元素
  • 模擬網路流量
  • 監控網路流量
  • 更新 Web 元素及其 CSS

Selenium 4 中的 Chrome DevTool API

Selenium 4 提供了新的 Chrome DevTool API,這些 API 能夠實現以下功能:

  • 獲取並監視網路流量。
  • 模擬地理位置以進行本地化測試。
  • 更新裝置模式以檢查 Web 應用程式的響應能力。

ChromiumDriver 類是從 Selenium 4 版本開始引入的。此類包含 getDevTools() 和 executeCdpCommand() 方法。它們有助於訪問 CDP。getDevTools() 方法返回新的 DevTools 物件,該物件允許我們使用 send() 方法(CDP 的預設 Selenium 命令)。

這些命令主要是包裝方法,有助於呼叫 CDP 函式。另一方面,executeCdpCommand() 方法有助於在引數的幫助下執行 CDP 方法。它沒有任何包裝器 API。

ChromeDriver 和 EdgeDriver 類繼承自 ChromiumDriver 類。因此,也可以從這些驅動程式訪問 Selenium CDP API。

使用 CDP 更新裝置模式

讓我們舉一個在其他裝置中訪問以下應用程式的例子。可以將應用程式配置為各種尺寸,以驗證其響應能力。用於實現此目的的 CDP 命令是 **Emulation.setDeviceMetricsOverride** 命令。此命令中要傳遞的最小引數是高度、寬度、移動和 deviceScaleFactor。

或者,我們可以使用 **DevTools::send()** 方法,藉助 **setDeviceMetricsOverride()** 方法。但是,**setDeviceMetricsOverride()** 將十二個引數作為引數。在十二個引數中,四個引數是必須的,八個引數是可選的。對於可選引數,我們必須使用 **Optional.empty()** 方法。

Selenium DevTools 1

示例

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chromium.HasCdp;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class UpdateDeviceCDP {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // device configurations
      Map dM = new HashMap(){
         {
            put("width", 500);
            put("height", 600);
            put("mobile", true);
            put("deviceScaleFactor", 50);
         }
      };
      ((HasCdp) driver).executeCdpCommand("Emulation.setDeviceMetricsOverride", dM);

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/selenium_automation_practice.php");
   }
}

它將顯示以下輸出:

Selenium DevTools 2

在上面的示例中,我們觀察到螢幕尺寸變小了,其規格在程式碼中傳遞。

使用 CDP 模擬網路速度

讓我們舉一個檢查當網際網路連線處於 2G 狀態時應用程式行為的例子。CDP 命令 **Network.emulateNetworkConditions** 用於實現此目的。此命令中需要傳遞的最小五個引數是離線、延遲、下載吞吐量、上傳吞吐量和 CONNECTIONTYPE。CONNECTIONTYPE 可以具有 3G、2G、4G、BLUETOOTH、WIFI、ETHERNET 和 NONE 等值。對於其餘引數,我們必須使用 **Optional.empty()** 方法。

示例

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.network.model.ConnectionType;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.devtools.v124.network.Network;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class UpdateNetworkCDP {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // network 2G configurations
      d.send(Network.enable(Optional.empty(),Optional.empty(), Optional.empty()));
      d.send(Network.emulateNetworkConditions(
         false,
         50,
         30,
         40,
         Optional.of(ConnectionType.CELLULAR2G),
         Optional.empty(),
         Optional.empty(),
         Optional.empty()
      ));

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/selenium_automation_practice.php");
   }
}

在上面的示例中,我們使用模擬的 2G 網路連線打開了應用程式。

使用 CDP 模擬地理位置

讓我們舉一個使用 **Emulation.setGeolocationOverride** 命令模擬地理位置的例子。

示例

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.emulation.Emulation;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class UpdateGeolocations {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // update geolocations latitude and longitude
      d.send(Emulation.setGeolocationOverride(
         Optional.of(48.78232),
         Optional.of(9.17702),
         Optional.of(80)
      ));

      // open application url
      driver.get("https://where-am-i.org/");
   }
}

它將顯示以下輸出:

Selenium DevTools 3

在上面的示例中,我們已將地理位置覆蓋到德國。

使用 CDP 獲取 HTTP 請求

讓我們舉一個在應用程式啟動時獲取 HTTP 請求及其響應、資料、標頭等的例子。要開始捕獲網路流量,我們將設定 **Network.enable**,它與 send() 方法一起使用。此外,我們將分別使用 **getRequest().getUrl()** 和 **getRequest().getMethod()** 方法獲取 URL 和方法名稱。

示例

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.network.Network;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class ObtainHttpReq {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // get network traffic
      d.send(Network.enable(Optional.empty(),
      Optional.empty(), Optional.empty()));
      d.addListener(Network.requestWillBeSent(),
      e -> {
         System.out.println("Get Request URI: " + e.getRequest().getUrl()+ "\n"
            + "along with method: "+ e.getRequest().getMethod() + "\n");
         e.getRequest().getMethod();
      });

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/login.php");

      // quit browser
      driver.quit();
   }
}

它將顯示以下輸出:

Get Request URI:
https://tutorialspoint.tw/selenium/practice/login.php

along with method: GET

使用 CDP 獲取控制檯日誌

讓我們舉一個獲取控制檯日誌的例子。這有助於除錯和對測試失敗進行根本原因分析。要開始捕獲控制檯日誌,我們將設定 **Log.enable**,它與 send() 方法一起使用。此外,我們將分別使用 **getText()** 和 **getLevel()** 方法獲取日誌文字和日誌級別。

示例

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.log.Log;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.concurrent.TimeUnit;

public class LogLevelCdp {
   public static void main(String[] args) throws InterruptedException {

      // Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // enable logging 
      d.send(Log.enable());

      // get log levels and text
      d.addListener(Log.entryAdded(),
         logEntry -> {
            System.out.println("Log text: "+logEntry.getText());
            System.out.println("Log level: "+logEntry.getLevel());
         });

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/login.php");

      // quit browser
      driver.quit();
   }
}

它將顯示以下輸出:

Log text: [DOM] Input elements should have autocomplete attributes
(suggested: "current-password"): 
(More info: https://www.chromium.org/developers/design-documents/create-amazing-password-forms) %o

Log level: verbose

使用 CDP 獲取效能指標

讓我們舉一個獲取應用程式效能指標的例子。要開始捕獲指標,我們將設定 **Performance.enable**,它與 send() 方法一起使用。此外,我們將使用 **Performance.getMetrics()** 方法獲取所有指標。

示例 1

package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.performance.Performance;
import org.openqa.selenium.devtools.v124.performance.model.Metric;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class PerformanceMonitoringCdp {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();

      // enable performance monitoring
      d.send(Performance.enable(Optional.empty()));

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/text-box.php");

      // get performance
      List<Metric> m = d.send(Performance.getMetrics());
      List<String> mN = m.stream()
         .map(o -> o.getName())
         .collect(Collectors.toList());

      d.send(Performance.disable());

      List<String> metricsToCheck = Arrays.asList(
         "Timestamp", "Documents", "Frames", "JSEventListeners",
         "LayoutObjects", "MediaKeySessions", "Nodes",
         "Resources", "DomContentLoaded", "NavigationStart"
      );

      metricsToCheck.forEach( metric -> System.out.println(metric +
         " is : " + m.get(mN.indexOf(metric)).getValue()));

      // open application url
      driver.get("https://tutorialspoint.tw/selenium/practice/login.php");

      // quit browser
      driver.quit();
   }
}

它將顯示以下輸出:

Timestamp is : 15204.440213
Documents is : 7
Frames is : 4
JSEventListeners is : 30
LayoutObjects is : 170
MediaKeySessions is : 0
Nodes is : 528
Resources is : 10
DomContentLoaded is : 15204.419683
NavigationStart is : 15203.25931

Process finished with exit code 0

示例 2

讓我們舉一個使用 CDP 命令 **Network.setExtraHTTPHeaders** 執行基本身份驗證的例子,該命令與 send() 方法一起使用,並帶有標頭資料。它將有助於進行身份驗證並繞過任何彈出視窗。

讓我們以以下頁面的示例為例,單擊“基本身份驗證”連結後,我們將收到一個彈出視窗,要求輸入憑據。

Selenium DevTools 4

在“使用者名稱”和“密碼”欄位中都傳遞憑據 admin,然後單擊“登入”按鈕繼續。

Selenium DevTools 5

最後,成功身份驗證後,我們將獲得一個包含以下文字的頁面:**恭喜!您必須擁有正確的憑據**。

Selenium DevTools 6

程式碼實現

package org.example;

import com.google.common.collect.ImmutableMap;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v124.network.Network;
import org.openqa.selenium.devtools.v124.network.model.Headers;
import org.openqa.selenium.edge.EdgeDriver;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class BasicAuthCdp {
   public static void main(String[] args) throws InterruptedException {

      //Initiate the Webdriver
      WebDriver driver = new EdgeDriver();

      //adding implicit wait of 15 secs
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

      // instance of DevTools
      DevTools d = ((HasDevTools) driver).getDevTools();

      // create a session
      d.createSession();
      d.send(Network.enable(Optional.empty(),Optional.empty(), Optional.empty()));

      String encodedAuth = Base64.getEncoder().encodeToString("admin:admin".getBytes());
      Map<String, Object> headers = ImmutableMap.of("Authorization", "Basic " + encodedAuth);

      d.send(Network.setExtraHTTPHeaders(new Headers(headers)));

      // open application
      driver.get("https://the-internet.herokuapp.com/basic_auth");

      WebElement e = driver.findElement(By.tagName("p"));
      System.out.println("Text is: " + e.getText());

      // quit browser
      driver.quit();
   }
}

它將顯示以下輸出:

Text is: Congratulations! You must have the proper credentials.

Process finished with exit code 0

在上面的示例中,我們在標頭中傳遞了身份驗證,因此在觸發測試時沒有遇到彈出視窗。

廣告