将 Cypress 测试与 Docker、Buildkite 和 CICD 集成 #frontend@twiliosendgrid

已发表: 2020-12-30

我们编写了许多端到端 (E2E) 赛普拉斯测试来验证我们的 Web 应用程序在后端仍能按预期工作。 在编写完这些浏览器自动化测试之后,我们希望在合并代码并部署到特定环境之前,始终让这些 Cypress 测试运行或以某种方式触发,就像我们的单元测试一样。 这导致我们希望在 Docker 容器中运行 Cypress 测试,以与我们的持续集成 (CI) 提供商和我们在云中用于运行这些容器的机器集成。

在部署流程方面,我们使用 Buildkite 作为我们的 CI 提供者。 当我们计划全面移动代码时,这使我们能够在 Buildkite 管道中为我们的应用程序生成自动化步骤。 对于更多上下文,管道是通常与应用程序存储库相关联的地方,当您创建拉取请求、推送新代码更改、将代码合并到主服务器以及部署到不同环境时,我们可以在其中查看构建或触发构建,并执行某些步骤来运行. 我们为不同的目的创建多个管道,例如部署、触发赛普拉斯测试和按计划运行的特定赛普拉斯测试。

这篇博文假设您之前已经编写过 Cypress 测试并运行了一些测试,但想了解如何在您的开发和部署流程中始终运行这些测试。 如果您想了解更多关于编写赛普拉斯测试的概述,您可以查看这篇较早的博客文章,然后在您有需要运行的内容时重新访问。

我们的目标是通过了解我们如何在部署管道中使用 Docker Compose 和 Buildkite 来完成有关如何将赛普拉斯测试与您的 CI 提供程序集成到 Docker 容器中的想法。 这些想法可以在您的基础架构中扩展,以便在触发赛普拉斯测试时应用策略、命令和环境变量。

我们的标准 CICD 流程

在我们的标准开发和部署流程中,我们设置了两个管道:

  1. 第一个处理我们推送代码时的部署步骤。
  2. 第二个触发我们的赛普拉斯测试并行运行并被记录。 此操作的成功或失败会影响部署管道。

在我们的部署管道中,我们构建了我们的 Web 应用程序资产,运行单元测试,并在部署到每个环境之前触发选定的赛普拉斯测试。 我们确保它们在取消按钮部署之前通过。 第二个管道中的这些触发赛普拉斯测试也在 Docker 容器中运行,并通过记录密钥连接到付费的赛普拉斯仪表板,因此我们可以回顾这些赛普拉斯测试的视频、屏幕截图和控制台输出以调试任何问题。

使用 Buildkite 的选择输入,我们设计了一个动态的选择您自己的冒险,因此用户可以选择“是”或“否”来决定在我们推送更多代码时运行和验证哪些赛普拉斯规范文件夹。 所有选项的默认答案都是“否”,但“是”的值将是赛普拉斯规范文件夹的全局路径。

有时,如果我们的代码更改不影响其他页面,我们不想运行所有 Cypress 测试。 相反,我们只想触发我们知道会受到影响的测试。 我们可能还需要为生产中的紧急错误问题部署快速修复,因为我们有足够的信心不运行 Cypress 测试,这可能需要 0 到 10 分钟,具体取决于我们触发的测试数量。 我们在这部分的可视化和 YML 步骤中提供了一个示例。

接下来,我们实现了我们自己的名为runCypress.sh的 Bash 脚本,以便在该选择步骤之后运行以解析选择的“是”或“否”值。 我们这样做是为了形成一个逗号分隔的规范路径列表,以运行并作为选项--spec附加到我们最终的赛普拉斯命令中,该命令在触发管道中的 Docker 容器中运行。 我们导出环境变量,例如“CYPRESS_SPECS”中形成的规范列表和“CYPRESS_TEST_ENV”中的当前测试环境,以用于我们在脚本末尾使用buildkite-agent pipeline upload "$DIRNAME"/triggerCypress.yml触发的管道buildkite-agent pipeline upload "$DIRNAME"/triggerCypress.yml

您可能已经注意到我们还如何导出“ASYNC”环境变量。 在 Buildkite 中,您可以根据成功或失败选择将触发的构建步骤设置为阻塞或非阻塞。 如果我们将“ASYNC”设置为 true,我们的主要部署管道步骤将继续运行,并且不会等待不同管道中触发的赛普拉斯测试完成。 管道的成功或失败不影响部署管道的成功或失败。

如果我们将“ASYNC”设置为 false,我们的主要部署管道步骤将被阻止,直到在不同管道中触发的赛普拉斯测试完成。 触发构建的成功或失败会导致部署管道的整体成功或失败。

当我们的代码仍处于打开拉取请求的功能分支中时,我们希望推送更多更改,触发一些赛普拉斯测试,并查看事情的表现。 但是,如果触发的测试失败,我们并不总是希望阻止其余的部署管道步骤运行,因为在此过程中可能会有更多的变化。 在这种情况下,我们将“ASYNC”设置为 false,以便在赛普拉斯测试失败时不阻塞。 对于我们已经将拉取请求合并到 master 并部署到 staging 但希望在部署到生产之前触发 Cypress 测试的情况,我们将“ASYNC”设置为 true,因为我们确实希望 Cypress 测试始终在投入生产之前通过.

回到runCypress.sh ,我们回想起脚本通过调用具有分配的环境变量值的triggerCypress.yml文件来触发第二个管道运行。 triggerCypress.yml文件看起来像这样。 您会注意到“触发”步骤和将值插入到构建消息中有助于调试和动态步骤名称。

无论我们触发赛普拉斯测试以从我们的部署管道运行到单独的触发管道,还是按计划在专用管道中运行赛普拉斯测试,我们都遵循并重用相同的步骤,同时仅更改环境变量值。

