import { makeDefaultAdb2cServiceMockValue, makeDefaultNotificationhubServiceMockValue, makeDefaultTasksRepositoryMockValue, makeDefaultUserGroupsRepositoryMockValue, makeDefaultUsersRepositoryMockValue, makeTasksServiceMock, } from './test/tasks.service.mock'; import { HttpException, HttpStatus } from '@nestjs/common'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; import { TasksService } from './tasks.service'; import { DataSource } from 'typeorm'; import { createAudioFile, createCheckoutPermissions, createTask, createUserGroup, getAudioFile, getAudioOptionItems, getCheckoutPermissions, getTask, makeTaskTestingModuleWithNotificaiton, } from './test/utility'; import { Adb2cTooManyRequestsError } from '../../gateways/adb2c/adb2c.service'; import { makeContext } from '../../common/log'; import { makeTestAccount, makeTestSimpleAccount, makeTestUser, } from '../../common/test/utility'; import { ADMIN_ROLES, LICENSE_ALLOCATED_STATUS, LICENSE_TYPE, TASK_STATUS, USER_ROLES, } from '../../constants'; import { makeTestingModule } from '../../common/test/modules'; import { createSortCriteria } from '../users/test/utility'; import { createWorktype } from '../accounts/test/utility'; import { createWorkflow, createWorkflowTypist, } from '../workflows/test/utility'; 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 { overrideBlobstorageService } from '../../common/test/overrides'; import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service'; import { truncateAllTable } from '../../common/test/init'; import { makeDefaultLicensesRepositoryMockValue } from '../accounts/test/accounts.service.mock'; import { DateWithZeroTime } from '../licenses/types/types'; import { createLicense } from '../licenses/test/utility'; describe('TasksService', () => { it('タスク一覧を取得できる(admin)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; expect( await service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ), ).toEqual({ tasks: [ { assignees: [{ typistName: 'XXXX XXX', typistUserId: 1 }], audioCreatedDate: '2023-01-01T01:01:01.000Z', audioDuration: '123000', audioFileId: 1, audioFinishedDate: '2023-01-01T01:01:01.000Z', audioFormat: 'DS', audioUploadedDate: '2023-01-01T01:01:01.000Z', authorId: 'AUTHOR', comment: 'comment', fileName: 'test.zip', fileSize: 123000, isEncrypted: true, jobNumber: '00000001', optionItemList: [ { optionItemLabel: 'label01', optionItemValue: 'value01' }, { optionItemLabel: 'label02', optionItemValue: 'value02' }, { optionItemLabel: 'label03', optionItemValue: 'value03' }, { optionItemLabel: 'label04', optionItemValue: 'value04' }, { optionItemLabel: 'label05', optionItemValue: 'value05' }, { optionItemLabel: 'label06', optionItemValue: 'value06' }, { optionItemLabel: 'label07', optionItemValue: 'value07' }, { optionItemLabel: 'label08', optionItemValue: 'value08' }, { optionItemLabel: 'label09', optionItemValue: 'value09' }, { optionItemLabel: 'label10', optionItemValue: 'value10' }, ], priority: '00', status: 'Uploaded', transcriptionFinishedDate: undefined, transcriptionStartedDate: undefined, typist: undefined, url: 'test/test.zip', workType: 'WorkType', }, ], total: 1, }); }); it('アカウント情報の取得に失敗した場合、エラーを返却する', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); usersRepositoryMockValue.findUserByExternalId = new Error('DB failed'); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('タスク一覧の取得に失敗した場合、エラーを返却する(admin)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); tasksRepositoryMockValue.getTasksFromAccountId = new Error('DB failed'); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('取得したタスク一覧が不正な形式の場合、エラーを返却する', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); tasksRepositoryMockValue.getTasksFromAccountId = { tasks: [ { id: 1, job_number: '00000001', account_id: 1, is_job_number_enabled: true, audio_file_id: 1, status: 'Uploaded', priority: '00', created_at: new Date('2023-01-01T01:01:01.000'), option_items: null, // 存在しない場合でも空配列であるはずのものがnullになっているため形式不正 finished_at: null, started_at: null, typist_user_id: null, template_file_id: null, typist_user: null, template_file: null, created_by: null, updated_by: null, updated_at: new Date('2023-01-01T01:01:01.000'), file: { id: 1, account_id: 1, owner_user_id: 1, url: 'test/test.zip', file_name: 'test.zip', author_id: 'AUTHOR', work_type_id: 'WorkType', started_at: new Date('2023-01-01T01:01:01.000'), duration: '123000', finished_at: new Date('2023-01-01T01:01:01.000'), uploaded_at: new Date('2023-01-01T01:01:01.000'), file_size: 123000, priority: '00', audio_format: 'DS', comment: 'comment', is_encrypted: true, deleted_at: null, task: null, }, }, ], permissions: [], count: 1, }; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('タスク一覧を取得できる(author)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); if (usersRepositoryMockValue.findUserByExternalId instanceof Error) { return; } usersRepositoryMockValue.findUserByExternalId.role = 'author'; const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const context = makeContext('trackingId', 'requestId'); const result = await service.tasksService.getTasks( context, userId, [USER_ROLES.AUTHOR], offset, limit, status, paramName, direction, ); expect(result).toEqual({ tasks: [ { assignees: [{ typistName: 'XXXX XXX', typistUserId: 1 }], audioCreatedDate: '2023-01-01T01:01:01.000Z', audioDuration: '123000', audioFileId: 1, audioFinishedDate: '2023-01-01T01:01:01.000Z', audioFormat: 'DS', audioUploadedDate: '2023-01-01T01:01:01.000Z', authorId: 'AUTHOR', comment: 'comment', fileName: 'test.zip', fileSize: 123000, isEncrypted: true, jobNumber: '00000001', optionItemList: [ { optionItemLabel: 'label01', optionItemValue: 'value01' }, { optionItemLabel: 'label02', optionItemValue: 'value02' }, { optionItemLabel: 'label03', optionItemValue: 'value03' }, { optionItemLabel: 'label04', optionItemValue: 'value04' }, { optionItemLabel: 'label05', optionItemValue: 'value05' }, { optionItemLabel: 'label06', optionItemValue: 'value06' }, { optionItemLabel: 'label07', optionItemValue: 'value07' }, { optionItemLabel: 'label08', optionItemValue: 'value08' }, { optionItemLabel: 'label09', optionItemValue: 'value09' }, { optionItemLabel: 'label10', optionItemValue: 'value10' }, ], priority: '00', status: 'Uploaded', transcriptionFinishedDate: undefined, transcriptionStartedDate: undefined, typist: undefined, url: 'test/test.zip', workType: 'WorkType', }, ], total: 1, }); expect( service.taskRepoService.getTasksFromAuthorIdAndAccountId, ).toHaveBeenCalledWith(context, 'abcdef', 1, 0, 20, 'JOB_NUMBER', 'ASC', [ 'Uploaded', 'Backup', ]); }); it('タスク一覧の取得に失敗した場合、エラーを返却する(author)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); tasksRepositoryMockValue.getTasksFromAuthorIdAndAccountId = new Error( 'DB failed', ); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [USER_ROLES.AUTHOR], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('タスク一覧を取得できる(typist)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); if (usersRepositoryMockValue.findUserByExternalId instanceof Error) { return; } usersRepositoryMockValue.findUserByExternalId.role = 'typist'; const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const context = makeContext('trackingId', 'requestId'); const result = await service.tasksService.getTasks( context, userId, [USER_ROLES.TYPIST], offset, limit, status, paramName, direction, ); expect(result).toEqual({ tasks: [ { assignees: [{ typistName: 'XXXX XXX', typistUserId: 1 }], audioCreatedDate: '2023-01-01T01:01:01.000Z', audioDuration: '123000', audioFileId: 1, audioFinishedDate: '2023-01-01T01:01:01.000Z', audioFormat: 'DS', audioUploadedDate: '2023-01-01T01:01:01.000Z', authorId: 'AUTHOR', comment: 'comment', fileName: 'test.zip', fileSize: 123000, isEncrypted: true, jobNumber: '00000001', optionItemList: [ { optionItemLabel: 'label01', optionItemValue: 'value01' }, { optionItemLabel: 'label02', optionItemValue: 'value02' }, { optionItemLabel: 'label03', optionItemValue: 'value03' }, { optionItemLabel: 'label04', optionItemValue: 'value04' }, { optionItemLabel: 'label05', optionItemValue: 'value05' }, { optionItemLabel: 'label06', optionItemValue: 'value06' }, { optionItemLabel: 'label07', optionItemValue: 'value07' }, { optionItemLabel: 'label08', optionItemValue: 'value08' }, { optionItemLabel: 'label09', optionItemValue: 'value09' }, { optionItemLabel: 'label10', optionItemValue: 'value10' }, ], priority: '00', status: 'Uploaded', transcriptionFinishedDate: undefined, transcriptionStartedDate: undefined, typist: undefined, url: 'test/test.zip', workType: 'WorkType', }, ], total: 1, }); expect( service.taskRepoService.getTasksFromTypistRelations, ).toHaveBeenCalledWith(context, 'userId', 0, 20, 'JOB_NUMBER', 'ASC', [ 'Uploaded', 'Backup', ]); }); it('タスク一覧の取得に失敗した場合、エラーを返却する(typist)', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); tasksRepositoryMockValue.getTasksFromTypistRelations = new Error( 'DB failed', ); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [USER_ROLES.TYPIST], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('AdB2Cのリクエスト上限超過時、専用のエラーを返却する', async () => { const tasksRepositoryMockValue = makeDefaultTasksRepositoryMockValue(); const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const userGroupsRepositoryMockValue = makeDefaultUserGroupsRepositoryMockValue(); const adb2cServiceMockValue = makeDefaultAdb2cServiceMockValue(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const licensesRepositoryMockValue = makeDefaultLicensesRepositoryMockValue(); adb2cServiceMockValue.getUsers = new Adb2cTooManyRequestsError(); const service = await makeTasksServiceMock( tasksRepositoryMockValue, usersRepositoryMockValue, userGroupsRepositoryMockValue, adb2cServiceMockValue, notificationhubServiceMockValue, licensesRepositoryMockValue, ); const userId = 'userId'; const offset = 0; const limit = 20; const status = ['Uploaded,Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; await expect( service.tasksService.getTasks( makeContext('trackingId', 'requestId'), userId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ), ).rejects.toEqual( new HttpException( makeErrorResponse('E000301'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); describe('DBテスト', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('[Admin] Taskが0件であっても実行できる', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); if (!source) fail(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: externalId } = await makeTestUser(source, { account_id: accountId, external_id: 'userId', role: 'admin', }); const service = module.get(TasksService); const offset = 0; const limit = 20; const status = ['Uploaded,Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const { tasks, total } = await service.getTasks( makeContext('trackingId', 'requestId'), externalId, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ); expect(tasks).toEqual([]); expect(total).toEqual(0); }); it('[Author] Authorは自分が作成者のTask一覧を取得できる', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); if (!source) fail(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: userId, external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'userId', role: 'author', author_id: 'MY_AUTHOR_ID', }); //「バグ 3661: [FB対応]Option Itemにチェックを付けると真っ白な画面になる」の確認のため // audio_file_idをTaskIdと異なる値にするために、AudioFileを作成 await createAudioFile( source, accountId, userId, 'MY_AUTHOR_ID', '', '00', ); // Taskを作成 await createTask( source, accountId, userId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); await createTask( source, accountId, userId, 'MY_AUTHOR_ID', '', '01', '00000002', 'Uploaded', ); const service = module.get(TasksService); const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const { tasks, total } = await service.getTasks( makeContext('trackingId', 'requestId'), external_id, [USER_ROLES.AUTHOR], offset, limit, status, paramName, direction, ); expect(total).toEqual(2); { const task = tasks[0]; expect(task.jobNumber).toEqual('00000001'); // AudioOptionItem const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { return { optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, }; }); expect(task.optionItemList).toEqual(audioOptionItems); } { const task = tasks[1]; expect(task.jobNumber).toEqual('00000002'); // AudioOptionItem const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { return { optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, }; }); expect(task.optionItemList).toEqual(audioOptionItems); } }); it('[Author] Authorは自分が作成者のTask一覧を取得できる(ソート条件がJob_number以外)', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); if (!source) fail(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: userId, external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'userId', role: 'author', author_id: 'MY_AUTHOR_ID', }); //「バグ 3661: [FB対応]Option Itemにチェックを付けると真っ白な画面になる」の確認のため // audio_file_idをTaskIdと異なる値にするために、AudioFileを作成 await createAudioFile( source, accountId, userId, 'MY_AUTHOR_ID', '', '00', ); // Taskを作成 await createTask( source, accountId, userId, 'MY_AUTHOR_ID', 'WORKTYPE1', '01', '00000001', 'Uploaded', ); await createTask( source, accountId, userId, 'MY_AUTHOR_ID', 'WORKTYPE2', '01', '00000002', 'Uploaded', ); const service = module.get(TasksService); const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; // バグ 3786: [FB対応]タスク一覧画面のOptionItemがソート条件によって表示順がおかしくなる の確認のため // Job_number以外のソート条件を指定 const paramName = 'WORK_TYPE'; const direction = 'DESC'; const { tasks, total } = await service.getTasks( makeContext('trackingId', 'requestId'), external_id, [USER_ROLES.AUTHOR], offset, limit, status, paramName, direction, ); expect(total).toEqual(2); { const task = tasks[0]; expect(task.jobNumber).toEqual('00000002'); // ソート条件がJob_number以外でもOptionItemがid順に取得されていることを確認 const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { return { optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, }; }); expect(task.optionItemList).toEqual(audioOptionItems); } { const task = tasks[1]; expect(task.jobNumber).toEqual('00000001'); // ソート条件がJob_number以外でもOptionItemがid順に取得されていることを確認 const audioOptionItems = Array.from({ length: 10 }).map((_, i) => { return { optionItemLabel: `label${i}:audio_file_id${task.audioFileId}`, optionItemValue: `value${i}:audio_file_id${task.audioFileId}`, }; }); expect(task.optionItemList).toEqual(audioOptionItems); } }); it('[Author] Authorは同一アカウントであっても自分以外のAuhtorのTaskは取得できない', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); if (!source) fail(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: userId_1, external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'userId_1', role: 'author', author_id: 'AUTHOR_ID_1', }); const { id: userId_2 } = await makeTestUser(source, { account_id: accountId, external_id: 'userId_2', role: 'author', author_id: 'AUTHOR_ID_2', }); await createTask( source, accountId, userId_1, 'AUTHOR_ID_1', '', '01', '00000001', 'Uploaded', ); await createTask( source, accountId, userId_2, 'AUTHOR_ID_2', '', '01', '00000002', 'Uploaded', ); const service = module.get(TasksService); const offset = 0; const limit = 20; const status = ['Uploaded', 'Backup']; const paramName = 'JOB_NUMBER'; const direction = 'ASC'; const { tasks, total } = await service.getTasks( makeContext('trackingId', 'requestId'), external_id, [USER_ROLES.AUTHOR], offset, limit, status, paramName, direction, ); expect(total).toEqual(1); { const task = tasks[0]; expect(task.jobNumber).toEqual('00000001'); } }); it('[Admin] Taskが100件であっても取得できる', async () => { const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); if (!source) fail(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'userId', role: 'none', }); const { id: authorUserId, author_id } = await makeTestUser(source, { account_id: accountId, external_id: 'userId', author_id: 'MY_AUTHOR_ID', role: 'author', }); const service = module.get(TasksService); for (let i = 0; i < 100; i++) { await createTask( source, accountId, authorUserId, author_id ?? '', `WORKTYPE${i + 1}`, '01', // 00000001 ~ 00000100 `000000${String(i + 1).padStart(2, '0')}`, 'Uploaded', ); } const offset = 0; const limit = 100; const status = ['Uploaded', 'Backup']; const paramName = 'WORK_TYPE'; const direction = 'DESC'; const { tasks, total } = await service.getTasks( makeContext('trackingId', 'requestId'), external_id, [ADMIN_ROLES.ADMIN, USER_ROLES.NONE], offset, limit, status, paramName, direction, ); expect(tasks.length).toEqual(100); expect(total).toEqual(100); // ソート条件がWORK_TYPEのため、WORK_TYPEが降順になっていることを確認 expect(tasks[0].workType).toEqual('WORKTYPE99'); expect(tasks[99].workType).toEqual('WORKTYPE1'); expect(tasks[0].optionItemList).toEqual( Array.from({ length: 10 }).map((_, i) => { return { optionItemLabel: `label${i}:audio_file_id${tasks[0].audioFileId}`, optionItemValue: `value${i}:audio_file_id${tasks[0].audioFileId}`, }; }), ); }); }); }); describe('changeCheckoutPermission', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('タスクのチェックアウト権限を変更できる。(個人指定)', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: typistUserId_2 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-2-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); const NotificationHubService = module.get( NotificationhubService, ); await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'typist-user-2', typistUserId: typistUserId_2 }], 'author-user-external-id', ['admin'], ); const permisions = await getCheckoutPermissions(source, taskId); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 3, task_id: taskId, user_id: typistUserId_2, user_group_id: null, }); const resultTask = await getTask(source, taskId); // 通知処理が想定通りの引数で呼ばれているか確認 expect(NotificationHubService.notify).toHaveBeenCalledWith( makeContext('trackingId', 'requestId'), [`user_${typistUserId_2}`], { authorId: 'MY_AUTHOR_ID', filename: 'x', priority: 'High', uploadedAt: resultTask?.file?.uploaded_at.toISOString(), }, ); }); it('タスクのチェックアウト権限を変更できる。(グループ指定)', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: typistUserId_2 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-2-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId: userGroupId_1 } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); const { userGroupId: userGroupId_2 } = await createUserGroup( source, accountId, 'USER_GROUP_B', [typistUserId_2], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId_1); const service = module.get(TasksService); const NotificationHubService = module.get( NotificationhubService, ); await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'USER_GROUP_B', typistGroupId: userGroupId_2 }], 'author-user-external-id', ['admin'], ); const permisions = await getCheckoutPermissions(source, taskId); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 3, task_id: taskId, user_id: null, user_group_id: userGroupId_2, }); const resultTask = await getTask(source, taskId); // 通知処理が想定通りの引数で呼ばれているか確認 expect(NotificationHubService.notify).toHaveBeenCalledWith( makeContext('trackingId', 'requestId'), [`user_${typistUserId_2}`], { authorId: 'MY_AUTHOR_ID', filename: 'x', priority: 'High', uploadedAt: resultTask?.file?.uploaded_at.toISOString(), }, ); }); it('タスクのチェックアウト権限を変更できる。(チェックアウト権限を外す)', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [], 'author-user-external-id', ['admin'], ); const permisions = await getCheckoutPermissions(source, taskId); expect(permisions.length).toEqual(0); }); it('ユーザーが存在しない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'not-exist-user', typistUserId: 999 }], 'author-user-external-id', ['admin'], ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010204')); } else { fail(); } } }); it('ユーザーがメール認証されていない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id_1', role: 'typist', }); const { id: typistUserId_2 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id_2', role: 'typist', email_verified: false, }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'not-verified-user', typistUserId: typistUserId_2 }], 'author-user-external-id', ['admin'], ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010204')); } else { fail(); } } }); it('ユーザーグループが存在しない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'not-exist-user-group', typistGroupId: 999 }], 'author-user-external-id', ['admin'], ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010204')); } else { fail(); } } }); it('タスクが存在しない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', ['admin'], ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('タスクのステータスがUploadedでない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Inprogress', ); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', ['admin'], ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('ユーザーのRoleがAuthorでタスクのAuthorIDと自身のAuthorIDが一致しない場合、タスクのチェックアウト権限を変更できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'OTHER_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'typist-user', typistUserId: typistUserId }], 'author-user-external-id', ['author'], ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('通知に失敗した場合、エラーとなる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); notificationhubServiceMockValue.notify = new Error('Notify Error.'); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId_1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: typistUserId_2 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-2-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId_1], ); await createCheckoutPermissions(source, taskId, typistUserId_1); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); try { await service.changeCheckoutPermission( makeContext('trackingId', 'requestId'), 1, [{ typistName: 'typist-user-2', typistUserId: typistUserId_2 }], 'author-user-external-id', ['admin'], ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } }); }); describe('checkout', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザーのRoleがTypistで、タスクのチェックアウト権限が個人指定である時、タスクをチェックアウトできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId], ); await createCheckoutPermissions(source, taskId, typistUserId); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); const initTask = await getTask(source, taskId); await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('InProgress'); expect(resultTask?.typist_user_id).toEqual(typistUserId); expect(resultTask?.started_at).not.toEqual(initTask?.started_at); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 3, task_id: 1, user_id: 1, user_group_id: null, }); }); it('ユーザーのRoleがTypistで、タスクのチェックアウト権限がグループ指定である時、タスクをチェックアウトできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const { userGroupId } = await createUserGroup( source, accountId, 'USER_GROUP_A', [typistUserId], ); await createCheckoutPermissions(source, taskId, typistUserId); await createCheckoutPermissions(source, taskId, undefined, userGroupId); const service = module.get(TasksService); const initTask = await getTask(source, taskId); await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('InProgress'); expect(resultTask?.typist_user_id).toEqual(typistUserId); expect(resultTask?.started_at).not.toEqual(initTask?.started_at); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 3, task_id: 1, user_id: 1, user_group_id: null, }); }); it('ユーザーのRoleがTypistで、タスクのステータスがPendingである時、タスクをチェックアウトできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Pending', ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const initTask = await getTask(source, taskId); await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('InProgress'); expect(resultTask?.typist_user_id).toEqual(typistUserId); //タスクの元々のステータスがPending,Inprogressの場合、文字起こし開始時刻は更新されない expect(resultTask?.started_at).toEqual(initTask?.started_at); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 2, task_id: 1, user_id: 1, user_group_id: null, }); }); it('第五階層のアカウントの場合、有効なライセンスが割当されている場合チェックアウトできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウントを作成 const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 }); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); // 本日の日付を作成 const today = new Date(); // 有効なライセンスを作成して紐づける await createLicense( source, 1, today, accountId, LICENSE_TYPE.NORMAL, LICENSE_ALLOCATED_STATUS.ALLOCATED, typistUserId, null, null, null, ); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Pending', ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const initTask = await getTask(source, taskId); await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('InProgress'); expect(resultTask?.typist_user_id).toEqual(typistUserId); //タスクの元々のステータスがPending,Inprogressの場合、文字起こし開始時刻は更新されない expect(resultTask?.started_at).toEqual(initTask?.started_at); expect(permisions.length).toEqual(1); expect(permisions[0]).toEqual({ id: 2, task_id: 1, user_id: 1, user_group_id: null, }); }); it('ユーザーのRoleがTypistで、対象のタスクのStatus[Uploaded,Inprogress,Pending]以外の時、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Backup', ); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('第五階層のアカウントの場合、ライセンスが未割当の場合チェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウントを作成 const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 }); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Backup', ); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010812')); } else { fail(); } } }); it('第五階層のアカウントの場合、ライセンスが有効期限切れの場合チェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウントを作成 const { id: accountId } = await makeTestSimpleAccount(source, { tier: 5 }); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); // 昨日の日付を作成 let yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); yesterday = new DateWithZeroTime(yesterday); // 期限切れのライセンスを作成して紐づける await createLicense( source, 1, yesterday, accountId, LICENSE_TYPE.NORMAL, LICENSE_ALLOCATED_STATUS.ALLOCATED, typistUserId, null, null, null, ); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Backup', ); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010805')); } else { fail(); } } }); it('ユーザーのRoleがTypistで、チェックアウト権限が存在しない時、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['typist'], 'typist-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010602')); } else { fail(); } } }); it('ユーザーのRoleがTypistで、既にチェックアウト中のタスク(InProgress)がある時、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.IN_PROGRESS, typistUserId, ); const { taskId, audioFileId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), audioFileId, ['typist'], 'typist-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('ユーザーのRoleがTypistで、別ユーザーによってチェックアウト中のタスク(InProgress)がある時、タスクをチェックアウトできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId1 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id1', role: 'typist', }); const { id: typistUserId2 } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id2', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.IN_PROGRESS, typistUserId1, ); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId2); const service = module.get(TasksService); await service.checkout( makeContext('trackingId', 'requestId'), 2, ['typist'], 'typist-user-external-id2', ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual(TASK_STATUS.IN_PROGRESS); expect(resultTask?.typist_user_id).toEqual(typistUserId2); expect(permisions.length).toBe(1); expect(permisions[0].task_id).toBe(taskId); expect(permisions[0].user_id).toBe(typistUserId2); }); it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Uploaded)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const service = module.get(TasksService); expect( await service.checkout( makeContext('trackingId', 'requestId'), 1, ['author'], 'author-user-external-id', ), ).toEqual(undefined); }); it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Finished)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', ); const service = module.get(TasksService); expect( await service.checkout( makeContext('trackingId', 'requestId'), 1, ['author'], 'author-user-external-id', ), ).toEqual(undefined); }); it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクが存在しない場合、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['author'], 'author-user-external-id', ), fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.NOT_FOUND); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('ユーザーのRoleがAuthorで、音声ファイルに紐づいたタスクでユーザーと一致するAuthorIDでない場合、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); await createTask( source, accountId, authorUserId, 'OTHOR_AUTHOR', '', '01', '00000001', 'Uploaded', ); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['author'], 'author-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010602')); } else { fail(); } } }); it('ユーザーのRoleに[Typist,author]が設定されていない時、タスクをチェックアウトできない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'none-user-external-id', role: 'none', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); try { await service.checkout( makeContext('trackingId', 'requestId'), 1, ['none'], 'none-user-external-id', ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010602')); } else { fail(); } } }); }); describe('checkin', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('API実行者が文字起こし実行中のタスクである場合、タスクをチェックインできる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const initTask = await getTask(source, taskId); await service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); expect(resultTask?.status).toEqual('Finished'); expect(resultTask?.finished_at).not.toEqual(initTask?.finished_at); }); it('タスクのステータスがInprogressでない時、タスクをチェックインできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await expect( service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('API実行者が文字起こし実行中のタスクでない場合、タスクをチェックインできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: anotherTypistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'another-typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', // API実行者のタスクではないため、typist_user_idは設定しない ); await createCheckoutPermissions(source, taskId, anotherTypistUserId); const service = module.get(TasksService); await expect( service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('タスクがない時、タスクをチェックインできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); await expect( service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); }); }); describe('suspend', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('API実行者が文字起こし実行中のタスクである場合、タスクを中断できる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', typistUserId, ); const service = module.get(TasksService); await service.suspend( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ); const resultTask = await getTask(source, taskId); expect(resultTask?.status).toEqual('Pending'); }); it('タスクのステータスがInprogressでない時、タスクを中断できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await expect( service.suspend( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('API実行者が文字起こし実行中のタスクでない場合、タスクを中断できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: anotherTypistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'another-typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', anotherTypistUserId, ); await createCheckoutPermissions(source, taskId, anotherTypistUserId); const service = module.get(TasksService); await expect( service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('タスクがない時、タスクを中断できない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); await expect( service.checkin( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); }); }); describe('cancel', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルできる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['typist', 'standard'], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); expect(permisions.length).toEqual(0); }); it('API実行者のRoleがTypistの場合、自身が文字起こし中断しているタスクをキャンセルできる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Pending', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['typist', 'standard'], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); expect(permisions.length).toEqual(0); }); it('API実行者のRoleがAdminの場合、文字起こし実行中のタスクをキャンセルできる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['admin', 'author'], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); expect(permisions.length).toEqual(0); }); it('API実行者のRoleがAdminの場合、文字起こし中断しているタスクをキャンセルできる', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Pending', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['admin', 'author'], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); expect(permisions.length).toEqual(0); }); it('タスクのステータスが[Inprogress,Pending]でない時、タスクをキャンセルできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'Uploaded', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); await expect( service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['admin', 'author'], ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('API実行者のRoleがTypistの場合、他人が文字起こし実行中のタスクをキャンセルできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: anotherTypistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'another-typist-user-external-id', role: 'typist', }); const { id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', 'InProgress', anotherTypistUserId, ); await createCheckoutPermissions(source, taskId, anotherTypistUserId); const service = module.get(TasksService); await expect( service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['typist', 'standard'], ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), ); }); it('タスクがない時、タスクをキャンセルできない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const service = module.get(TasksService); await expect( service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['typist', 'standard'], ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010603'), HttpStatus.NOT_FOUND), ); }); it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); const { id: authorUserId, author_id } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'AUTHOR_ID', }); //ワークタイプIDを作成 await createWorktype(source, accountId, '01'); // テンプレートファイルを作成 const { id: templateFileId } = await createTemplateFile( source, accountId, 'template-file-name', 'https://example.com', ); // ワークフローを作成 const { id: workflowId } = await createWorkflow( source, accountId, authorUserId, undefined, templateFileId, ); // ワークフロータイピストを作成 await createWorkflowTypist(source, workflowId, typistUserId); const { taskId } = await createTask( source, accountId, authorUserId, author_id ?? '', '', '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const NotificationHubService = module.get( NotificationhubService, ); await service.cancel( makeContext('trackingId', 'requestId'), 1, 'typist-user-external-id', ['typist', 'standard'], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); // タスクのテンプレートファイルIDを確認 expect(resultTask?.template_file_id).toEqual(templateFileId); // タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認 expect(permisions.length).toEqual(1); expect(permisions[0].user_id).toEqual(typistUserId); // 通知処理が想定通りの引数で呼ばれているか確認 expect(NotificationHubService.notify).toHaveBeenCalledWith( makeContext('trackingId', 'requestId'), [`user_${typistUserId}`], { authorId: 'AUTHOR_ID', filename: 'x', priority: 'High', uploadedAt: resultTask?.file?.uploaded_at.toISOString(), }, ); }); it('API実行者のRoleがAdminの場合、自身が文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う(API実行者のAuthorIDと音声ファイルに紐づくWorkType)', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); // タスクの文字起こし担当者 const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); // 自動ルーティングされるタイピストユーザーを作成 const { id: autoRoutingTypistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'auto-routing-typist-user-external-id', role: 'typist', }); // API実行者 const { id: myAuthorUserId, external_id, role, } = await makeTestUser(source, { account_id: accountId, external_id: 'my-author-user-external-id', role: 'author admin', author_id: 'MY_AUTHOR_ID', }); // 音声ファイルのアップロード者 const { id: authorUserId, author_id } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'AUTHOR_ID', }); //ワークタイプIDを作成 const { id: workTypeId, custom_worktype_id } = await createWorktype( source, accountId, '01', ); // テンプレートファイルを作成 const { id: templateFileId } = await createTemplateFile( source, accountId, 'template-file-name', 'https://example.com', ); // ワークフローを作成 const { id: workflowId } = await createWorkflow( source, accountId, myAuthorUserId, workTypeId, templateFileId, ); // ワークフロータイピストを作成 await createWorkflowTypist(source, workflowId, autoRoutingTypistUserId); const { taskId } = await createTask( source, accountId, authorUserId, author_id ?? '', custom_worktype_id, '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const NotificationHubService = module.get( NotificationhubService, ); await service.cancel( makeContext('trackingId', 'requestId'), 1, external_id, role.split(' ') as Roles[], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); // タスクのテンプレートファイルIDを確認 expect(resultTask?.template_file_id).toEqual(templateFileId); // タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認 expect(permisions.length).toEqual(1); expect(permisions[0].user_id).toEqual(autoRoutingTypistUserId); // 通知処理が想定通りの引数で呼ばれているか確認 expect(NotificationHubService.notify).toHaveBeenCalledWith( makeContext('trackingId', 'requestId'), [`user_${autoRoutingTypistUserId}`], { authorId: 'AUTHOR_ID', filename: 'x', priority: 'High', uploadedAt: resultTask?.file?.uploaded_at.toISOString(), }, ); }); it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => { if (!source) fail(); const notificationhubServiceMockValue = makeDefaultNotificationhubServiceMockValue(); const module = await makeTaskTestingModuleWithNotificaiton( source, notificationhubServiceMockValue, ); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); // タスクの文字起こし担当者 const { id: typistUserId, external_id, role, } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', role: 'typist', }); // 音声ファイルのアップロード者 const { id: authorUserId, author_id } = await makeTestUser(source, { account_id: accountId, external_id: 'author-user-external-id', role: 'author', author_id: 'AUTHOR_ID', }); const { taskId } = await createTask( source, accountId, authorUserId, author_id ?? '', 'custom_worktype_id', '01', '00000001', 'InProgress', typistUserId, ); await createCheckoutPermissions(source, taskId, typistUserId); const service = module.get(TasksService); const NotificationHubService = module.get( NotificationhubService, ); await service.cancel( makeContext('trackingId', 'requestId'), 1, external_id, role.split(' ') as Roles[], ); const resultTask = await getTask(source, taskId); const permisions = await getCheckoutPermissions(source, taskId); expect(resultTask?.status).toEqual('Uploaded'); expect(resultTask?.typist_user_id).toEqual(null); // タスクのチェックアウト権限が削除されていることを確認 expect(permisions.length).toEqual(0); // 通知処理が想定通りの引数で呼ばれていないか確認 expect(NotificationHubService.notify).not.toHaveBeenCalled(); }); }); describe('backup', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('文字起こし完了のタスクをバックアップできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: 'typist', }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.FINISHED, typistUserId, ); // 作成したデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.FINISHED); expect(task?.is_job_number_enabled).toBe(true); } const service = module.get(TasksService); await service.backup( makeContext(admin.external_id, 'requestId'), audioFileId, admin.external_id, ); // バックアップしたデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.BACKUP); expect(task?.is_job_number_enabled).toBe(false); } }); it('文字起こしバックアップ済みのタスクをバックアップできる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: 'typist', }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.BACKUP, typistUserId, false, ); // 作成したデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.BACKUP); expect(task?.is_job_number_enabled).toBe(false); } const service = module.get(TasksService); await service.backup( makeContext(admin.external_id, 'requestId'), audioFileId, admin.external_id, ); // バックアップしたデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.BACKUP); expect(task?.is_job_number_enabled).toBe(false); } }); it('タスクのステータスが[Finished,Backup]でない時、エラーを返却する', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: 'typist', }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.IN_PROGRESS, typistUserId, ); // 作成したデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.IN_PROGRESS); expect(task?.is_job_number_enabled).toBe(true); } const service = module.get(TasksService); try { await service.backup( makeContext(admin.external_id, 'requestId'), audioFileId, admin.external_id, ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('指定タスクが存在しない時、エラーを返却する', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: 'typist', }); const { taskId } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.FINISHED, typistUserId, ); // 作成したデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.FINISHED); expect(task?.is_job_number_enabled).toBe(true); } const service = module.get(TasksService); try { await service.backup( makeContext(admin.external_id, 'requestId'), 9999, // 存在しないタスクID admin.external_id, ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.NOT_FOUND); expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); } else { fail(); } } }); it('DBアクセスに失敗した場合、エラーを返却する', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'author-user-external-id', role: 'author', author_id: 'MY_AUTHOR_ID', }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: 'typist', }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.FINISHED, typistUserId, ); // 作成したデータを確認 { const task = await getTask(source, taskId); expect(task?.status).toBe(TASK_STATUS.FINISHED); expect(task?.is_job_number_enabled).toBe(true); } const service = module.get(TasksService); //DBアクセスに失敗するようにする const tasksService = module.get( TasksRepositoryService, ); tasksService.backup = jest.fn().mockRejectedValue('DB failed'); try { await service.backup( makeContext(admin.external_id, 'requestId'), audioFileId, admin.external_id, ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } }); }); describe('getNextTask', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('次タスクを取得できる(JobNumber順)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'JOB_NUMBER', 'ASC'); const { taskId: taskId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const { taskId: taskId3, audioFileId: audioFileId3 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000003', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId3, typistUserId); const { taskId: taskId2, audioFileId: audioFileId2 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId2, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId2, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(audioFileId3); } }); it('次タスクを取得できる(JobNumber順+優先度)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'JOB_NUMBER', 'ASC'); const { taskId: taskId1, audioFileId: audioFileId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '00', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const { taskId: taskId3, audioFileId: audioFileId3 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '00', '00000003', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId3, typistUserId); const { taskId: taskId2 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId2, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId1, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(audioFileId3); } }); it('次タスクを取得できる(JobNumber順、先頭)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'JOB_NUMBER', 'ASC'); const { taskId: taskId1, audioFileId: audioFileId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const { taskId: taskId3, audioFileId: audioFileId3 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000003', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId3, typistUserId); const { taskId: taskId2 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', '', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId2, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId3, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(audioFileId1); } }); it('次タスクを取得できる(Worktype順)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'WORK_TYPE', 'ASC'); const { taskId: taskId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype1', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const { taskId: taskId3, audioFileId: audioFileId3 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype2', '01', '00000003', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId3, typistUserId); const { taskId: taskId2, audioFileId: audioFileId2 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype3', '01', '00000002', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId2, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId3, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(audioFileId2); } }); it('次タスクを取得できる(Status順)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'STATUS', 'ASC'); const { taskId: taskId1, audioFileId: audioFileId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype1', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const { taskId: taskId3 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype2', '01', '00000003', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId3, typistUserId); const { taskId: taskId2, audioFileId: audioFileId2 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype3', '01', '00000002', TASK_STATUS.PENDING, ); await createCheckoutPermissions(source, taskId2, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId2, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(audioFileId1); } }); it('次タスクが存在しない場合undefinedを返す(JobNumber順)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'JOB_NUMBER', 'ASC'); const { taskId: taskId1, audioFileId: audioFileId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype1', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); const nextAudioFileId = await service.getNextTask( context, typistExternalId, audioFileId1, ); // 実行結果が正しいか確認 { expect(nextAudioFileId).toEqual(undefined); } }); it('指定タスクが存在しない場合エラーを返す(JobNumber順)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId, external_id: typistExternalId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); await createSortCriteria(source, typistUserId, 'WORK_TYPE', 'ASC'); const { taskId: taskId1, audioFileId: audioFileId1 } = await createTask( source, account.id, authorUserId, 'MY_AUTHOR_ID', 'worktype1', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId1, typistUserId); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); // 実行結果が正しいか確認 try { await service.getNextTask(context, typistExternalId, audioFileId1 + 1); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); } else { fail(); } } }); }); describe('deleteTask', () => { 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(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('管理者として、アカウント内のタスクを削除できる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const authorId = 'AUTHOR_ID'; const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, authorId, '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.UPLOADED); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const blobStorageService = module.get(BlobstorageService); const context = makeContext(admin.external_id, 'requestId'); overrideBlobstorageService(service, { deleteFile: jest.fn(), }); await service.deleteTask(context, admin.external_id, audioFileId); // 実行結果が正しいか確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task).toBe(null); expect(audioFile).toBe(null); expect(checkoutPermissions.length).toBe(0); expect(optionItems.length).toBe(0); // Blob削除メソッドが呼ばれているか確認 expect(blobStorageService.deleteFile).toBeCalledWith( context, account.id, account.country, 'x.zip', ); } }); it('Authorとして、自身が追加したタスクを削除できる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account } = await makeTestAccount(source, { tier: 5 }); const authorId = 'AUTHOR_ID'; const { id: authorUserId, external_id: authorExternalId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, authorId, '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.UPLOADED); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const blobStorageService = module.get(BlobstorageService); const context = makeContext(authorExternalId, 'requestId'); overrideBlobstorageService(service, { deleteFile: jest.fn(), }); await service.deleteTask(context, authorExternalId, audioFileId); // 実行結果が正しいか確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task).toBe(null); expect(audioFile).toBe(null); expect(checkoutPermissions.length).toBe(0); expect(optionItems.length).toBe(0); // Blob削除メソッドが呼ばれているか確認 expect(blobStorageService.deleteFile).toBeCalledWith( context, account.id, account.country, 'x.zip', ); } }); it('ステータスがInProgressのタスクを削除しようとした場合、エラーとなること', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account } = await makeTestAccount(source, { tier: 5 }); const authorId = 'AUTHOR_ID'; const { id: authorUserId, external_id: authorExternalId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, authorId, '', '01', '00000001', TASK_STATUS.IN_PROGRESS, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.IN_PROGRESS); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const context = makeContext(authorExternalId, 'requestId'); overrideBlobstorageService(service, { // eslint-disable-next-line @typescript-eslint/no-empty-function deleteFile: async () => {}, }); try { await service.deleteTask(context, authorExternalId, audioFileId); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010601')); } else { fail(); } } }); it('Authorが自身が作成したタスク以外を削除しようとした場合、エラーとなること', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account } = await makeTestAccount(source, { tier: 5 }); const authorId1 = 'AUTHOR_ID1'; const authorId2 = 'AUTHOR_ID2'; const { id: authorUserId1 } = await makeTestUser(source, { account_id: account.id, author_id: authorId1, external_id: 'author-user-external-id1', role: USER_ROLES.AUTHOR, }); const { external_id: authorExternalId2 } = await makeTestUser(source, { account_id: account.id, author_id: authorId2, external_id: 'author-user-external-id2', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId1, authorId1, '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.UPLOADED); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId1); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const context = makeContext(authorExternalId2, 'requestId'); overrideBlobstorageService(service, { // eslint-disable-next-line @typescript-eslint/no-empty-function deleteFile: async () => {}, }); try { await service.deleteTask(context, authorExternalId2, audioFileId); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010602')); } else { fail(); } } }); it('削除対象タスクが存在しない場合、エラーとなること', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { admin } = await makeTestAccount(source, { tier: 5 }); const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); overrideBlobstorageService(service, { // eslint-disable-next-line @typescript-eslint/no-empty-function deleteFile: async () => {}, }); try { await service.deleteTask(context, admin.external_id, 1); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); } else { fail(); } } }); it('タスクのDB削除に失敗した場合、エラーとなること', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account } = await makeTestAccount(source, { tier: 5 }); const authorId = 'AUTHOR_ID'; const { id: authorUserId, external_id: authorExternalId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, authorId, '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.UPLOADED); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const context = makeContext(authorExternalId, 'requestId'); // DBアクセスに失敗するようにする const tasksRepositoryService = module.get( TasksRepositoryService, ); tasksRepositoryService.deleteTask = jest .fn() .mockRejectedValue('DB failed'); overrideBlobstorageService(service, { // eslint-disable-next-line @typescript-eslint/no-empty-function deleteFile: async () => {}, }); try { await service.deleteTask(context, authorExternalId, audioFileId); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } }); it('blobストレージからの音声ファイル削除に失敗した場合でも、エラーとならないこと', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); // 第五階層のアカウント作成 const { account, admin } = await makeTestAccount(source, { tier: 5 }); const authorId = 'AUTHOR_ID'; const { id: authorUserId } = await makeTestUser(source, { account_id: account.id, author_id: 'AUTHOR_ID', external_id: 'author-user-external-id', role: USER_ROLES.AUTHOR, }); const { id: typistUserId } = await makeTestUser(source, { account_id: account.id, external_id: 'typist-user-external-id', role: USER_ROLES.TYPIST, }); const { taskId, audioFileId } = await createTask( source, account.id, authorUserId, authorId, '', '01', '00000001', TASK_STATUS.UPLOADED, ); await createCheckoutPermissions(source, taskId, typistUserId); // 作成したデータを確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task?.id).toBe(taskId); expect(task?.status).toBe(TASK_STATUS.UPLOADED); expect(task?.audio_file_id).toBe(audioFileId); expect(audioFile?.id).toBe(audioFileId); expect(audioFile?.file_name).toBe('x.zip'); expect(audioFile?.author_id).toBe(authorId); expect(checkoutPermissions.length).toBe(1); expect(checkoutPermissions[0].user_id).toBe(typistUserId); expect(optionItems.length).toBe(10); } const service = module.get(TasksService); const context = makeContext(admin.external_id, 'requestId'); overrideBlobstorageService(service, { deleteFile: async () => { throw new Error('blob failed'); }, }); await service.deleteTask(context, admin.external_id, audioFileId); // 実行結果が正しいか確認 { const task = await getTask(source, taskId); const audioFile = await getAudioFile(source, audioFileId); const checkoutPermissions = await getCheckoutPermissions(source, taskId); const optionItems = await getAudioOptionItems(source, taskId); expect(task).toBe(null); expect(audioFile).toBe(null); expect(checkoutPermissions.length).toBe(0); expect(optionItems.length).toBe(0); } }); });