Cypress 如何管理环境变量和配置?
Cypress 测试要在开发、测试、预发布、生产等多个环境中跑,每个环境的 API 地址、账号密码、超时阈值都不一样。如果把这些值硬编码在测试代码里,换个环境就全崩了——这正是环境变量和配置管理要解决的问题。
Cypress 提供了一套分层的环境变量体系,优先级从高到低依次是:命令行 --env 参数 > CYPRESS_ 前缀系统变量 > cypress.env.json 文件 > cypress.config.js 中的 env 字段。理解这套优先级,才能知道变量到底从哪来、被谁覆盖了。下面逐层拆解。
cypress.config.js 中定义默认环境变量
cypress.config.js 是 Cypress 的主配置入口,在 env 字段中可以声明所有环境变量的默认值:
javascriptconst { 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()
javascriptit('验证登录接口返回 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() 会返回所有环境变量的对象,方便一次性取多个值。
临时修改:运行时覆盖
javascriptdescribe('生产环境模拟', () => { 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 文件中的后续测试仍会读到修改后的值,所以最好在 after 或 afterEach 中手动恢复。
多环境配置的实战方案
项目里通常有三个以上的环境,靠一个 cypress.config.js 不够用。常见的做法是拆分配置文件:
shellcypress/ 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 可以直接复用:
bashnpm 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 示例
yamljobs: 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 示例
yamle2e-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=prod | CI 动态覆盖 |
| 2 | CYPRESS_ 前缀系统变量 | CYPRESS_API_URL=prod | CI/本地临时设置 |
| 3 | cypress.env.json | {"API_URL":"staging"} | 本地开发(不入库) |
| 4(最低) | cypress.config.js 的 env | env: { 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' })。