全网最细,web自动化测试实战场景(滚动元素的滚动操作)直接上干g货......

前言

使用 selenium 进行 web 自动化测试对我们来说是个常规操作。用了很多次后,我们经常会抱怨 selenium 封装的操作实在是太少了。

比如说 selenium 没有对页面的滚动提供丰富 API , 有的只有一个孤零零的 location_once_scrolled_into_view 方法,把一个元素滚动到可视范围之内。 这远远不能满足日常的需求啊!要知道,现在大多数的网页都需要不停的滚动鼠标加载新内容。

如果是单个窗口的滚动还好,但是遇到一些变态的 ERP 系统就为难了。 每一个页面都像是战国时代的诸侯国,被割裂成一块块相互独立的模块,每个模块都需要滚动操作, 全局的窗口滚动根本就不好使。

我们来看一个例子。
打开禅道的演示页面, 除了窗口本身需要滚动以获取底部的更多内容以外, “最新动态” 和 “我的待办” 都有自己独立的滚动条。

这样的模块实现的技术有几种。有的会把一个区域的内容放在一个 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)

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/438319.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

融资项目——OpenFeign的降级与熔断

当一个微服务调用其他微服务时,如果被调用的微服务因各种原因无法在规定时间内提供服务,则可以直接使用本地的服务作为备选,即进行降级熔断。 如之前所提到的微服务为例: 如果希望实现降级熔断,可以在本地创建一个实现…

Mac版2024 CleanMyMac X 4.14.6 核心功能详解以及永久下载和激活入口

CleanMyMac 是 macOS 上久负盛名的系统清理工具,2018 年,里程碑式版本 CleanMyMac X 正式发布。不仅仅是命名上的变化,焕然一新的 UI、流畅的动画也让它显得更加精致。新增的系统优化、软件更新等功能,使得在日常使用 macOS 时有了…

【Linux】Linux原生异步IO(一):libaio-介绍

1、IO模型 1.1 简述 相信大家在搜索的时候,都会看到下面这张图,IO的使用场景:同步、异步、阻塞、非阻塞,可以组合成四种情况: 同步阻塞I/O: 用户进程进行I/O操作,一直阻塞到I/O操作完成为止。同步非阻塞I/O: 用户程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可…

Cesium-记录差值线

