DZone>性能区>Selenium中的ExpectedConditions
Selenium中的预期条件(ExpectedConditions
在这个Selenium教程中,你将学习如何在Selenium中使用预期条件来解决由于WebElements的动态加载而引起的时间相关问题。
通过
CORE -
Aug. 06, 22 - 性能区 -教程
喜欢 (1)
评论
保存
鸣叫
234 次浏览
加入DZone社区,获得完整的会员体验。
大多数网络产品都使用AJAX(异步JavaScript和XML),页面上的元素在不同的时间间隔内加载。当使用Selenium框架进行自动化测试时,这可能导致时间问题。如果一个测试运行在DOM中不存在的WebElement上怎么办?findElement函数将引发ElementNotVisibleException。
下面是由于元素的动态加载,在Selenium中可能导致问题的其他情况。
- WebElement(例如:按钮)是可见的,但不能点击。
- Web元素(如标签)存在于DOM中,但某个文本应该存在于元素的values属性中。
- WebPage的标题应该由一个区分大小写的子串组成,还有更多。
克服由于WebElements的动态加载而产生的问题的理想方法是在测试代码实现中引入Selenium waits。等待将提供额外的缓冲时间,以完成元素的加载并对其进行必要的操作。与其说是等待一个指定的时间长度(也叫隐式等待),不如说是在一个特定的条件下进行等待。这些在Selenium中被称为预期条件。
显式等待(最大持续时间)可以被执行,直到满足 "特定条件"(例如,直到元素不可见)。如果在最大持续时间过后,该条件仍未得到满足,就会产生一个适当的异常。
作为一名自动化测试工程师,我遇到过这样的情况:在Selenium中使用预期条件的明确等待有助于解决由于Web元素的动态加载而导致的时间相关问题。在这个Selenium教程中,我们将了解如何在Selenium Java中使用预期条件。
Selenium WebDriver中的预期条件(ExpectedConditions
Selenium WebDriver提供的预期条件用于对某一条件进行显式等待。Selenium WebDriver在继续执行之前会等待指定的条件发生。这为必须执行的操作提供了所需的等待时间,例如定位WebElement或对该元素的其他有效操作。
在Selenium中使用ExpectedConditions的显式等待
在Implicit Wait中,当一个特定的WebElement不能立即使用时,DOM会被Selenium WebDriver轮询一定的时间。一旦设置了Implicit Wait,它在WebDriver对象的整个生命周期内都是可用的。
另一方面,在Selenium中使用ExpectedConditions的Explicit Wait可以让你在执行进入下一步之前等待指定条件的发生。如果在预期的时间内没有满足条件,就会产生一个适当的异常。
爪哇
driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
By elem_dynamic = By.id("dynamic-element");
wait.until(ExpectedConditions.presenceOfElementLocated(elem_dynamic));
在上面演示Selenium Java中预期条件的片段中,Selenium WebDriver最多等待10秒,直到找到ID为 "动态元素 "的WebElement。每隔500毫秒,Selenium WebDriver就会调用ExpectedCondition,直到它返回成功。
如果WebElement在10秒内(即最大等待时间)可用,ExpectedCondition返回true,并执行到下一个步骤。如果在10秒的最大持续时间内,该元素仍未出现在DOM中,则会抛出一个TimeoutException。
Selenium Java中的预期条件类型
Selenium WebDriver中的预期条件提供了经常用于Selenium自动化测试场景的自动测试条件。像其他Selenium语言绑定一样,Java中的预期条件提供了在测试代码中实现明确等待的方法。
下面是Selenium中ExpectedConditions的两个主要类别。
ExpectedCondition <WebElement
顾名思义,Web元素的定位器被用作ExpectedCondition的参数。根据条件类型,执行显式等待,直到满足预期条件或等待时间过期。
如果预期条件得到满足,它将返回WebElement/WebElement列表/其他信息,这取决于ExpectedCondition的核心实现。
例如,ExpectedConditions类(org.openqa.selenium.support.ui.ExpectedConditions包的)中的numberOfElementsToBeLessThan方法,如果使用Web定位器(作为参数传递)定位的WebElements的数量少于预期数量(也作为参数传递),则返回一个WebElements的列表。
Selenium Java中的Expected Conditions中的 elementToBeClickable方法,如果定位的元素是可点击的(即可以点击),则返回一个WebElement。用于定位WebElement的适当的Selenium定位器被传递给该方法。
ExpectedCondition <WebDriver
这类ExpectedCondition在所需操作成功执行后返回一个WebDriver实例。
例如,Selenium Java中的Expected Conditions中的frameToBeAvailableAndSwitchToIt方法将WebDriver切换到使用frameLocator(作为参数传递给该方法)定位的指定框架。框架可以使用ID或Name网络定位器来定位。
如果给定的框架不能被切换到,就会产生一个异常。
预期条件 <Boolean
布尔类型的条件需要一个字符串参数,等待被应用于参数的条件。在成功执行条件时,返回布尔值true,而如果不满足条件则返回false。
例如,当网络定位器(作为参数传递给该方法)定位的WebElement包含指定的文本时,textToBePresentInElementLocated方法返回true。
预期条件 <警报
如果页面上有一个Alert类型的窗口,Selenium Java中的这一类预期条件会返回一个警报。一旦警报出现,WebDriver会切换到警报窗口。切换后,可以对Alert窗口进行各种操作,如Accept()、Dismiss()、sendKeys()和getText()。
如果在指定的等待时间内Alert窗口不可用,该方法返回Null。
Selenium Java中常用的ExpectedConditions
现在我们已经介绍了Selenium Java中不同类型(或类别)的预期条件,让我们来看看一些广泛使用的用于实现显式等待的预期条件。
elementToBeSelected方法
elementToBeSelected是一个重载方法,属于ExpectedCondition 类别。
方法类别- ExpectedCondition
ExpectedConditionelementToBeSelected(finalBy locator)
它让WebDriver等待,直到WebElement用指定的定位器被选中。Selenium Java中的这个预期条件方法需要一个用于定位所需元素的单一参数 "locator"。
一旦该元素被选中,它就会返回true,否则就会返回false。
语法
语法
static ExpectedCondition<Boolean> elementToBeSelected(final By locator)
ExpectedConditionelementToBeSelected(final WebElement element)
要选择的WebElement被作为参数传递给'elementToBeSelected'方法。elementToBeSelected方法反过来调用elementSelectionStateToBe方法,其参数为WebElement和布尔值'true'。
语法
语法
ExpectedCondition<Boolean> elementToBeSelected(final WebElement element)
elementToBeClickable方法
ElementToBeSelected方法是Selenium Java中预期条件的一个重载方法,属于ExpectedCondition 类别。该方法等待Web元素可见并启用,以便对其进行点击操作。
方法类别- ExpectedCondition
下面是 elementToBeClickable 方法的简介。
ExpectedConditionelementToBeClickable(By locator)
Selenium WebDriver等待,直到使用指定的网络定位器定位的元素可见并启用,这样该元素就可以被点击了。
语法
语法
ExpectedCondition<WebElement> elementToBeClickable(final By locator)
ExpectedCondition<WebElement<elementToBeClickable(WebElement)
Selenium WebDriver会等待,直到作为参数传递的WebElement是可见的,并能被点击。
语法
语法
ExpectedCondition<WebElement> elementToBeClickable(final WebElement element)
presenceOfElementLocated方法
该方法等待指定的WebElement出现在页面的DOM中。一个元素的存在并不一定意味着该特定元素是可见的。
该方法需要一个参数--用于在页面上找到该元素的定位器。一旦找到了,它就会返回WebElement。
方法类别--ExpectedCondition (预期条件)。
语法
语法
ExpectedCondition<WebElement> presenceOfElementLocated(final By locator)
visibilityOfElementLocated方法
该方法用于检查指定的元素是否存在于页面的DOM中,但它也是可见的。
该方法需要一个参数--用于在页面上寻找元素的定位器。一旦找到了,它就会返回WebElement。
方法类别- ExpectedCondition <WebElement
语法
语法
ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator)
titleIs方法
Selenium Java中的这个预期条件方法检查当前页面的标题是否符合预期的标题。如果标题与预期的标题相匹配,它将返回true。
如果标题不匹配,它返回false。
方法类别- ExpectedCondition </p
语法
爪哇
ExpectedCondition<Boolean> titleIs(final String title)
titleContains方法
它检查当前页面的标题或WebElement的标题中是否包含一个特定的子串。如果标题中存在区分大小写的子串,它将返回true。
方法类别- ExpectedCondition </p
语法
语法
ExpectedCondition< Boolean> titleContains(final String title)
textToBePresentInElementLocated方法
这个ExpectedCondition检查给定的文本(作为参数传递给该方法)是否存在于符合给定网络定位器的WebElement中。
如果指定的文本存在于该元素中,它返回布尔值true;否则,它返回false。
方法类别- ExpectedCondition <Boolean
语法
语法
ExpectedCondition <Boolean> textToBePresentInElementLocated(final By locator, final String text)
textToBePresentInElementLocated方法
这个ExpectedCondition检查给定的文本(作为参数传递给该方法)是否存在于符合给定网络定位器的WebElement中。
如果指定的文本存在于该元素中,它返回布尔值true;否则,它返回false。
方法类别- ExpectedCondition <Boolean
语法
爪哇
ExpectedCondition <Boolean> textToBePresentInElementLocated(final By locator, final String text)
urlToBe方法
这个ExpectedCondition检查当前页面的URL是否与作为参数传递给urlToBe()方法的URL匹配(或相同)。
如果当前页面的URL与预期的URL(在参数中)相同,它将返回true;否则,它将返回false。
方法类别- ExpectedCondition <Boolean
语法
爪哇
ExpectedCondition<Boolean> urlToBe(final String url)
frameToBeAvailableAndSwitchToIt方法
Selenium Java中预期条件的frameToBeAvailableAndSwitchToIt方法用于检查给定的框架是否可以切换到。Selenium中的框架可以用以下任何一种方法来识别。
- 通过定位器
- 框架索引(整数)
- 框架名称(字符串)
- 网络元素(使用适当的网络定位器定位)。
在这些行中,frameToBeAvailableAndSwitchToIt方法是一个重载方法,它提供了一个选项,使用上述列出的选项来检查页面上定位Frame(和iFrames)的给定框架。
如果所述的Frame(或iFrame)在页面上存在,该方法会触发driver.switchTo().frame操作,这样焦点就会转移到该框架上。
方法类别- ExpectedCondition(预期条件
下面是frameToBeAvailableAndSwitchToIt方法的细节。
ExpectedConditionframeToBeAvailableAndSwitchToIt (By locator)
ExpectedCondition检查给定的框架是否可以被切换到。使用传递给该方法的网络定位器定位所需的框架。
在成功执行时,它将给定的驱动程序切换到指定的框架;否则,它返回null。
语法
语法
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final By locator)
ExpectedConditionframeToBeAvailableAndSwitchToIt(int frameLocator)
它检查给定的框架是否可以被切换到。使用指定的frameindex(或frameLocator)定位页面上的框架,该框架为Integer类型。
语法
语法
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final int frameLocator)
ExpectedConditionframeToBeAvailableAndSwitchToIt (WebElement locator)
使用执行findElement方法的WebElement来定位要切换到的框架。在成功执行时,它在切换到该框架后返回一个WebDriver实例。
语法
语法
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final WebElement frameLocator)
ExpectedConditionframeToBeAvailableAndSwitchToIt(String frameLocator)
使用框架名称定位给定的框架,该名称作为参数传递给frameToBeAvailableAndSwitchToIt方法。
如果页面上有指定名称的框架,它会将WebDriver切换到指定的框架。如果该框架不存在,它将返回null。
语法
语法
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(final String frameLocator)
alertIsPresent方法
顾名思义,这个ExpectedCondition指示命令,如果页面上有一个Alert窗口。根据警报窗口的类别(即简单警报、提示警报、确认警报),必须对该窗口执行适当的操作。
如果警报窗口存在,这个方法会在内部触发driver.switchTo().alert(),这样焦点就会在警报窗口上。
方法类别- ExpectedCondition (预期条件
语法
语法
ExpectedCondition<Alert> alertIsPresent()
例子:Selenium Java中的ExpectedConditions
为了演示Selenium Java中的ExpectedConditions,我们在IntelliJ中创建一个名为ExpectedCond的TestNG项目。该项目包含一个名为org.expconditions的包,它又包含一个名为Test_ExpConditions的类文件。
TestNG框架用于创建和维护Selenium自动化测试的测试场景。在实现上,我们使用Selenium 4的Java语言绑定。Selenium 4 Java(Alpha-7)的依赖性从Maven中央仓库下载。
XML
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0-alpha-7</version>
</dependency>
testng.xml 配置文件有助于组织测试。下面显示的是pom.xml和testng.xml的完整实现。
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.expconditions</groupId>
<artifactId>expcond</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0-alpha-7</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>4.0.0-alpha-7</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>4.0.0-alpha-7</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Expected Conditions Demo">
<test verbose="2" preserve-order="true" name="Explicit Wait with Expected Conditions">
<classes>
<class name="org.expconditions.Test_ExpConditions">
</class>
</classes>
</test>
</suite>
所有的测试都在LambdaTest的云Selenium Grid上运行。要访问Selenium网格,你应该注意LambdaTest配置文件页面上的用户名和访问密钥。测试是在Chrome(最新版本)+Windows 10组合上执行的--能力是使用LambdaTest能力生成器生成的。所有的测试都在Selenium 4网格上运行。
由于所有的测试都是同一个文件的一部分,远程WebDriver在方法[testSetUp()]中被实例化,该方法在@BeforeClass注释下实现。一个字符串数组str_url包含用于后续章节中提到的测试的测试URLs。一旦所有证明Selenium中ExpectedConditions的测试被执行,WebDriver实例就被释放。
下面是@BeforeClass和@AfterClass注解下的方法的实现。
爪哇
package org.expconditions;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class Test_ExpConditions
{
/* protected static ChromeDriver driver; */
WebDriver driver = null;
public static String status = "passed";
String username = "user-name";
String access_key = "access-key";
String[] str_urlarr =
{
"https://phptravels.com/demo/",
"http://the-internet.herokuapp.com/javascript_alerts",
"http://the-internet.herokuapp.com/dynamic_content?with_content=static",
"https://phptravels.com/demo/",
"https://jqueryui.com/spinner/",
"https://lambdatest.github.io/sample-todo-app/"
};
@BeforeClass
public void testSetUp() throws MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("build", "[Java] Testing Expected Conditions with Selenium");
capabilities.setCapability("name", "[Java] Testing Expected Conditions with Selenium");
capabilities.setCapability("platformName", "Windows 10");
capabilities.setCapability("browserName", "Chrome");
capabilities.setCapability("browserVersion","latest");
capabilities.setCapability("tunnel",false);
capabilities.setCapability("network",true);
capabilities.setCapability("console",true);
capabilities.setCapability("visual",true);
driver = new RemoteWebDriver(new URL("http://" + username + ":" + access_key + "@hub.lambdatest.com/wd/hub"),
capabilities);
System.out.println("Started session");
}
@Test(description="Demo of ExpectedConditions.elementToBeClickable", enabled=true)
protected void test_elem_clickable() throws InterruptedException
{
/* Implementation goes here */
}
@Test(description="Demo of ExpectedConditions.alertIsPresent", enabled=true)
protected void test_alert_present() throws InterruptedException
{
/* Implementation goes here */
}
@Test(description="Demo of ExpectedConditions.textToBePresentInElementLocated", enabled=true)
protected void test_text_present() throws InterruptedException
{
/* Implementation goes here */
}
@Test(description="Demo of ExpectedConditions.visibilityOfElementLocated", enabled=true)
protected void test_elem_visibility() throws InterruptedException
{
/* Implementation goes here */
}
@Test(description="Demo of ExpectedConditions.frameToBeAvailableAndSwitchToIt", enabled=true)
protected void test_available_frame() throws InterruptedException
{
/* Implementation goes here */
}
@Test(description="Demo of ExpectedConditions.elementToBeSelected", enabled=true)
protected void test_elem_selected() throws InterruptedException
{
/* Implementation goes here */
}
@AfterClass
public void tearDown()
{
if (driver != null)
{
driver.quit();
}
}
}
让我们看看所有各自的测试,在那里我们展示了Selenium中广泛使用的几个ExpectedConditions。
elementsToBeClickable ExpectedCondition In Selenium Java
测试场景
- 转到phptravels.com/demo/
- 找到 "Google Play "按钮
- 等待按钮可被点击
- 点击该按钮
- 如果页面的URL(因点击Google Play按钮而打开)与预期的URL不一致,则断言。
实施
爪哇语
@Test(description="Demo of ExpectedConditions.elementToBeClickable", enabled=true)
protected void test_elem_clickable() throws InterruptedException
{
driver.navigate().to(str_urlarr[0]);
driver.manage().window().maximize();
String parentWindowHandle = driver.getWindowHandle();
/* Click on the Link */
By elem_gplay_locator = By.cssSelector(".fa-google");
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,600)", "");
/* Selenium Java 3.141.59 */
/* WebDriverWait wait = new WebDriverWait(web_driver, 5); */
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
WebElement elem_gplay_btn = wait.until(ExpectedConditions.elementToBeClickable(elem_gplay_locator));
elem_gplay_btn.click();
/* Check if the link is clicked by comparing the window title */
Set<String> allWindowHandles = driver.getWindowHandles();
Iterator<String> iterator = allWindowHandles.iterator();
while(iterator.hasNext())
{
String chld_window = iterator.next();
if (!parentWindowHandle.equalsIgnoreCase(chld_window))
{
driver.switchTo().window(chld_window);
System.out.println("Switched to the window where Google Store is open");
}
}
Assert.assertEquals(driver.getCurrentUrl(), "https://play.google.com/store/apps/details?id=com.phptravelsnative");
Thread.sleep(3000);
System.out.println("Demo of ExpectedConditions.elementToBeClickable successful\n");
}
代码演练
1- 在phptravels.com/demo/ 找到 "Get It On Google Play "按钮。
爪哇
By elem_gplay_locator = By.cssSelector(".fa-google");
2- 使用JavascriptExecutor提供的 "window.scroll "命令,进行600像素的垂直滚动。
爪哇
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,600)", "");
3- 创建一个WebDriverWait(或Explicit Wait),等待时间为5秒。
由于我们使用的是selenium-java(4.0.0-alpha-7),WebDriver等待的创建方法如下:
Selenium 4(适用于Java)
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
如果使用selenium-java(3.141.59),等待(5秒)的创建方式如下:
Selenium 3 (for Java)
爪哇
WebDriverWait wait = new WebDriverWait(web_driver, 5);
由于我们使用的是Selenium 4 for Java,所以我们使用了前一种方法来创建WebDriverWait(或Explicit Wait)。
Java
/* Selenium Java 3.141.59 */
/* WebDriverWait wait = new WebDriverWait(web_driver, 5); */
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
4- WebDriver进行5秒的显式等待,直到所需元素可被点击(即可以被点击)。如果没有找到该元素,就会产生一个异常;否则,执行就会进入下一步,在这里我们点击按钮。
爪哇
WebElement elem_gplay_btn = wait.until(ExpectedConditions.elementToBeClickable(elem_gplay_locator));
elem_gplay_btn.click();
5- 由于链接(点击后)在一个新窗口(或标签)中打开,我们使用其窗口句柄切换到新窗口。
爪哇
Set<String> allWindowHandles = driver.getWindowHandles();
Iterator<String> iterator = allWindowHandles.iterator();
while(iterator.hasNext())
{
String chld_window = iterator.next();
if (!parentWindowHandle.equalsIgnoreCase(chld_window))
{
driver.switchTo().window(chld_window);
System.out.println("Switched to the window where Google Store is open");
}
}
6- 如果当前的URL(在新窗口中)与预期的URL不匹配,则断言。
语法
Assert.assertEquals(driver.getCurrentUrl(), "https://play.google.com/store/apps/details?id=com.phptravelsnative");
执行
从LambdaTest上的Automation Dashboard获得的执行快照中可以看出,该测试已成功执行。
alertIsPresent ExpectedCondition In Selenium Java
测试场景
- 转到the-internet.herokuapp.com/javascript\…
- 找到 "Click for JS Alert "按钮。
- 点击该按钮,调用警报窗口。
- 等待,直到警报窗口出现。
- 接受警报。
实施
Java
@Test(description="Demo of ExpectedConditions.alertIsPresent", enabled=true)
protected void test_alert_present() throws InterruptedException
{
driver.navigate().to(str_urlarr[1]);
driver.manage().window().maximize();
WebElement elem_alert_btn = driver.findElement(By.xpath("//button[.='Click for JS Alert']"));
elem_alert_btn.click();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
Alert bAlertPresent = wait.until(ExpectedConditions.alertIsPresent());
System.out.println("Alert window is now present");
bAlertPresent.accept();
Thread.sleep(2000);
System.out.println("Demo of ExpectedConditions.alertIsPresent successful\n");
}
代码演练
- 转到测试URLthe-internet.herokuapp.com/javascript_…并使用Selenium的findElement方法找到 "Click on JS Alert "按钮。该元素是使用XPath属性定位的。
爪哇
WebElement elem_alert_btn = driver.findElement(By.xpath("//button[.='Click for JS Alert']"));
2- 点击该按钮以调用警报。
爪哇
elem_alert_btn.click();
3- 做一个5秒的显式等待,直到ExpectedCondition alertIsPresent被满足(或者满足)。
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
Alert bAlertPresent = wait.until(ExpectedConditions.alertIsPresent());
4- 如果警报不存在,会抛出一个异常;否则,WebDriver会切换到警报窗口。使用accept()方法接受该警报。
语法
bAlertPresent.accept();
执行
如下图所示,警报窗口已经出现,测试成功执行。
textToBePresentInElementLocated ExpectedCondition In Selenium Java
测试场景
- 转到the-internet.herokuapp.com/dynamic_con…该页面包含动态内容,即每次刷新时内容都会改变。
- 转到动态内容的元素(第三个文本区)。
- 检查在步骤(2)中指定的文本区中是否有 "laudantium "这个文本。如果没有找到该文本,刷新页面并再次执行搜索操作。
- 在检测到存在所需文本的文本区中打印内容。
执行
爪哇
@Test(description="Demo of ExpectedConditions.textToBePresentInElementLocated", enabled=true)
protected void test_text_present() throws InterruptedException
{
String stText = "laudantium";
Integer counter = 1;
Boolean bTextPresent = false;
driver.navigate().to(str_urlarr[2]);
driver.manage().window().maximize();
By elem_dynam_con_locator = By.cssSelector("#content.large-10 > div:nth-of-type(3) > .large-10");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
while (!bTextPresent)
{
try
{
System.out.println(driver.findElement(elem_dynam_con_locator).getText());
bTextPresent = wait.until(ExpectedConditions.textToBePresentInElementLocated(elem_dynam_con_locator, stText));
if (bTextPresent)
{
System.out.println("The text " + stText + " is present");
break;
}
}
catch (TimeoutException e)
{
/* e.printStackTrace(); */
counter++;
System.out.println("Presence: " + bTextPresent + " Counter " + counter);
driver.navigate().refresh();
continue;
}
}
System.out.println("ExpectedConditions.textToBePresentInElement successful with text " + stText + " found after " + counter + " attempts\n");
}
代码演练
- 转到测试的URL。如下图所示,标记区域的文本在每次页面重新加载时都会发生变化,而页面其余区域的内容则保持不变(或在页面刷新后也是静态的)。
2- 创建一个类型为 "By "的变量,我们使用cssSelector属性来定位WebElement。我们没有使用Chrome中的Inspect,而是使用了Chrome中的POM Builder扩展来获取所需元素的cssSelector。
爪哇
By elem_dynam_con_locator = By.cssSelector("#content.large-10 > div:nth-of-type(3) > .large-10");
3- 创建一个5秒的显式等待(或WebDriverWait)。
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
4- 在一个While循环中,将元素中的文本与预期文本进行比较。如果没有找到文本(最大持续时间为5秒),将抛出一个TimeoutException。在捕获(对于TimeoutException)中,我们增加搜索计数器并使用Selenium提供的navigate().refresh()方法刷新页面。
爪哇
try
{
.....................
.....................
.....................
bTextPresent = wait.until(ExpectedConditions.textToBePresentInElementLocated(elem_dynam_con_locator, stText));
catch (TimeoutException e)
{
/* e.printStackTrace(); */
counter++;
driver.navigate().refresh();
continue;
}
如果文本存在,ExpectedCondition textToBePresentInElementLocated返回true。
爪哇
bTextPresent = wait.until(ExpectedConditions.textToBePresentInElementLocated(elem_dynam_con_locator, stText));
下面是步骤(4)的完整实现。
爪哇
while (!bTextPresent)
{
try
{
System.out.println(driver.findElement(elem_dynam_con_locator).getText());
bTextPresent = wait.until(ExpectedConditions.textToBePresentInElementLocated(elem_dynam_con_locator, stText));
if (bTextPresent)
{
System.out.println("The text " + stText + " is present");
break;
}
}
catch (TimeoutException e)
{
/* e.printStackTrace(); */
counter++;
driver.navigate().refresh();
continue;
}
}
执行
如果搜索词不存在于所需的WebElement中,就会抛出一个异常,并且计数器被递增。如执行截图所示,搜索词 "laudantium "在11次尝试后被找到。
在Selenium Java中的 visibilityOfElementLocated ExpectedCondition
测试场景
- 转到phptravels.com/demo/。
- 找到标题为 "Affiliate "的链接(或元素)。
- 进行垂直滚动,直到ExpectedCondition visibilityOfElementLocated返回步骤(2)中提到的WebElement。
- 点击该WebElement,如果当前页面的标题与所需的标题不一致,则断言。
执行
爪哇
@Test(description="Demo of ExpectedConditions.visibilityOfElementLocated", enabled=true)
protected void test_elem_visibility() throws InterruptedException
{
WebElement elem_affiliate_link = null;
driver.navigate().to(str_urlarr[3]);
driver.manage().window().maximize();
By elem_affiliate_locator = By.cssSelector("a[title='Affiliate']");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
while (elem_affiliate_link != null)
{
elem_affiliate_link = wait.until(ExpectedConditions.visibilityOfElementLocated(elem_affiliate_locator));
if (elem_affiliate_link == null)
{
((JavascriptExecutor) driver).executeScript("window.scrollBy(0,100)", "");
/* Only for checking if the scroll goes through */
Thread.sleep(1000);
}
}
Thread.sleep(3000);
/* We have found the element that points to the Affiliate Link */
driver.findElement(elem_affiliate_locator).click();
Assert.assertEquals(driver.getTitle(), "Become an Affiliate Partner - PHPTRAVELS");
System.out.println("ExpectedConditions.visibilityOfElementLocated test successful\n");
}
代码演练
-
在测试的URL上,创建一个类型为 "By "的变量,并在其中使用cssSelector属性。
爪哇
By elem_affiliate_locator = By.cssSelector("a[title='Affiliate']");
2- 创建一个5秒的显式等待。
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
3- 在一个while循环中,执行检查ExpectedCondition visibilityOfElementLocated是否返回一个有效的WebElement。如果该条件返回Null(即该元素不存在于页面上或等待超时),执行100像素的垂直滚动,并检查是否存在所需的Web元素(即Affiliate)。
爪哇
while (elem_affiliate_link != null)
{
elem_affiliate_link = wait.until(ExpectedConditions.visibilityOfElementLocated(elem_affiliate_locator));
if (elem_affiliate_link == null)
{
((JavascriptExecutor) driver).executeScript("window.scrollBy(0,100)", "");
/* Only for checking if the scroll goes through */
Thread.sleep(1000);
}
}
4- 对使用 ExpectedConditions.visibilityOfElementLocated (element_locator) 定位的 Selenium WebElement 进行点击操作。
爪哇
driver.findElement(elem_affiliate_locator).click();
5- 如果当前页面的标题与预期的标题不一致,则断言。
语法
Assert.assertEquals(driver.getTitle(), "Become an Affiliate Partner - PHPTRAVELS");
执行情况
如下所示,测试URL上的'affiliate link'被成功打开。
frameToBeAvailableAndSwitchToIt ExpectedCondition In Selenium Java
测试场景
- 转到jqueryui.com/spinner/。
- 找到标签名为 "iframe "的元素,检查网页上存在的框架数量。
- 进行200像素的垂直滚动,直到有了预定的框架。
- 使用ExpectedConditions.frameToBeAvailable andSwitchToIt(frame_locator)方法切换到预定的框架。
- 点击位于框架内的一个按钮。
实施
爪哇
@Test(description="Demo of ExpectedConditions.frameToBeAvailableAndSwitchToIt", enabled=true)
protected void test_available_frame() throws InterruptedException
{
driver.navigate().to(str_urlarr[4]);
driver.manage().window().maximize();
/* To check how many frames are available on the page */
List<WebElement> iframeElements = driver.findElements(By.tagName("iframe"));
System.out.println("The total number of iframes are " + iframeElements.size());
/* Scroll where the iFrame is present */
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,200)", "");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
By frame_locator = By.xpath("//*[@id=\"content\"]/iframe");
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame_locator));
Thread.sleep(3000);
/* Click the button inside the iFrame */
By elem_set_value = By.xpath("//button[@id='setvalue']");
wait.until(ExpectedConditions.presenceOfElementLocated(elem_set_value)).click();
Thread.sleep(2000);
System.out.println("ExpectedConditions.frameToBeAvailableAndSwitchToIt test successful\n");
}
代码演练
1- 在导航到测试网址jqueryui.com/spinner/,我们使用标签名为 "iframe "的findElements方法找到iFrames的总数。
爪哇
List<WebElement> iframeElements = driver.findElements(By.tagName("iframe"));
System.out.println("The total number of iframes are " + iframeElements.size());
2- 使用JavascriptExecutor的executor方法 "window.scrollBy "进行200像素的垂直滚动。
爪哇
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,200)", "");
3- 使用WebDriverWait,持续时间设置为5秒,创建一个明确的等待。
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
4- 将By类实例化,以便使用Selenium的findElement方法定位WebElement。
爪哇
By frame_locator = By.xpath("//*[@id=\"content\"]/iframe");
5- 使用步骤(4)中声明的Web定位器找到所需的框架,Selenium Java中预期条件的frameToBeAvailableAndSwitchToIt方法切换到预定的框架。如果该框架不在页面上,该方法返回null。
爪哇
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame_locator));
6- 点击 "setValue "按钮,该按钮位于框架内。
爪哇
By elem_set_value = By.xpath("//button[@id='setvalue']");
7- Selenium Java中预期条件的presenceOfElementLocated方法被用来检测WebElement的存在,该元素具有步骤(6)中定义的网络定位器。点击操作是在按钮上进行的。
爪哇
wait.until(ExpectedConditions.presenceOfElementLocated(elem_set_value)).click();
执行
从Automation Dashboard获得的执行快照表明,测试已经成功执行。
elementToBeSelected ExpectedCondition In Selenium Java
测试场景
- 转到lambdatest.github.io/sample-todo…
- 找到名称为 "li1 "和 "li2 "的元素。
- 点击(或启用)位于步骤(2)中的元素。
- 等到元素--"li1 "和 "li2 "被选中(或启用)。
- 等待,直到名称为 "li3 "的元素被选中。
- 如果为元素 "li3 "抛出一个超时异常,则测试通过。
实施
爪哇
@Test(description="Demo of ExpectedConditions.elementToBeSelected", enabled=true)
protected void test_elem_selected() throws InterruptedException
{
driver.navigate().to(str_urlarr[5]);
driver.manage().window().maximize();
WebElement elem_li1 = driver.findElement(By.name("li1"));
WebElement elem_li2 = driver.findElement(By.name("li2"));
elem_li1.click();
Thread.sleep(2000);
elem_li2.click();
Thread.sleep(2000);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(ExpectedConditions.elementToBeSelected(elem_li1));
wait.until(ExpectedConditions.elementToBeSelected(By.name("li2")));
try
{
/* wait for the element li3 to be selected */
wait.until(ExpectedConditions.elementToBeSelected(By.name("li3")));
}
catch (TimeoutException e)
{
e.printStackTrace();
System.out.println("Pass - Elem li3 is not selected");
}
System.out.println("ExpectedConditions.elementToBeSelected test successful\n");
}
代码演练
1- Selenium自动化测试中的findElement方法被用来定位名称为 "li1 "和 "li2 "的WebElements。
爪哇
WebElement elem_li1 = driver.findElement(By.name("li1"));
WebElement elem_li2 = driver.findElement(By.name("li2"));
2- 使用点击方法 "选择"(或启用)这些元素。
爪哇
elem_li1.click();
Thread.sleep(2000);
elem_li2.click();
Thread.sleep(2000);
3- Selenium Java中Expected Conditions的 elementToBeSelected方法用于检查元素 "li1 "和 "li2 "是否被选中。最大的等待时间被设定为5秒。
爪哇
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(ExpectedConditions.elementToBeSelected(elem_li1));
wait.until(ExpectedConditions.elementToBeSelected(By.name("li2")));
4- elementToBeSelected方法被用于名称为 "li3 "的元素。在5秒(最大等待时间)之后,ExpectedCondtions会产生一个超时异常。
爪哇
try
{
/* wait for the element li3 to be selected */
wait.until(ExpectedConditions.elementToBeSelected(By.name("li3")));
}
catch (TimeoutException e)
{
e.printStackTrace();
System.out.println("Pass - Elem li3 is not selected");
}
执行情况
正如预期的那样,对于名称为 "li3 "的元素,测试结果是一个超时异常。
在Selenium中自定义ExpectedConditions
在有些情况下,你想把多个条件合并成一个,并在测试案例中触发相同的条件。考虑一种情况,测试寻找元素的可见性,并发布可见性;它检查元素是否可点击。这可以通过在Selenium中创建一个自定义ExpectedCondition'来实现。
自定义ExpectedCondition是一个类,它。
- 执行ExpectedCondition接口(例如ExpectedCondition,ExpectedCondition,等等)。
- 有一个带有ExpectedCondition参数的构造函数(可选)。
- 使用Java中的@Override注解来重写应用方法
以下是Selenium Java中自定义ExpectedCondition的实现示例。
爪哇
class CustomElemLocated implements ExpectedCondition<WebElement>
{
By some_locator = By.cssSelector("some_css_locator");
WebElement elem_some_webelement;
@Override
public WebElement apply(WebDriver driver)
{
elem_some_webelement = driver.findElement(some_locator);
return elem_some_webelement;
}
}
让我们来看看如何在Selenium Java中创建自定义的ExpectedCondition,并将以下测试场景自动化。
测试场景
- 转到phptravels.com/demo/。
- 找到标题为 "Affiliate "的链接(或元素)。
- 点击WebElement,如果当前页面的标题和URL与要求的标题和URL不一致,则断言。
实施
我们在org.expconditions包下创建了一个名为Test_customconditions的新文件。这是创建新文件时项目和testng.xml的样子。
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Expected Conditions Demo">
<test verbose="2" preserve-order="true" name="Explicit Wait with Expected Conditions">
<classes>
<class name="org.expconditions.Test_customconditions">
</class>
</classes>
</test>
</suite>
实施
爪哇
package org.expconditions;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.*;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
public class Test_customconditions
{
WebDriver driver = null;
public static String status = "passed";
String username = "user-name";
String access_key = "access-key";
String testURL = "https://phptravels.com/demo/";
String testURLTitle = "Demo Script Test drive - PHPTRAVELS";
String affLinkURL = "https://phptravels.com/affiliate/";
String affLinkTitle = "Become an Affiliate Partner - PHPTRAVELS";
@BeforeClass
public void testSetUp() throws MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("build", "[Java] Testing Custom Expected Conditions with Selenium");
capabilities.setCapability("name", "[Java] Testing Custom Expected Conditions with Selenium");
capabilities.setCapability("platformName", "Windows 10");
capabilities.setCapability("browserName", "Chrome");
capabilities.setCapability("browserVersion","latest");
capabilities.setCapability("tunnel",false);
capabilities.setCapability("network",true);
capabilities.setCapability("console",true);
capabilities.setCapability("visual",true);
driver = new RemoteWebDriver(new URL("http://" + username + ":" + access_key + "@hub.lambdatest.com/wd/hub"),
capabilities);
System.out.println("Started session");
}
@AfterClass
public void tearDown()
{
if (driver != null)
{
driver.quit();
}
}
@Test(description="Demo of Custom ExpectedConditions in Selenium")
public void test_elem_visibility() throws InterruptedException
{
WebElement elem_affiliate_link = null;
driver.get(testURL);
Thread.sleep(5000);
/* Selenium Java 3.141.59 */
/* WebDriverWait wait = new WebDriverWait(web_driver, 5); */
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
if (((boolean) wait.until(new TestURLLoaded(testURL, testURLTitle))) == false)
{
throw new RuntimeException("PHP demo page is not displayed");
}
elem_affiliate_link = wait.until(new ElementLocated());
while ( elem_affiliate_link == null)
{
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,100)", "");
elem_affiliate_link = wait.until(new ElementLocated());
}
/* Affiliate Link is visible */
if (elem_affiliate_link != null)
{
elem_affiliate_link.click();
Thread.sleep(2000);
if (((boolean) (wait.until(new TestURLLoaded(affLinkURL, affLinkTitle))) == false))
{
throw new RuntimeException("Affiliate link page is not displayed");
}
}
System.out.println("Demo of Custom ExpectedConditions in Selenium is successful\n");
}
}
/*
Custom ExpectedCondition function to check whether the Page Title & Page URL match
with the expected Page Title and Page URL
*/
class TestURLLoaded implements ExpectedCondition<Boolean>
{
String expTitle;
String expURL;
public TestURLLoaded(String expURL, String expTitle)
{
this.expTitle = expTitle;
this.expURL = expURL;
}
@Override
public Boolean apply(WebDriver driver)
{
Boolean bURL = false, bTitle = false;
bURL = driver.getCurrentUrl().contains(expURL);
bTitle = driver.getTitle().contains(expTitle);
return bTitle && bURL;
}
}
/*
Custom ExpectedCondition function to check whether the Affiliate Link Title & Page URL match
with the expected Page Title and Page URL
*/
class ElementLocated implements ExpectedCondition<WebElement>
{
By elem_affiliate_locator = By.cssSelector("a[title='Affiliate']");
WebElement elem_affiliate_link;
@Override
public WebElement apply(WebDriver driver)
{
elem_affiliate_link = driver.findElement(elem_affiliate_locator);
return elem_affiliate_link;
}
}
代码演练
我们首先使用一个自定义的ExpectedCondition,检查URL和页面标题是否与测试中的预期一致。TestURLLoaded类实现了ExpectedCondition并重写了apply方法。
如果页面标题和页面URL是正确的,apply方法返回True,否则它返回false。
爪哇
class TestURLLoaded implements ExpectedCondition<Boolean>
{
String expTitle;
String expURL;
public TestURLLoaded(String expURL, String expTitle)
{
this.expTitle = expTitle;
this.expURL = expURL;
}
@Override
public Boolean apply(WebDriver driver)
{
Boolean bURL = false, bTitle = false;
bURL = driver.getCurrentUrl().contains(expURL);
bTitle = driver.getTitle().contains(expTitle);
return bTitle && bURL;
}
}
在测试代码中,我们在前面实现的自定义条件下等待10秒的时间。
爪哇
@Test(description="Demo of Custom ExpectedConditions in Selenium")
public void test_elem_visibility() throws InterruptedException
{
WebElement elem_affiliate_link = null;
driver.get(testURL);
Thread.sleep(5000);
/* Selenium Java 3.141.59 */
/* WebDriverWait wait = new WebDriverWait(web_driver, 5); */
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
if (((boolean) wait.until(new TestURLLoaded(testURL, testURLTitle))) == false)
{
throw new RuntimeException("PHP demo page is not displayed");
}
....................................
....................................
....................................
}
WebDriver最多等待10秒,直到((boolean) wait.until(new TestURLLoaded(testURL, testURLTitle))返回真或假。如果自定义的ExpectedCondition返回false(即引发异常),这意味着URL和页面标题与测试中的预期不符。
true的值意味着我们可以继续进行测试方案中的下一步(即定位Affiliate链接并点击同一链接)。
ElementLocated类是一个自定义条件类,实现了ExpectedCondition接口。
爪哇
class ElementLocated implements ExpectedCondition<WebElement>
{
By elem_affiliate_locator = By.cssSelector("a[title='Affiliate']");
WebElement elem_affiliate_link;
@Override
public WebElement apply(WebDriver driver)
{
elem_affiliate_link = driver.findElement(elem_affiliate_locator);
return elem_affiliate_link;
}
}
在应用方法中,我们使用cssSelector定位器来定位WebElement(即Affiliate链接),并返回相同的信息供测试代码使用。
语法
@Override
public WebElement apply(WebDriver driver)
{
elem_affiliate_link = driver.findElement(elem_affiliate_locator);
return elem_affiliate_link;
}
在测试案例中,进行100像素的垂直滚动,直到自定义的ExpectedCondition返回true(即找到了所需的WebElement)。
爪哇
@Test(description="Demo of Custom ExpectedConditions in Selenium")
public void test_elem_visibility() throws InterruptedException
{
WebElement elem_affiliate_link = null;
......................
......................
while ( elem_affiliate_link == null)
{
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,100)", "");
elem_affiliate_link = wait.until(new ElementLocated());
}
......................
......................
}
一旦找到带有联盟链接的WebElement,我们就点击它并使用自定义的ExpectedCondition(即TestURLLoaded)来检查联盟页面的页面标题和页面URL是否符合预期。自定义条件被用于wait.until()方法,等待时间设置为10秒。
爪哇
@Test(description="Demo of Custom ExpectedConditions in Selenium")
public void test_elem_visibility() throws InterruptedException
{
.....................
.....................
.....................
/* Affiliate Link is visible */
if (elem_affiliate_link != null)
{
elem_affiliate_link.click();
Thread.sleep(2000);
if (((boolean) (wait.until(new TestURLLoaded(affLinkURL, affLinkTitle))) == false))
{
throw new RuntimeException("Affiliate link page is not displayed");
}
}
.....................
.....................
}
执行情况
从LambdaTest的自动化仪表板上获得的执行快照中可以看出,测试页面上的联盟链接被找到了,并且对该链接的点击操作是成功的。
条件符合预期
在Selenium中,预期条件被用来实现显式等待。与隐式等待相比,它更有优势,在隐式等待中,即使Web元素的位置比总时长早很多,也会在整个 "等待 "时长内进行等待。ExpectedCondition 、ExpectedCondition 、ExpectedCondition 和ExpectedCondition 是Selenium Java中ExpectedConditions的四个主要类别。
Selenium自动化测试中的自定义ExpectedConditions在你想结合不同的条件来实现一个特定的任务时非常有用。自定义 ExpectedCondition 实现了 ExpectedCondition 接口,并重写了 apply 方法。总而言之,带有ExpectedConditions的显式等待比隐式等待有很大的优势,在测试实现中,只要适用,就应该优先考虑。
实施 要素 执行(计算) 框架(网络) IFrame(视频格式) Java(编程语言) 字符串 测试 数据类型 Selenium
经Himanshu Sheth许可发表于DZone。点击这里查看原文。
DZone贡献者所表达的观点属于他们自己。
DZone上的热门文章
评论