关于后端:Selenium-用这个力量做任何你想做的事情

35次阅读

共计 11665 个字符,预计需要花费 30 分钟才能阅读完成。

大家好,我是 Yuan,明天为大家介绍一个很有意思的我的项目。
Selenium 自动化浏览器。就是这样!你能够通过这种力量做任何你想做的事件。

“getDevTools() 办法返回新的 Chrome DevTools 对象,容许您应用 send() 办法发送针对 CDP 的内置 Selenium 命令。这些命令是包装办法,使调用 CDP 函数更加清晰和简便。”

——SHAMA UGALE

首先,什么是 Chrome DevTools?

Chrome DevTools 简介

Chrome DevTools 是一组间接内置在基于 Chromium 的浏览器(如 Chrome、Opera 和 Microsoft Edge)中的工具,用于帮忙开发人员调试和钻研网站。

借助 Chrome DevTools,开发人员能够更深刻地拜访网站,并可能:

  • 查看 DOM 中的元素
  • 即时编辑元素和 CSS
  • 检查和监控网站的性能
  • 模仿用户的地理位置
  • 模仿更快 / 更慢的网络速度
  • 执行和调试 JavaScript
  • 查看控制台日志
  • 等等

Selenium 4 Chrome DevTools API

Selenium 是反对 web 浏览器自动化的一系列工具和库的综合我的项目。Selenium 4 增加了对 Chrome DevTools API 的原生反对。借助这些新的 API,咱们的测试当初能够:

  • 捕捉和监控网络流量和性能
  • 模仿地理位置,用于地位感知测试、本地化和国际化测试
  • 更改设施模式并测试利用的响应性

这只是冰山一角!

Selenium 4 引入了新的 ChromiumDriver 类,其中包含两个办法用于拜访 Chrome DevTools:getDevTools() 和 executeCdpCommand()。

getDevTools() 办法返回新的 DevTools 对象,容许您应用 send() 办法发送针对 CDP 的内置 Selenium 命令。这些命令是包装办法,使调用 CDP 函数更加清晰和简便。

executeCdpCommand() 办法也容许您执行 CDP 办法,但更加原始。它不应用包装的 API,而是容许您间接传入 Chrome DevTools 命令和该命令的参数。如果某个 CDP 命令没有 Selenium 包装 API,或者您心愿以与 Selenium API 不同的形式进行调用,则能够应用 executeCdpCommand()。

像 ChromeDriver 和 EdgeDriver 这样的基于 Chromium 的驱动程序当初继承自 ChromiumDriver,因而您也能够从这些驱动程序中拜访 Selenium CDP API。

让咱们摸索如何利用这些新的 Selenium 4 API 来解决各种应用案例。

模仿设施模式

咱们明天构建的大多数利用都是响应式的,以满足来自各种平台、设施(如手机、平板、可穿戴设施、桌面)和屏幕方向的终端用户的需要。

作为测试人员,咱们可能心愿将咱们的应用程序搁置在不同的尺寸中,以触发应用程序的响应性。

咱们如何应用 Selenium 的新 CDP 性能来实现这一点呢?

用于批改设施度量的 CDP 命令是 Emulation.setDeviceMetricsOverride,并且此命令须要输出宽度、高度、挪动设施标记和设施缩放因子。这四个键在此场景中是必须的,但还有一些可选的键。

在咱们的 Selenium 测试中,咱们能够应用 DevTools::send() 办法并应用内置的 setDeviceMetricsOverride() 命令,然而这个 Selenium API 承受 12 个参数 – 除了 4 个必须的参数外,还有 8 个可选的参数。对于咱们不须要发送的这 8 个可选参数中的任何一个,咱们能够传递 Optional.empty()。

然而,为了简化这个过程,只传递所需的参数,我将应用上面代码中的原始 executeCdpCommand() 办法。

package com.devtools;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import java.util.HashMap;
import java.util.Map;

public class SetDeviceMode {final static String PROJECT_PATH = System.getProperty("user.dir");

    public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
        ChromeDriver driver;
        driver = new ChromeDriver();

