Merged PR 669: Pipeline上でdocker-composeを用いてMySQLを起動する方法を調査する

## 概要
[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で実行して確認済
This commit is contained in:
湯本 開 2024-01-23 07:58:42 +00:00
parent 6e931c5afb
commit cf56239da2
33 changed files with 1708 additions and 835 deletions

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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 'ライセンスの期限切れ通知をするかどうか';

View File

@ -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",

View File

@ -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();
}
};

View File

@ -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,

View File

@ -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,
}),
],

View File

@ -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,
}),
],

View File

@ -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(

View File

@ -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,
}),
],

View File

@ -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;
});

View File

@ -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,

View File

@ -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,
}),
],

View File

@ -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;
});

View File

@ -172,6 +172,7 @@ export const selectLicenseAllocationHistory = async (
license_id: licence_id,
},
order: {
id: 'DESC',
executed_at: 'DESC',
},
});

View File

@ -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,
}),
],

View File

@ -21,7 +21,7 @@ export const makeNotificationServiceMock = async (
providers: [NotificationService],
imports: [
ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'],
envFilePath: ['.env.test', '.env'],
}),
],
})

View File

@ -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,
}),
],

View File

@ -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;
});

View File

@ -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,

View File

@ -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,
}),
],

View File

@ -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 () => {

View File

@ -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;
});

View File

@ -67,7 +67,7 @@ export const makeUsersServiceMock = async (
providers: [UsersService],
imports: [
ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'],
envFilePath: ['.env.test', '.env'],
}),
],
})

View File

@ -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,

View File

@ -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,
}),
],

View File

@ -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);

View File

@ -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,
}),
],

View File

@ -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;
});