使用 Cypress 进行可视化回归测试:一种务实的方法

2024-03-08 20:36

本文主要是介绍使用 Cypress 进行可视化回归测试:一种务实的方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

每次组件库 Picasso 发布新版本时,都会更新所有的前端应用程序,让绝大部分新功能能与整个平台的设计保持一致。上个月,推出了 Toptal Talent Portal 的 Picasso 更新,这是我们的用户用来找工作和与客户互动的平台。 已知了这个版本将有设计方面的重要更改,并且为了尽量减少意想不到的问题,使用可视化回归测试技术来帮助我们在发布前发现问题是有意义的。

 视觉回归测试并不是一个新概念。 Toptal 的许多其他项目已经在使用它,包括 Picasso 本身。Percy、Happo 和 Chromatic 等工具可用于帮助团队构建健康的视觉回归流水线,最初确实考虑过添加它们。 最后觉得设置过程太耗时,可能会打乱计划。 我们已经为开始迁移的代码冻结设定了日期,距离截止日期只剩下几天了,但别无选择,只能发挥创意。

通过 UI 测试进行视觉回归测试

虽然我们在项目中没有视觉回归测试,但我们确实很好地使用 Cypress 覆盖了的 UI 集成测试。 尽管这不是该工具的主要用途,但 Cypress 在其文档中有一页专门用于可视化测试,另一页列出了所有可用的插件以帮助配置 Cypress 以进行可视化测试。

从Cypress到屏幕截图

在浏览了可用的文档之后,决定尝试一下 cypress-snapshot-plugin。 设置只需要几分钟,完成以后,我们很快意识到不是在追求传统的视觉回归输出。大多数视觉回归工具通过比较快照和检测已知的、可接受的基线与页面或组件的修改版本之间的像素差异来帮助识别不需要的更改。 如果像素差异大于设定的容差阈值,则页面或组件被标记为需要手动检查。 不过,在此版本中,我们知道我们将对大多数 UI 组件进行一些小的更改,因此设置阈值不适用。 即使给定的组件碰巧有 100% 的不同,它在新版本的上下文中可能仍然是正确的。 同样,小到几个像素的偏差可能意味着组件当前不适合生产。

 那时,两件截然不同的事情变得清晰起来:注意到像素差异无助于识别问题,而对组件进行并排比较正是我们所需要的。 我们将快照插件放在一边,开始使用组件在应用 Picasso 更新之前和之后创建一个图像集合。 这样,就可以快速扫描所有更改,以确定新版本是否仍然符合网站的需求和图书馆的标准。新的计划是截取一个组件的屏幕截图,将其存储在本地,然后在具有更新的 Picasso 版本的分支中截取相同组件的新屏幕截图,然后将它们合并为一个图像。 最终,这种新方法与我们开始的方法并没有太大不同,但它在实施阶段为我们提供了更大的灵活性,因为不再需要导入插件并使用其新命令。

利用 API 比较图像

有了明确的目标,是时候看看 Cypress 如何帮助我们获得所需的屏幕截图了。 如前所述,我们进行了大量的 UI 测试,涵盖了人才门户的大部分内容,因此为了尽可能多地收集关键组件,我们决定在每次交互后截取各个元素的屏幕截图。另一种方法是在测试期间的关键时刻截取整个页面的屏幕截图,但我们认为这些图像太难比较了。 此外,此类比较更容易出现人为错误,例如遗漏页脚已更改的信息。第三种选择是通过每一个测试用例来决定要捕获什么,但这会花费更多时间,因此坚持使用页面上的所有元素似乎是一种实际的妥协。

