组件库UI自动化

一、背景

  • 背景:
    • 组件库全局改动场景多,组件之间耦合场景多–时常需要全场景回归
    • 组件库demo有200多个,手动全局回归耗时耗力
    • 细微偏差纯视觉无法辨别
  • 可行性分析:
    • 组件库功能占比
      • L1(视觉层):图片对比确保整体视觉一致性(占比40%)
      • L2(属性层):传统断言验证核心功能(占比50%)
      • L3(交互层):行为模拟验证动态逻辑(占比10%)
    • 时间成本分析
      • 视觉层:5个工作日可实现所有demo截图对比,无需补充场景,单月用例维护时间只需2个工作日
      • 属性层:无法一步实现所有demo属性测试,单月用例维护/场景维护或大于5个工作日
    • 技术实现可行性
      • 视觉层:python 可实现,selenium可实现浏览器驱动和页面截图,PIL可实现图片对比
      • 属性层:可实现架构多,但目前没有找到快速获取组件属性的方式和属性校准的方式
  • 应用场景:
    • 视觉密集型组件(图表/静态图等)
    • 回归测试中视觉回归防御
  • 整体思路:
    • 找到组件库demo对应URL规则批量抓取
    • 截图保存到本地
    • PIL工具对比输出差异
      二、操作步骤
      2.1 开发前的准备工作
      准备工作一
  • Selenium驱动安装
    准备工作二
  • demo目录结构分析
    2.2 开发
    代码逻辑:
    爬取所有路径下demo名称,数组形式输出
import osdef list_directories(path):"""列出指定路径下的所有直接子目录返回格式:目录名称列表(按字母顺序排序)"""try:# 获取路径下所有条目entries = os.listdir(path)# 过滤出目录并排序directories = sorted([entry for entry in entriesif os.path.isdir(os.path.join(path, entry))])return directoriesexcept FileNotFoundError:print(f"错误:路径不存在 - {path}")return []except PermissionError:print(f"错误:没有访问权限 - {path}")return []except Exception as e:print(f"未知错误:{str(e)}")return []if __name__ == "__main__":drislist = []target_path = "/Users/forest/Desktop/"dirs = list_directories(target_path)if dirs:print(f"在 {target_path} 下找到 {len(dirs)} 个目录:")for idx, directory in enumerate(dirs, 1):print(f"{idx}. {directory}")target_path1 = "/Users/forest/Desktop/"+directory+"/demo"dirs1 = list_directories(target_path1)if dirs1:for idx, directory1 in enumerate(dirs1, 1):print(f"{idx}. {directory1}")drislist.append(directory+"-"+directory1)else:print("未找到任何目录或路径无效")# 测试用例print(drislist)test_path = "/Users/forest/Desktop/"

图片对比compare_images方法


from PIL import Image, ImageChops
from datetime import datetimedef compare_images(image1_path, image2_path, output_diff_path=None):# 打开两张图片img1 = Image.open(image1_path)img2 = Image.open(image2_path)# 确保图片尺寸相同if img1.size != img2.size:raise ValueError("图片尺寸不一致,无法对比!")# 计算差异diff = ImageChops.difference(img1, img2)if diff.getbbox() is None:print("图片完全一致!")return 0.0  # 差异百分比# 统计差异像素pixels = list(diff.getdata())diff_pixels = sum(1 for pixel in pixels if pixel != (0, 0, 0, 0))total_pixels = len(pixels)diff_percentage = (diff_pixels / total_pixels) * 100# 保存差异图(可选)if output_diff_path:diff.save(output_diff_path)print(f"差异图已保存至: {output_diff_path}")print(f"图片差异百分比: {diff_percentage:.2f}%")return diff_percentage

