通过 CI/CD 运行测试
Studio 的 CI/CD 界面可生成 GitHub Actions 或 GitLab CI 的流水线文件。本指南介绍该文件运行的内容、作业可运行的三个位置、密钥、生成的 JUnit XML 和留存的证据,以及 CI 机器可能遇到的错误。
流水线文件
在 CI/CD 界面上,选择 GitHub Actions 或 GitLab CI、浏览器、检查项和作业运行位置,然后生成文件。Studio 会先在本地验证文件,也可以在同一界面提交并推送文件。在终端中运行 nexus init --ci github 或 nexus init --ci gitlab 也会生成相同的文件。
| 部分 | GitHub Actions | GitLab CI |
|---|---|---|
| 文件 | .github/workflows/nexus-ci.yml | .gitlab-ci.yml |
| 触发条件 | 拉取请求、推送到 main 或 master,以及带有 tc_ids 输入的手动运行 (workflow_dispatch)。开启每夜回归测试后,还会添加采用 UTC 时间的 schedule cron 表达式,默认为 0 6 * * *。 | 项目的流水线规则。文件中没有定时配置:如需每夜运行,请在 GitLab 中添加流水线计划。 |
| Runner | 云托管运行器使用 runs-on: ubuntu-latest,自托管运行器使用 runs-on: [self-hosted] | 镜像为 mcr.microsoft.com/playwright:v1.62.1-noble;自托管运行器使用 tags: [self-hosted] |
| 步骤 | actions/checkout@v4;使用 Node.js 22 的 actions/setup-node@v4,Docker 目标除外;npm ci;npx playwright install --with-deps;node bin/nexus.js ci --all,或使用你选择的测试 ID | npm ci;运行 node bin/nexus.js ci 并使用 TC_IDS 变量或 --all。镜像已包含浏览器。 |
| 构建产物 | actions/upload-artifact@v4,if: always(),名称为 nexus-evidence,路径为 evidence/ | artifacts: when: always, reports: junit: evidence/ci/junit.xml, paths: evidence/ |
选择多个浏览器时,GitHub 会为每个浏览器运行一个作业,设置 fail-fast: false,并为每个作业添加 --project=<browser>。所选检查项会添加 --visual、--a11y、--chaos=、--loop= 或 --no-retry。
退出码和 JUnit XML
nexus ci 会运行你指定的测试 (TC1,TC2),或通过 --all 运行所有测试。测试通过时退出码为 0,失败时为 1,未运行任何测试或命令有误时为 2。JUnit XML 会写入 evidence/ci/junit.xml;使用 --junit=<path> 可将其写入其他位置。
作业运行位置:三种选项
每种选项都需要一台已激活的机器:引擎不会在未激活的机器上运行测试套件,每台已激活的机器都会占用套餐中的机器名额 (套餐与机器)。云托管运行器 runs-on: ubuntu-latest 会为每个作业启动一台新的虚拟机,因此无法保留激活状态;请使用你自己的持久化运行器。
选项 A:在 Studio 所在的机器上使用自托管运行器
- 在已安装并激活 Nexus Studio 的 Windows 11 电脑或迷你电脑上注册运行器:在 GitHub 中,进入仓库的 设置、Actions、运行器、新建自托管运行器;在 GitLab 中,进入 设置、CI/CD、运行器。
- 在 CI/CD 界面上,选择 我的机器。此时,GitHub 的文件中会使用
runs-on: [self-hosted],GitLab 的文件中会使用tags: [self-hosted]。 - 使用激活 Studio 的 Windows 用户身份运行运行器。引擎会从该用户配置文件中的
.sentinel-studio\license.json读取激活信息,因此以其他账户运行的运行器服务将找不到激活信息。
作业使用本机的激活信息:每台机器激活一次,已计入你的套餐,且流水线中无需密钥。自托管运行器仅可用于私有仓库,正如 Studio 所警告的那样:如果用于公开仓库,任何发起拉取请求的人都能在你的机器上运行代码。
方案 B: 在 VPS 的容器中运行运行器
一台安装了 Ubuntu 24.04 LTS x86_64、Docker Engine 和 Compose v2 的 VPS,通过 SSH 密钥认证连接。它占用你套餐中的一个机器名额。
- 在 CI/CD 界面上,选择 我的机器 + Docker。除了流水线文件,Studio 还会将
docker-compose.sentinel-runner.yml、Dockerfile.runner和运行器的两个入口脚本写入工作区。Dockerfile.runner使用mcr.microsoft.com/playwright:v1.62.1-noble作为基础镜像。 - 界面显示的命令应粘贴到 VPS 的 SSH 会话中,而不是 Studio 自带的终端中。对于 GitHub,它会获取有效期为 1 小时的注册令牌,并设置
REPO_URL、RUNNER_TOKEN和RUNNER_NAME;对于 GitLab,则设置GITLAB_URL和GITLAB_RUNNER_TOKEN。然后:
docker compose -f docker-compose.sentinel-runner.yml up -d --build sentinel-runner
docker compose -f docker-compose.sentinel-runner.yml up -d sentinel-runner-gitlab
第一行用于 GitHub,第二行用于 GitLab。在 Linux 容器内,许可证通过 /etc/machine-id 识别机器:以只读方式挂载宿主机的该文件,/etc/machine-id:/etc/machine-id:ro,并将运行器主目录中的 .sentinel-studio 文件夹保存在卷上,以便重建后仍保留激活信息。使用 nexus license activate 和你的密钥手动激活一次,切勿通过流水线文件激活。
目前,运行器镜像在 VPS 上通过 Dockerfile.runner 构建。仓库尚未提供容器镜像仓库:下一版本将发布托管在 GitHub Container Registry 上的镜像,供 Studio 的 VPS 运行时使用。
方案 C: CI 作业通过 SSH 在主机上启动运行
无论使用哪种运行器,作业都保持轻量,测试套件则在您自己的主机上运行,工作区和引擎位于该主机的指定路径下,符合 Studio 的 SSH 运行时要求。CI/CD 界面不会生成此作业;以下是 Studio 自身的 SSH 运行时所使用的选项:
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -o ConnectTimeout=8 <user>@<host> "cd <path> && node bin/nexus.js ci --all"
scp -r -o BatchMode=yes -o StrictHostKeyChecking=yes <user>@<host>:<path>/evidence ./evidence
- 仅使用密钥认证。
BatchMode=yes绝不会提示输入密码。将 CI 机密中的私钥写入仅供该作业读取的文件,并在作业结束时删除该文件。 StrictHostKeyChecking=yes。 主机密钥必须已存在于运行器的known_hosts中:将主机公钥行保存在 CI 变量中,并在首次执行ssh前将其写入该文件。切勿将此选项设为no。- 退出码会传回。
ssh会以远程命令的退出码退出,因此测试套件失败时,该步骤也会失败;scp则会将包括 JUnit XML 在内的证据传回,供制品处理步骤使用。 - 主机会检查自身的许可证,并占用您套餐中的一个机器名额。
密钥
- 将令牌、Webhook URL 和 SSH 私钥存储为 CI 机密:在 GitHub 中,依次进入设置、机密和变量、Actions,或使用
gh secret set <KEY>;在 GitLab 中,依次进入设置、CI/CD、变量,将其保存为掩码变量。切勿将它们写入代码仓库、流水线文件或日志。 - 生成的 GitHub 工作流仅从
secrets.<KEY>读取集成密钥,且仅在 Nexus 步骤中读取:TELEGRAM_*、SLACK_ENABLED、SLACK_WEBHOOK_URL、JIRA_*和通知开关。CI/CD 界面会为每个密钥列出一条gh secret set命令;gh会提示输入值,但不会打印任何内容。 - 许可证密钥不应放在 CI 中。请手动激活持久化运行器一次:密钥仅发送一次,不会保存。如果您的流程仍要求将密钥放在 CI 系统中,请务必仅将其存储为掩码机密;生成的流水线不会读取它。
- 切勿在步骤中回显机密。引擎会清除其作为证据归档的文本中的机密,例如 JUnit 失败消息和日志;但不会清除作业自身控制台输出中的机密,而 CI 服务仅会遮蔽存储为机密的值。
将 JUnit XML 和证据保存为制品
- GitHub 会将
evidence/上传为nexus-evidence,使用矩阵时则为每个浏览器上传一个nexus-evidence-<browser>,无论运行成功还是失败。JUnit XML 位于其中的evidence/ci/junit.xml。 - GitLab 会保留
evidence/,并将evidence/ci/junit.xml作为 JUnit 报告呈现,因此失败的测试会显示在合并请求中。 - 在 Studio 中,您可以通过 CI/CD 界面启动 GitHub 工作流运行,并将其证据下载到工作区中的
evidence/ci-remote/run-<id>。 - 副本存储在哪里。 制品是存储在 CI 服务中的证据副本,包括屏幕截图和日志;如果使用托管服务,这些内容就存储在他人的硬件上。请根据您的政策设置制品保留期限,或将证据保留在自己的运行器上,仅上传
evidence/ci/junit.xml。
故障排查
云托管或临时运行器上的 SEAT_LIMIT
对于许可证而言,每台新虚拟机都是一台新机器,因此临时运行器每次执行作业都需要激活。当套餐中的所有机器名额都已激活时,激活请求将被拒绝,并返回 SEAT_LIMIT: “您套餐中的所有机器名额均已使用。请在账户中停用一台机器。” 请使用持久化的自托管运行器(选项 A 或 B),并在账户的许可证 & 机器中停用不再使用的机器(了解有关 SEAT_LIMIT 的更多信息)。
运行器已离线数天
每台机器的许可证至少每 7 天须验证一次。此后会显示通知,并额外提供 4 天宽限期,然后进入只读模式:在验证成功之前,测试套件不会运行,但证据仍可查看。运行器重新联网后,nexus license renew 会再次验证(离线工作)。
容器中出现“no /etc/machine-id”
容器中没有可供许可证读取的机器 ID。请挂载宿主机的机器 ID:-v /etc/machine-id:/etc/machine-id:ro,或在 compose 文件的 volumes: 下添加同样的挂载配置。
作业以退出码 2 退出
未运行任何测试:没有测试与指定 ID 匹配,或命令有误。请检查传递给 nexus ci 的 ID,即 GitHub 中的 tc_ids 或 GitLab 中的 TC_IDS。
主机密钥验证失败
StrictHostKeyChecking=yes 拒绝连接不在 known_hosts 中或密钥已更改的主机。请先在主机本身核对密钥指纹,再从可信来源添加该主机的密钥。不要关闭此项检查。