Selenium WebDriver让我们轻松实现与浏览器的交互,通过页面元素定位,执行对应的元素操作及断言设置,这一系列的步骤开启了Web自动化脚本的创建。相信大家对于元素定位及其执行并不陌生,今天我们就来聊一聊Selenium WebDriver中另一大特色JS语句的执行,即JavaScriptExecutor。
1.什么是JavaScriptExecutor
JavaScriptExecutor 是Selenium WebDriver提供的一个接口,它提供了一种通过WebDriver直接执行JavaScript的方式,在选定窗口或当前页面上运行 JavaScript 的方法。如果你用的是Java语言,那么可以通过导入“org.openqa.selenium.JavascriptExecutor” 直接使用它;如果你用的是Python, 那就更方便了,直接“from selenium import webdriver”即可。
2.为什么在 Selenium 中使用 JavaScriptExecutor
通常情况下我们会使用各种Web 定位器来定位页面元素,例如 id、name、XPath 等。但是如果这些定位器无法按预期工作,定位不到对应的元素,这时我们就可以通过JavaScriptExecutor来尝试解决这类问题。
同理,当我们对页面上某个元素执行点击操作时,最常见的就是driver.findElement(By.id(“button”)).click(); 但是click() 方法并非适用于所有 Web 浏览器,有时同一个 Web 控件在不同浏览器上的行为也有可能不同。为了应对这类情况,JavaScriptExecutor同样是一个最优的解决方案,因为JS语句本身就是?Web 脚本语言,用来控制网页行为。
3.Selenium中使用JavaScriptExecutor场景介绍
(1)点击按钮
方法一:
Python版
driver.execute_script("document.getElementById('XXX').click()")
Java版
js.executeScript("document.getElementById('XXX').click();");
方法二:
Python版
driver.execute_script("arguments[0].click()",button)
Java版
js.executeScript("arguments[0].click();", button);
方法二中的arguments指的是execute_script()方法中js代码后面的所有参数,arguments[0]表示第一个参数,argument[1]表示第二个参数。
(2)在不使用 sendKeys() 方法的情况下在文本框中键入文本
Python版
driver.execute_script("document.getElementById('XXX').value='someValue' ")
Java版
js.executeScript("document.getElementById('XXX').value='someValue';");
(3)通过值传递“真”|“假”来处理复选框
Python版
driver.execute_script("document.getElementById('XXX').checked=false")
Java版
js.executeScript("document.getElementById('enter element id').checked=false;");
(4)在Selenium WebDriver中生成Alert弹框
Python版
driver.execute_script("alert('注册成功');")
Java版
js.executeScript("alert('注册成功');");
(5)使用Javascript刷新浏览器窗口
Python版
driver.execute_script("history.go(0)")
Java版
js.executeScript("history.go(0)");
(6)获取网页标题
Python版
driver.execute_script("return document.title")
Java版
js.executeScript("return document.title;").toString();
(7)获取当前域名
Python版
driver.execute_script("return document.domain")
Java版
js.executeScript("return document.domain;").toString();
(8)实现页面滚动效果
Python版
# 通过JS进行页面滚动至末尾 driver.execute_script("window.scrollBy(0,document.body.scrollHeight)") # 通过JS进行页面回滚至开始 driver.execute_script("window.scrollBy(0,-document.body.scrollHeight)")
Java版
# 通过JS进行页面滚动至末尾 js.executeScript(“window.scrollBy(0,document.body.scrollHeight)”); # 通过JS进行页面回滚至开始 js.executeScript(“window.scrollBy(0,-document.body.scrollHeight)”);
(9)获取整个页面的内容
Python版
driver.execute_script(return document.documentElement.innerText)
Java版
js.executeScript(" return document.documentElement.innerText;").toString();
4.Demo实战演练
我们以“大众点评”,通过Selenium Python + JavaScriptExecutor进行多版本迭代实战演练,获取首页网红餐厅信息。
测试场景1
不通过JavaScriptExecutor,使用常规元素定位及操作实现;
(1)通过Chrome浏览器,打开“大众点评”主页
(2)定位搜索框,搜索“网红餐厅”
(3)获取首页搜索结果中的全部餐厅名称
(4)获取获取首页“有团购”的餐厅名称
(5)获取获取首页“可订座”的餐厅名称
(6)关闭浏览器
【测试脚本实现】
(1)相关库的导入;
(2)初始化Chrome驱动,开启大众点评首页,且窗口最大化;
(3)通过ID定位搜索框,搜索“网红餐厅”;
(4)这时由于搜索结果显示页面属于新开启的页面,我们需要切换到当前页面窗口;
(5)获取首页搜索结果中的所有“网红餐厅”名称;
通过观察发现,首页中显示的餐厅共有15个,并且餐厅名称的XPath都有固定的规则,仅通过li的下标值的递增:
第一个餐厅名称的XPath:
//*[@id="shop-all-list"]/ul/li[1]/div[2]/div[1]/a/h4
最后一个餐厅名称的XPath:
//*[@id="shop-all-list"]/ul/li[15]/div[2]/div[1]/a/h4
所以通过range(1,16)循环获取当前页面上15个餐厅的名称:
(6)获取获取首页前5个“有团购”的餐厅名称;
(7)获取获取首页前5个“可订座”的餐厅名称;
(8)关闭退出。
【运行结果】
测试场景2
通过JavaScriptExecutor实现上述场景,基于场景1,本场景中还增加演示通过JS获取页面标题,当前域名,执行页面滚动操作,实现Alert弹框操作效果。
【测试脚本实现】
(1)相关库的导入;
(2)初始化Chrome驱动,开启大众点评首页,且窗口最大化;
(3)通过JS在文本框中输入“网红餐厅”,通过JS执行搜索;
(4)同场景一,需要切换到当前页面窗口(结果展示窗口);
(5)通过执行JS,进行页面滚动操作,查看当前页面中的餐厅信息;
(6)获取首页搜索结果中的所有“网红餐厅”名称;
我们直接从页面获取餐厅名称JS Path,通过观察发现,不难发现首页餐厅名称的JS Path也是有规律的,仅通过li:nth-child的下标值的递增:
第一个餐厅名称的JS Path:
document.querySelector("#shop-all-list > ul > li:nth-child(1) > div.txt > div.tit > a > h4")
最后一个餐厅名称的JS Path:
document.querySelector("#shop-all-list > ul > li:nth-child(15) > div.txt > div.tit > a > h4")
在定位到元素后,我们需要获取该元素的文本信息,通过JS语句获取餐厅名称元素的文本信息方式如下:
return document.querySelector('#shop-all-list > ul > li:nth-child(1) > div.txt > div.tit > a> h4').innerText
由于querySelector()中的字符串内容比较长,建议将上面的JS命令进行拆分:
style = "#shop-all-list > ul > li:nth-child(1) > div.txt > div.tit > a> h4" js_style = "return document.querySelector(" + "'" + style + "'" + ").innerText"
下面我们同样结合range(1,16)循环获取当前页面上所有餐厅的名称:
(7)获取获取首页前5个“有团购”的餐厅名称,同理,我们通过定位“有团购”勾选框,获取其JS Path;
document.querySelector ("body > div.section.Fix.J-shop-search > div.content-wrap > div.shop-wrap > div.content > div.filter-box.J_filter_box > div.filt-classify > a:nth-child(1) > i.icon-check")
获取前5个“有团购”餐厅名称代码如下:
(8)获取获取首页前5个“可订座”的餐厅名称,同理,我们通过定位“可订座”勾选框,获取其JS Path;
document.querySelector ("body > div.section.Fix.J-shop-search > div.content-wrap > div.shop-wrap > div.content > div.filter-box.J_filter_box > div.filt-classify > a:nth-child(2) > i")
获取前5个“可订座”餐厅名称代码如下:
(9)通过JS获取当前页面标题;
(10)通过JS获取当前域名;
(11)通过JS以弹框形式显示“查询成功”消息;
(12)关闭退出。
【运行结果】
测试场景3(优化)
从场景2中可以看出,有三次都在获取当前页面中的餐厅名称,且获取名称所用到的JS代码非常相似,可见代码存在冗余情况。为了后期能够有效维护代码,我们可以将获取餐厅名称的脚步单独拿出来,作为一个函数,每次需要的时候直接调用即可。
对需要重复使用的方法进行函数封装:
完整代码如下:
5.总结
JavaScriptExecutor 让我们能够通过 WebDriver在网页上执行 JavaScript 代码,在传统定位方式失效或者某些浏览器下元素执行方式失效的情况下,JavaScriptExecutor 不失为一个最优的备选方案;在同等情况下,它还能使自动化脚本更高效地执行。
以上为大家分享了如何在 Selenium WebDriver中使用 JavascriptExecutor,通过对JavascriptExecutor 常用方法的介绍,并结合具体场景演示了JS在Selenium WebDriver中的实际应用,希望能够给大家的测试工作带来帮助,感兴趣的读者不妨一试。
作者:罗狮小钉