5月27日 23:02

Cypress 如何管理环境变量和配置?

Cypress 测试要在开发、测试、预发布、生产等多个环境中跑,每个环境的 API 地址、账号密码、超时阈值都不一样。如果把这些值硬编码在测试代码里,换个环境就全崩了——这正是环境变量和配置管理要解决的问题。

Cypress 提供了一套分层的环境变量体系,优先级从高到低依次是:命令行 --env 参数 > CYPRESS_ 前缀系统变量 > cypress.env.json 文件 > cypress.config.js 中的 env 字段。理解这套优先级,才能知道变量到底从哪来、被谁覆盖了。下面逐层拆解。

cypress.config.js 中定义默认环境变量

cypress.config.js 是 Cypress 的主配置入口,在 env 字段中可以声明所有环境变量的默认值:

javascript
const { defineConfig } = require('cypress'); module.exports = defineConfig({ e2e: { baseUrl: 'http://localhost:3000', env: { API_BASE_URL: 'https://dev.api.example.com', TIMEOUT_MS: 10000, }, }, });

这种方式最简单,适合放不敏感的默认值。但有两个限制:第一,所有环境变量都暴露在代码仓库里,敏感信息不能放这里;第二,每次改值都要改文件提交,不适合频繁切换环境。

cypress.env.json —— 独立的环境变量文件

Cypress 会自动加载项目根目录下的 cypress.env.json,它的值会覆盖 cypress.config.js 中同名的 env 变量:

json
{ "API_BASE_URL": "https://staging.api.example.com", "ADMIN_USERNAME": "staging_admin" }

重要cypress.env.json 必须加入 .gitignore,防止敏感信息提交到仓库。

这种方式的好处是:本地开发时每个测试人员可以维护自己的 cypress.env.json,互不干扰,而仓库里只保留 cypress.config.js 的默认值。CI 环境中则通过命令行参数或系统变量覆盖,不需要这个文件。

CYPRESS_ 前缀的系统环境变量

任何以 CYPRESS_cypress_ 开头的系统环境变量,Cypress 都会自动识别并注入。变量名会去掉前缀并转为大写:

bash
# 设置系统环境变量 export CYPRESS_API_BASE_URL=https://prod.api.example.com export CYPRESS_ADMIN_PASSWORD=secret123 # 运行测试 npx cypress run

在测试中通过 Cypress.env('API_BASE_URL') 就能拿到值。这个机制特别适合 CI 环境——在 CI 平台的安全变量配置里设置 CYPRESS_ 前缀变量,测试运行时自动生效,不需要额外代码。

命令行 --env 参数:优先级最高的覆盖方式

--env 参数的优先级最高,会覆盖上面所有来源的同名变量:

bash
# 传递单个变量 npx cypress run --env API_BASE_URL=https://prod.api.example.com # 传递多个变量,用逗号分隔 npx cypress run --env API_BASE_URL=https://prod.api.example.com,ADMIN_PASSWORD=ci_secret

CI 管道中经常这样用:构建脚本根据目标环境动态拼接 --env 参数,实现一套代码跑多套环境。

在测试代码中读取和临时修改环境变量

读取:Cypress.env()

javascript
it('验证登录接口返回 200', () => { const apiUrl = Cypress.env('API_BASE_URL'); const username = Cypress.env('ADMIN_USERNAME'); cy.request({ url: `${apiUrl}/login`, method: 'POST', body: { username, password: Cypress.env('ADMIN_PASSWORD') }, }).then((response) => { expect(response.status).to.eq(200); }); });

不带参数调用 Cypress.env() 会返回所有环境变量的对象,方便一次性取多个值。

临时修改:运行时覆盖

