在做web项目时,通常需要开发一些自动化用例,自动化用例执行可以设置触发条件,也可以定时执行,在每次代码发生变更的情况下,自动触发自动化用例执行,可以及时检测修改代码是否引入新的问题,提高产品的自信度。在开发web端自动化用例代码时,目前大多采用主流的selenium测试框架,selenium框架中的webdriver驱动浏览器模拟人的行为对页面进行操作,开发过程主要可以拆分为以下几个阶段:
a)、web页面加载
b)、定位页面元素
c)、操作页面元素,主要包括文本框输入、鼠标移动、鼠标点击等
d)、判断返回结果
其中最主要的就是 b、c 两步,首先要定位到对应的元素,然后才能对元素进行操作。在selenium中提供了8中元素定位方式,可以通过元素ID号、标签名称、元素name属性、标签文本内容、cssselector、xpath等方式进行定位,这8中定位方式基本可以满足所有的元标签元素定位需求。
但是,在实际使用中会发现,使用如上方式进行元素操作经常会遇到如下两个问题:
a)、一是代码执行较慢
b)、二是代码执行稳定性不高,待操作的元素明明存在,但可能是由于窗口大小发生变化导致元素位置发生变化,甚至元素重叠的情况,导致代码报错“元素不存在”,或者“元素不在所点击的位置(点击操作有可能被另一个元素所接受)”等莫名其妙的错误,降低了自动化用例执行的稳定性。
针对这种情况,对于自动化代码中不稳定的部分,经常出错的部分,可以将这部分对网页元素进行操作的代码换成对应的JavaScript脚本,由于浏览器原生的支持JavaScript,JavaScript代码直接在浏览器内核中执行,就不会出现元素不在所点击的位置等错误,可以大大提高自动化用例执行的稳定性和执行效率。
下面以使用selenium 调用JavaScript脚本操作百度主页进行示例演示,首先使用selenium打开Chrome浏览器,加载百度主页:
#coding:utf-8
"""
Created by cheng star at 2018/4/15 13:31
@email : [email protected]
"""
from selenium import webdriver
from time import sleep
url = "http://www.baidu.com"
driver = webdriver.Chrome()
driver.get(url)
driver.implicitly_wait(10)
百度主页关键字输入框和查询按钮的HTML结构如下:
1、输入关键字并点击查询按钮(方法一)
首先使用DOM对象的getElementById方法定位元素,然后给value属性赋值实现关键字输入,然后以同样的方式获取查询按钮对象,并触发按钮的click点击操作。
query = """
var keywordInput = document.getElementById("kw") ; // 根据全局唯一的ID获取输入框对象
keywordInput.value = "selenium" ;
setTimeout(function() {
// 延迟 5 秒点击查询按钮(setTimeout是异步执行)
var queryBtn = document.getElementById("su") ; // 根据全局唯一的ID获取查询按钮对象
queryBtn.click() ;
} , 5000) ;
"""
driver.execute_script(query)
2、输入关键字并点击查询按钮(方法二)
与方法一类似,首先使用DOM对象的getElementById方法定位元素,然后给value属性赋值实现关键字输入,对于查询按钮,也是以同样的方式获取查询按钮对象,但是并不是调用按钮对象的click方法,而是构造一个event事件对象,并将事件对象绑定在查询按钮上实现按钮的点击操作。这样做是因为,有些HTML标签元素没有onclick属性,所以直接调用click方法并不会触发对象的点击操作。
# 方法二(对于没有绑定onclick属性的元素,click方法无效,可以使用dispatchEvent方法)
query = """
var keywordInput = document.getElementById("kw") ; // 根据全局唯一的ID获取输入框对象
keywordInput.value = "selenium javascript" ;
setTimeout(function() {
var queryBtn = document.getElementById("su") ; // 根据全局唯一的ID获取查询按钮对象
var e = document.createEvent("MouseEvents") ; // 创建事件对象
e.initEvent("click" , true , true) ; // 初始化事件对象为 click 事件
queryBtn.dispatchEvent(e) ;
} , 5000) ;
"""
driver.execute_script(query)
3、执行JavaScript脚本返回元素对象 WebElement
使用python调用selenium框架执行JavaScript脚本也可以将JavaScript的执行结果返回给python的一个对象,对象类型是WebElement,只需要在调用的JavaScript脚本中使用return 语句返回对应的内容即可。
# 执行JS脚本返回标签元素对象 WebElement
getKeywordInput = """
var keywordInput = document.getElementById("kw") ;
return keywordInput ;
"""
keywordInputElement = driver.execute_script(getKeywordInput)
keywordInputElement.send_keys("selenium javascript")
4、执行JavaScript脚本在多个相似元素标签中进行过滤,并操作元素标签(点击百度主页的“新闻” 超链接)
百度主页“新闻” 超链接对应的HTML结构如下:
观察以上HTML内容可以发现,只需要将新闻关键字,对所有 a 标签进行搜索即可定位新闻超链接,对应的JavaScript代码如下:
clickNewsLink = """
var linkParentElement = document.getElementById("u1") ; // 获取超链接的HTML父元素节点
var links = linkParentElement.getElementsByTagName("a") ; // 获取linkParentElement元素下的所有超链接
for(var i = 0 ; i < links.length ; i ++) {
// 通过 新闻 关键字过滤需要的超链接
var linkText = links[i].innerHTML.trim() ;
if(linkText.indexOf("新闻") != -1) {
links[i].click() ; // 点击超链接
break ;
}
}
"""
driver.execute_script(clickNewsLink)
5、执行JavaScript脚本下拉浏览器滚动条
# 执行JS脚本操作页面下拉框
scrollScript = """
var keywordInput = document.getElementById("kw") ; // 根据全局唯一的ID获取输入框对象
keywordInput.value = "selenium" ;
setTimeout(function() {
// 延迟 5 秒点击查询按钮(setTimeout是异步执行)
var queryBtn = document.getElementById("su") ; // 根据全局唯一的ID获取查询按钮对象
queryBtn.click() ;
setTimeout(function() {
// document.documentElement.scrollTop = 10000 ; // 适用于除 Chrome浏览器外的其他浏览器
document.body.scrollTop = 10000 ; // Chrome浏览器使用这种方法
} , 5000) ; // 延迟5 秒下拉滚动条到页面最低端
} , 5000) ;
"""
driver.execute_script(scrollScript)
6、在页面众多相似元素中定位需要操作的元素,使用多种条件组合过滤
当页面HTML中存在多个相似的元素标签,很难一次性准确定位时,这时候需要使用一些额外的过滤条件进行判断,常用的过滤条件包括:hasAttribute判断元素是否有某一属性、getAttribute("name") == "XXX"判断元素属性内容是否等于XXX、获取元素标签内容innerHTML并进行判断等。
如下HTML代码中包含两组 a 标签,两组 a 标签对外展示的效果相同,只是当点击第一组链接时会有alert提示框弹出,现在需要使用JavaScript脚本点击第一组 a 标签中的“javascript language"链接,并弹出alert提示框,HTML结构如下:
相似标签过滤
Part One
Part Two
对应的JavaScript代码如下:
script = """
var a_tags = document.getElementsByTagName("a") ; // 获取当前页面的所有 a 标签元素
for(var i = 0 ; i < a_tags.length ; i ++) {
// 经过观察发现,要点击的 javascript 超链接有一个 name = "javascript" 属性和 关键字javascript
var a_text = a_tags[i].innerHTML.trim() ; // 获取超链接的内容
if(a_tags[i].hasAttribute("name") && a_text.indexOf("javascript language") != -1) {
// 获取具有属性 name 且内容中包含javascript language 字符串的a标签,并触发点击操作
a_tags[i].click() ;
break ;
}
}
"""
driver.execute_script(script)
以上分别介绍了在使用selenium自动化测试框架做自动化脚本开发时,使用JavaScript脚本代码操作页面元素的一些常用方法,其中主要用到了DOM(文档对象模型)进行元素查找定位,并配合使用元素的hasAttribute、getAttribute、innerHTML等属性方法。