NestJS + Docker + Jest でE2Eテストを実行する備忘録

# 概要

以下の参考記事をもとに業務で導入した方法を備忘録として残します。

https://zenn.dev/nikaera/books/nestjs-azure-dev/viewer/e2e-test-docker-compose

# やり方

## E2Eテスト用DockerFileを作成

```Dockerfile:Dockerfile.test
# FROM ベースイメージを指定する
# as build-stage ビルド用のイメージと実行用のイメージを分ける
# -alpine 軽量イメージ
FROM node:14.16.1-alpine as build-stage

# 作業ディレクトリを作成
WORKDIR /work

COPY . /work/

RUN npm install

# コマンドを実行する
CMD ["npm","run","test:e2e"]
```

## dev環境をmigration用DockerFileを作成

```Dockerfile:Dockerfile.migrate
FROM node:14.16.1-alpine

WORKDIR /work

COPY ./src/databases /work/src/databases
COPY ./package.json ./package-lock.json ./ormconfig.ts ./tsconfig.json /work/

RUN npm install

CMD ["npm", "run", "typeorm", "migration:run"]
```

## E2Eテスト用のdocker-composehuxairu

```yaml:unit-test.yml
# docker-composeで使用するバージョン
version: '3'

# アプリケーションを動かすための各要素
services:
  # コンテナ名
  app:
    # ComposeFileを実行し、ビルドされるときのpath
    build:
      # docker buildコマンドを実行した場所
      context: "."
      # Dockerfileのある場所
      dockerfile: "Dockerfile.test"
      # image ID
    image: hoge-test
    # コンテナ名
    container_name: hoge-test
    # ポート番号
    ports:
      - '3000:3000'
      # 環境変数
    environment:
      PORT: xxx
      TZ: 'Asia/Tokyo'
      DB_HOST: 'xx'
      DB_PORT: 'xxxx'
      DB_USERNAME: 'xxxx'
      DB_PASSWORD: 'xxxx'
      DB_NAME: 'hoge'
      REDIS_HOST: 'xx'
      REDIS_PORT: 'xx'
      # サービス間の依存関係
    depends_on:
      - db
      - redis

  redis:
    image: redis:5.0
    container_name: redis_container-test
    ports:
      - "xxxx:xxxx"

  db:
    image: mysql:8.0
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    container_name: db_container_test
    ports:
      - xxxx:xxxx
    environment:
      TZ: 'Asia/Tokyo'
      MYSQL_ROOT_PASSWORD: xxxx
      MYSQL_DATABASE: xxxx
      MYSQL_USER: xxxx
      MYSQL_PASSWORD: xxxx
```

## テスト環境用`TypeOrm`設定ファイルの作成

>同期-アプリケーションの起動ごとにデータベーススキーマを自動作成する必要があるかどうかを示します。このオプションには注意してください。本番環境では使用しないでください。本番環境のデータが失われる可能性があります。このオプションは、デバッグおよび開発中に役立ちます。その代わりに、CLIを使用してschema：syncコマンドを実行できます。

https://github.com/typeorm/typeorm/blob/master/docs/faq.md

```ts:ormconfig.test.ts
module.exports = {
  type: 'mysql',
  host: process.env.DB_HOST || 'localhost',
  port: process.env.DB_PORT || 'xxxx',
  username: process.env.DB_USERNAME || 'xxxx',
  password: process.env.DB_PASSWORD || 'xxxx',
  database: process.env.DB_NAME || 'xxxx',
  //  アプリケーション実行時にEntityをデータベースに同期する
  synchronize: true,
  // 実行されるSQLをログとして吐く
  logging: true,
  entities: ['src/domain/entities/*.ts'],
  migrations: ['src/databases/migrations/*.ts'],
  seeds: ['src/test/databases/seeders/*.seed.{js,ts}'],
  subscribers: ['src/subscribers/**/*.ts'],
  cli: {
    migrationsDir: 'src/databases/migrations',
    entitiesDir: 'src/domain/entities',
    seedersDir: 'src/databases/seeders',
    subscribersDir: 'src/subscribers',
  },
}

```

## テスト実行

```bash
# E2Eテストコンテナ立ち上げ
docker-compose -f unit-test.yml build

# E2Eテストコンテナ起動 テスト終わったらコンテナ落とす
docker-compose -f unit-test.yml up  --abort-on-container-exit
Recreating redis_container ... done
Recreating db_container    ... done
Recreating xxx-api-test ... done
Attaching to redis_container-test, db_container_test, xxx-api-test

xxx-api-test |
xxx-api-test | > sample@0.0.1 test:e2e /work
xxx-api-test | > jest --config ./src/test/e2e/jest-e2e.json
xxx-api-test |
xxx-api-test | PASS src/test/e2e/contractor-reps.e2e-spec.ts (92.288 s)
xxx-api-test   契約担当者(E2E)
xxx-api-test     ログインしていない場合は401が返ります
xxx-api-test       ✓ OK /contractor-reps (GET) (1471 ms)
xxx-api-test     契約担当者一覧テスト_サービス・システム管理
xxx-api-test       ✓ OK /contractor-reps (GET) (1195 ms)
// 省略

xxx-api-test Test Suites: 1 passed, 1 total
xxx-api-test Tests:       38 passed, 38 total
xxx-api-test Snapshots:   0 total
xxx-api-test Time:        92.428 s
xxx-api-test Ran all test suites.
xxxx-api-test exited with code 0
```

## 最後に

読んでいただきありがとうございます。
今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。