主方法

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
from datetime import datetimefrom app.diff.diff import compare_images
from app.diff.moduleDemoData import moduleDemoDatasindex = 0now = datetime.now()
date_str1 = now.strftime("%Y-%m-%d")
date_str ='2025-08-11'
print(date_str)
# 配置 Chrome 选项(无头模式)
chrome_options = Options()
chrome_options.add_argument("--headless")  # 无界面模式
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--window-size=1920,1080")  # 截图尺寸# 启动浏览器driver = webdriver.Chrome(options=chrome_options)output_diff_path = '/Users/forest/PycharmProjects/static'# 等待页面加载(可根据需要调整)
passModuleDemoData = []
localModuleDemoData = []
for moduleDemoData in moduleDemoDatas:passUrl = "http://localhost:4600/v2/~examplesh-"+moduleDemoData+"-example"driver.get(passUrl)time.sleep(5)
# 截图并保存passScreenshot_path = "/Users/forest/pass"+moduleDemoData+".png"driver.save_screenshot(passScreenshot_path)print(f"截图已保存至: {passScreenshot_path}")passModuleDemoData.append(passScreenshot_path)for moduleDemoData in moduleDemoDatas:localUrl = "-"+moduleDemoData+"-example"driver.get(localUrl)time.sleep(5)# 截图并保存localScreenshot_path = "moduleDemoData+".png"driver.save_screenshot(localScreenshot_path)print(f"截图已保存至: {localScreenshot_path}")localModuleDemoData.append(localScreenshot_path)for moduleDemoData in moduleDemoDatas:print(compare_images(passModuleDemoData[index], localModuleDemoData[index]))if compare_images(passModuleDemoData[index], localModuleDemoData[index]) > 0:compare_images(passModuleDemoData[index], localModuleDemoData[index], output_diff_path+"error"+date_str1+moduleDemoData+".png")print("error"+moduleDemoData)index += 1
# 关闭浏览器
driver.quit()

参数列表:罗列代码中涉及的参数和含义
参数 含义
compare_images :return 0无差异

暂时无法在飞书文档外展示此内容
三、总结
总结本次技术应用中可积累的代码和经验
技术经验
有待提升

  • 可分批运行
  • …版本发现bug数
  • 样式隔离节省回归时间30%以上
  • 滚动截图

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试题:JVM与G1要点总结

一.Java内存区域 1.运行时数据区的介绍 2.站在线程的角度看Java内存区域 3.深入分析堆和栈的区别 4.方法的出入栈和栈上分配、逃逸分析及TLAB 5.虚拟机中的对象创建步骤 6.对象的内存布局 1.运行时数据区的介绍 运行时数据区的类型:程序计数器、Java虚拟机栈、本地方…

车辆安全供电系统开发原则和实践

摘要在汽车行业中,安全应用的重要性在不断提升,例如受车辆自动化发展以及机械备用系统重要性降低的影响。为应对这些趋势,安全相关的电气和 / 或电子系统(E/E 系统)的电源输入必须由供电系统来保障,这使得功…

WebSocket客户端库:websocket-fruge365

🚀 从零开始打造一个WebSocket客户端库:websocket-fruge365 📖 前言 在现代Web开发中,实时通信已经成为不可或缺的功能。无论是聊天应用、实时数据监控,还是在线协作工具,WebSocket都扮演着重要角色。然而…

rocketmq批量执行跑批任务报错

rocketmq批量执行跑批任务,报下面的错误,怎么处理一下呢?是修改配置还是修改代码还是? org.apache.rocketmq.client.exception.MQBrokerException: CODE: 215 DESC: [FLOW]client has exhausted the send quota for the current …

大语言模型(LLM)简介与应用分享

1. 什么是大语言模型(LLM) 大语言模型(Large Language Model,简称 LLM)是基于 深度学习 和 海量文本数据 训练而成的人工智能模型。 采用 Transformer 架构参数规模巨大(数十亿到数千亿)能够 理…

【算法笔记】选择排序、插入排序、冒泡排序、二分查找问题

