文章目录
- [1. 为什么要切换窗口?](#1. 为什么要切换窗口?)
- [2. 多窗口处理](#2. 多窗口处理)
- [3. frame处理](#3. frame处理)
- 总结
✨✨✨学习的道路很枯燥,希望我们能并肩走下来!
编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。

本文开始
1. 为什么要切换窗口?
问题 :直接定位一个重新打开的新窗口的元素,可以定位到吗?
答案 :不能直接定位新窗口元素;
切换原因 : WebDriver的设计原理,driver一次只能连接一个页面的DOM, 当遇到不同的页面,需要切换窗口,也就是切换句柄;
句柄:每个页面的唯一标识/标签;-每次获取句柄都会变化;
切换原因解释:
xml
// WebDriver 设计原理:一次只能连接一个页面的DOM
WebDriver driver = new ChromeDriver();
// 初始状态:连接到窗口A的DOM
// 内存中的结构:
// WebDriver实例 → 窗口A的DOM树
// 新窗口打开后:
// 物理上:窗口A(旧) 窗口B(新)
// WebDriver:仍然连接到窗口A的DOM树 ← 驱动只能看到这个!
// 尝试定位时:
driver.findElement(By.id("newWindowElement"));
// WebDriver只在窗口A的DOM树中搜索
// 窗口B的元素根本不在这个DOM树中
xml
浏览器实际状态:在窗口A打开了窗口B
┌─────────────────┐ ┌─────────────────┐
│ 窗口A (旧) │ │ 窗口B (新) │
│ │ │ │
│ <div id="old"> │ │ <div id="new"> │
│ 旧内容 │ │ 新内容 │
│ </div> │ │ </div> │
└─────────────────┘ └─────────────────┘
↑ ↑
│ │
└────────────────────────┘
用户能看到两个窗口
WebDriver视角:句柄没变只能看到窗口A
┌─────────────────┐
│ 窗口A的DOM树 │ ← WebDriver唯一能看到的地方
│ │
│ <div id="old"> │
│ 旧内容 │
│ </div> │
└─────────────────┘
// 当你想要"定位新窗口元素"时:
// WebDriver说:"找不到元素"
多窗口介绍:
=》切换窗口原因:在一个浏览器中同时打开多个窗口或选项卡。
=》如果不进行窗口切换,就无法在新窗口中进行后续的操作。
特殊情况:异步刷新不需要切换句柄
异步刷新和新窗口的区别:
1)异步刷新:更新当前页面的DOM(同一个document对象)
2)新窗口:加载全新的HTML文档(不同的document对象)
判断 异步刷新 和 新窗口页面方式如下:
2. 多窗口处理
多窗口处理逻辑:
1)获取当前窗口句柄;
2)获取所有窗口句柄;
3)判断是否是想要操作的窗口?
是想要操作的窗口:直接对窗口操作
不是想要操作的窗口:切换窗口,再对新窗口操作
getWindowHandles() 确实能获取到所有打开的页面句柄,包括标签页、弹出窗口等。
大致逻辑如下
java
// 标准使用模式
String mainWindow = driver.getWindowHandle(); // 1. 保存原窗口
// 触发打开新窗口的操作...
Set<String> allWindows = driver.getWindowHandles(); // 2. 获取所有句柄
// 切换到新窗口操作...
driver.switchTo().window(mainWindow); // 3. 切回原窗口
小练习代码演示:
java
/**
* 多窗口切换小练习
*
*/
@Test
public void twoHandleSwitch() {
List<Executable> executableList = new ArrayList<>();
//1. 获取驱动
WebDriver driver = WebDriverManager.chromedriver().create();
//2. 声明隐式等待
webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
//3. 打开要操作的页面 URL
String url = "https://study_up_up/frame";
webDriver.get(url);
//4. 获取当前页面句柄
String originalWindow = webDriver.getWindowHandle();
System.out.println("第一个页面句柄:" + originalWindow);
String title1 = webDriver.getTitle();
System.out.println("最初页面标题=:" + title1);
//断言-当前页面标题是否包含测试
executableList.add(() -> assertTrue(title1.contains("测试")));
//5. 进行业务逻辑操作,打开一个新窗口
WebElement element = webDriver.findElement(By.xpath("//*[text()='元素定位']"));
element.click();//点击元素,进入新页面
//6. 获取所有窗口句柄-能获取当前 WebDriver 会话管理的所有窗口/标签页句柄。
//所有句柄=通过driver所有打开的窗口
Set<String> windowHandles = webDriver.getWindowHandles();
//7. 判断窗口是否需要切换,如果需要就直接切换
for(String windowHandle : windowHandles) {
//判断不是想要操作的页面,就切换窗口
if(!windowHandle.equals(originalWindow)) {
webDriver.switchTo().window(windowHandle);
break;
}
}
//8. 新窗口业务逻辑
String title2 = webDriver.getTitle();
//判断页面标题包含测试
executableList.add(() -> {assertThat(title2, containsString("测试"));});
//9. 切回默认页面
webDriver.switchTo().window(originalWindow);
String title3 = webDriver.getTitle();
System.out.println("title3: " + title3);
//10.断言
assertAll(executableList);
}
【注】
为什么使用Set存储所有句柄呢?:
- 无序(不保证顺序)
- 不允许重复元素
- 快速查找
为什么使用WebDriverManager创建驱动呢?
简洁,一行代码配置驱动,没有对应浏览器驱动会自动配置;
自动下载和管理 ChromeDriver + 创建 ChromeDriver 实例;
setup() + new ChromeDriver() = create();
旧版配置驱动:
步骤1: 设置驱动(setup)
WebDriverManager.chromedriver().setup();
步骤2: 创建驱动实例
WebDriver driver = new ChromeDriver();
3. frame处理
frame介绍:
1)frame 是 html 中的框架。可以在同一个浏览器中显示多个页面。
2)frame 标签包含 frameset、frame、iframe 三种。
frameset和frame需要配套使用,frame嵌套在frameset中,frameset中可以有多个frame;frame是frameset中的单个框架
iframe是独立的,可以直接嵌套在html中,iframe可以多层嵌套,自己套自己;
了解frame原因 :如果不进行 frame 切换,就无法定位到 frame 中的元素进行后续的自动化操作。
【注】现在使用较多的是iframe框架
frameset :和普通的标签一样,不会影响正常的定位。
frame/iframe :可以使用 index、id、name、webelement 任意种方式定位。
为什么需要切换框架?
DOM树隔离
每个 frame/iframe 都有独立的 DOM树 -#document
WebDriver 一次只能操作一个 DOM 树
必须切换到对应框架才能定位其中的元素
frameset - html5已废弃
typescript
<!-- frame 必须放在 frameset 内 -->
<frameset rows="50%,50%">
<frame src="top.html" name="topFrame">
<frame src="bottom.html" name="bottomFrame">
</frameset>
iframe(内联框架)-主流使用
作用:在当前页面中嵌入另一个HTML文档
typescript
<!-- iframe 示例(现代用法) -->
<body>
<h1>主页面</h1>
<iframe id="contentFrame" name="myIframe"
src="embedded.html" width="800" height="600"
title="内嵌内容"
></iframe>
<p>其他内容...</p>
</body>
常用方法:切换frame框架的方法
java
//3种方式切入frame框架中
webDriver.switchTo().frame(id) 切换到 frame
webDriver.switchTo().frame(name) 切换到 frame
webDriver.switchTo().frame(WebElement) 切换到 frame
//切换到父框架
webDriver.switchTo().parentFrame()
//切回到最外层
webDriver.switchTo().defaultContent()
单frame处理小练习:
java
/**
* frame框架的处理
* frame框架相当于一个单独的DOM树,需要切进frame才能操作其内元素
* 原理:driver只能操作一个DOM树
* 断言小技巧:如使用assertAll();点击assertAll(),进入其中选择对应方法参数,复制出来用
* 不容易导包错误;
*/
@Test
public void frame() {
List<Executable> executableList = new ArrayList<>();
//1.获取驱动
WebDriver driver = WebDriverManager.chromedriver().create();
//2.隐式等待
webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
//3.打开操作的界面
String url = "https://study_up_up/frame";
webDriver.get(url);
//4.业务逻辑操作-获取第一个frame框架中按钮的文本
System.out.println("---------开始---------");
//5.frame框架切换
//5.1 切入第一个框架
webDriver.switchTo().frame("frame1");
WebElement frame1_element = webDriver.findElement(By.xpath("//*[@id='frame_btn']"));
String frame1_elementText = frame1_element.getText();
System.out.println("第一个frame按钮的文本:" + frame1_elementText);
executableList.add(() -> {
assertThat(frame1_elementText, containsString("ui_frame1"));
});
//5.2 切入第二个frame: 先切入父框架,再切入第二个frame
webDriver.switchTo().parentFrame();
webDriver.switchTo().frame("Main");
WebElement frame2_element = webDriver.findElement(By.xpath("//*[@class='el-button el-button--success']"));
String frame2_elementText = frame2_element.getText();
System.out.println("第二个frame按钮的文本:" + frame2_elementText);
executableList.add(() -> {
assertThat(frame2_elementText, equalTo("练习按钮ui_frame3"));
});
//整体断言使用
assertAll(executableList);
}
多frame框架处理代码演示:
java
@Test
public void moreFrame() throws InterruptedException {
List<Executable> executableList = new ArrayList<>();
//1.声明webdriver
WebDriver driver = WebDriverManager.chromedriver().create();
//2.声明隐式等待
webDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
//3.打开操作界面
String url = "https://study_up_up/frame";
webDriver.get(url);
//4.业务逻辑操作-获取第二层frame中的文本
//4.1 iframe两层切换,先切换到第一层,再切换到第二层
WebElement fir_frame = webDriver.findElement(By.xpath("//*[@class='iframe-div']/iframe"));
//使用元素定位,切入第一层
webDriver.switchTo().frame(fir_frame);
WebElement sec_frame = webDriver.findElement(By.xpath("//*[@class='ma-2 frame2']/iframe"));
//使用元素定位,切入第二层
webDriver.switchTo().frame(sec_frame);
//获取第二层frame框架中的文本
WebElement element = webDriver.findElement(By.xpath("//*[@id='main-message']/h1/span/span"));
String text = element.getText();
System.out.println("第二层frame中的文本:" + text);
executableList.add(() -> {
assertThat(text, equalTo("cn.vuejs.org"));
});
//5.切换到外层,定位其他元素,defaultContent()-切回到最外层
webDriver.switchTo().defaultContent();
WebElement element2 = webDriver.findElement(By.xpath("//*[@id='locate_id']"));
String text2 = element2.getText();
System.out.println("text2: " + text2);
//5.断言
assertAll(executableList);
}
【注】
第一次运行: 下载驱动,后续运行: 使用缓存(除非版本变化)
WebDriver driver = WebDriverManager.chromedriver().create();
缓存位置通常:
Windows: C:\Users<user>.cache\selenium
macOS/Linux: ~/.cache/selenium
使用场景推荐:
✅ 新项目开发
✅ 个人学习和测试
✅ 快速原型
✅ 中小型项目
总结
✨✨✨各位读友,本篇分享到内容是否更好的让你理解了 (),如果对你有帮助给个👍赞鼓励一下吧!!
🎉🎉🎉世上没有绝望的处境,只有对处境绝望的人。
🎉🎉🎉一遇挫折就灰心丧气的人,永远是个失败者。而一向努力奋斗,坚韧不拔的人会走向成功。
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