        DevTools devTools = driver.getDevTools();
        devTools.createSession();
        Map deviceMetrics = new HashMap()
        {{put("width", 600);
            put("height", 1000);
            put("mobile", true);
            put("deviceScaleFactor", 50);
        }};
        driver.executeCdpCommand("Emulation.setDeviceMetricsOverride", deviceMetrics);
        driver.get("https://www.google.com");
    }
}

在第 19 行,我创立了一个蕴含此命令所需键的映射。

而后在第 26 行,我调用 executeCdpCommand() 办法,并传递两个参数:命令名称为 “Emulation.setDeviceMetricsOverride”,以及蕴含参数的设施度量映射。

在第 27 行,我关上了渲染了我提供的规格的 “Google” 首页,如下图所示。

借助像 Applitools Eyes 这样的解决方案,咱们不仅能够应用这些新的 Selenium 命令在不同的视口上疾速进行测试,还能够在规模上放弃任何不一致性。Eyes 足够智能,不会对因为不同的浏览器和视口导致的 UI 中渺小且难以觉察的变动报告谬误的后果。

模仿地理位置

在许多状况下,咱们须要测试特定的基于地位的性能,例如优惠、基于地位的价格等。为此,咱们能够应用 DevTools API 来模仿地位。

  @Test
    public void mockLocation(){
        devTools.send(Emulation.setGeolocationOverride(Optional.of(48.8584),
                Optional.of(2.2945),
                Optional.of(100)));
        driver.get("https://mycurrentlocation.net/");
        try {Thread.sleep(30000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }

模仿网络速度

许多用户通过连贯到 Wi-Fi 或蜂窝网络的手持设施拜访 Web 应用程序。遇到信号弱的网络信号,因而互联网连贯速度较慢是很常见的。

在互联网连贯速度较慢(2G)或间歇性断网的状况下,测试应用程序在这种条件下的行为可能很重要。

伪造网络连接的 CDP 命令是 Network.emulateNetworkConditions。对于此命令的必须和可选参数的信息能够在文档中找到。

通过拜访 Chrome DevTools,就能够模仿这些场景。让咱们看看如何做到这一点。

package com.devtools;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.network.Network;
import org.openqa.selenium.devtools.network.model.ConnectionType;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class SetNetwork {final static String PROJECT_PATH = System.getProperty("user.dir");

    public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
        ChromeDriver driver;
        driver = new ChromeDriver();
        
        DevTools devTools = driver.getDevTools();
        devTools.createSession();
        devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
        devTools.send(Network.emulateNetworkConditions(
                false,
                20,
                20,
                50,
                Optional.of(ConnectionType.CELLULAR2G)
        ));
        driver.get("https://www.google.com");
    }
}

在第 21 行,咱们通过调用 getDevTools() 办法获取 DevTools 对象。而后,咱们调用 send() 办法来启用 Network,并再次调用 send() 办法来传递内置命令 Network.emulateNetworkConditions() 和咱们心愿与此命令一起发送的参数。

最初,咱们应用模仿的网络条件关上 Google 首页。

捕捉 HTTP 申请

应用 DevTools,咱们能够捕捉应用程序发动的 HTTP 申请,并拜访办法、数据、头信息等等。

让咱们看看如何应用示例代码捕捉 HTTP 申请、URI 和申请办法。

package com.devtools;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.network.Network;

import java.util.Optional;

public class CaptureNetworkTraffic {

    private static ChromeDriver driver;
    private static DevTools chromeDevTools;

    final static String PROJECT_PATH = System.getProperty("user.dir");

    public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
        driver = new ChromeDriver();
        chromeDevTools = driver.getDevTools();
        chromeDevTools.createSession();

        chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
        chromeDevTools.addListener(Network.requestWillBeSent(),
                entry -> {System.out.println("Request URI :" + entry.getRequest().getUrl()+"\n"
                    + "With method :"+entry.getRequest().getMethod() + "\n");
                    entry.getRequest().getMethod();
                });
        driver.get("https://www.google.com");
        chromeDevTools.send(Network.disable());
    }
}

开始捕捉网络流量的 CDP 命令是 Network.enable。对于此命令的必须和可选参数的信息能够在文档中找到。

在咱们的代码中,第 22 行应用 DevTools::send() 办法发送 Network.enable CDP 命令以启用网络流量捕捉。