算法的笔记,直接上代码,思路和问题这些,都在代码注释上面 1、工具类 为了生成测试代码和比较器,专门写了一个数组工具类,代码如下: /*** 数组工具类*/ public class ArrUtil {/*** 生成随机数组* 长度是[0,…

行业分享丨基于SimSolid的大型汽车连续冲压模具刚度分析

*本文投稿自机械零部件制造业用户 汽车连续模具的刚度直接决定了冲压件质量(尺寸精度、表面缺陷)与模具寿命。传统有限元分析(FEA)在面对大型复杂模具装配体时,存在网格划分困难、计算资源消耗大、周期长等瓶颈。本文以…

用AI生成的html页面设计放到到Axure上实现再改造的方法

要将 AI 生成的 HTML 原型导入 Axure,该方法的核心逻辑是以 Figma 为 “中间桥梁”(因 Axure 无法直接读取 HTML,需通过 Figma 转换格式),分 3 步即可完成,以下是详细操作指南(含每步目标、具体…

从入门到实战:Linux sed命令全攻略,文本处理效率翻倍

从入门到实战:Linux sed命令全攻略,文本处理效率翻倍 文章目录从入门到实战:Linux sed命令全攻略,文本处理效率翻倍一、认识sed:什么是流编辑器?二、吃透sed工作原理:为什么它能高效处理文本&am…

TIOBE 8月编程语言榜深度解析:Python占比突破26%,Perl成最大黑马

根据TIOBE最新发布的2025年8月编程语言排行榜,一场静默的技术变革正在上演:Python以26.14%的占比首次突破26%大关,连续12个月稳居榜首。这一数据不仅刷新了Python自身的历史纪录,更成为TIOBE指数自2001年创立以来的最高单语言占比…

从发现到恢复,看瑞数信息如何构建“抗毁重构”实战路径

在信息化社会,“韧性”“弹性”这些词汇常被用来形容系统抵御和应对风险的能力,但对于身处关键基础设施行业的运营者来说,这些概念往往过于抽象,难以直接指导实践。 相比之下,“抗毁重构”更具画面感。它不仅是一个管理…

深入理解 jemalloc:从内存分配机制到技术选型

在高性能服务(如数据库、缓存、JVM)的底层优化中,内存分配效率直接影响系统整体性能。本文将从操作系统底层的malloc机制切入,详解 jemalloc 的设计理念、开源应用场景、实战案例,技术选型分析 一、操作系统底层的内存…

websoket使用记录

1.项目使用记录1.医疗项目中渲染回收柜温湿度,需要实时更新2.回收柜安瓿回收和余液回收时,需要前端发送指令给回收柜,比如开门、关门等。还需要收到回收柜结果,比如回收的药品信息等。我项目中用的是浏览器自带的websoket&#xf…

DevOps篇之通过GitLab CI 流水线实现k8s集群中helm应用发布

一. 设计思路 构建一个 GitLab CI 流水线,并且要集成到 K8s 集群中的 Helm 应用发布流程。首先,需要了解 GitLab CI 的基本结构,比如.gitlab-ci.yml 文件的配置,包括 stages、jobs、变量设置等。然后,结合之前讨论的 H…

详尽 | Deeplabv3+结构理解

https://arxiv.org/pdf/1802.02611.pdf https://link.springer.com/chapter/10.1007/978-3-319-10578-9_23 目录 Deeplabv3 Encoder部分 Decoder部分 补充摘要 SPP 空间金字塔池化层模块 Dilated/Atrous Conv 空洞卷积 Deeplabv3 deeplab-v3是语义分割网络,组…

【51单片机】【protues仿真】基于51单片机音乐盒(8首歌曲)系统

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 一、主要功能 1、数码管显示当前歌曲序号 2、按键切换歌曲和播放暂停​ 3、内置8首音乐 二、使用步骤 基于51单片机的音乐盒是一种能够存储和播放多首歌曲的电子设备,通过定时器产…

@ZooKeeper 详细介绍部署与使用详细指南

文章目录 **ZooKeeper 详细介绍、部署与使用** 1. 概述 & 核心介绍 1.1 什么是 ZooKeeper? 1.2 核心特性 1.3 核心概念 1.4 典型应用场景 2. 部署 (以 3 节点集群为例) 2.1 环境准备 2.2 安装步骤 (在所有节点执行) 2.3 启动与停止集群 2.4 防火墙配置 (如果开启) 3. 基本…

腾讯Hunyuan-MT-7B翻译模型完全指南:2025年开源AI翻译的新标杆

🎯 核心要点 (TL;DR) 突破性成就:腾讯混元MT-7B在WMT25全球翻译竞赛中获得30/31项第一名双模型架构:Hunyuan-MT-7B基础翻译模型 Hunyuan-MT-Chimera-7B集成优化模型广泛语言支持:支持33种语言互译,包括5种中国少数民…

Web 集群高可用全方案:Keepalived+LVS (DR) 负载均衡 + Apache 服务 + NFS 共享存储搭建指南

文章目录Keepalived LVS(DR) Apache NFS项目背景业务场景与核心需求传统架构的痛点与局限技术方案的选型逻辑项目价值与预期目标项目实践项目环境基础配置配置 router配置免密登录-可选配置 nfs配置 web配置 LVS-RS配置 HA 和 LVS-DS配置 ha1配置 ha2测…

Prometheus监控预警系统深度解析:架构、优劣、成本与竞品

目录 一、Prometheus是什么?核心定位与架构 二、竞品分析(Prometheus vs. Zabbix vs. Nagios vs. Commercial SaaS) 三、部署成本分析 四、服务器资源消耗分析 五、给您的最终建议 一、Prometheus是什么?核心定位与架构 Prom…