在自动化测试中,会遇到多窗口、多iframe、多alert的情况。此时,会使用driver.switchTo()来解决。
下面时关于driver.switchTo()的详细介绍:
1.多windows操作。
在页面A上操作时,点击某个元素之后,可能会打开新的窗口。如果需要操作新窗口上的元素,进必须跳转到新的窗口上。
@Test public void fTest() throws InterruptedException { //launchBrowser是自己封装的方法 ,主要是为了启动浏览器驱动,打开指定url,页面加载的等待超时时间设置为3S
//这里测试使用的是qq邮箱的登录页面 launchBrowser("https://mail.qq.com/cgi-bin/loginpage", 3); //定位并点击“手机版”元素,打开手机版页面,此时会打开新的窗口 driver.findElement(By.partialLinkText("手机版")).click(); Thread.sleep(3000); //获取当前窗口句柄(此时是获得https://mail.qq.com/cgi-bin/loginpage页面的句柄) String currentHandle = driver.getWindowHandle(); //获得所有的窗口句柄,如果不是currentHandle,则进入 SetwindowHandles = driver.getWindowHandles(); for (String windowHandle : windowHandles) { if (!currentHandle.equals(windowHandle) ) { //进入到手机版页面的窗口 driver.switchTo().window(windowHandle); } } //此时才能操作手机版页面的元素 driver.findElement(By.cssSelector("a[href='http://app.mail.qq.com/cgi-bin/appdownload?check=false&stype=1&subtype=8&fr=&url=ios&downloadclick=']")).click();;
//如果想要操作qq邮箱登录页面的元素,此时需要退回到之前的窗口
driver.switchTo().window(currentHandle);
}
上面是通过switchTo()方法,进入新的页面,并操作对应元素。
还有另为一种方式:
我们点击链接之后,打开新的窗口,就是因为这个链接中有属性 target="_blank"
所以,我们可以通过JQuery脚本来去除该元素的target的属性。去除之后再点击的时候,就不会打开新的浏览器窗口了。
这个qq邮箱的页面http://app.mail.qq.com/,首次执行JQuery会失败,第二次会成功。猜测可能是因为第一次执行之后,会触发引入jQuery的操作。为了使代码具有通用性,直接引入jQuery。
但是很多安全性高一些的网站,会限制引入的域名地址。会造成引入JQuery失败。为了解决该问题,教大家一个万能的方法:下载某页面的JQuery源代码,放到本地文件中。封装读取并执行JQuery的帮助类。
帮助类代码:
package com.claire.jing.utils; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import org.openqa.selenium.JavascriptExecutor; public class ImportJQueryUtil { public static void importJQueryUtil(JavascriptExecutor jse) { StringBuffer buffer = new StringBuffer(); FileInputStream inputStream = null; try { inputStream = new FileInputStream("F:\\开发资料\\jQuery源码\\jquery-1.10.2.min.js"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } InputStreamReader reader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(reader); String temp=null; try { while ((temp = bufferedReader.readLine()) !=null) { buffer.append(temp); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } jse.executeScript(buffer.toString()); } }
使用JQuery来删除元素指定属性
@Test public void fTest() throws InterruptedException { //方式2:使用JQuery来删除target="_blank" //launchBrowser是自己封装的方法 ,主要是为了启动浏览器驱动,打开指定url,页面加载的等待超时时间设置为3S launchBrowser("https://mail.qq.com/cgi-bin/loginpage", 20); //该js脚本判断是否引入了JQuery String js = "return (typeof($)==\"undefined\")"; boolean flag = (boolean)((JavascriptExecutor)driver).executeScript(js); //如果没引入,则调用帮助类,执行JQuery源码。 //这里之所以不使用直接增加Script节点引入JQuery,是因为很多安全性高一些的网站,会限制引入的域名地址。会造成引入JQuery失败 if (flag) { ImportJQueryUtil.importJQueryUtil((JavascriptExecutor)driver); } //这里可以判断下,是否引入成功了 //System.out.println((boolean)((JavascriptExecutor)driver).executeScript(js)); //http://app.mail.qq.com/" target="_blank">手机版 //该a链接带有属性target="_blank"--拥有该属性的链接,点击后才会打开新的页面。只要通过js来移除该属性,点击之后,就不会打开新的浏览器窗口了 String jquery = "var com=$('a[href=\"http://app.mail.qq.com/\"]');" + "com.removeAttr(\"target\");" + "com[0].click();"; ((JavascriptExecutor)driver).executeScript(jquery); //观察一下执行结果 Thread.sleep(4000); quit(); }
2.Iframe
有些页面元素时包在IFrame中的,此时想要操作Iframe上的元素,必须先进入Iframe里面去。
下面举例多层iframe嵌套的情况:
@Test public void fTest() throws InterruptedException { launchBrowser("http://XXX/index.html", 10); //为了不需要每次都登录,可以设置添加cookie() driver.manage().deleteCookieNamed("JSESSIONID"); driver.manage().addCookie(new Cookie("qqq", "BD04BA5FA2019D6C9DB28E25A5B14D85")); try { //为了cookie使用的久一些,可以设置cookie的有效期。 //即使这里设置了cookie有效期,cookie也是有可能会无效的(一般情况下,会将sessionId存到cookie中): //第一:服务端的session是有有效期的,如果session过期了,那么这个cookie也就无效了。 //第二,当服务端的内存报警时,就可能会清除session。这种情况下,你的cookie也会失效 //第三,当服务端重启之后,缓存和session都会清空的,你的cookie自然就失效了 driver.manage().addCookie(new Cookie("JSESSIONID", "FB9F06DDF0D15C491EFAD6D444893F80","/lmcanon_web_auto",(new SimpleDateFormat("yyyy-MM-dd hh:m:ss")).parse("2018-12-12 12:12:12") )); } catch (ParseException e) { logger.error("日期转换出错"); e.printStackTrace(); } driver.get("http://XXX/index.html"); logger.info("成功打开首页"); driver.findElement(By.cssSelector("i[class=\"Hui-iconfont menu_dropdown-arrow\"]")).click(); logger.info("成功定位习题管理,并点击"); //定位习题管理子标签,该标签是需要点击父标签习题管理之后,才会可见的。 //下面使用了ExpectedConditions中提供的visibilityOfElementLocated()来判断该字标签是否可见,可见之后才对其进行点击操作 WebDriverWait wait = new WebDriverWait(driver, 3); wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("a[data-href=\"stem-list.html\"]"))).click(); logger.info("成功定位子元素习题管理并点击"); //想要点击“添加习题”按钮,发现该按钮在iframe中,必须先进入iframe才能定位并操作该元素 WebElement IframeElement = waitElement(By.cssSelector("iframe[src='stem-list.html']")); driver.switchTo().frame(IframeElement); logger.info("成功进入第一层Iframe,并进入"); driver.findElement(By.cssSelector("a[class=\"btn btn-primary radius\"]")).click(); logger.info("成功定位第一层frame内的添加习题按钮并点击"); //嵌套iframe情况,想要点击添加习题弹窗上的元素,就必须进入第二层iframe //进入第二层Iframe //首先定位第二层iframe WebElement iframe2 = driver.findElement(By.id("layui-layer-iframe2")); driver.switchTo().frame(iframe2); logger.info("成功进入第二层iframe"); //定位第二层iframe的元素 // WebElement subjectType = driver.findElement(By.cssSelector("select[name=\"subjectType\"]")); Select select = new Select(subjectType); select.selectByIndex(2); logger.info("成功定位第二层iframe内的题目领域元素,并选择为mysql数据库"); //退出当前iframe-----注意:下面方法是退回到的top window 层 driver.switchTo().defaultContent(); logger.info("成功退回到first frame."); //操作topWindow上的元素,证明成功退回 driver.findElement(By.cssSelector("i[class=\"Hui-iconfont menu_dropdown-arrow\"]")).click(); logger.info("成功定位习题管理,并点击"); }
3.alert操作
其实现在前台系统中的alert页面越来越少了。因为它的体验不是很好。但是在一些后台系统中,还是会遇到alert操作。Alert弹窗分三种,Alert,prompt(需要输入内容的弹窗),confirm
1. alert() 弹出个提示框 (确定)
警告消息框 alert 方法有一个参数,即希望对用户显示的文本字符串。该字符串不是 HTML 格式。该消息框提供了一个“确定”按钮让用户关闭该消息框,并且该消息框是模式对话框,也就是说,用户必须先关闭该消息框然后才能继续进行操作。
2. confirm() 弹出个确认框 (确定,取消)
确认消息框 使用确认消息框可向用户问一个“是-或-否”问题,并且用户可以选择单击“确定”按钮或者单击“取消”按钮。confirm 方法的返回值为 true 或 false。该消息框也是模式对话框:用户必须在响应该对话框(单击一个按钮)将其关闭后,才能进行下一步操作。
3. prompt() 弹出个输入框(确定,取消)。
如果用户单击提示框的取消按钮,则返回 null。如果用户单击确认按钮,则返回输入字段当前显示的文本。
在用户点击确定按钮或取消按钮把对话框关闭之前,它将阻止用户对浏览器的所有输入。在调用 prompt() 时,将暂停对 JavaScript 代码的执行,在用户作出响应之前,不会执行下一条语。
@Test
public void fTest() throws InterruptedException {
launchBrowser("D:\\javascript\\Untitled-3.html", 10);
WebDriverWait wait = new WebDriverWait(driver, 3);
Alert alert2 = wait.until(ExpectedConditions.alertIsPresent());
System.out.println(alert2.getText());
//取消
alert2.dismiss();
//确定
alert2.accept();
//输入内容
alert2.sendKeys("hello");
Thread.sleep(4000);
}