我们使用Cypress的 API 来生成图像。 cy.screenshot() 命令可以开箱即用地创建单独的组件图像,After Screenshot API 允许重命名文件、更改目录以及区分视觉回归运行和标准回归运行。 通过结合这两者,我们创建了不影响功能测试的运行,并能够将图像存储在适当的文件夹中。首先,我们扩展了插件目录中的 index.js 文件以支持两种新的运行类型(基线和比较)。 然后,根据运行类型设置图像的路径:

 
  1. // plugins/index.js

  2. const fs = require('fs')

  3. const path = require('path')

  4. module.exports = (on, config) => {

  5. // Adding these values to your config object allows you to access them in your tests.

  6. config.env.baseline = process.env.BASELINE || false

  7. config.env.comparison = process.env.COMPARISON || false

  8. on('after:screenshot', details => {

  9. // We only want to modify the behavior of baseline and comparison runs.

  10. if (config.env.baseline || config.env.comparison) {

  11. // We keep track of the file name and number to make sure they are saved in the proper order and in their relevant folders.

  12. // An alternative would have been to look up the folder for the latest image, but this was the simpler approach.

  13. let lastScreenshotFile = ''

  14. let lastScreenshotNumber = 0

  15. // We append the proper suffix number to the image, create the folder, and move the file.

  16. const createDirAndRename = filePath => {

  17. if (lastScreenshotFile === filePath) {

  18. lastScreenshotNumber++

  19. } else {

  20. lastScreenshotNumber = 0

  21. }

  22. lastScreenshotFile = filePath

  23. const newPath = filePath.replace(

  24. '.png',

  25. ` #${lastScreenshotNumber}.png`

  26. )

  27. return new Promise((resolve, reject) => {

  28. fs.mkdir(path.dirname(newPath), { recursive: true }, mkdirErr => {

  29. if (mkdirErr) {

  30. return reject(mkdirErr)

  31. }

  32. fs.rename(details.path, newPath, renameErr => {

  33. if (renameErr) {

  34. return reject(renameErr)

  35. }

  36. resolve({ path: newPath })

  37. })

  38. })

  39. })

  40. }

  41. const screenshotPath = `visualComparison/${config.env.baseline ? 'baseline' : 'comparison'}`

  42. return createDirAndRename(details.path

  43. .replace('cypress/integration', screenshotPath)

  44. .replace('All Specs', screenshotPath)

  45. )

  46. }

  47. })

  48. return config

  49. }

然后通过将相应的环境变量添加到项目的 package.json 中的 Cypress 调用来调用每个运行:

 
  1. "scripts": {

  2. "cypress:baseline": "BASELINE=true yarn cypress:open",

  3. "cypress:comparison": "COMPARISON=true yarn cypress:open"

  4. }

运行新命令后,可以看到运行期间截取的所有屏幕截图都已移动到相应的文件夹中。

接下来,尝试覆盖 cy.get(),这是 Cypress 返回 DOM 元素的主要命令,并对调用的任何元素及其默认实现进行截图。 不幸的是,cy.get() 是一个很难更改的命令,因为在其自己的定义中调用原始命令会导致无限循环。 解决此限制的建议方法是创建一个单独的自定义命令,然后让该新命令在找到元素后截取屏幕截图:

  1. Cypress.Commands.add("getAndScreenshot", (selector, options) => {

  2. // Note: You might need to tweak the command when getting multiple elements.

  3. return cy.get(selector).screenshot()

  4. });

  5. it("get overwrite", () => {

  6. cy.visit("https://example.cypress.io/commands/actions");

  7. cy.getAndScreenshot(".action-email")

  8. })

但是,与页面上的元素进行交互的调用已经包含在内部 getElement() 函数中。 所以我们所要做的就是确保在调用包装器时截取屏幕截图。

通过视觉回归测试得到的结果

一旦我们有了屏幕截图,剩下要做的就是合并它们。 为此,使用 Canvas 创建了一个简单的节点脚本。 最后,脚本能够生成 618 张比较图像! 通过打开人才门户很容易发现一些差异,但有些问题并不那么明显。 

图 4. 不遵循新毕加索指南的示例; 预计会有所不同,但新版本应该有红色背景和白色文本

图 5. 略有损坏的组件布局示例 

为 UI 测试增加价值

首先,添加的视觉回归测试被证明是有用的,并且发现了一些如果没有它们我们可能会错过的问题。 尽管和预计组件会有所不同,但了解实际更改的内容有助于缩小问题案例的范围。 所以,如果你的项目有一个接口,但还没有执行这些测试,那就开始吧!

 这里的第二个教训,也许是更重要的一个教训,是我们再次被提醒完美是好的敌人。 如果我们因为没有事先设置而排除了为此版本运行视觉回归测试的可能性,那么可能会在迁移过程中错过一些错误。 相反,我们商定了一个计划,虽然不理想,但执行起来很快,朝着它努力,就可以得到回报。

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方进群即可自行领取。

这篇关于使用 Cypress 进行可视化回归测试:一种务实的方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/788325

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma