场景
button dropdown就是把按钮和下拉菜单弄到了一起。处理这种对象的思路一般是先点击这个按钮,等待下拉菜单显示出来,然后使用层级定位方法来获取下拉菜单中的具体项。
代码
下面的代码演示了如何找到watir-webdriver这个菜单项。其处理方法是先点击info按钮,然后等到下拉菜单出现后定位下拉菜单的ul元素,再定位ul元素中link text为watir-webdriver的link,并点击之。
button_dropdown.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>button group</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('.btn').click(function(){
alert($(this).text());
});
});
</script>
</head>
<body>
<h3>button group</h3>
<div class="row-fluid">
<div class="span3">
<div class="well">
<div class="btn-toolbar">
<div class="btn-group">
<div class="btn">first</div>
<div class="btn">second</div>
<div class="btn">third</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
button_dropdown.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ButtonDropdown {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/button_dropdown.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 定位text是watir-webdriver的下拉菜单
// 首先显示下拉菜单
dr.findElement(By.linkText("Info")).click();
(new WebDriverWait(dr, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d){
return d.findElement(By.className("dropdown-menu")).isDisplayed();
}
});
// 通过ul再层级定位
dr.findElement(By.className("dropdown-menu")).findElement(By.linkText("watir-webdriver")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理navs
场景
navs可以看作是简单的类似于tab的导航栏。一般来说导航栏都是ul+li。先定位ul再去层级定位li中的link基本就能解决问题。
代码
navs.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Navs</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(
function(){
$('.nav').find('li').click(function() {
$(this).parent().find('li').removeClass('active');
$(this).addClass('active');
});
}
);
</script>
</head>
<body>
<h3>Navs</h3>
<div class="row-fluid">
<div class="span3">
<ul class="nav nav-pills">
<li class="active">
<a href="#">Home</a>
</li>
<li><a href="#">Content</a></li>
<li><a href="#">About</a></li>
</ul>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
navs.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class Navs {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/navs.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 方法1:层级定位,先定位ul再定位li
dr.findElement(By.className("nav")).findElement(By.linkText("About")).click();
Thread.sleep(1000);
// 方法2: 直接定位link
dr.findElement(By.linkText("Home")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理面包屑
场景
在实际的测试脚本中,有可能需要处理面包屑。处理面包屑主要是获取其层级关系,以及获得当前的层级。一般来说当前层级都不会是链接,而父层级则基本是以链接,所以处理面包屑的思路就很明显了。找到面包屑所在的div或ul,然后再通过该div或ul找到下面的所有链接,这些链接就是父层级。最后不是链接的部分就应该是当前层级了。
代码
breadcrumb.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>breadcrumb</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(
function(){
}
);
</script>
</head>
<body>
<h3>breadcrumb</h3>
<div class="row-fluid">
<div class="span3">
<ul class="breadcrumb">
<li><a href="#">Home</a> <span class="divider">/</span></li>
<li><a href="#">Library</a> <span class="divider">/</span></li>
<li class="active">Data</li>
</ul>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
breadcrumb.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class Breadcrumb {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/breadcrumb.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 获得其父层级
List<WebElement> ancestors = dr.findElement(By.className("breadcrumb")).findElements(By.tagName("a"));
for(WebElement link : ancestors){
System.out.println(link.getText());
}
// 获取当前层级
// 由于页面上可能有很多class为active的元素
// 所以使用层级定位最为保险
WebElement current = dr.findElement(By.className("breadcrumb")).findElement(By.className("active"));
System.out.println(current.getText());
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理对话框
场景
页面上弹出的对话框是自动化测试经常会遇到的一个问题。很多情况下这个弹出的对话框是一个iframe,处理起来有点麻烦,需要进行switch_to操作。但现在很多前端框架的对话框都是div形式的,这就让我们的处理变得十分简单了。
处理对话框一般会做下面的一些事情
- 打开对话框
- 关闭对话框
- 操作对话框中的元素
代码
下面的代码演示了如何打开、关闭以及点击对话框中的链接
modal.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>modal</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#click').click(function(){
$(this).parent().find('p').text('try watir-webdriver right now!');
});
});
</script>
</head>
<body>
<h3>modal</h3>
<div class="row-fluid">
<div class="span6">
<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn btn-primary" data-toggle="modal" id="show_modal">Click</a>
<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<p>watir-webdriver is better than slenium-webdriver</p>
<a href="#" id="click">click me</a>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<button class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
modal.java
public class Modal {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/modal.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 打开对话框
dr.findElement(By.id("show_modal")).click();
(new WebDriverWait(dr, 10)).until(
new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.findElement(By.id("myModal")).isDisplayed();
}
}
);
// 点击对话框中的链接
// 由于对话框中的元素被蒙板所遮挡,直接点击会报 Element is not clickable的错误
// 所以使用js来模拟click
// 在watir-webdriver中只需要fire_event(:click)就可以了
WebElement link = dr.findElement(By.id("myModal")).findElement(By.id("click"));
((JavascriptExecutor)dr).executeScript("$(arguments[0]).click()", link);
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的属性及内容
场景
获取测试对象的内容是前端自动化测试里一定会使用到的技术。比如我们要判断页面上是否显示了一个提示,那么我们就需要找到这个提示对象,然后获取其中的文字,再跟我们的预期进行比较。在webdriver中使用element.getAttribute()方法可以获取dom元素(测试对象)的属性。
获取测试对象的属性能够帮我们更好的进行对象的定位。比如页面上有很多class都是'btn'的div,而我们需要定位其中1个有具有title属性的div。由于selenium-webdriver是不支持直接使用title来定位对象的,所以我们只能先把所有class是btn的div都找到,然后遍历这些div,获取这些div的title属性,一旦发现具体title属性的div,那么返回这个div既可。在webdriver中,使用element.getText()方法可以返回dom节点的内容(text)。
代码
下面的代码演示了如何获取测试对象的title属性和该对象的文字内容
attribute.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>attribute</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>attribute</h3>
<div class="row-fluid">
<div class="span6">
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
attribute.java
public class Attribute {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/attribute.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement link = dr.findElement(By.id("tooltip"));
// 获得tooltip的内容
System.out.println(link.getAttribute("data-original-title"));
// 获取该链接的text
System.out.println(link.getText());
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的css属性
场景
当你的测试用例纠结细枝末节的时候,你就需要通过判断元素的css属性来验证你的操作是否达到了预期的效果。比如你可以通过判断页面上的标题字号以字体来验证页面的显示是否符合预期。当然,这个是强烈不推荐的。因为页面上最不稳定的就是css了,css变动频繁,而且通过属性也不能直观的判断页面的显示效果,还不如让人为的去看一眼,大问题一望即知。
代码
下面的代码演示了如何获取测试对象的css属性。
css.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>attribute</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>attribute</h3>
<div class="row-fluid">
<div class="span6">
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
css.java
public class Css {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/css.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement link = dr.findElement(By.id("tooltip"));
System.out.println(link.getCssValue("color"));
System.out.println(dr.findElement(By.tagName("h3")).getCssValue("font"));
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的状态
场景
在web自动化测试中,我们需要获取测试对象的四种状态
- 是否显示。使用element.isDisplayed()方法;
- 是否存在。使用findElement方法,捕获其抛出的异常,如果是NoSuchElementException的话则可以确定该元素不存在;
- 是否被选中。一般是判断表单元素,比如radio或checkbox是否被选中。使用element.isSelected()方法;
- 是否enable,也就是是否是灰化状态。使用element.isEnabled()方法;
代码
status.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>status</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>status</h3>
<div class="row-fluid">
<div class="span3">
<input name="user" placeholder="Disabled TextField" disabled />
</div>
<div class="span3">
<a class="btn disabled">Disabled Button</a>
</div>
<div class="span3">
<input name="radio" type="radio" />
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
status.java
public class Status {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/status.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement textField = dr.findElement(By.name("user"));
System.out.println(textField.isEnabled());
// 直接用isEnabled方法去判断该button的话返回的会是true
// 这是因为button是使用css方法去disabled的,并不是真正的disable
// 这时候需要判断其class里是否有disabled这值来判断其是否处于disable状态
System.out.println(dr.findElement(By.className("btn")).isEnabled());
// 隐藏掉textField
// 判断其是否显示
((JavascriptExecutor)dr).executeScript("$(arguments[0]).hide()", textField);
System.out.println(textField.isDisplayed());
// 使用click方法选择raido
WebElement radio = dr.findElement(By.name("radio"));
radio.click();
System.out.println(radio.isSelected());
try{
dr.findElement(By.id("none"));
} catch(NoSuchElementException e){
System.out.println("element does not exist");
}
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
在这里我们遇到了一种情况,那就是测试对象看上去是disabled,但是使用enabled方法却返回true。这时候一般思路是判断该对象的css属性或class,通过这些值去进一步判断对象是否disable。
}