😊

Cypressで環境別にe2eテストを実行する

2022/12/23に公開

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内でconfigenvに含まれます。

これを利用して、最後に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