web自动化测试框架selenium调用JavaScript代码常用操作解析

        在做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结构如下:

<span class="bg s_ipt_wr quickdelete-wrap">
    <span class="soutu-btn" style="display: block;"/>
    <input id="kw" class="s_ipt" autocomplete="off" maxlength="255" value="" name="wd"/><!-- 关键字输入框 -->
    <a id="quickdelete" class="quickdelete" href="javascript:;" title="清空" style="top: 0px; right: 0px; display: none;"/>
</span>
<span class="bg s_btn_wr">
    <input id="su" class="bg s_btn btnhover" type="submit" value="百度一下"/><!-- 查询按钮 -->
</span>

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结构如下:

<div id="u1">
    <a class="mnav" name="tj_trnews" href="http://news.baidu.com">新闻</a>
    <a class="mnav" name="tj_trhao123" href="http://www.hao123.com">hao123</a>
    <a class="mnav" name="tj_trmap" href="http://map.baidu.com">地图</a>
    <a class="mnav" name="tj_trvideo" href="http://v.baidu.com">视频</a>
    <a class="mnav" name="tj_trtieba" href="http://tieba.baidu.com">贴吧</a>
    <a class="mnav" name="tj_trxueshu" href="http://xueshu.baidu.com">学术</a>
    <a class="lb" onclick="return false;" name="tj_login" href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5">登录</a>
    <a class="pf" name="tj_settingicon" href="http://www.baidu.com/gaoji/preferences.html">设置</a>
    <a class="bri" style="display: block;" name="tj_briicon" href="http://www.baidu.com/more/">更多产品</a>
</div>

        观察以上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结构如下:

<html>
    <head>
        <title>相似标签过滤</title>
    </head>
    <body>
        <h2>Part One</h2>
        <div id = "language">
            <a name = "python" href="javascript:alert('part one - python')">python language</a><br>
            <a name = "java" href="javascript:alert('part one - java')">java language</a><br>
            <a name = "C#" href="javascript:alert('part one - C#')">C# language</a><br>
            <a name = "scala" href="javascript:alert('part one - scala')">scala language</a><br>
            <a name = "javascript" href="javascript:alert('part one - javascript')">javascript language</a><br>
        </div>
        
        <h2>Part Two</h2>
        <div id = "language">
            <a href="javascript:alert('part two - python')">python language</a><br>
            <a href="javascript:alert('part two - java')">java language</a><br>
            <a href="javascript:alert('part two - C#')">C# language</a><br>
            <a href="javascript:alert('part two - scala')">scala language</a><br>
            <a href="javascript:alert('part two - javascript')">javascript language</a><br>
        </div>
    </body>
</html>

        对应的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等属性方法。


猜你喜欢

转载自blog.csdn.net/cxx654/article/details/79949366