はじめに
Next.js開発においてAPIエンドポイントのURLを環境変数化した場合にアプリ自体は動くがテストが通らなくなる事案が発生
調べによるとJESTは環境変数を.env.test.localに記載してもうまく読み込んでくれない場合がある模様
環境
OS: Windows 10
node -v: v14.18.0
yarn -v: 1.22.17
package.json
{ "name": "hoge-project", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "test": "jest --env=jsdom --verbose", "gen-types": "graphql-codegen --config codegen.yml" }, "dependencies": { "@apollo/client": "^3.4.17", "@apollo/react-hooks": "^4.0.0", "@heroicons/react": "^1.0.5", "autoprefixer": "^10.4.0", "cross-fetch": "^3.1.4", "graphql": "^16.0.1", "next": "11.1.2", "postcss": "^8.3.11", "react": "17.0.2", "react-dom": "17.0.2", "setimmediate": "^1.0.5", "tailwindcss": "^2.2.19" }, "devDependencies": { "@babel/core": "^7.16.0", "@graphql-codegen/cli": "2.3.0", "@graphql-codegen/typescript": "^2.4.1", "@graphql-codegen/typescript-operations": "2.2.1", "@graphql-codegen/typescript-react-apollo": "3.2.2", "@testing-library/dom": "^8.11.1", "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.0.3", "@types/node": "^16.11.8", "@types/react": "^17.0.35", "babel-jest": "^27.3.1", "eslint": "7", "eslint-config-next": "12.0.4", "jest": "^27.3.1", "jest-css-modules": "^2.1.0", "msw": "^0.35.0", "next-page-tester": "^0.30.0", "typescript": "^4.5.2" }, "jest": { "testPathIgnorePatterns": [ "<rootDir>/.next/", "<rootDir>/node_modules/" ], "moduleNameMapper": { "\\.(css)$": "<rootDir>/node_modules/jest-css-modules" } } }
対処法
対処1 Home.test.tsx以外の全てのテストファイルの import 直下に下記環境変数を定義してからyarn testを実行
process.env.NEXT_PUBLIC_HASURA_URL = 'https://xxx.hasura.app/v1/graphql'
こちらはテストをGitHubにアップロードするのをためらってしまうため実用的ではない
対処2 環境変数を各テストケースで毎回読み込む
以下の記事に解決策は書いてあったものその通りの方法を実施した場合ではエラーが出たため自環境では各テストケースで環境変数を読み込む実装とした
Jestを用いたNext.jsのテスト内で環境変数を利用する - Breath Note
プロジェクト直下に
test/setupEnv.ts を作成し、以下を実装
import { loadEnvConfig } from '@next/env' export const setupEnv = async (): Promise<void> => { loadEnvConfig(process.env.PWD || process.cwd()) }
各テストのテストケースで上記のsetupEnvを実行する
XXXXX.test.tsx
// .......................... import { setupEnv } from "../test/setupEnv" //....................... describe('.................................', () => { it ('.................................', async () => { await setupEnv() // ......................................
こちらは各テストケースに記載する手間はあるが、外部ファイルから環境変数を読み込む形でテストを利用できる
対処3 環境変数をテスト準備時に読み込む
対処2ではhandlersがsetupEnvより前に記述されている場合に環境変数を読み込んでくれないという事案が発生する
解決方法としては await setupEnv() の処理をテスト準備処理をしているコード上部に持ってきてawaitを取り除いてsetupEnv() を行う
こうすることでsetupEnv()を各テストケースに記載する手間も省けるのでこの形が最も良い
XXXXX.test.tsx
// .......................... import { setupEnv } from "../test/setupEnv" setupEnv() //.......................テスト準備の処理 // 本チャンテストにsetupEnvを記述する必要なし describe('.................................', () => { it ('.................................', async () => { // ......................................