Cypressで環境別にe2eテストを実行する
e2eテストは、localhostだけにとどまることではなく、実際にtesting/stagingとかの環境にデプロイされているサイトにも実行します。今回はローカルで、複数の環境にデプロイメントされているアプリケーションに対して、Cypressのe2eテストを実行する方法を紹介します。
環境変数の読み込み
環境変数にするのは、よく変わるもの、もしくはセンシティブなデータとかが多いでしょう。
公式ではcypress.env.json
ファイルが.env
の代わりに環境変数を提供することができます。
もう一つのやり方は、コマンド実行するときに、--env NAME=VALUE
の形で注入することも可能です。
npx cypress run --config baseUrl=xxx --env xxx=xxx
これは複数の引数を注入するのに向いていなく、ローカル開発の場合は、cypress.env.json
ファイルを利用すると手軽に導入できます。コード内では、Cypress.env('key')
の形で読み込みが可能です。
process.env
は使えないの?
完全に余談ですが、これは場合によるものです。例えばCIの場合、env
ブロックの中に環境変数を入れたりしますが、ここのものは全て「OSレベル」扱いとなっているようで、process.env
からアクセス可能です。
- name: Run tests
uses: cypress-io/github-action@v4
env:
CI: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CYPRESS_USERNAME: ${{secrets.CYPRESS_USERNAME}}
CYPRESS_PASSWORD: ${{secrets.CYPRESS_PASSWORD}}
CYPRESS_PROJECT_ID: ${{secrets.CYPRESS_PROJECT_ID}}
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
with:
browser: chrome
record: true
parallel: true
install: false
build: npm run build
start: npm run start
spec: cypress/**/*cy.{js,ts}
wait-on: "http://frontend.com, http://backend.com"
wait-on-timeout: 300
この例のCI
にアクセスするには、process.env.CI
からいけます。もしCypress.env('CI')
で使いたい場合は、他の環境変数のように、CYPRESS_
のプリフィックスをつける必要があります。
ローカル環境ではいわゆるOSレベルの環境変数をつけるのは汚染してしまう良くない実践なので、公式の方法で良いでしょう。
複数の環境に対してテストしたい
cypressでenvファイルを指定することができないため(もしできるのならご指摘お願いします)、シンプルにコマンドのargとして渡すことができません。ただ、環境別の環境変数セットがあるので、なんとか今何環境に対して実行するかを区別したいですね。
まず環境変数のファイルをいくつか用意します。
touch env/dev.json env/stg.json
次にそれぞれの環境変数を対応するファイルにコピペーして、.gitignoreにも追加します。
それで、--env
フラグで渡した引数は、cypress.config.js
ファイルに読み込みできます。ただ、もちろんprocess.env
からではなく、setupNodeEvents
内でconfig
のenv
に含まれます。
これを利用して、最後にcypress.config.js
で--env
で渡した環境名を見ながら、環境変数ファイルを読み込みます。
const { defineConfig } = require('cypress')
const { readFileSync } = require('fs')
module.exports = defineConfig({
reporter: 'junit',
reporterOptions: {
mochaFile: 'cypress/results/output.xml',
},
e2e: {
setupNodeEvents(on, config) {
const envName = config.env.ENV || 'local'
// read different config file depending on env
const content = readFileSync(`./env/${envName}.json`)
const values = JSON.parse(content)
config.env = { ...values }
return config
},
// default for local
baseUrl: 'http://localhost:3000'
},
chromeWebSecurity: false,
})
baseUrl
はデフォルト値としてローカルホストを入れていますが、これはコマンドに--config baseUrl=xxx
をつけることで上書きできます。
スクリプト追加
もちろん、一々コマンドに--env ENV=stg
とかつけるのも面倒なので、ここはpackage.json
にスクリプトを追加します。
"scripts": {
"test": "cypress run",
"test:dev": "cypress run --config baseUrl=https://dev.e2e.com --env ENV=dev",
"test:stg": "cypress run --config baseUrl=https://stg.e2e.com --env ENV=stg",
"gui-test": "cypress open",
"gui-test:dev": "cypress open --config baseUrl=https://dev.e2e.com --env ENV=dev",
"gui-test:stg": "cypress open --config baseUrl=https://stg.e2e.com --env ENV=stg",
},
全てのテスト実行するときはnpm run test
でOKです。GUIでデバッグするときはnpm run gui-test:dev
とかで。baseUrlはe2eテスト実行するサイトのURLなので、ローカル以外の環境の場合は確実に入れておきましょう。
もし一部のみのファイルを実行したいときは、コマンドに引数を注入します:
npm run test:dev -- --spec "cypress/e2e/testA/xxx.cy.ts"
npm run test:stg -- --spec "cypress/e2e/01-*/*"
終わりに
シンプルなはずのものですが、自分が最初にCypressで環境変数を扱うときに少し苦労していました。他のjsプロジェクトのように、.env
ファイルに環境変数をおいて、その後process.env
から取得するのができません(理由は単純にNode.js環境ではないからです)。確かにprocess.env
+.env
ファイルより若干手間になったが、環境別にテストを実行するとの目的は達成できています。このような内容が誰かの参考になれると嬉しいです。
ではでは。
Discussion