持续集成 使用 Cypress 在持续集成中的踩坑记录与 windows 测试环境搭建

大大灰灰狼 · 2019年04月09日 · 最后由 冯莹 回复于 2020年07月20日 · 3718 次阅读

由于项目比较偏前端,我们的 UI 自动化采用了 cypress
在选型好了工具以后,所有的自动化也需要集成到 jenkins 流水线中集成,达到持续集成的目的

原始方案

一开始跑 UI 自动化所使用的 salve,我们选择主流方案,使用跟编译打包同样的 slave。

发现问题
  • UI 自动化执行的时间比较长,最短也需要执行 3 分钟左右。在限制了 slave 管道的情况下 (考虑到资源消耗,我厂设置每台 slave 最多同时执行 5 个任务),UI 自动化持续独占 slave,导致研发同学持续提交的过程经常被中断,拖累了生产效率。
  • 在实际执行的过程中,因为经常会出现 “卡 case”(跑着跑着就不动了) 等问题。调查 log 后发现是跑 case 的时候自动断开浏览器 session,升级 cypress 版本也无法解决问题。猜测可能是操作系统版本和 xvfb 等插件版本对 chrome 兼容性的问题。

改进方案

占用生产的 slave 问题比较好解决,先尝试用 jenkins label 分割 slave 群,独占一个台 slave 执行 UI 自动化。
Cypress 卡 case 的问题,因为怀疑是环境问题,于是首选尝试使用官方提供的 docker 镜像来运行测试。同时将测试场景分成多个 spec,每个 spec 文件中只有一个 describe(调研发现卡 case 通常发生在初始化 describe,即 scenario 的时候)

又发现问题
  • 使用官方提供的镜像后,发现卡 case 的问题虽然次数不那么频繁,但是依然存在。
  • docker 中运行 chrome/electric 市场崩溃。尝试过增加初始内存,但也只是缓解崩溃次数。
  • 中途考虑过换自动化方案,使用 webdriver+selenium grid 的上古方案。在 docker 环境下实际执行过程中还是回碰到 chrome 崩溃的问题。另外项目中途换工具的成本其实也不低。还有就是爽过 cypress 以后,实际上已经回不去 webdriver 了。。

终极方案

我厂大部分测试同学使用的是 windows 机器开发脚本。在碰到卡 case 啊,chrome 崩溃等问题的时候,windows 机器均无法复现跑得飞起。那是不是使用 windows 机器作为 slave 就可以解决上面碰到的所有问题了呢。

Windows slave 的必要性
  • 借助浏览器的 headless 模式,目前在持续集成中我们比较主流的做法是在 linux slave 中直接跑 UI 自动化。 但是 Cypress 的本质上是浏览器插件,chrome 等浏览器目前支持的 headless 模式还无法提供对插件的支持。操作系统为 Linux 的 jenkins slave 中必须按照官方提示安装 xvfb 等插件来提供运行支持。 shell apt-get install xvfb libgtk2.0-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2
  • 从用户使用习惯上考虑,市面上绝大部分的用户使用的是 windows。使用 windows 及真实浏览器执行出的结果是最可信的。

确定了必要性和可行性,就开始准备做 windows slave。
公司的 jenkins 等基础设施建在云主机上。需要增加 slave 的时候,必须要走财务流程申请新的云主机,流程冗长复杂,而且还不便宜。
然后我突然想到办公室里面有好几台空闲的的 PC 机器 (win10),用作显示 CI monitor,略显浪费。那是不是可以把这几台 windows pc 做成 jenkins slave 集群,当土生云使用呢。

给 jenkins 增加 windows slave
通信问题

为了达到把本地机器装载到 jenkins slave 集群中的目的,host 和 slave 之间的通信问题得先解决。
找运维同学配合,绕过各种 IP、访问限制,确保两点即可

  • host 和 slave 之间可以相互访问
  • 开发机和 slave 之间可以相互访问
在 slave 上安装依赖环境

需要在 slave 上安装执行 jenkins 以及 UI 自动化的环境

  • java8
  • nodejs
  • git 等等
在 slave 上安装 jenkins agent

按照这个教程,做到第四步。后面,我们采用直接在 slave 上用 bat 文件启动 agent.jar 的方案。
启动脚本
其中-Dfile.encoding=UTF8可以解决在 console 中的乱码问题
然后依次把其他 slave 机器设置好,执行 bat 文件后,java 进程以 cmd 窗口的形式存在在 slave 上。
成功后,jenkins 上查看结果。
slave上线成功

做到这一步,只需要把 UI 测试配置上这个 slave 集群的 label,然后就可以正常在流水线中跑 UI 自动化了。

新的问题

按理来说现在自动化也可以独立跑了,cypress 也不挂了,完美了啊。
结果在实践中发现承载 jenkins 的命令行窗口,经常因为不同的原因挂掉

  • 其他同学看到命令行习惯性的关掉
  • win10 的自动更新机制(关了自动更新服务也不起作用) 会定时重启机器
  • 在命令行窗口中点击了右键让命令行窗口处于挂起状态

所以又得想个办法把这些窗口隐藏起来。

使 bat 变成 windows 服务

两种方式可以达到目的

  • 使用 nssm.exe 工具,借助工具的托管,可以轻松的让 bat 变成 windows services nssm.exe install [服务名] [bat文件路径]
  • 根据教程第四步及以后的内容做成服务。(不推荐,使用此方法做成服务后,删除服务时候需要使用sc命令。比较麻烦)

做成 windows 服务以后,再也不同担心被误关窗口了。而且重启后也会自动启动。

问题又来了

jenkins agent 做成服务以后,跑 UI 自动化的时候,发现 cypress 的 viewport 设置失效,始终会以手机的 viewport 来执行测试。
经过调查和多次验证,发现问题还真出在 jenkins agent 被.net 框架包装成服务时。同样的 bat 文件,直接执行就不会有 viewport 的问题。

所以必须要放弃服务化,用另外一种方式使 agent 以命令行方式执行。

vbs

虽然start \min命令,可以使 bat 文件在一开始就以最小化的方式执行。这种方式下我们还是能在任务栏看到这个命令行窗口。

所以最终还是直接选择使用 vbs 来包装这个 bat 文件。

  • 在 bat 文件同目录中创建记事本文件
  • 键入下面脚本,其中 Run 命令后面跟的是用 cmd 来跑 jenkins agent 启动 bat 的意思。参数 0 表示启动后不在界面显示 (只能通过任务管理器查看进程)。完了以后把扩展名改成 vbs。
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("cmd.exe /c jenkins_slave_start.bat"), 0
  • 右键创建这个脚本的快捷方式,在 windows->run 中输入 shell:startup 打开启动项,把快捷方式拖入到启动文件夹中。 原始目录中的vbs文件和启动目录中的快捷方式

双击启动这个进程后,windows slave 成功上线。服务器的界面上也看不到任何窗口了。而且服务器重启的时候,也会通过启动项把这个服务启动起来。

同样的方式,我们也用来启动了 selenium grid 等其他可以用 bat 启动的服务。

不完美的地方

至此,windows slave 算搭建完成了。vbs 隐藏界面的方式看上去很美好,但是也会有问题, 比如

  • 操作反馈十分不友好,你甚至不知道自己有没有点击成功。需要去查看进程。
  • 无法看到 log。如果服务出了问题没办法拿到日志。

所以后面还可以改进的地方还挺多。
顺带提一下因为重新引入 windows slave 的关系,最近又重新捡起了 vbs,开心 -v-

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 1 条回复 时间 点赞

免费版和花钱的差别大么

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册