From cf56239da22b4dfd02fad087f38a2ed90b9c82c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=AF=E6=9C=AC=20=E9=96=8B?= Date: Tue, 23 Jan 2024 07:58:42 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20669:=20Pipeline=E4=B8=8A=E3=81=A7?= =?UTF-8?q?docker-compose=E3=82=92=E7=94=A8=E3=81=84=E3=81=A6MySQL?= =?UTF-8?q?=E3=82=92=E8=B5=B7=E5=8B=95=E3=81=99=E3=82=8B=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E3=82=92=E8=AA=BF=E6=9F=BB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3427: Pipeline上でdocker-composeを用いてMySQLを起動する方法を調査する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3427) - MySQLでUnitTestを実施する仕組みを作成 - DevContainerにUnitTestからのみアクセスされるMySQLが動くコンテナ( `test_mysql_db` )を追加 - テストでMySQLを使用し、上記 `test_mysql_db` に対してアクセスするよう構成 - テストの前処理で `test_mysql_db` の全てのテーブルをTRUNCATEする処理を実行し、データをクリアする - 常にテスト用MySQLは起動しているが、テスト実行前にクリアされるので空っぽ前提の状態でテストを実施できる - 実際にMySQLを使用して実行されるテストを1つ追加 - `users.service.spec.ts | UsersService.createUser` が対象 - Pipeline上でDevContainerを起動し、DevContainer内で `npm ci` `(UnitTest用DBへの) migration` `npm run test` を行う仕組みを作成 - Pipelineを追加 - **StagingPipelineでテスト・ステップを切り出し** - Pipelineテスト用DevContainer(のdocker-compose.yml)を作成 - 構成は通常の物と同一だが、ネットワーク設定だけ外部のMySQLやRedisと通信しない前提に変更している - テストの実行環境を自己ホストではなく、一般で提供されているマシンに変更 - 自己ホストのマシンにdocker-composeが入ってない/ビルド後のクリア処理が大変等の理由 - テストで使用する環境変数を `.env.test` という別環境変数に切り出し - そうすることで、PipelineでKeyVaultへのアクセスをする必要がなくなる - **migrationの漏れを修正** - テストが通らないことで発覚したmigration漏れを修正 - **テストコードを修正** - **Date型のミリ秒単位の誤差を setMillseconds(0) を用いることで0にセットするコードを追加(ライセンス付近)** ## レビューポイント - **WIPレビュー以降の追加の修正で違和感のある箇所はないか** - コミット履歴等で追っていただいた方が楽かと思います - 直近の`Merge branch 'develop' into feature/3427/poc-mysql-test` 以降がWIP以降に変更されたコードです - **レビュー通過後、developのPipelineについては手動で同等のコードに変更→PRをdevelopにマージ予定だが進め方として問題はないか** - [※WIPでレビュー済み] テスト用DevContainerを別途作成したが、現行のDevContainerを使用するよう頑張った方がいいか? - [※WIPでレビュー済み] CI/CDの実行速度面を考慮し、使用されないMySQLとRedisのサービスとネットワーク作成が同居しているdocker-compose.ymlの実行を避けたが、管理対象は増えているので議論の余地はある - [※WIPでレビュー済み] MySQLでUnitTestを実行する際に懸念事項はないか - [※WIPでレビュー済み] Dockerを起動する関係でCI/CDのスピードが数分遅くなると思われるが、許容可能か - [※WIPでレビュー済み] `.env.test` に置き換えて問題ないか ## 動作確認状況 - ローカル&Pipelineで実行して確認済 --- azure-pipelines-staging.yml | 68 +- .../.devcontainer/docker-compose.yml | 10 + .../.devcontainer/pipeline-docker-compose.yml | 35 + dictation_server/.env.test | 37 + dictation_server/db/dbconfig.yml | 4 + .../migrations/053-delete-license-alert.sql | 6 + dictation_server/package.json | 5 +- dictation_server/src/common/test/init.ts | 21 + dictation_server/src/common/test/modules.ts | 2 +- .../accounts/accounts.controller.spec.ts | 2 +- .../accounts/accounts.service.spec.ts | 951 ++++++++++++------ .../src/features/auth/auth.controller.spec.ts | 2 +- .../src/features/auth/auth.service.spec.ts | 147 ++- .../features/files/files.controller.spec.ts | 2 +- .../src/features/files/files.service.spec.ts | 217 ++-- .../src/features/files/test/utility.ts | 2 +- .../licenses/licenses.controller.spec.ts | 2 +- .../licenses/licenses.service.spec.ts | 227 +++-- .../src/features/licenses/test/utility.ts | 1 + .../notification.controller.spec.ts | 2 +- .../test/notification.service.mock.ts | 2 +- .../features/tasks/tasks.controller.spec.ts | 2 +- .../src/features/tasks/tasks.service.spec.ts | 297 ++++-- .../src/features/tasks/test/utility.ts | 2 +- .../templates/templates.controller.spec.ts | 2 +- .../templates/templates.service.spec.ts | 41 +- .../src/features/terms/terms.service.spec.ts | 37 +- .../features/users/test/users.service.mock.ts | 2 +- .../src/features/users/test/utility.ts | 2 +- .../features/users/users.controller.spec.ts | 2 +- .../src/features/users/users.service.spec.ts | 255 +++-- .../workflows/workflows.controller.spec.ts | 2 +- .../workflows/workflows.service.spec.ts | 154 ++- 33 files changed, 1708 insertions(+), 835 deletions(-) create mode 100644 dictation_server/.devcontainer/pipeline-docker-compose.yml create mode 100644 dictation_server/.env.test create mode 100644 dictation_server/db/migrations/053-delete-license-alert.sql create mode 100644 dictation_server/src/common/test/init.ts diff --git a/azure-pipelines-staging.yml b/azure-pipelines-staging.yml index 86f970d..65c19c4 100644 --- a/azure-pipelines-staging.yml +++ b/azure-pipelines-staging.yml @@ -27,9 +27,30 @@ jobs: exit 1 fi displayName: 'タグが付けられたCommitがmainブランチに存在するか確認' -- job: backend_build +- job: backend_test dependsOn: initialize condition: succeeded('initialize') + displayName: UnitTest + pool: + vmImage: ubuntu-latest + steps: + - checkout: self + clean: true + fetchDepth: 1 + - task: Bash@3 + displayName: Bash Script (Test) + inputs: + targetType: inline + workingDirectory: dictation_server/.devcontainer + script: | + docker-compose -f pipeline-docker-compose.yml build + docker-compose -f pipeline-docker-compose.yml up -d + docker-compose exec -T dictation_server sudo npm ci + docker-compose exec -T dictation_server sudo npm run migrate:up:test + docker-compose exec -T dictation_server sudo npm run test +- job: backend_build + dependsOn: backend_test + condition: succeeded('backend_test') displayName: Build And Push Backend Image pool: name: odms-deploy-pipeline @@ -43,51 +64,6 @@ jobs: command: ci workingDir: dictation_server verbose: false - - task: AzureKeyVault@2 - displayName: 'Azure Key Vault: kv-odms-secret-stg' - inputs: - ConnectedServiceName: 'omds-service-connection-stg' - KeyVaultName: kv-odms-secret-stg - SecretsFilter: '*' - - task: Bash@3 - displayName: Bash Script (Test) - inputs: - targetType: inline - script: | - cd dictation_server - npm run test - env: - JWT_PUBLIC_KEY: $(token-public-key) - JWT_PRIVATE_KEY: $(token-private-key) - SENDGRID_API_KEY: $(sendgrid-api-key) - NOTIFICATION_HUB_NAME: $(notification-hub-name) - NOTIFICATION_HUB_CONNECT_STRING: $(notification-hub-connect-string) - STORAGE_ACCOUNT_NAME_US: $(storage-account-name-us) - STORAGE_ACCOUNT_NAME_AU: $(storage-account-name-au) - STORAGE_ACCOUNT_NAME_EU: $(storage-account-name-eu) - STORAGE_ACCOUNT_KEY_US: $(storage-account-key-us) - STORAGE_ACCOUNT_KEY_AU: $(storage-account-key-au) - STORAGE_ACCOUNT_KEY_EU: $(storage-account-key-eu) - STORAGE_ACCOUNT_ENDPOINT_US: $(storage-account-endpoint-us) - STORAGE_ACCOUNT_ENDPOINT_AU: $(storage-account-endpoint-au) - STORAGE_ACCOUNT_ENDPOINT_EU: $(storage-account-endpoint-eu) - ADB2C_TENANT_ID: $(adb2c-tenant-id) - ADB2C_CLIENT_ID: $(adb2c-client-id) - ADB2C_CLIENT_SECRET: $(adb2c-client-secret) - MAIL_FROM: xxxxxx - APP_DOMAIN: xxxxxxxxx - EMAIL_CONFIRM_LIFETIME: 0 - TENANT_NAME: xxxxxxxxxxxx - SIGNIN_FLOW_NAME: xxxxxxxxxxxx - STORAGE_TOKEN_EXPIRE_TIME: 0 - REFRESH_TOKEN_LIFETIME_WEB: 86400000 - REFRESH_TOKEN_LIFETIME_DEFAULT: 2592000000 - ACCESS_TOKEN_LIFETIME_WEB: 7200000 - REDIS_HOST: xxxxxxxxxxxx - REDIS_PORT: 0 - REDIS_PASSWORD: xxxxxxxxxxxx - ADB2C_CACHE_TTL: 0 - STAGE: local - task: Docker@0 displayName: build inputs: diff --git a/dictation_server/.devcontainer/docker-compose.yml b/dictation_server/.devcontainer/docker-compose.yml index 47cf396..ca3a9a8 100644 --- a/dictation_server/.devcontainer/docker-compose.yml +++ b/dictation_server/.devcontainer/docker-compose.yml @@ -2,6 +2,7 @@ version: '3' services: dictation_server: + container_name: dictation_server_dev_container env_file: ../.env build: . working_dir: /app/dictation_server @@ -16,6 +17,15 @@ services: - CHOKIDAR_USEPOLLING=true networks: - external + test_mysql_db: + image: mysql:8.0-bullseye + environment: + MYSQL_ROOT_PASSWORD: root_password + MYSQL_DATABASE: odms + MYSQL_USER: user + MYSQL_PASSWORD: password + networks: + - external networks: external: name: omds_network diff --git a/dictation_server/.devcontainer/pipeline-docker-compose.yml b/dictation_server/.devcontainer/pipeline-docker-compose.yml new file mode 100644 index 0000000..19708a2 --- /dev/null +++ b/dictation_server/.devcontainer/pipeline-docker-compose.yml @@ -0,0 +1,35 @@ +version: '3' + +services: + dictation_server: + container_name: dictation_server_dev_container + env_file: ../.env + build: . + working_dir: /app/dictation_server + ports: + - '8081:8081' + volumes: + - ../../:/app + - node_modules:/app/dictation_server/node_modules + expose: + - '8081' + environment: + - CHOKIDAR_USEPOLLING=true + depends_on: + - test_mysql_db + networks: + - network + test_mysql_db: + image: mysql:8.0-bullseye + environment: + MYSQL_ROOT_PASSWORD: root_password + MYSQL_DATABASE: odms + MYSQL_USER: user + MYSQL_PASSWORD: password + networks: + - network +networks: + network: + name: test_network +volumes: + node_modules: \ No newline at end of file diff --git a/dictation_server/.env.test b/dictation_server/.env.test new file mode 100644 index 0000000..a2748df --- /dev/null +++ b/dictation_server/.env.test @@ -0,0 +1,37 @@ +STAGE=local +NO_COLOR=TRUE +CORS=TRUE +PORT=8081 +TENANT_NAME=xxxxxxxxxx +SIGNIN_FLOW_NAME=b2c_1_signin_xxx +ADB2C_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +ADB2C_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +ADB2C_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +ADB2C_ORIGIN=https://example.com/xxxxxxxxx.onmicrosoft.com/b2c_1_signin_xxx/ +KEY_VAULT_NAME=xxxxxxxxxxxx +JWT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA5IZZNgDew9eGmuFTezwdHYLSaJvUPPIKYoiOeVLD1paWNI51\n7Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3yCTR6wcWR3PfFJrl9vh5SOo79koZ\noJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbWFJXnDe0DVXYXpJLb4LAlF2XAyYX0\nSYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qSfiL9zWk9dvHoKzSnfSDzDFoFcEoV\nchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//mBNNaDHv83Yuw3mGShT73iJ0JQdk\nTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GOOQIDAQABAoIBADrwp7u097+dK/tw\nWD61n3DIGAqg/lmFt8X4IH8MKLSE/FKr16CS1bqwOEuIM3ZdUtDeXd9Xs7IsyEPE\n5ZwuXK7DSF0M4+Mj8Ip49Q0Aww9aUoLQU9HGfgN/r4599GTrt31clZXA/6Mlighq\ncOZgCcEfdItz8OMu5SQuOIW4CKkCuaWnPOP26UqZocaXNZfpZH0iFLATMMH/TT8x\nay9ToHTQYE17ijdQ/EOLSwoeDV1CU1CIE3P4YfLJjvpKptly5dTevriHEzBi70Jx\n/KEPUn9Jj2gZafrUxRVhmMbm1zkeYxL3gsqRuTzRjEeeILuZhSJyCkQZyUNARxsg\nQY4DZfECgYEA+YLKUtmYTx60FS6DJ4s31TAsXY8kwhq/lB9E3GBZKDd0DPayXEeK\n4UWRQDTT6MI6fedW69FOZJ5sFLp8HQpcssb4Weq9PCpDhNTx8MCbdH3Um5QR3vfW\naKq/1XM8MDUnx5XcNYd87Aw3azvJAvOPr69as8IPnj6sKaRR9uQjbYUCgYEA6nfV\n5j0qmn0EJXZJblk4mvvjLLoWSs17j9YlrZJlJxXMDFRYtgnelv73xMxOMvcGoxn5\nifs7dpaM2x5EmA6jVU5sYaB/beZGEPWqPYGyjIwXPvUGAAv8Gbnvpp+xlSco/Dum\nIq0w+43ry5/xWh6CjfrvKV0J2bDOiJwPEdu/8iUCgYEAnBBSvL+dpN9vhFAzeOh7\nY71eAqcmNsLEUcG9MJqTKbSFwhYMOewF0iHRWHeylEPokhfBJn8kqYrtz4lVWFTC\n5o/Nh3BsLNXCpbMMIapXkeWiti1HgE9ErPMgSkJpwz18RDpYIqM8X+jEQS6D7HSr\nyxfDg+w+GJza0rEVE3hfMIECgYBw+KZ2VfhmEWBjEHhXE+QjQMR3s320MwebCUqE\nNCpKx8TWF/naVC0MwfLtvqbbBY0MHyLN6d//xpA9r3rLbRojqzKrY2KiuDYAS+3n\nzssRzxoQOozWju+8EYu30/ADdqfXyIHG6X3VZs87AGiQzGyJLmP3oR1y5y7MQa09\nJI16hQKBgHK5uwJhGa281Oo5/FwQ3uYLymbNwSGrsOJXiEu2XwJEXwVi2ELOKh4/\n03pBk3Kva3fIwEK+vCzDNnxShIQqBE76/2I1K1whOfoUehhYvKHGaXl2j70Zz9Ks\nrkGW1cx7p+yDqATDrwHBHTHFh5bUTTn8dN40n0e0W/llurpbBkJM\n-----END RSA PRIVATE KEY-----\n" +JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd\nHYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3\nyCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW\nFJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS\nfiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//\nmBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO\nOQIDAQAB\n-----END PUBLIC KEY-----\n" +SENDGRID_API_KEY=SG.P_xxxx_xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx-pc +MAIL_FROM=noreply@example.com +NOTIFICATION_HUB_NAME=ntf-odms-dev +NOTIFICATION_HUB_CONNECT_STRING=Endpoint=sb://example.com/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= +APP_DOMAIN=http://localhost:8081/ +STORAGE_TOKEN_EXPIRE_TIME=30 +STORAGE_ACCOUNT_NAME_US=saxxxxusxxx +STORAGE_ACCOUNT_NAME_AU=saxxxxauxxx +STORAGE_ACCOUNT_NAME_EU=saxxxxeuxxx +STORAGE_ACCOUNT_KEY_US=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX== +STORAGE_ACCOUNT_KEY_AU=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX== +STORAGE_ACCOUNT_KEY_EU=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX== +STORAGE_ACCOUNT_ENDPOINT_US=https://xxxxxxxxxxxx.blob.core.windows.net/ +STORAGE_ACCOUNT_ENDPOINT_AU=https://xxxxxxxxxxxx.blob.core.windows.net/ +STORAGE_ACCOUNT_ENDPOINT_EU=https://xxxxxxxxxxxx.blob.core.windows.net/ +ACCESS_TOKEN_LIFETIME_WEB=7200000 +REFRESH_TOKEN_LIFETIME_WEB=86400000 +REFRESH_TOKEN_LIFETIME_DEFAULT=2592000000 +EMAIL_CONFIRM_LIFETIME=86400000 +REDIS_HOST=redis-cache +REDIS_PORT=6379 +REDIS_PASSWORD=omdsredispass +ADB2C_CACHE_TTL=86400 +TEMPLATE_ROOT=dist \ No newline at end of file diff --git a/dictation_server/db/dbconfig.yml b/dictation_server/db/dbconfig.yml index 25fdfa9..f19fc0c 100644 --- a/dictation_server/db/dbconfig.yml +++ b/dictation_server/db/dbconfig.yml @@ -6,3 +6,7 @@ ci: dialect: mysql dir: ./dictation_server/db/migrations datasource: DB_USERNAME:DB_PASS@tcp(DB_HOST:DB_PORT)/DB_NAME?charset=utf8mb4&collation=utf8mb4_0900_ai_ci&parseTime=true +test: + dialect: mysql + dir: /app/dictation_server/db/migrations + datasource: user:password@tcp(test_mysql_db:3306)/odms?charset=utf8mb4&collation=utf8mb4_0900_ai_ci&parseTime=true \ No newline at end of file diff --git a/dictation_server/db/migrations/053-delete-license-alert.sql b/dictation_server/db/migrations/053-delete-license-alert.sql new file mode 100644 index 0000000..e7e6871 --- /dev/null +++ b/dictation_server/db/migrations/053-delete-license-alert.sql @@ -0,0 +1,6 @@ +-- +migrate Up +ALTER TABLE `users_archive` DROP COLUMN `license_alert`; + + +-- +migrate Down +ALTER TABLE `users_archive` ADD COLUMN `license_alert` BOOLEAN NOT NULL COMMENT 'ライセンスの期限切れ通知をするかどうか'; \ No newline at end of file diff --git a/dictation_server/package.json b/dictation_server/package.json index 1afac08..7ca9f5b 100644 --- a/dictation_server/package.json +++ b/dictation_server/package.json @@ -17,7 +17,7 @@ "tc": "tsc --noEmit", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"", "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "test": "jest", + "test": "jest -w 1", "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", @@ -26,7 +26,8 @@ "openapi-format": "cat \"src/api/odms/openapi.json\" | jq -c . > \"src/api/odms/openapi.json\" && prettier --write \"src/api/odms/*.json\"", "migrate:up": "sql-migrate up -config=/app/dictation_server/db/dbconfig.yml -env=local", "migrate:down": "sql-migrate down -config=/app/dictation_server/db/dbconfig.yml -env=local", - "migrate:status": "sql-migrate status -config=/app/dictation_server/db/dbconfig.yml -env=local" + "migrate:status": "sql-migrate status -config=/app/dictation_server/db/dbconfig.yml -env=local", + "migrate:up:test": "sql-migrate up -config=/app/dictation_server/db/dbconfig.yml -env=test" }, "dependencies": { "@azure/identity": "^3.1.3", diff --git a/dictation_server/src/common/test/init.ts b/dictation_server/src/common/test/init.ts new file mode 100644 index 0000000..e919d16 --- /dev/null +++ b/dictation_server/src/common/test/init.ts @@ -0,0 +1,21 @@ +import { DataSource } from "typeorm"; + +export const truncateAllTable = async (source: DataSource) => { + const entities = source.entityMetadatas; + const queryRunner = source.createQueryRunner(); + + try { + await queryRunner.startTransaction(); + await queryRunner.query('SET FOREIGN_KEY_CHECKS=0'); + for (const entity of entities) { + await queryRunner.query(`TRUNCATE TABLE \`${entity.tableName}\``); + } + await queryRunner.query('SET FOREIGN_KEY_CHECKS=1'); + await queryRunner.commitTransaction(); + } catch (err) { + await queryRunner.rollbackTransaction(); + throw err; + } finally { + await queryRunner.release(); + } +}; \ No newline at end of file diff --git a/dictation_server/src/common/test/modules.ts b/dictation_server/src/common/test/modules.ts index 61c0396..7c51a50 100644 --- a/dictation_server/src/common/test/modules.ts +++ b/dictation_server/src/common/test/modules.ts @@ -48,7 +48,7 @@ export const makeTestingModule = async ( const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), AuthModule, diff --git a/dictation_server/src/features/accounts/accounts.controller.spec.ts b/dictation_server/src/features/accounts/accounts.controller.spec.ts index 2761b0e..f69ece1 100644 --- a/dictation_server/src/features/accounts/accounts.controller.spec.ts +++ b/dictation_server/src/features/accounts/accounts.controller.spec.ts @@ -13,7 +13,7 @@ describe('AccountsController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index 9b192c9..4bfd687 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -78,23 +78,36 @@ import { AccountsRepositoryService } from '../../repositories/accounts/accounts. import { UsersRepositoryService } from '../../repositories/users/users.repository.service'; import { createWorkflow, getWorkflows } from '../workflows/test/utility'; import { UsersService } from '../users/users.service'; +import { truncateAllTable } from '../../common/test/init'; describe('createAccount', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('アカウントを作成できる', async () => { @@ -754,20 +767,32 @@ describe('createAccount', () => { describe('createPartnerAccount', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1740,20 +1765,32 @@ describe('AccountsService', () => { describe('getLicenseSummary', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('第五階層のライセンス情報を取得する', async () => { @@ -1787,7 +1824,7 @@ describe('getLicenseSummary', () => { // 有効期限が14日後のライセンスを追加(5ライセンス) const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + 14); - expiryDate.setHours(23, 59, 59, 999); + expiryDate.setHours(23, 59, 59, 0); for (let i = 0; i < 5; i++) { await createLicenseSetExpiryDateAndStatus( source, @@ -1812,7 +1849,7 @@ describe('getLicenseSummary', () => { await createLicenseSetExpiryDateAndStatus( source, childAccountId1, - new Date(2500, 1, 1, 23, 59, 59), + new Date(2037, 1, 1, 23, 59, 59), element, 1, ); @@ -1823,7 +1860,7 @@ describe('getLicenseSummary', () => { await createLicenseSetExpiryDateAndStatus( source, childAccountId2, - new Date(2500, 1, 1, 23, 59, 59), + new Date(2037, 1, 1, 23, 59, 59), 'Unallocated', ); } @@ -1887,20 +1924,32 @@ describe('getLicenseSummary', () => { describe('getPartnerAccount', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1942,7 +1991,7 @@ describe('getPartnerAccount', () => { // 有効期限が14日後のライセンスを追加(5ライセンス) const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + 14); - expiryDate.setHours(23, 59, 59, 999); + expiryDate.setHours(23, 59, 59, 0); for (let i = 0; i < 5; i++) { await createLicenseSetExpiryDateAndStatus( source, @@ -1960,7 +2009,7 @@ describe('getPartnerAccount', () => { // 有効期限が15日後のライセンスを追加 expiryDate.setDate(expiryDate.getDate() + 15); - expiryDate.setHours(23, 59, 59, 999); + expiryDate.setHours(23, 59, 59, 0); await createLicenseSetExpiryDateAndStatus( source, childAccountId3, @@ -1975,7 +2024,7 @@ describe('getPartnerAccount', () => { await createLicenseSetExpiryDateAndStatus( source, childAccountId1, - new Date(2500, 1, 1, 23, 59, 59), + new Date(2037, 1, 1, 23, 59, 59), element, ); }); @@ -1985,7 +2034,7 @@ describe('getPartnerAccount', () => { await createLicenseSetExpiryDateAndStatus( source, childAccountId2, - new Date(2500, 1, 1, 23, 59, 59), + new Date(2037, 1, 1, 23, 59, 59), 'Unallocated', ); } @@ -2029,20 +2078,32 @@ describe('getPartnerAccount', () => { describe('getOrderHistories', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2161,20 +2222,32 @@ describe('getOrderHistories', () => { describe('issueLicense', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2468,20 +2541,32 @@ describe('issueLicense', () => { describe('getDealers', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('Dealerを取得できる', async () => { @@ -2551,20 +2636,32 @@ describe('getDealers', () => { describe('createTypistGroup', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('TypistGroupを作成できる', async () => { @@ -2851,20 +2948,32 @@ describe('createTypistGroup', () => { describe('getTypistGroup', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('指定したIDのTypistGroupを取得できる', async () => { @@ -3051,20 +3160,32 @@ describe('getTypistGroup', () => { describe('updateTypistGroup', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('TypistGroupを更新できる', async () => { @@ -3467,20 +3588,32 @@ describe('updateTypistGroup', () => { describe('getWorktypes', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -3587,20 +3720,32 @@ describe('getWorktypes', () => { describe('createWorktype', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -3740,20 +3885,32 @@ describe('createWorktype', () => { describe('updateWorktype', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -4019,20 +4176,32 @@ describe('updateWorktype', () => { describe('deleteWorktype', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -4267,20 +4436,32 @@ describe('deleteWorktype', () => { describe('getOptionItems', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -4406,20 +4587,32 @@ describe('getOptionItems', () => { describe('updateOptionItems', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -4732,20 +4925,32 @@ describe('updateOptionItems', () => { describe('updateActiveWorktype', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -4960,20 +5165,32 @@ describe('updateActiveWorktype', () => { describe('ライセンス発行キャンセル', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('ライセンス発行のキャンセルが完了する(第一階層で実行)', async () => { @@ -5274,20 +5491,32 @@ describe('ライセンス発行キャンセル', () => { describe('パートナー一覧取得', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('パートナー一覧を取得する', async () => { @@ -5442,20 +5671,32 @@ describe('パートナー一覧取得', () => { describe('アカウント情報更新', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('アカウント情報を更新する(第五階層が実行/セカンダリ管理者ユーザがnull)', async () => { @@ -5660,20 +5901,32 @@ describe('アカウント情報更新', () => { describe('getAccountInfo', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('パラメータのユーザに対応するアカウント情報を取得できる', async () => { @@ -5720,20 +5973,32 @@ describe('getAccountInfo', () => { }); describe('getAuthors', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('アカウント内のAuthorユーザーの一覧を取得できる', async () => { @@ -5872,20 +6137,32 @@ describe('getAuthors', () => { describe('getTypists', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('アカウント内のTypistユーザーの一覧を取得できる', async () => { @@ -6054,20 +6331,32 @@ describe('getTypists', () => { describe('deleteAccountAndData', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('アカウント情報が削除されること', async () => { @@ -6450,20 +6739,32 @@ describe('deleteAccountAndData', () => { }); describe('getAccountInfoMinimalAccess', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('IDトークンのsub情報からアカウントの階層情報を取得できること(第五階層)', async () => { @@ -6583,20 +6884,32 @@ describe('getAccountInfoMinimalAccess', () => { }); describe('getCompanyName', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); diff --git a/dictation_server/src/features/auth/auth.controller.spec.ts b/dictation_server/src/features/auth/auth.controller.spec.ts index 93a7999..a762b74 100644 --- a/dictation_server/src/features/auth/auth.controller.spec.ts +++ b/dictation_server/src/features/auth/auth.controller.spec.ts @@ -14,7 +14,7 @@ describe('AuthController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/auth/auth.service.spec.ts b/dictation_server/src/features/auth/auth.service.spec.ts index 856f719..c0b47d4 100644 --- a/dictation_server/src/features/auth/auth.service.spec.ts +++ b/dictation_server/src/features/auth/auth.service.spec.ts @@ -20,6 +20,7 @@ import { v4 as uuidv4 } from 'uuid'; import { TIERS, USER_ROLES } from '../../constants'; import { decode, isVerifyError } from '../../common/jwt'; import { RefreshToken, AccessToken } from '../../common/token'; +import { truncateAllTable } from '../../common/test/init'; describe('AuthService', () => { it('IDトークンの検証とペイロードの取得に成功する', async () => { @@ -162,20 +163,32 @@ describe('AuthService', () => { describe('checkIsAcceptedLatestVersion', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('同意済み利用規約バージョンが最新のときにチェックが通ること(第五)', async () => { @@ -325,20 +338,32 @@ describe('checkIsAcceptedLatestVersion', () => { describe('generateDelegationRefreshToken', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('代行操作が許可されたパートナーの代行操作用リフレッシュトークンを取得できること', async () => { @@ -459,20 +484,32 @@ describe('generateDelegationRefreshToken', () => { describe('generateDelegationAccessToken', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('代行操作用リフレッシュトークンから代行操作用アクセストークンを取得できること', async () => { @@ -558,20 +595,32 @@ describe('generateDelegationAccessToken', () => { describe('updateDelegationAccessToken', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -743,7 +792,7 @@ describe('updateDelegationAccessToken', () => { } // 代行操作対象アカウントを削除 - deleteAccount(source, partnerAccount.id); + await deleteAccount(source, partnerAccount.id); try { await service.updateDelegationAccessToken( diff --git a/dictation_server/src/features/files/files.controller.spec.ts b/dictation_server/src/features/files/files.controller.spec.ts index 9b7eb76..3986b38 100644 --- a/dictation_server/src/features/files/files.controller.spec.ts +++ b/dictation_server/src/features/files/files.controller.spec.ts @@ -10,7 +10,7 @@ describe('FilesController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/files/files.service.spec.ts b/dictation_server/src/features/files/files.service.spec.ts index 89c9f68..62e4286 100644 --- a/dictation_server/src/features/files/files.service.spec.ts +++ b/dictation_server/src/features/files/files.service.spec.ts @@ -40,23 +40,36 @@ import { TASK_STATUS, USER_ROLES, } from '../../constants'; +import { truncateAllTable } from '../../common/test/init'; describe('publishUploadSas', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -287,20 +300,32 @@ describe('publishUploadSas', () => { describe('タスク作成から自動ルーティング(DB使用)', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('タスク作成時に、自動ルーティングを行うことができる(APIの引数として渡されたAuthorIDとworkType)', async () => { @@ -997,20 +1022,32 @@ describe('タスク作成から自動ルーティング(DB使用)', () => { describe('音声ファイルダウンロードURL取得', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1490,20 +1527,32 @@ describe('音声ファイルダウンロードURL取得', () => { describe('テンプレートファイルダウンロードURL取得', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1933,20 +1982,32 @@ describe('テンプレートファイルダウンロードURL取得', () => { describe('publishTemplateFileUploadSas', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2036,20 +2097,32 @@ describe('publishTemplateFileUploadSas', () => { describe('templateUploadFinished', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); diff --git a/dictation_server/src/features/files/test/utility.ts b/dictation_server/src/features/files/test/utility.ts index 12bb21c..1fe086b 100644 --- a/dictation_server/src/features/files/test/utility.ts +++ b/dictation_server/src/features/files/test/utility.ts @@ -152,7 +152,7 @@ export const makeTestingModuleWithBlobAndNotification = async ( const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), AuthModule, diff --git a/dictation_server/src/features/licenses/licenses.controller.spec.ts b/dictation_server/src/features/licenses/licenses.controller.spec.ts index 70daf6c..1b3fdc4 100644 --- a/dictation_server/src/features/licenses/licenses.controller.spec.ts +++ b/dictation_server/src/features/licenses/licenses.controller.spec.ts @@ -11,7 +11,7 @@ describe('LicensesController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/licenses/licenses.service.spec.ts b/dictation_server/src/features/licenses/licenses.service.spec.ts index 1a5b023..63db663 100644 --- a/dictation_server/src/features/licenses/licenses.service.spec.ts +++ b/dictation_server/src/features/licenses/licenses.service.spec.ts @@ -26,23 +26,36 @@ import { } from '../../common/test/utility'; import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service'; import { overrideSendgridService } from '../../common/test/overrides'; +import { truncateAllTable } from '../../common/test/init'; describe('ライセンス注文', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -190,20 +203,32 @@ describe('ライセンス注文', () => { describe('カードライセンス発行', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -268,20 +293,32 @@ describe('カードライセンス発行', () => { describe('カードライセンスを取り込む', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); it('カードライセンス取り込みが完了する', async () => { @@ -601,20 +638,32 @@ describe('カードライセンスを取り込む', () => { describe('ライセンス割り当て', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -702,6 +751,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -768,6 +818,8 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); + await createLicense( source, 1, @@ -874,6 +926,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -939,6 +992,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1004,6 +1058,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1069,6 +1124,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() - 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1110,6 +1166,7 @@ describe('ライセンス割り当て', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1161,20 +1218,32 @@ describe('ライセンス割り当て', () => { describe('ライセンス割り当て解除', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1192,6 +1261,7 @@ describe('ライセンス割り当て解除', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1271,6 +1341,7 @@ describe('ライセンス割り当て解除', () => { }); const date = new Date(); date.setDate(date.getDate() + 30); + date.setMilliseconds(0); await createLicense( source, 1, @@ -1316,20 +1387,32 @@ describe('ライセンス割り当て解除', () => { describe('ライセンス注文キャンセル', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); diff --git a/dictation_server/src/features/licenses/test/utility.ts b/dictation_server/src/features/licenses/test/utility.ts index 321f9c0..3dfdda3 100644 --- a/dictation_server/src/features/licenses/test/utility.ts +++ b/dictation_server/src/features/licenses/test/utility.ts @@ -172,6 +172,7 @@ export const selectLicenseAllocationHistory = async ( license_id: licence_id, }, order: { + id: 'DESC', executed_at: 'DESC', }, }); diff --git a/dictation_server/src/features/notification/notification.controller.spec.ts b/dictation_server/src/features/notification/notification.controller.spec.ts index fc14685..bbf71a7 100644 --- a/dictation_server/src/features/notification/notification.controller.spec.ts +++ b/dictation_server/src/features/notification/notification.controller.spec.ts @@ -10,7 +10,7 @@ describe('NotificationController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/notification/test/notification.service.mock.ts b/dictation_server/src/features/notification/test/notification.service.mock.ts index b11c985..1984c27 100644 --- a/dictation_server/src/features/notification/test/notification.service.mock.ts +++ b/dictation_server/src/features/notification/test/notification.service.mock.ts @@ -21,7 +21,7 @@ export const makeNotificationServiceMock = async ( providers: [NotificationService], imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], }), ], }) diff --git a/dictation_server/src/features/tasks/tasks.controller.spec.ts b/dictation_server/src/features/tasks/tasks.controller.spec.ts index 01e7e75..72b8ac5 100644 --- a/dictation_server/src/features/tasks/tasks.controller.spec.ts +++ b/dictation_server/src/features/tasks/tasks.controller.spec.ts @@ -10,7 +10,7 @@ describe('TasksController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/tasks/tasks.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts index eaf6e56..02d361c 100644 --- a/dictation_server/src/features/tasks/tasks.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -37,6 +37,7 @@ import { createTemplateFile } from '../templates/test/utility'; import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service'; import { Roles } from '../../common/types/role'; import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service'; +import { truncateAllTable } from '../../common/test/init'; describe('TasksService', () => { it('タスク一覧を取得できる(admin)', async () => { @@ -584,22 +585,34 @@ describe('TasksService', () => { describe('DBテスト', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); - }); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } + }); - afterEach(async () => { - if (!source) return; - await source.destroy(); - source = null; - }); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); + source = null; + }); it('[Admin] Taskが0件であっても実行できる', async () => { const notificationhubServiceMockValue = @@ -775,20 +788,32 @@ describe('TasksService', () => { describe('changeCheckoutPermission', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1405,20 +1430,32 @@ describe('changeCheckoutPermission', () => { describe('checkout', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1605,7 +1642,6 @@ describe('checkout', () => { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', - author_id: 'MY_AUTHOR_ID', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, @@ -1652,7 +1688,6 @@ describe('checkout', () => { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', - author_id: 'MY_AUTHOR_ID', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, @@ -1989,20 +2024,32 @@ describe('checkout', () => { describe('checkin', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2192,20 +2239,32 @@ describe('checkin', () => { describe('suspend', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2391,20 +2450,32 @@ describe('suspend', () => { describe('cancel', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -3007,20 +3078,32 @@ describe('cancel', () => { describe('backup', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -3301,20 +3384,32 @@ describe('backup', () => { describe('getNextTask', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); diff --git a/dictation_server/src/features/tasks/test/utility.ts b/dictation_server/src/features/tasks/test/utility.ts index b4de930..171f061 100644 --- a/dictation_server/src/features/tasks/test/utility.ts +++ b/dictation_server/src/features/tasks/test/utility.ts @@ -47,7 +47,7 @@ export const makeTaskTestingModuleWithNotificaiton = async ( const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), AuthModule, diff --git a/dictation_server/src/features/templates/templates.controller.spec.ts b/dictation_server/src/features/templates/templates.controller.spec.ts index 00bd2fc..20ffb00 100644 --- a/dictation_server/src/features/templates/templates.controller.spec.ts +++ b/dictation_server/src/features/templates/templates.controller.spec.ts @@ -10,7 +10,7 @@ describe('TemplatesController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/templates/templates.service.spec.ts b/dictation_server/src/features/templates/templates.service.spec.ts index a366b30..8ef101f 100644 --- a/dictation_server/src/features/templates/templates.service.spec.ts +++ b/dictation_server/src/features/templates/templates.service.spec.ts @@ -7,24 +7,37 @@ import { makeContext } from '../../common/log'; import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service'; import { HttpException, HttpStatus } from '@nestjs/common'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; +import { truncateAllTable } from '../../common/test/init'; describe('getTemplates', () => { - let source: DataSource | undefined = undefined; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + let source: DataSource | null = null; + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); - source = undefined; + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); + source = null; }); it('テンプレートファイル一覧を取得できる', async () => { diff --git a/dictation_server/src/features/terms/terms.service.spec.ts b/dictation_server/src/features/terms/terms.service.spec.ts index 5950404..4a6ac7e 100644 --- a/dictation_server/src/features/terms/terms.service.spec.ts +++ b/dictation_server/src/features/terms/terms.service.spec.ts @@ -6,23 +6,36 @@ import { makeContext } from '../../common/log'; import { v4 as uuidv4 } from 'uuid'; import { HttpException, HttpStatus } from '@nestjs/common'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; +import { truncateAllTable } from '../../common/test/init'; describe('利用規約取得', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); diff --git a/dictation_server/src/features/users/test/users.service.mock.ts b/dictation_server/src/features/users/test/users.service.mock.ts index 0984d0f..c2da3db 100644 --- a/dictation_server/src/features/users/test/users.service.mock.ts +++ b/dictation_server/src/features/users/test/users.service.mock.ts @@ -67,7 +67,7 @@ export const makeUsersServiceMock = async ( providers: [UsersService], imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], }), ], }) diff --git a/dictation_server/src/features/users/test/utility.ts b/dictation_server/src/features/users/test/utility.ts index 58a7512..849aa34 100644 --- a/dictation_server/src/features/users/test/utility.ts +++ b/dictation_server/src/features/users/test/utility.ts @@ -113,7 +113,7 @@ export const makeTestingModuleWithAdb2c = async ( const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), AuthModule, diff --git a/dictation_server/src/features/users/users.controller.spec.ts b/dictation_server/src/features/users/users.controller.spec.ts index b64a9fc..d060ac2 100644 --- a/dictation_server/src/features/users/users.controller.spec.ts +++ b/dictation_server/src/features/users/users.controller.spec.ts @@ -13,7 +13,7 @@ describe('UsersController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/users/users.service.spec.ts b/dictation_server/src/features/users/users.service.spec.ts index a02016e..dc3b656 100644 --- a/dictation_server/src/features/users/users.service.spec.ts +++ b/dictation_server/src/features/users/users.service.spec.ts @@ -46,21 +46,36 @@ import { import { v4 as uuidv4 } from 'uuid'; import { createOptionItems, createWorktype } from '../accounts/test/utility'; import { createWorkflow, getWorkflows } from '../workflows/test/utility'; +import { truncateAllTable } from '../../common/test/init'; describe('UsersService.confirmUser', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -419,20 +434,32 @@ describe('UsersService.confirmUserAndInitPassword', () => { describe('UsersService.createUser', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1364,20 +1391,32 @@ describe('UsersService.createUser', () => { describe('UsersService.getUsers', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1841,20 +1880,32 @@ describe('UsersService.getSortCriteria', () => { describe('UsersService.updateUser', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2425,20 +2476,32 @@ describe('UsersService.updateUser', () => { describe('UsersService.updateAcceptedVersion', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2513,20 +2576,32 @@ describe('UsersService.updateAcceptedVersion', () => { describe('UsersService.getUserName', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2555,20 +2630,32 @@ describe('UsersService.getUserName', () => { describe('UsersService.getRelations', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -2620,6 +2707,8 @@ describe('UsersService.getRelations', () => { // 作成したデータを確認 { const workflows = await getWorkflows(source, account.id); + workflows.sort((a, b) => a.id - b.id); + expect(workflows.length).toBe(4); expect(workflows[0].worktype_id).toBe(worktype1.id); expect(workflows[0].author_id).toBe(user1); diff --git a/dictation_server/src/features/workflows/workflows.controller.spec.ts b/dictation_server/src/features/workflows/workflows.controller.spec.ts index afab754..3b12b75 100644 --- a/dictation_server/src/features/workflows/workflows.controller.spec.ts +++ b/dictation_server/src/features/workflows/workflows.controller.spec.ts @@ -10,7 +10,7 @@ describe('WorkflowsController', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ - envFilePath: ['.env.local', '.env'], + envFilePath: ['.env.test', '.env'], isGlobal: true, }), ], diff --git a/dictation_server/src/features/workflows/workflows.service.spec.ts b/dictation_server/src/features/workflows/workflows.service.spec.ts index 7b0e3cc..d04e4c5 100644 --- a/dictation_server/src/features/workflows/workflows.service.spec.ts +++ b/dictation_server/src/features/workflows/workflows.service.spec.ts @@ -19,23 +19,36 @@ import { overrideAdB2cService } from '../../common/test/overrides'; import { WorkflowsRepositoryService } from '../../repositories/workflows/workflows.repository.service'; import { HttpException, HttpStatus } from '@nestjs/common'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; +import { truncateAllTable } from '../../common/test/init'; describe('getWorkflows', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await(async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -267,22 +280,34 @@ describe('getWorkflows', () => { describe('createWorkflows', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); - }); - afterEach(async () => { - if (!source) return; - await source.destroy(); - source = null; + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); + source = null; + }); it('アカウント内にWorkflowを作成できる(WorktypeIDあり、テンプレートファイルあり)', async () => { if (!source) fail(); const module = await makeTestingModule(source); @@ -606,6 +631,7 @@ describe('createWorkflows', () => { //実行結果を確認 { const workflows = await getWorkflows(source, account.id); + workflows.sort((a, b) => a.id - b.id); expect(workflows.length).toBe(2); expect(workflows[1].account_id).toBe(account.id); expect(workflows[1].author_id).toBe(authorId); @@ -1193,19 +1219,32 @@ describe('createWorkflows', () => { describe('updateWorkflow', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; }); @@ -1623,6 +1662,7 @@ describe('updateWorkflow', () => { //作成したデータを確認 { const workflows = await getWorkflows(source, account.id); + workflows.sort((a, b) => a.id - b.id); const workflowTypists = await getAllWorkflowTypists(source); expect(workflows.length).toBe(2); expect(workflows[0].id).toBe(preWorkflow1.id); @@ -1658,6 +1698,7 @@ describe('updateWorkflow', () => { //実行結果を確認 { const workflows = await getWorkflows(source, account.id); + workflows.sort((a, b) => a.id - b.id); expect(workflows.length).toBe(2); expect(workflows[1].account_id).toBe(account.id); expect(workflows[1].author_id).toBe(authorId2); @@ -2380,19 +2421,32 @@ describe('updateWorkflow', () => { describe('deleteWorkflows', () => { let source: DataSource | null = null; - beforeEach(async () => { - source = new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: false, - entities: [__dirname + '/../../**/*.entity{.ts,.js}'], - synchronize: true, // trueにすると自動的にmigrationが行われるため注意 - }); - return source.initialize(); + beforeAll(async () => { + if (source == null) { + source = await (async () => { + const s = new DataSource({ + type: 'mysql', + host: 'test_mysql_db', + port: 3306, + username: 'user', + password: 'password', + database: 'odms', + entities: [__dirname + '/../../**/*.entity{.ts,.js}'], + synchronize: false, // trueにすると自動的にmigrationが行われるため注意 + }); + return await s.initialize(); + })(); + } }); - afterEach(async () => { - if (!source) return; - await source.destroy(); + + beforeEach(async () => { + if (source) { + await truncateAllTable(source); + } + }); + + afterAll(async () => { + await source?.destroy(); source = null; });