/*** param {Object} startTime Date格式的开始时间* param {Object} endTime Date格式的结束时间* param {Object} coordinates [x1,y1,x2,y2,x3,y3.......]* param {Object} entityCollection 实体收集器*/ async function interpolationLine(startTime,endTime,coordinat…

工厂 模式

一、工厂模式是什么? 是C多态的一种很好的具体表现。通过继承,重写抽象父类的虚函数,并在main函数中通过基类指针指向子类对象的一种编码风格 工厂模式分为三种(简单工厂模式,工厂方法模式,抽象工厂模式&…

晶圆测量新利器:光谱共焦传感器优势解析

光谱共焦位移传感器和激光三角位移传感器在表面测量领域均占据重要位置,它们各自在测量物体厚度方面表现出独特的优势。尽管两者具备测量功能,但根据应用环境和所需精度,它们的适应性呈现出显著差异。 具体而言,光谱共焦位移传感器…

PSCA电源控制集成之分布式PPU

PPU的放置是一个重要考虑因素。最简单的方法是将所有的PPU都放置在SCP所在的始终开启的域中。将所有的PPU放置在一个层次结构中,集成问题,如地址映射、互连、时钟和复位等问题都比较简单。然而,有几个原因可能导致这不是最佳选择。 首先&…

Qt---项目代码解析

文章目录 一、main.cpp代码解析二、widget.h代码解析三、widget.cpp代码解析(一) form file 四、.pro Qt项目的工程文件 一、main.cpp代码解析 main函数的形参就是命令行参数。qt是CDefinitely图形界面化编程,要想编写一个qt的图形界面程序,一定要有QAp…

【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!

🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏《Spring 狂野之旅:从入门到入魔》 &a…

蚂蚁感冒 刷题笔记

/* 解题思路 首先根据题意可知 1.蚂蚁速度均为1 即同向蚂蚁永远不可能追上 我们需要求最后感冒蚂蚁的数量 因为蚂蚁碰头将会掉头 效果和俩蚂蚁互相穿过继续走是一样的 所以我们将俩蚂蚁碰头视作穿过 2. 如果俩蚂蚁相向而行 则俩蚂蚁必定碰头 首先 我们获得第一个感冒蚂蚁的…

Vue+OpenLayers7入门到实战:OpenLayers7如何使用gifler库来实现gif动态图图片叠加到地图上

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 OpenLayers7本身不支持gif图片作为图标要素显示到地图上,所以需要通过其他办法来实现支持gif图片。 本章介绍如何使用OpenLayers7在地图上使用gifler库先生成canvas画板,然后通过canvas画板的重绘事件来重新渲染地图…

URL输入到页面渲染过程详解

当我们在浏览器中输入一个URL并按下回车键时,浏览器会执行一系列步骤来解析URL、发送请求、接收响应,并最终渲染页面。这个过程涉及到多个阶段,包括DNS解析、TCP握手、发送HTTP请求、服务器处理请求、返回HTTP响应、浏览器解析和渲染等。下面…

19-Java中介者模式 ( Mediator Pattern )

Java中介者模式 摘要实现范例 中介者模式(Mediator Pattern)提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护中介者模式是用来降低多个对象和类之间的通信复杂性中介者模式属于行为型模式…

算法刷题Day2 | 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

目录 0 引言1 有序数组列表1.1 我的题解(双指针)1.2 根据官方解题修改后 2 长度最小的子数组2.1 我的题解2.2 官方滑动窗口(双指针)题解 3 螺旋矩阵3.1 我的题解 🙋‍♂️ 作者:海码007📜 专栏&…

CXYGZL实现钉钉、飞书和微信全面覆盖!!!

非常欣慰能在这里与大家分享,CXYGZL已圆满实现多端互通的目标!!! 无论您是在手机、电脑还是平板上使用钉钉、企微还是飞书,只需将CXYGZL轻松集成到您的办公软件中,即可实现无缝审批处理各项任务&#xff0c…

FreeRTOS_day2

作业:1.使用ADC采样光敏电阻数值,如何根据这个数值调节LED灯亮度。 2.总结DMA空闲中断接收数据的使用方法 打开DAM,允许接收外部设备数据,调用中断接收回调函数

王道机试C++第 3 章 排序与查找:排序问题 Day28(含二分查找)

查找 查找是另一类必须掌握的基础算法,它不仅会在机试中直接考查,而且是其他某些算法的基础。之所以将查找和排序放在一起讲,是因为二者有较强的联系。排序的重要意义之一便是帮助人们更加方便地进行查找。如果不对数据进行排序,…

热插拔更换ESXI宿主机系统硬盘导致紫屏故障案例一则

关键词 vmware、esxi5.5raid、热插拔、紫屏 华为 CH121V3刀片、SSD硬盘 There are many things that can not be broken! 如果觉得本文对你有帮助,欢迎点赞、收藏、评论! 一、问题现象 现网vmware云平台一台华为E9000刀箱CH121V3刀片服务…

面试经典150题——环形链表

Suffering, for the weak is the tomb of death, and for the strong is the soil of germinal ambition.​ 1. 题目描述 2. 题目分析与解析 2.1 思路一 这个题目就是判断一个链表有没有环,其实我们之讲过一个题目,就实现了判断链表有没有环的步骤&a…

1 数据分析概述与职业操守 (3%)

1、 EDIT数字化模型 E——exploration探索 (是什么) 业务运行探索:探索关注企业各项业务的运行状态、各项指标是否合规以及各项业务的具体数据情况等。 D——diagnosis 诊断 (为什么) 问题根源诊断:当业务指标偏离正常值时&…