Selenium 简明教程

Selenium WebDriver - DevTools

Selenium Webdriver 的最新版本是 4.x 版本。Selenium 4 附带了许多改进,包括 Chrome DevTools(CDP) 上的新 API。它提供了对浏览器更精细的控制,可以对其执行测试。

What are the Chrome DevTools?

Chrome DevTools 是一系列针对基于 Chromium 的浏览器的工具,比如 Chrome、Edge 和 Opera。它们有助于启用调试,并获取关于测试中的应用程序的其他信息。CDP 的优势如下所示:

  1. Obtain the Console Logs

  2. Run and debug JavaScript

  3. Mock Geolocations

  4. 在文档对象模型 (DOM) 中检查 Web 元素

  5. Mock Network Traffic

  6. Monitor Network Traffic

  7. 更新 Web 元素及其 CSS

Chrome DevTool APIs in Selenium 4

Selenium 4 可用于新的 Chrome 开发工具 API,这些 API 具有以下所列功能:

  1. 获取并监视网络流量。

  2. 模拟地理位置以进行本地化测试。

  3. 更新设备模式以检查 Web 应用程序的响应能力。

ChromiumDriver 类从 Selenium 4 版本引入。此类包含方法 getDevTools() 和 executeCdpCommand()。它们有助于访问 CDP。getDevTools() 方法会返回新的 DevTools 对象,它允许我们使用 send() 方法(CDP 的默认 Selenium 命令)。

这些命令主要是帮助调用 CDP 函数的封装方法。另一方面,executeCdpCommand() 方法可帮助在参数的帮助下运行 CDP 方法。它不依赖于任何封装 API。

ChromeDriver 和 EdgeDriver 类是从 ChromiumDriver 类继承的。因此,这些驱动程序也可以访问 Selenium CDP API。

Update Device Mode using CDP

让我们举一个示例,其中我们在其他设备中访问下面的应用程序。可以将应用程序配置为多种尺寸以验证其响应能力。为此使用的 CDP 命令是 Emulation.setDeviceMetricsOverride 命令。此命令中要传递的最小参数是 height、width、mobile 和 deviceScaleFactor。

作为替代方法,我们可以借助 setDeviceMetricsOverride() 方法来使用 DevTools::send() 方法。但是, setDeviceMetricsOverride() 使用 12 个参数。12 个参数中,4 个是必填,8 个是可选的。对于可选参数,我们必须使用 Optional.empty() 方法。

selenium devtools 1

Example

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://www.tutorialspoint.com/selenium/practice/selenium_automation_practice.php");
   }
}

它将显示以下输出 −

selenium devtools 2

在上面的示例中,我们可以看到屏幕尺寸已经变小,具有在代码中传递的规格。

Simulate Network Speed using CDP

让我们举一个示例,其中当互联网连接为 2G 时,我们将检查应用程序的行为。CDP 命令 Network.emulateNetworkConditions 用于实现此目的。此命令中需要传递的至少 5 个参数是 offline、latency、download throughput、upload throughput 和 CONNECTIONTYPE。CONNECTIONTYPE 可以具有如下值:3G、2G、4G、BLUETOOTH、WIFI、ETHERNET 和 NONE。对于其他参数,我们必须使用 Optional.empty() 方法。

Example

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://www.tutorialspoint.com/selenium/practice/selenium_automation_practice.php");
   }
}

在上面的示例中,我们已经使用模拟的 2G 网络连接打开了应用程序。

Emulate Geolocations using CDP

让我们举一个示例,其中我们将使用 Emulation.setGeolocationOverride 命令来模拟地理位置。

Example

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

在上面的示例中,我们已将地理位置覆写为德国。

Obtain HTTP Requests using CDP

我们举一个示例,在该示例中,将在启动应用程序的同时获取 HTTP 请求及其响应、数据、标题等。要开始捕获网络流量,我们将设置与 send() 方法一起使用的 Network.enable 。此外,我们将分别使用 getRequest().getUrl()getRequest().getMethod() 方法获取 URL 和方法名称。

Example

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://www.tutorialspoint.com/selenium/practice/login.php");

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

它将显示以下输出 −

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

along with method: GET

Obtain Console Logs using CDP

我们举一个示例,在该示例中,将获取控制台日志。这有助于调试和对测试失败进行根本原因分析。要开始捕获控制台日志,我们将设置与 send() 方法一起使用的 Log.enable 。此外,我们将分别使用 getText()getLevel() 方法获取日志文本和日志级别。

Example

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://www.tutorialspoint.com/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

Obtain Performance Metrics using CDP

我们举一个示例,在该示例中,将获取应用程序的性能指标。要开始捕获指标,我们将设置与 send() 方法一起使用的 Performance.enable 。此外,我们将使用 Performance.getMetrics() 方法获取所有指标。

Example 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://www.tutorialspoint.com/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://www.tutorialspoint.com/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

Example 2

我们举一个示例,在该示例中,将使用与 send() 方法一起使用的 CDP 命令 Network.setExtraHTTPHeaders 和标题数据执行基本身份验证。这将有助于验证身份并绕过任何弹出窗口。

让我们举下面的页面的示例,单击“基本身份验证”链接后,我们将获得一个弹出窗口,要求提供凭据。

selenium devtools 4

凭据 admin 在“用户名”和“密码”字段中均已传递,然后单击 Sign In 按钮以继续。

selenium devtools 5

最后,在成功身份验证后,我们将获得一个带有文本 - Congratulations! You must have the proper credentials 的页面。

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

在上面的示例中,我们在标头中传递了身份验证,因此在触发测试时没有遇到弹出窗口。