Web 自动化测试: 如实现可滚动元素的滚动操作

发表于:2021-9-23 09:17

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:佚名    来源:知乎

  使用 selenium 进行 Web 自动化测试对我来说是个常规操作。用了很多次后,我经常会抱怨 selenium 封装的操作实在是太少了,比 cypress 差远了。
  比如说 selenium 没有对页面的滚动提供丰富 API , 有的只有一个孤零零的 location_once_scrolled_into_view 方法,把一个元素滚动到可视范围之内。 这远远不能满足日常的需求啊!要知道,现在大多数的网页都需要不停的滚动鼠标加载新内容。
  如果是单个窗口的滚动还好,但是遇到一些变态的 ERP 系统就为难了。 每一个页面都像是战国时代的诸侯国,被割裂成一块块相互独立的模块,每个模块都需要滚动操作, 全局的窗口滚动根本就不好使,就像周王无法再调令其他诸侯国一样。
  我们来看一个例子。打开禅道的演示页面:https://demo.zentao.net/my/, 除了窗口本身需要滚动以获取底部的更多内容以外, “最新动态” 和 “我的待办” 都有自己独立的滚动条。selenium 如何控制这样的诸侯国呢?
  这样的模块实现的技术有几种。有的会把一个区域的内容放在一个 iframe 当中,有的是包裹在一个 div 标签当中。不管是哪一种方式,实际上,我们都可以把他们当成是单个元素进行处理,如何来操作这些可以被滚动的元素呢?
  上面说过,官方的 Selenium API 当中只有一个 el.location_once_scrolled_into_view 方法把某个元素滚动到可视范围内。这个方法并不够灵活,如果想要更加灵活的操作,比如滑动到底部、滑动一半等,就需要借助 JavaScript 。 基本上,如果 selenium 没有实现的操作,都可以借助 JS 操作。
  对于一个网页的 DOM 对象来说呢,有全局的 window.scrollTo 方法,可以对整个窗口实现滚动操作。如果想把网页滚动到最底部,可以在任意网页按 F12 进入开发者工具,选择 console 输入 JS 代码:
   window.scrollTo(0, document.body.scrollHeight);
  同样的, 在 DOM 对象当中,也实现了对单个元素的滚动操作。 直接设置元素的 scrollTop 属性,表示讲可滚动元素的高度设置到多高。以禅道为例,如果要把 "最新动态" 这个元素向下滚动 800px,可以编写对应的 JS 代码:
   // 定位元素
   el = document.querySelector("div[data-name=最新动态]>div.panel-body");
   // 向下滚动 800 像素
   el.scrollTop = 800;
  如果想滚动到一半,也可以通过元素的 scrollHeight 属性控制:
   el.scrollTop = el.scrollHeight * 0.5;
  如果元素可以左右滚动,则可以设置元素的 scrollLeft 属性:
   el.scrollLeft = el.scrollWidth * 0.5;
  通过设置 scrollTop 和 scrollLeft 属性有时候比较麻烦,可以适用 scrollTo 方法简化操作, 表示滚动到一半的宽度,一半的高度;
   el.scrollTo(el.scrollWidth * 0.5, el.scrollHeight * 0.5);
  也可以适用 scrollBy 表示从现在的位置往右边和下边滑动多少像素点:
   el.scrollBy(el.scrollWidth * 0.1, el.scrollHeight * 0.1);
  如果希望通过 Selenium 实现滚动操作,可以调用 selenium 当中的 execute_script 方法去执行对应的 js 语句。要实现上面的效果,可以访问页面之后,执行 JS 语句:
   from selenium import webdriver
   
   driver = webdriver.Chrome()
   driver.get("https://demo.zentao.net/my/")
   js_code = """
   el = document.querySelector("div[data-name=最新动态]>div.panel-body");
   el.scrollTo(0, el.scrollHeight);
   """
   driver.execute_script(js_code);
  对 selenium 比较熟悉的同学可以封装一个上层 API, 当需要执行滚动操作时,直接调用方法就可以了:
   class SeleniumUpAPI:
       """Selenium的上层封装"""
       def __init__(self, driver:Remote):
           self.driver = driver
   
       def element_scroll_to(self, el:WebElement, x_percent=0, y_percent=0):
           """滚动元素到百分比位置.
           x: 宽度的比率,0.5
           y: 高度的比率,0.5
           """
           jscode = """arguments[0].scrollTo(
               arguments[1] * arguments[0].scrollWidth,
               arguments[2] * arguments[0].scrollHeight
               );
           """
           self.driver.execute_script(jscode, el, x_percent, y_percent)
  最后贴上完整的代码:
   import time
   from selenium.webdriver import Remote, Chrome
   from selenium.webdriver.remote.webelement import WebElement
   
   class SeleniumUpAPI:
       """Selenium的上层封装"""
       def __init__(self, driver:Remote):
           self.driver = driver
   
       def element_scroll_to(self, el:WebElement, x_percent=0, y_percent=0):
           """滚动元素到百分比位置.
           x: 宽度的比率,0.5
           y: 高度的比率,0.5
           """
           jscode = """arguments[0].scrollTo(
               arguments[1] * arguments[0].scrollWidth,
               arguments[2] * arguments[0].scrollHeight
               );
           """
           self.driver.execute_script(jscode, el, x_percent, y_percent)
   
       def element_scroll_by(self, el:WebElement, x_percent=0, y_percent=0):
           """每次滚动多少个像素点,以元素百分比操作
           x: 宽度的比率,0.1
           y: 高度的比率,0.1
           """
           jscode = """arguments[0].scrollBy(
               arguments[1] * arguments[0].scrollWidth,
               arguments[2] * arguments[0].scrollHeight
               );
           """
           self.driver.execute_script(jscode, el, x_percent, y_percent)
   
   
   
   class Element:
       def scroll(self, x_percent=0, y_percent=0):
           """滚动.
           x: 宽度的比率,0.5
           y: 高度的比率,0.5
           """
           jscode = """arguments[0].scroll({
               top:arguments[1] * arguments[0].scrollHeight,
               left:arguments[1] * arguments[0].scrollWidth
               });
           """
           self.driver.execute_script(self, el, y_percent, x_percent)
   
   if __name__ == "__main__":
       driver = Chrome()
       driver.get("https://example.cypress.io/commands/actions")
       d = SeleniumUpAPI(driver)
       el = d.driver.find_element("id", "scroll-vertical")
       el.location_once_scrolled_into_view
       time.sleep(2)
       d.scroll_element(el, 0.5, 0.5)

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号