Jestでprocess.envを使用しようとするとundefinedになったので、globalSetupで環境変数を設定することにした

jest.config.ts

globalSetupは、Jest設定ファイル(この場合はJavaScriptオブジェクト)の一部で、テストスイート全体が実行される前に一度だけ実行されるスクリプトを指定するプロパティです。

この設定は、全テストケースが実行される前に一度だけ実行したい何かがある場合に便利です。例えば、データベースの接続を開始したり、特定の環境変数を設定したりすることができます。

jest.config.tsで設定しています。

export default {
  clearMocks: true,
  collectCoverage: true,
  coverageDirectory: "coverage",
  coverageProvider: "v8",
  roots: ["<rootDir>/tests"],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  verbose: true,
  coveragePathIgnorePatterns: [
    "/tests/",
    "/node_modules/",
    "<rootDir>/db-service/appDataSource.ts",
  ],
  coverageThreshold: {
    "**/*": {
      statements: 70,
    },
  },
  globalSetup: "<rootDir>/tests/setupEnv.ts",
};

globalSetupに指定されたスクリプトは、テスト環境が設定される前に実行されます。これは、テスト環境が必要ないセットアップタスク(例えば、データベースのセットアップや、環境変数の設定など)に特に有用です。

<rootDir>/tests/setupEnv.tsというパスにあるスクリプトがテストスイート全体が実行される前に一度だけ実行されます。<rootDir>はJestによって自動的に解釈され、プロジェクトのルートディレクトリ(つまり、設定ファイルが存在する場所)を指します。

なお、globalSetupとは対照的に、globalTeardownという設定もあり、これはテストスイート全体の実行が終了した後に一度だけ実行されるスクリプトを指定します。これは例えば、データベース接続をクローズするなどの後処理に利用できます。

setupEnv.ts

export default (): void => {
  process.env.DB_HOST = "localhost";
  process.env.DB_NAME = "db";
  process.env.DB_USER = "root";
  process.env.DB_PASSWORD = "root";
  process.env.ENTITY_PATH = "entity/*.ts";
  return;
};

このスクリプトは環境変数を設定し、テストの実行環境を準備する役割を果たします。テストコードではこれらの環境変数を参照して、例えばデータベースに接続するための情報を取得します。

もともとどのようなエラーが出ていたか

DB接続時にprocess.envから取得してくるはずのコネクション情報がうまく設定されていないという問題がありました。うまく設定されていないので、当然DB接続でコケてました。

テストコードで以下を実行する部分があるのですが、ここでprocess.env.DB_USERとかが軒並みundefinedになってました。

const appDataSource: DataSource = new DataSource({
  type: "mysql",
  host: process.env.DB_HOST,
  port: 3306,
  username: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  synchronize: false,
  logging: false,
  entities: [entityPath],
  migrations: [],
  subscribers: [],
});

テストコードを載せます。

import httpTrigger from "../../SampleTableAccess/index";
import { mock } from "jest-mock-extended";
import { Context } from "@azure/functions";

beforeAll(() => {
  jest.clearAllMocks();
});

test("サンプルデータアクセステスト", async () => {
  const context = mock<Context>();
  const req = {
    body: {},
  };
  await httpTrigger(context, req);
  expect(context.res?.status).toBe(200);
});

実は、globalSetupで設定しなくても
import httpTrigger from "../../SampleTableAccess/index";
の前で以下のように設定すればprocess.envを設定していくことはできます。
process.env.DB_HOST = “localhost”;

これはjestの仕様と言うふうに捉えたらいいです。

ただ、テストごとにprocess.envを変更したいと言うようなニーズがない限り、ここでの設定はしないかな?と思います。

というのも、通常私はテストは実際のファイルに対応させて作成しており、それぞれのファイルで毎度同じことを書くのは面倒だと思うからです。DBの設定情報もそれに当たります。