第 23 行增加了一个监听器,用于监听应用程序发送的所有申请。对于应用程序捕捉的每个申请,咱们应用 getRequest().getUrl() 提取 URL,并应用 getRequest().getMethod() 提取 HTTP 办法。

第 29 行,咱们关上了 Google 的首页,并在管制台上打印了此页面收回的所有申请的 URI 和 HTTP 办法。

一旦咱们实现了申请的捕捉,咱们能够发送 Network.disable 的 CDP 命令以进行捕捉网络流量,如第 30 行所示。

拦挡 HTTP 响应

为了拦挡响应,咱们将应用 Network.responseReceived 事件。当 HTTP 响应可用时触发此事件,咱们能够监听 URL、响应头、响应代码等。要获取响应注释,请应用 Network.getResponseBody 办法。

 @Test
    public void validateResponse() {final RequestId[] requestIds = new RequestId[1];
        devTools.send(Network.enable(Optional.of(100000000), Optional.empty(), Optional.empty()));
        devTools.addListener(Network.responseReceived(), responseReceived -> {if (responseReceived.getResponse().getUrl().contains("api.zoomcar.com")) {System.out.println("URL:" + responseReceived.getResponse().getUrl());
                System.out.println("Status:" + responseReceived.getResponse().getStatus());
                System.out.println("Type:" + responseReceived.getType().toJson());
                responseReceived.getResponse().getHeaders().toJson().forEach((k, v) -> System.out.println((k + ":" + v)));
                requestIds[0] = responseReceived.getRequestId();
                System.out.println("Response Body: \n" + devTools.send(Network.getResponseBody(requestIds[0])).getBody() + "\n");
            }
        });
        driver.get("https://www.zoomcar.com/bangalore");
        driver.findElement(By.className("search")).click();}

拜访控制台日志

咱们都依赖日志来进行调试和剖析故障。在测试和解决具备特定数据或特定条件的应用程序时,日志能够帮忙咱们调试和捕捉谬误音讯,提供更多在 Chrome DevTools 的控制台选项卡中公布的见解。

咱们能够通过调用 CDP 日志命令来通过咱们的 Selenium 脚本捕捉控制台日志,如下所示。

package com.devtools;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.log.Log;

public class CaptureConsoleLogs {
    
    private static ChromeDriver driver;
    private static DevTools chromeDevTools;
    final static String PROJECT_PATH = System.getProperty("user.dir");

    public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
        driver = new ChromeDriver();
        chromeDevTools = driver.getDevTools();
        chromeDevTools.createSession();

        chromeDevTools.send(Log.enable());
        chromeDevTools.addListener(Log.entryAdded(),
                logEntry -> {System.out.println("log:"+logEntry.getText());
                    System.out.println("level:"+logEntry.getLevel());
                });
        driver.get("https://testersplayground.herokuapp.com/console-5d63b2b2-3822-4a01-8197-acd8aa7e1343.php");
    }
}

在咱们的代码中,第 19 行应用 DevTools::send() 来启用控制台日志捕捉。

而后,咱们增加一个监听器来捕捉应用程序记录的所有控制台日志。对于应用程序捕捉的每个日志,咱们应用 getText() 办法提取日志文本,并应用 getLevel() 办法提取日志级别。

最初,关上应用程序并捕捉应用程序公布的控制台谬误日志。

捕捉性能指标

在当今快节奏的世界中,咱们以如此快的速度迭代构建软件,咱们也应该迭代性地检测性能瓶颈。性能较差的网站和加载较慢的页面会让客户感到不满。

咱们可能在每次构建时验证这些指标吗?是的,咱们能够!

捕捉性能指标的 CDP 命令是 Performance.enable。对于这个命令的信息能够在文档中找到。

让咱们看看如何在 Selenium 4 和 Chrome DevTools API 中实现这个过程。

package com.devtools;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.performance.Performance;
import org.openqa.selenium.devtools.performance.model.Metric;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class GetMetrics {final static String PROJECT_PATH = System.getProperty("user.dir");

    public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
        ChromeDriver driver = new ChromeDriver();
        DevTools devTools = driver.getDevTools();
        devTools.createSession();
        devTools.send(Performance.enable());

        driver.get("https://www.google.org");

        List<Metric> metrics = devTools.send(Performance.getMetrics());
        List<String> metricNames = metrics.stream()
                .map(o -> o.getName())
                .collect(Collectors.toList());

        devTools.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 :" + metrics.get(metricNames.indexOf(metric)).getValue()));
    }
}