这些步骤包括:

  1. 使用最新标签和唯一版本标签构建 Docker 映像
  2. 将 Docker 镜像推送到我们的私有注册表
  3. 根据我们在 Docker 容器中的环境变量值,拉下同一个图像以运行我们的赛普拉斯测试

这些步骤在pipeline.cypress.yml文件中进行了概述,如下所示:

当我们触发赛普拉斯测试运行时,它将在赛普拉斯触发管道中启动一个单独的构建。 根据构建的成功或失败,赛普拉斯测试运行将阻止或允许我们在主分支构建从暂存到生产时部署到生产。

单击“Triggered cypress/integration/…”步骤将带您进入触发管道的构建,并使用类似这样的视图查看测试的进展情况。

如果您对 Docker 部分是如何连接的感到好奇,我们的Dockerfile.cypressdocker-compose.cypress.yml使用从我们的管道导出的那些环境变量,然后使用我们应用程序的package.json中指向右侧的正确 Cypress 命令测试环境并运行选定的规范文件。 下面的片段显示了我们可以扩展和改进以更加灵活的一般方法。


除了在我们通常的集成和部署周期中运行的测试之外,我们还创建了专用的 Buildkite 管道。 这些管道按计划运行,以针对我们的暂存环境进行重要测试,以确保我们的前端和后端服务正常工作。 我们重用了类似的管道步骤,调整了 Buildkite 管道设置中的某些环境变量值,并设置了一个 cron 计划以在预定时间运行。 这有助于我们在暂存环境中发现许多错误和问题,因为我们会继续监控测试的执行情况,以及下游或我们自己的代码推送是否可能导致测试失败。

并行化

我们还利用并行化标志来利用我们可以从我们的 Ops 团队设置的构建代理队列中启动的 AWS 机器的数量。 有了这个并行化标志,赛普拉斯会根据我们在 Buildkite 的“并行”属性中设置的数量自动神奇地启动一定数量的机器。

我们能够在大约 5 分钟内为我们的一个应用程序存储库运行 200 多个测试。

然后,它将所有赛普拉斯测试展开,以在这些机器上并行运行,同时为特定构建运行保留每个测试的记录。 这大大提高了我们的测试运行时间!

以下是并行化赛普拉斯测试时的一些提示:

  • 遵循仪表板服务中的建议以获得最佳机器数量,并在环境变量中设置机器数量以实现管道的灵活性。
  • 拆分成更小的测试文件,尤其是将运行时间较长的测试分解成块,我们可以更好地跨机器并行化。
  • 确保您的赛普拉斯测试是独立的,不会相互影响或相互依赖。 在处理更新、创建或删除相关的流程时,请使用单独的用户和数据资源,以避免测试相互踩踏并陷入竞争条件。 您的测试文件可以按任何顺序运行,因此请确保在运行所有测试时这不是问题。
  • 对于 Buildkite,除了parallel选项之外,请记住将 Buildkite 构建 ID 环境变量值传递给--ci-build-id选项,以便在跨机器并行测试时知道与哪个唯一构建运行相关联。

回顾:

为了将您的赛普拉斯测试连接到您的 CI 提供商,例如 Buildkite,您需要:

  1. 使用您的应用程序代码构建 Docker 映像,使用必要的赛普拉斯基础映像和在 Node 环境中针对某些浏览器运行测试所需的依赖项。
  2. 将您的 Docker 映像推送到带有特定标签的注册表
  3. 在后面的步骤中拉下相同的图像
  4. 如果您使用的是赛普拉斯仪表板服务,请以无头模式和记录键运行赛普拉斯测试。
  5. 设置不同的环境变量值并将它们插入您为赛普拉斯运行的命令中,以针对这些 Docker 容器中的特定测试环境触发选定的赛普拉斯测试。

这些通用步骤可以重复使用并应用于按计划运行的赛普拉斯测试和其他用例,例如触发测试以在部署管道之外针对选定的浏览器运行。 关键是利用 CI 提供者的功能,并根据环境变量值将命令设置为灵活且可配置的。

根据环境变量值将您的命令设置为灵活且可配置的。

一旦您通过 CI 提供商在 Docker 中运行测试(并且如果您为 Dashboard Service 付费),您就可以利用跨多台机器并行化测试的优势。 您可能必须修改现有的测试和资源,使它们不依赖于另一个,以避免任何测试相互影响。

我们还讨论了您可以自己尝试的想法,例如创建一个测试套件来验证您的后端 API 或触发测试以针对您选择的浏览器运行。 在 Cypress 文档中还有更多设置持续集成的方法

此外,在部署流程或计划间隔期间运行这些赛普拉斯测试非常重要,以确保您的开发环境始终按预期工作。 无数次,我们的赛普拉斯测试发现了与下游后端服务相关的问题,这些服务以某种方式关闭或更改,表现为前端应用程序错误。 在我们推出新的 React 代码更改后,他们尤其使我们免于网页中的意外错误。

在我们的测试环境中勤奋地维护通过测试并监控失败的测试运行会导致更少的支持票证和更快乐的生产客户。 当您推送新的代码更改时,保持一套健康稳定的赛普拉斯测试运行可以让您更有信心相信一切正常,我们建议您和您的团队对赛普拉斯测试也这样做。

有关赛普拉斯测试的更多资源,请查看以下文章:

  • 编写 E2E 测试时要考虑什么
  • 编写柏树测试的 1,000 英尺概述
  • TypeScript 包含 Cypress 测试中的所有内容
  • 在 Cypress 测试中处理电子邮件流
  • 配置、组织和整合赛普拉斯测试的想法