javascript
describe('生产环境模拟', () => { let originalUrl; before(() => { originalUrl = Cypress.env('API_BASE_URL'); Cypress.env('API_BASE_URL', 'https://prod.api.example.com'); }); after(() => { // 恢复原始值,避免影响其他测试 Cypress.env('API_BASE_URL', originalUrl); }); it('生产环境接口响应时间应小于 2s', () => { cy.request(Cypress.env('API_BASE_URL') + '/health').then((res) => { expect(res.duration).to.be.lessThan(2000); }); }); });

Cypress.env(key, value) 修改的值只在当前测试运行期间生效,测试结束后自动恢复。但同一 spec 文件中的后续测试仍会读到修改后的值,所以最好在 afterafterEach 中手动恢复。

多环境配置的实战方案

项目里通常有三个以上的环境,靠一个 cypress.config.js 不够用。常见的做法是拆分配置文件:

shell
cypress/ config/ development.json staging.json production.json cypress.config.js

各环境配置文件内容示例:

json
{ "baseUrl": "https://staging.example.com", "env": { "API_BASE_URL": "https://staging.api.example.com", "TIMEOUT_MS": 15000 } }

然后在 package.json 中配置快捷命令:

json
{ "scripts": { "cy:open:dev": "cypress open --config-file cypress/config/development.json", "cy:open:staging": "cypress open --config-file cypress/config/staging.json", "cy:run:prod": "cypress run --config-file cypress/config/production.json" } }

这样执行 npm run cy:run:prod 就自动加载生产环境配置,不需要每次手动传参。

dotenv 集成:在配置文件中加载 .env

如果团队已经在用 .env 管理项目的环境变量,Cypress 可以直接复用:

bash
npm install dotenv --save-dev
javascript
// cypress.config.js const { defineConfig } = require('cypress'); require('dotenv').config(); module.exports = defineConfig({ e2e: { baseUrl: process.env.BASE_URL || 'http://localhost:3000', env: { API_SECRET: process.env.API_SECRET, TEST_ENV: process.env.TEST_ENV || 'development', }, }, });

.env 文件同样要加入 .gitignore。这个方案的优势是:项目其他部分(如 Next.js、Node 服务)也读 .env,一套文件多处复用,维护成本低。

CI/CD 中的环境变量管理

不同 CI 平台的注入方式略有差异,但核心思路一致:把敏感值放在平台的 Secrets 配置中,非敏感值放在环境变量中。

GitHub Actions 示例

yaml
jobs: e2e-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: npm ci - name: Run Cypress env: CYPRESS_API_SECRET: ${{ secrets.API_SECRET }} CYPRESS_TEST_ENV: production run: npx cypress run

GitLab CI 示例

yaml
e2e-test: image: cypress/browsers:latest script: - npm ci - npx cypress run --env API_BASE_URL=$STAGING_API_URL variables: STAGING_API_URL: "https://staging.api.example.com"

关键原则:永远不要在 YAML 文件里直接写密码和密钥,一律用平台 Secrets 功能。

环境变量优先级完整对照表

优先级来源示例适用场景
1(最高)--env 命令行参数--env API_URL=prodCI 动态覆盖
2CYPRESS_ 前缀系统变量CYPRESS_API_URL=prodCI/本地临时设置
3cypress.env.json{"API_URL":"staging"}本地开发(不入库)
4(最低)cypress.config.jsenvenv: { API_URL: 'dev' }默认值

优先级高的会覆盖低的同名变量。如果同一个变量在四处都设置了,最终取优先级最高的那个值。

常见问题排查

变量读不到,返回 undefined

检查变量名是否一致。CYPRESS_ 前缀的变量名会去掉前缀,比如系统变量 CYPRESS_API_KEY 在测试中用 Cypress.env('API_KEY') 读取。注意大小写:Cypress 内部会将变量名转为大写。

cypress.env.json 没生效

确认文件在项目根目录(与 cypress.config.js 同级),且文件名拼写正确。另外检查 JSON 格式是否合法——多一个逗号都会导致静默失败。

CI 中环境变量覆盖不了本地值

可能是变量名不匹配。本地 cypress.env.json 写的是 api_base_url,CI 用 CYPRESS_API_BASE_URL 注入,两者大小写不同,Cypress 不会自动合并。建议统一用大写命名。

dotenv 加载失败

require('dotenv').config() 要放在 cypress.config.js 的最顶部,且 .env 文件路径要正确。如果 .env 不在项目根目录,需要指定路径:require('dotenv').config({ path: '../.env' })

标签:Cypress