首先,咱们通过调用 DevTools 的 createSession() 办法创立一个会话,如第 19 行所示。

接下来,咱们通过将 Performance.enable() 命令发送给 send() 来启用 DevTools 来捕捉性能指标,如第 20 行所示。

一旦启用了性能捕捉,咱们能够关上应用程序,而后将 Performance.getMetrics() 命令发送给 send()。这将返回一个 Metric 对象的列表,咱们能够通过流式解决来获取捕捉的所有指标的名称,如第 25 行所示。

而后,咱们通过将 Performance.disable() 命令发送给 send() 来禁用性能捕捉,如第 29 行所示。

为了查看咱们感兴趣的指标,咱们定义了一个名为 metricsToCheck 的列表,而后通过循环遍历该列表来打印指标的值。

根本身份验证

在 Selenium 中,无奈与浏览器弹出窗口进行交互,因为它只能与 DOM 元素进行交互。这对于身份验证对话框等弹出窗口形成了挑战。

咱们能够通过应用 CDP API 间接与 DevTools 解决身份验证来绕过此问题。设置申请的附加标头的 CDP 命令是 Network.setExtraHTTPHeaders。

以下是在 Selenium 4 中调用此命令的办法。

package com.devtools;

import org.apache.commons.codec.binary.Base64;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.network.Network;
import org.openqa.selenium.devtools.network.model.Headers;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class SetAuthHeader {

  private static final String USERNAME = "guest";
  private static final String PASSWORD = "guest";
  final static String PROJECT_PATH = System.getProperty("user.dir");

  public static void main(String[] args){System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    ChromeDriver driver = new ChromeDriver();

    //Create DevTools session and enable Network
    DevTools chromeDevTools = driver.getDevTools();
    chromeDevTools.createSession();
    chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

    //Open website
    driver.get("https://jigsaw.w3.org/HTTP/");

    //Send authorization header
    Map<String, Object> headers = new HashMap<>();
    String basicAuth ="Basic" + new String(new Base64().encode(String.format("%s:%s", USERNAME, PASSWORD).getBytes()));
    headers.put("Authorization", basicAuth);
    chromeDevTools.send(Network.setExtraHTTPHeaders(new Headers(headers)));

    //Click authentication test - this normally invokes a browser popup if unauthenticated
    driver.findElement(By.linkText("Basic Authentication test")).click();

    String loginSuccessMsg = driver.findElement(By.tagName("html")).getText();
    if(loginSuccessMsg.contains("Your browser made it!")){System.out.println("Login successful");
    }else{System.out.println("Login failed");
    }

    driver.quit();}
}

咱们首先应用 DevTools 对象创立一个会话,并启用 Network。这在第 25-26 行中展现。

接下来,咱们关上咱们的网站,而后创立用于发送的身份验证标头。

在第 35 行,咱们将 setExtraHTTPHeaders 命令发送到 send(),同时发送标头的数据。这部分将对咱们进行身份验证并容许咱们绕过浏览器弹出窗口。

为了测试这个性能,咱们点击了根本身份验证测试链接。如果您手动尝试这个操作,您会看到浏览器弹出窗口要求您进行登录。但因为咱们发送了身份验证标头,所以咱们的脚本中不会呈现这个弹出窗口。

相同,咱们会收到音讯“您的浏览器登录胜利!”。

总结

通过增加 CDP API,Selenium 曾经变得更加弱小。当初,咱们能够加强咱们的测试,捕捉 HTTP 网络流量,收集性能指标,解决身份验证,并模仿地理位置、时区和设施模式。以及在 Chrome DevTools 中可能呈现的任何其余性能!

参考:

  1. Selenium 官方网站:https://www.selenium.dev/
  2. Selenium 文档:https://www.selenium.dev/documentation/en/
  3. Selenium 教程:https://www.selenium.dev/documentation/en/getting_started/
  4. Selenium API 文档:https://www.selenium.dev/selenium/docs/api/py/index.html

本文由 mdnice 多平台公布

正文完
 0