使用 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 文件以支持两种新的运行类型(基线和比较)。 然后,根据运行类型设置图像的路径:

// plugins/index.js
const fs = require('fs')
const path = require('path')
module.exports = (on, config) => {
// Adding these values to your config object allows you to access them in your tests.config.env.baseline = process.env.BASELINE || falseconfig.env.comparison = process.env.COMPARISON || falseon('after:screenshot', details => {// We only want to modify the behavior of baseline and comparison runs.if (config.env.baseline || config.env.comparison) {// We keep track of the file name and number to make sure they are saved in the proper order and in their relevant folders.// An alternative would have been to look up the folder for the latest image, but this was the simpler approach.let lastScreenshotFile = ''let lastScreenshotNumber = 0// We append the proper suffix number to the image, create the folder, and move the file.const createDirAndRename = filePath => {if (lastScreenshotFile === filePath) {lastScreenshotNumber++} else {lastScreenshotNumber = 0}lastScreenshotFile = filePathconst newPath = filePath.replace('.png',` #${lastScreenshotNumber}.png`)return new Promise((resolve, reject) => {fs.mkdir(path.dirname(newPath), { recursive: true }, mkdirErr => {if (mkdirErr) {return reject(mkdirErr)}fs.rename(details.path, newPath, renameErr => {if (renameErr) {return reject(renameErr)}resolve({ path: newPath })})})})}const screenshotPath = `visualComparison/${config.env.baseline ? 'baseline' : 'comparison'}`return createDirAndRename(details.path.replace('cypress/integration', screenshotPath).replace('All Specs', screenshotPath))}})return config
}

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

"scripts": {"cypress:baseline": "BASELINE=true yarn cypress:open","cypress:comparison": "COMPARISON=true yarn cypress:open"
}

 

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

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

Cypress.Commands.add("getAndScreenshot", (selector, options) => {// Note: You might need to tweak the command when getting multiple elements.return cy.get(selector).screenshot()
});
it("get overwrite", () => {cy.visit("https://example.cypress.io/commands/actions");cy.getAndScreenshot(".action-email")
})

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

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

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

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

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

为 UI 测试增加价值

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

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

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取 

 

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

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

相关文章

搜维尔科技:【简报】元宇宙数字人赛道,2022年金奖《金魚姬》赏析!

一名网络直播主名叫琉璃,在即将展开她日常进行的每日准时直播前,肚子极为不舒服,突然很想上厕所,由于时间紧迫,导致琉璃需要在厕所里面完成直播!为了掩饰自己所在的处境,她决定运用自己设计的虚…

Python基础教程——用Python处理Excel!

Excel是一种常见的电子表格文件格式,广泛用于数据记录和处理。Python提供了多个第三方库,可以方便地对Excel文件进行读写、数据操作和处理。本文将介绍如何使用Python对Excel文件进行处理,并提供相应的代码示例和详细说明。 一、安装第三方库…

springboot 企业微信 网页授权

html 引入jquery $(function () {// alert("JQ onready");// 当前企业的 corp_idconst corp_id xxxxxx;// 重定向 URL → 最终打开的画面地址,域名是在企业微信上配置好的域名const redirect_uri encodeURI(http://xxxxx.cn);//企业的agentId 每个应用都…

vue3 ts defineProps、defineEmits、defineExpose、defineOptions、defineSlots

文章目录 前言一、defineProps二、defineEmits三、defineExpose四、defineOptions( Vue3.3 新特性)五、defineSlots(Vue3.3 新特性) 前言 本章我们来讲解vue3 ts 中 defineProps、defineEmits、defineExpose、defineOptions、defineSlots的使用及作用。 …

计算机毕业设计——SpringBoot 个人博客管理系统(附源码)

1,绪论 1.1 背景调研 在互联网飞速发展的今天,互联网已经成为人们快速获取、发布和传递信息的重要渠道,它在人们政治、经济、生活等各个方面发挥着重要的作用。互联网上发布信息主要是通过网站来实现的,获取信息也是要在互联网中…

数模学习day11-系统聚类法

本文参考辽宁石油化工大学于晶贤教授的演示文档聚类分析之系统聚类法及其SPSS实现。 目录 1.样品与样品间的距离 2.指标和指标间的“距离” 相关系数 夹角余弦 3.类与类间的距离 (1)类间距离 (2)类间距离定义方式 1.最短…

软件测试|快速、可靠的JavaScript依赖管理工具——yarn

简介 Yarn是一个由Facebook于2016年推出的JavaScript软件包管理器。它的目标是解决npm(Node.js的默认软件包管理器)在性能和可靠性方面的一些问题。Yarn旨在提供更快、更安全、更稳定的依赖项安装过程,使JavaScript开发人员能够更轻松地管理…

【STM32】HAL库的RCC复位状态判断及软件复位

【STM32】HAL库的RCC复位状态判断及软件复位 在实际开发中 有时候会遇到复位状态不同 导致结果不同的情况 比如在上电复位时 电压不稳定 可能导致一些外部芯片无法正常工作 从而导致进行了错误的操作流程 所以 可以在程序运行后 加一个复位状态判断 用来检测是否正常复位 否则…

Python 编写不同时间格式的函数

该代码是一个时间相关的功能模块,提供了一些获取当前时间的函数。 Report_time() 函数返回当前时间的格式化字符串,例如 "20240110114512"。Y_M_D_h_m_s_time() 函数返回当前时间的年、月、日、时、分、秒的元组格式。Y_M_D_h_m_s() 函数返回…

搬运5款知名度不高,但十分好用的软件

​ 其实有许多工具,知名度不高,用的人也很少,不过并不代表它们不好用,小编励志做一个合格的搬运工,让大家都能用上好用的软件。 1.文本比较——Diffchecker ​ Diffchecker是一款在线文本比较工具,可以找…

【Vue3】2-4 : 声明式渲染及响应式数据实现原理

本书目录:点击进入 一、声明式渲染 1.1 什么是JS表达式:能够进行赋值的操作 ▶ 正确 ▶ 错误示例 二、示例:2秒后,页面中 message 由 hello world 变成 hi vue ▶ 效果 三、原理:利用ES6的Proxy对象对底层进…

zippo打火机激光打标机

激光打标技术是一种高精度的加工方式,能够在各种材料表面进行精细的打标,包括金属、塑料、玻璃等。随着科技的不断进步,激光打标技术的应用范围越来越广泛,特别是在制造行业,已经成为一种重要的加工手段。 Zippo打火机…