OMDSCloud/dictation_server/src/features/tasks/tasks.service.spec.ts
2024-03-06 11:23:50 +09:00

4823 lines
147 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>(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>(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>(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>(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>(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>(TasksService);
const NotificationHubService = module.get<NotificationhubService>(
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>(TasksService);
const NotificationHubService = module.get<NotificationhubService>(
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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(TasksService);
const NotificationHubService = module.get<NotificationhubService>(
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>(TasksService);
const NotificationHubService = module.get<NotificationhubService>(
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>(TasksService);
const NotificationHubService = module.get<NotificationhubService>(
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>(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>(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>(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>(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>(TasksService);
//DBアクセスに失敗するようにする
const tasksService = module.get<TasksRepositoryService>(
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>(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>(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>(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>(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>(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>(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>(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>(TasksService);
const blobStorageService =
module.get<BlobstorageService>(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>(TasksService);
const blobStorageService =
module.get<BlobstorageService>(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>(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>(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>(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>(TasksService);
const context = makeContext(authorExternalId, 'requestId');
// DBアクセスに失敗するようにする
const tasksRepositoryService = module.get<TasksRepositoryService>(
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>(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);
}
});
});