Selenium WebDriver java提供了windowsUtils类来和Windows操作系统交互。在测试开始时,我们需要关掉已经一些进程。
如下例子,关闭已打开的火狐浏览器:
@Before
public void setUp()
{
WindowsUtils.tryToKillByName("firefox.exe");
driver = new FirefoxDriver();
driver.get("http://www.google.com");
driver.manage().window().maximize();
}
我们可以使用tryToKillByName方法来关闭任何的windows的进程。如果这个进程不存在则会抛出一个异常,但是,测试还是会正常的执行下去。
u 通过WebDriver读取windows注册表中的值
WindowsUtils类提供了多种方法和windows操作系统的注册表进行交互,如果测试是运行在windows操作系统上的IE浏览器,则可能需要修改一些IE注册表里的设置。使用WindowsUtils类就可以很方便的解决。
我们需要导入org.openqa.selenium.os.WindowsUtils类然后使用readStringRegistryValue()方法来读取注册表里的键值。package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testRegistry() {
WebDriver driver = new InternetExplorerDriver();
driver.get("D:\\demo\\checkbox.html");
String osname = WindowsUtils.readStringRegistryValue
("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\OS");
System.out.println(osname);
}
}
WindowsUtil也基于返回值的不同提供了多种方法来读取注册表的值,例子中返回的是String所以使用readStringRegistryValue(),还可以据不同的数据类型使用readIntegerRegistryValue(),readBooleanRegistryValue()根。
u 通过WebDriver修改windows注册表的值
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testRegistry() {
WebDriver driver = new InternetExplorerDriver();
driver.get("D:\\demo\\checkbox.html");
WindowsUtils.writeStringRegistryValue
("HKEY_CURRENT_USER\\SOFTWARE\\Selenium\\SeleniumVersion",
"2.24");
assertEquals("2.24",
WindowsUtils.readStringRegistryValue
("HKEY_CURRENT_USER\\SOFTWARE\\Selenium\\SeleniumVersion"));
}
}
writeStringRegistryValue()通过注册表的路径找到相应的位置,如果值存在则修改,如果不存在则新建一条新的,同时基于写入数据类型也提供了其他两种方法writeIntegerRegistryValue(),writeBooleanRegistryValue()。
u 使用隐式的等待同步测试
Selenium WebDriver提供了隐式等待来同步测试。当使用了隐式等待执行测试的时候,如果WebDriver没有在DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常。
换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找DOM。默认的时间是0 。
一旦设置了隐式等待,则它存在在整个WebDriver对象实例的生命周期中,但是,隐式的等待会让一个正常响应的应用的测试变慢,它将会在寻找每个元素的时候都进行等待,这样就增加了整个测试过程的执行时间。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get
("http://demo.tutorialzine.com/2009/09/" + "simple-ajax-website-jquery/demo.html");
//等待10秒
driver.manage().timeouts(). implicitlyWait(10, TimeUnit.SECONDS);
WebElement page4button = driver. findElement(By.linkText("Page 4"));
page4button.click();
WebElement message = driver.findElement(By.id("pageContent"));
//等待Ajax的内容出现
Thread.sleep(4000);
assertTrue(message.getText().contains("Nunc nibh tortor"));
}
}
Selenium WebDriver提供了Timeouts接口来设置隐式等待。Timeouts接口下又提供了implicitlyWait()方法,接收一个查询元素所需要等待癿时间参数。
Thread.sleep(4000)意思义等待4秒钟,如果没有返句加上pageContent本身就存在,所以它癿内容就是最初没有点击时候的文本,不是我们所期望的。。
u 使用显式的等待同步测试
Selenium WebDriver也提供了显式的等待,相对亍隐式来说更好的控制方法来同步测试。不像隐式等待,你可以在执行下一次操作时,自定义等待条件。
显式的等待叧需要执行在需要同步的地方而不影响脚本其他癿地方。
Selenium WebDriver提供了WebDriverWait和ExpectedCondition类来执行显式等待。
ExpectedCondition类提供了一系列预定义好的条件来等待。下面的表格中显示了一些我们经常在自动化测试中遇到的常用条件。
预定义条件 | 方法名 |
元素可见可点击 | elementToBeClickable(By locator) |
元素被选中 | elementToBeSelected(WebElement element) |
存在一个元素 | presenceOfElementLocated(By locator) |
元素中出现指定癿文本 | textToBePresentInElement(By locator, String text) |
元素癿值 | textToBePresentInElementValue(By locator, String text) |
标题 | titleContains(String title) |
package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://demo.tutorialzine.com/2009/09/simple-ajax-website-jquery/demo.html");
WebElement page4button = driver.findElement(By.linkText("Page 4"));
page4button.click();
//设置等待时间10秒
WebDriverWait wait = new WebDriverWait(driver, 10);
//等待直到符合元素文本内容出现。
wait.until(ExpectedConditions.textToBePresentInElement
(By.id("pageContent"),
"Nunc nibh tortor, " +
"congue pulvinar rhoncus quis, " +
"porta sed odio. Quisque ornare, " +
"velit elementum porta consequat, " +
"nibh augue tincidunt magna, " +
"at ullamcorper ligula felis vitae felis."));
WebDriverWait每500毫秒调用一次ExpectedCondition直到正确的返回值。
可见返样的好处就是随时控制所需要等待的地方,更加精确的控制所需要癿条件
u 使用自定义的期望条件同步测试
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.w3school.com.cn/" +
"ajax/ajax_example.asp");
WebElement button = driver.findElement(By.tagName("button"));
//验证点击之前的文本
assertTrue(driver.findElement
(By.cssSelector("#myDiv h3"))
.getText().contains("Let AJAX"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//创建一个新的ExpecctedCondition接口,就必须实现apply方法
WebElement message = wait.until
(new ExpectedCondition<WebElement>(){
public WebElement apply(WebDriver d){
return d.findElement(By.cssSelector("#myDiv p"));
}
});
//验证点击后的文本
assertTrue(message.getText().contains("AJAX is"));
driver.close();
}
}
这里通过ExpectedCondition和WebDriverWait类我们自定义了一个期望条件。在这个例子中我们需要在5秒内定位到指定的元素,其实通过自身的presenceOfElementLocated(By locator)方法也能实现.
等待元素的属性值改变:
(new WebDriverWait(driver, 10)).until(
new ExpectedCondition<Boolean>()
{
public Boolean apply(WebDriver d)
{
return d.findElement(By.id("userName")).getAttribute("readonly").contains("true");
}});
如下例子也是等待某属性改变:
driver.get("http://www.jquery.com");
WebElement button =
driver.findElement(By.linkText("RUN CODE"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//这里apply的返回值为Boolean
Boolean classname = wait.until
(new ExpectedCondition<Boolean>(){
public Boolean apply(WebDriver d){
return d.findElement(
By.cssSelector(".jq-codeDemo p"))
.getAttribute("class")
.contains("ohmy");
}
});
driver.close();
等待元素变为可见:
package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.jquery.com");
WebElement button =
driver.findElement(By.linkText("RUN CODE"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//创建一个新的ExpecctedCondition接口,就必须实现apply方法
Boolean classname = wait.until
(new ExpectedCondition<Boolean>(){
public Boolean apply(WebDriver d){
return d.findElement(
By.cssSelector(".jq-codeDemo p"))
.isDisplayed();
}
});
driver.close();
}
}
等待DOM的事件
Web应用可能使用了AJAX的框架如jQuery来操作网页内容。例如,jQuery经常异步的会去从服务器加载一个很大的JSON文件。当jQuery正在处理文件的时候,测试可以使用active属性。自定义的等待可以通过执行一段JavaScript代码并检查返回值来完成。
(new WebDriverWait(driver, 10)).until(
new ExpectedCondition<Boolean>()
{
public Boolean apply(WebDriver d)
{
JavascriptExecutor js = (JavascriptExecutor) d;
return (Boolean)js.executeScript("return jQuery.active == 0");
}});
u 检查元素是否存在
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
WebDriver driver = new InternetExplorerDriver();
@Test
public void testisElementPresent(){
driver.get("http://www.baidu.com");
driver.findElement(By.id("kw")).sendKeys("selenium");
//判断搜索按钮是否存在
if(isElementPresent(By.id("su1"))){
//点击按钮
driver.findElement(By.id("su")).click();
}else{
fail("元素不存在");
}
}
private boolean isElementPresent(By by)
{
try
{
driver.findElement(by);
return true;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
}
u 检查元素的状态
isSelected() | 检查元素是否被选中(单选,多选,下拉框) |
disDisplayed() | 检查元素是否可见 |
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
@Test
public void testRadioButton() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\RadioButton.html");
//使用value值来定位单选按钮
WebElement apple =
driver.findElement(By.cssSelector("input[value='Apple']"));
//检查是否已选择,如果没有则点击选择
if(!apple.isSelected()){
apple.click();
}
//验证apple选项已经选中
assertTrue(apple.isSelected());
//也可以得到所有的单选按钮
List<WebElement> fruit =
driver.findElements(By.name("fruit"));
//查询Orange选项是否存在,如果存在则选择
for(WebElement allFruit : fruit){
if(allFruit.getAttribute("value").equals("Orange")){
if(!allFruit.isSelected()){
allFruit.click();
assertTrue(allFruit.isSelected());
break;
}
u 通过名称识别和处理一个弹出窗口
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton = driver.findElement(By.id("helpbutton1"));
helpButton.click();
try
{
//转到HelpWindow
driver.switchTo().window("HelpWindow");
}
catch (NoSuchWindowException e)
{
e.printStackTrace();
}
//验证新窗口里的文本
assertEquals("PopUpWindow", driver.findElement(By.tagName("p")).getText());
//关闭子窗口
driver.close();
//回到父窗口
driver.switchTo().window(parentWindowId);
//验证父窗口的title
assertTrue(driver.getTitle().equals("help"));
driver.close();
}
}
u 通过标题识别处理一个弹出窗口
很多时候开发人员并没有给弹出的窗口分配一个name属性。这种情况下,我们可以使用handle属性。但是,handle的值是不停的变化的,这让识别窗口变的有些困难,尤其是多个窗口的时候。我们使用handle和title来识别一个弹出窗口。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.Set;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton =
driver.findElement(By.id("helpbutton2"));
helpButton.click();
//得到所有的窗口
Set<String> allWindowsId = driver.getWindowHandles();
//通过title得到新的窗口
for (String windowId : allWindowsId)
{
if (driver.switchTo().window(windowId)
.getTitle().equals("PopUpWindow"))
{
driver.switchTo().window(windowId);
break;
}
}
//验证新窗口的文本
assertEquals("PopUpWindow", driver.findElement(By.tagName("p")).getText());
//关闭弹出窗口
driver.close();
//关闭父窗口
driver.switchTo().window(parentWindowId);
driver.close();
}
}
u 通过网页内容识别处理一个弹出窗口
package com.example.tests;
import static org.junit.Assert.*;
import java.util.Set;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton =
driver.findElement(By.id("helpbutton2"));
helpButton.click();
//得到所有的窗口
Set<String> allWindowsId = driver.getWindowHandles();
//通过查找页面内容得到新的窗口
for (String windowId : allWindowsId) {
driver.switchTo().window(windowId);
if (driver.getPageSource().contains("Welcome")){
driver.switchTo().window(windowId);
break;
}
}
//验证新窗口的文本
assertEquals("PopUpWindow",
driver.findElement(By.tagName("p")).getText());
//关闭弹出窗口
driver.close();
//关闭父窗口
driver.switchTo().window(parentWindowId);
driver.close();
}
}
通过driver.getPageSource()方法得到页面的html内容,再调用contains()方法来判断是否含有指定的内容。这样做的缺点就是如果页面内容很多,获得的速度会慢,而且contains()里面查找内容必须是唯一,否则可能识别的窗口不是你所期望的。
u 处理一个简单的JavaScript警告窗
//获取alert窗口
Alert alertBox = driver.switchTo().alert();
alertBox.accept();
//验证alert窗口里的文字
assertEquals("Hello World",alertBox.getText());
driver.close();
driver.switchTo().alert()将窗口移劢到警告框上。
alert.getText()得到警告框上癿信息。
如果找不到警告框则会抛出NoAlertPresentException异常。
u 处理一个确认框
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\alert.html");
//点击确定按钮
getConfirmBox().accept();
//验证点击后的文字
assertEquals("你点击了确定按钮!",
driver.findElement(By.cssSelector("span")).getText());
//点击取消按钮
getConfirmBox().dismiss();
assertEquals("你点击了取消按钮!",
driver.findElement(By.cssSelector("span")).getText());
driver.close();
}
//封装得到窗口的方法
private Alert getConfirmBox(){
//点击按钮弹出确认提示框
WebElement button = driver.findElement(By.id("confirm"));
button.click();
//获取确认提示框
Alert confirmBox = driver.switchTo().alert();
assertEquals("我是确认提示框!",confirmBox.getText());
return confirmBox;
}
}
点击确认是使用accept()方法,点击取消使用dismiss()方法。
u 处理一个提示框
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testPromptAlert(){
driver.get("D:\\demo\\alert.html");
WebElement button = driver.findElement(By.id("prompt"));
button.click();
//获得提示框
Alert promptAlert = driver.switchTo().alert();
assertEquals("点都点了,就输入点什么吧",promptAlert.getText());
//输入一些数据
promptAlert.sendKeys("洛阳亲友如相问,就说我在写代码");
//点击确定按钮
promptAlert.accept();
//验证输入的数据
String actualTest = driver.findElement(By.tagName("span"))
.getText();
assertEquals("洛阳亲友如相问,就说我在写代码", actualTest);
driver.close();
}
}
u 识别处理框架
//通过id定位到左边的框架
driver.switchTo().frame("left");
String leftMsg = driver.findElement(By.tagName("p")).getText();
assertEquals("i am left page",leftMsg);
//回到初始的焦点
driver.switchTo().defaultContent();
//通过name定位到右边的框架
driver.switchTo().frame("right");
String rightMsg = driver.findElement(By.tagName("p")).getText();
assertEquals("i am right page",rightMsg);
driver.close();
通过index获取frame框架:
//通过index来定位框架
driver.switchTo().frame(1);
//验证中间框架的文本
String middleMsg = driver.findElement(By.tagName("p"))
.getText();
assertEquals("i am middle page",middleMsg);
u 通过页面内容识别和处理框架
//得到所有的frame元素
List<WebElement> frames = driver.findElements(By.tagName("frame"));
//通过页面的内容得到中间的框架
for (int i = 0; i < frames.size(); i++)
{
driver.switchTo().frame(i);
if (driver.getPageSource().contains("middle"))
{
break;
//没有匹配的时候需要回到最初的页面
}
else
{
driver.switchTo().defaultContent();
}
String actualText = driver.findElement(By.tagName("p")).getText();
assertEquals("i am middle page", actualText);
u 处理IFRAM
//首先获得父窗口
driver.switchTo().frame("left");
//取得iframe元素
WebElement weiboIframe = driver.findElement(By.tagName("iframe"));
//获得iframe窗口
driver.switchTo().frame(weiboIframe);
//验证iframe里面的页面内容
String actualText = driver.findElement(By.linkText("新浪微博")).getText();
assertEquals("新浪微博", actualText);
driver.switchTo().defaultContent();
定位frame中的元素
场景
处理frame需要用到2个方法,分别是switchTo().frame(element|index|id)和switchTo.defaultContent()
switchTo().frame()方法的参数值得一提。其支持
- WebElement, 可以传入一个已经定位的frame元素。如 switchTo().frame(dr.findElement(By.id("myFrame")))
- int index, 可以传入页面上frame的索引,如0表示第1个frame
- String id, 可以传入frame的id
switchTo().frame()方法把当前定位的主体切换了frame里。怎么理解这句话呢?我们可以从frame的实质去理解。frame中实际上是嵌入了另一个页面,而webdriver每次只能在一个页面识别,因此才需要用switch_to.frame方法去获取frame中嵌入的页面,对那个页面里的元素进行定位。
switchTo.defaultContent方法的话则是从frame中嵌入的页面里跳出,跳回到最外面的原始页面中。
如果页面上只有1个frame的话那么这一切都是很好理解的,但如果页面上有多个frame,情况有稍微有点复杂了。
代码
下面的代码中frame.html里有个id为f1的frame,而f1中又嵌入了id为f2的frame,该frame加载了百度的首页。
frame.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>frame</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>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" src="inner.html" width="800", height="600"></iframe>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
inner.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="http://www.baidu.com" width="700" height="500"></iframe>
<a href="javascript:alert('watir-webdriver better than selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
frame.java
public class Frame {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/frame.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 先到f1再到f2
dr.switchTo().frame("f1");
dr.switchTo().frame("f2");
// 往f2中的百度关键字文本框中输入内容
dr.findElement(By.id("kw")).sendKeys("watir-webdriver");
Thread.sleep(1000);
// 直接跳出所有frame
dr.switchTo().defaultContent();
// 再到f1
dr.switchTo().frame("f1");
dr.findElement(By.linkText("click")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
假设页面上有A、B两个frame,其中B在A内,那么定位B中的内容则需要先到A,然后再到B。如果是定位A中的内容,那么直接switch_to.frame('A')就可以了;
页面中使用frame会影响页面渲染速度,如果你遇到页面中有多个frame的情况,你完全可以提出1个页面前端性能的缺陷;
如果实在搞不定页面上的frame,送你一句歌词:也许放弃才能靠近你。那么及时放弃跟此frame相关的用例才是明智之举;
action
场景
由于webdriver是要模拟真实的用户操作,因此webdriver的Action类中提供了很多与操作有关的方法。
下面列举一下Action类的一些主要方法
- keyDown。模拟按键按下
- keyUp。模拟按键弹起
- click
- sendKeys
- doubleClick。鼠标左键双击
- clickAndHold。鼠标左键点击住不放
- release。鼠标左键弹起,可以与click_and_hold配合使用
- moveToElement。把鼠标移动到元素的中心点
- contextClick。鼠标右键点击
- dragAndDrop。拖拽
代码
Actions action = new Actions(driver)
action.keyDown(Keys.SHIFT).
click(element).
click(second_element).
keyUp(Keys.SHIFT).
dragAndDrop(element, third_element).
build().
perform()
讨论
具体使用方法可以参考api文档。action的api文档算是比较全面了。
上传文件
场景
上传文件的方法是找到上传文件的对象,通常是的对象。然后直接往这个对象sendKeys,传入需要上传文件的正确路径。绝对路径和相对路径都可以,但是上传的文件必须存在,否则会报错。
代码
upload_file.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</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">
</script>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
upload_file.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.Alert;
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 Upload {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/upload_file.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
dr.findElement(By.cssSelector("input[type=file]")).sendKeys("src/navs.html");
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
执行js
场景
如果你熟悉js的话,那么使用webdriver执行js就是一件很高效的事情了。在webdriver脚本中直接执行js的好处很多,这里就不一一枚举了。
webdriver提供了JavascriptExecutor(dr).executeScript()接口来帮助我们完成这一工作。在实际的测试脚本中,以下两种场景是经常遇到的
- 在页面直接执行一段js
- 在某个已经定位的元素的上执行js
代码
下面的代码演示了如何在页面以及在已经定位的元素上执行js
js.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>js</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>js</h3>
<div class="row-fluid">
<div class="span6 well">
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
<a class="btn">Button</a>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
js.java
public class Js {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/js.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 在页面上直接执行js
((JavascriptExecutor)dr).executeScript("$('#tooltip').fadeOut();");
Thread.sleep(1000);
// 在已经定位的元素上执行js
WebElement button = dr.findElement(By.className("btn"));
((JavascriptExecutor)dr).executeScript("$(arguments[0]).fadeOut();", button);
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
前进和后退
场景
说实话,这两个功能一般不太常用。所能想到的场景大概也就是在几个页面间来回跳转,省去每次都get url。
代码
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class ForwardAndBack {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
Thread.sleep(2000);
String firstUrl = "http://www.baidu.com";
System.out.printf("now accesss %s \n", firstUrl);
dr.get(firstUrl);
Thread.sleep(1000);
String secondUrl = "http://www.soso.com";
System.out.printf("now accesss %s \n", secondUrl);
dr.get(secondUrl);
Thread.sleep(1000);
System.out.printf("now back to %s \n", firstUrl);
dr.navigate().back();
Thread.sleep(1000);
System.out.printf("forward to %s \n", secondUrl);
dr.navigate().forward();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
定位一组对象
场景
从上一节的例子中可以看出,webdriver可以很方便的使用findElement方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,这时候就需要使用findElements方法。
定位一组对象一般用于以下场景:
- 批量操作对象,比如将页面上所有的checkbox都勾上
- 先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox,然后选择最后一个
代码
checkbox.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
<script type="text/javascript" async="" src="https://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 src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r" />
</div>
</div>
</form>
</div>
</body>
</html>
find_element.java
public class SimpleLocate {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/checkbox.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 选择所有的checkbox并全部勾上
List<WebElement> checkboxes = dr.findElements(By.cssSelector("input[type=checkbox]"));
for(WebElement checkbox : checkboxes) {
checkbox.click();
}
dr.navigate().refresh();
// 打印当前页面上有多少个checkbox
System.out.printf("%d\n", checkboxes.size());
// 选择页面上所有的input,然后从中过滤出所有的checkbox并勾选之
List<WebElement> inputs = dr.findElements(By.tagName("input"));
for(WebElement input : inputs){
if(input.getAttribute("type").equals("checkbox")){
input.click();
}
}
// 把页面上最后1个checkbox的勾给去掉
List<WebElement> allCheckboxes = dr.findElements(By.cssSelector("input[type=checkbox]"));
allCheckboxes.get(allCheckboxes.size() - 1).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
checkbox.html必须与find_elments.rb在同一级目录下
操作测试对象
场景
定位到具体的对象后,我们就可以对这个对象进行具体的操作,比如先前已经看到过的点击操作(click)。一般来说,webdriver中比较常用的操作对象的方法有下面几个
- click 点击对象
- sendKeys 在对象上模拟按键输入
- clear 清除对象的内容,如果可以的话
代码
下面的代码演示了如何点击元素,如何往文本框中输入文字以及如何清空文字。
operate_element.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Level Locate</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" />
</head>
<body>
<h3>Level locate</h3>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link1</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" id="dropdown1" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link2</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
operate_element.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class OperateElement {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/operate_element.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// click
dr.findElement(By.linkText("Link1")).click();
Thread.sleep(1000);
dr.findElement(By.linkText("Link1")).click();
// send_keys
WebElement element = dr.findElement(By.name("q"));
element.sendKeys("something");
Thread.sleep(1000);
// clear
element.clear();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
send keys模拟按键输入
场景
sendKeys方法可以模拟一些组合键操作,比如ctrl+a等。另外有时候我们需要在测试时使用tab键将焦点转移到下一个元素,这时候也需要sendKeys。在某些更复杂的情况下,还会出现使用sendKeys来模拟上下键来操作下拉列表的情况。
代码
下面的代码演示了如何将A多行文本框中的内容清空并复制到B文本框中。
send_keys.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>send keys</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" />
</head>
<body>
<h3>send keys</h3>
<div class="row-fluid">
<div class="span3">
<div class="well">
<label>A</label>
<textarea rows="10", cols="10" id="A">I think watir-webdriver is better than selenium-webdriver</textarea>
</div>
</div>
<div class="span3">
<div class="well">
<label>B</label>
<textarea rows="10", cols="10" id="B"></textarea>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
send_keys.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class SendKeys {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/send_keys.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// copy content of A
dr.findElement(By.id("A")).sendKeys(Keys.chord(Keys.CONTROL + "a"));
Thread.sleep(1000);
dr.findElement(By.id("A")).sendKeys(Keys.chord(Keys.CONTROL + "x"));
// paste to B
dr.findElement(By.id("B")).sendKeys(Keys.chord(Keys.CONTROL + "v"));
// SendKeys to A
dr.findElement(By.id("A")).sendKeys(Keys.chord("watir webdriver is better than selenium webdriver"));
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理button group
场景
button group就是按钮组,将一组按钮排列在一起。处理这种对象的思路一般是先找到button group的包裹(wrapper)div,然后通过层级定位,用index或属性去定位更具体的按钮。
代码
下面的代码演示了如何找到second这个按钮。其处理方法是先找到button group的父div,class为btn-group的div,然后再找到下面所有的div(也就是button),返回text是second的div。
button_group.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_group.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 ButtonGroup {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/button_group.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 定位text是second的按钮
List<WebElement> btns = dr.findElement(By.className("btn-group")).findElements(By.className("btn"));
for(WebElement btn : btns){
if(btn.getText().equals("second")){
btn.click();
break;
}
}
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
自己查资料搞清楚detect方法的作用。