saito.k d5e5e59f8c Merged PR 128: API実装(ソート条件変更)
## 概要
[Task1835: API実装(ソート条件変更)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1835)

- ソート条件変更APIを実装
  - トークンからB2CのIDを取得→userテーブルからユーザー情報を取得
  - ユーザーIDでソート条件テーブルを検索→レコードを更新
- ソート条件テーブルにレコードを作成する
  - アカウント作成時の処理にソート条件レコードを作成する処理を追加
  - ユーザー追加時にも処理を追加
- テスト修正

## レビューポイント
- APIの引数をチェックする関数をControllerに配置してもよいか
- ソート条件のレコードを作成するタイミングに漏れはないか
- 実装漏れはないか

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場

## 動作確認状況
- ローカルで確認

## 補足
- 相談、参考資料などがあれば
2023-06-06 08:20:21 +00:00

384 lines
12 KiB
TypeScript

import { ConfigModule, ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { Aadb2cUser, B2cMetadata, JwkSignKey } from '../../../common/token';
import {
AdB2cService,
ConflictError,
} from '../../../gateways/adb2c/adb2c.service';
import { CryptoService } from '../../../gateways/crypto/crypto.service';
import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service';
import { User } from '../../../repositories/users/entity/user.entity';
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
import { UsersService } from '../users.service';
import { SortCriteria } from '../../../repositories/sort_criteria/entity/sort_criteria.entity';
import { SortCriteriaRepositoryService } from '../../../repositories/sort_criteria/sort_criteria.repository.service';
export type CryptoMockValue = {
getPublicKey: string | Error;
};
export type SortCriteriaRepositoryMockValue = {
updateSortCriteria: SortCriteria | Error;
};
export type UsersRepositoryMockValue = {
updateUserVerified: undefined | Error;
findUserById: User | Error;
createNormalUser: User | Error;
findSameAccountUsers: User[] | Error;
findUserByExternalId: User | Error;
existsAuthorId: boolean | Error;
};
export type AdB2cMockValue = {
getMetaData: B2cMetadata | Error;
getSignKeySets: JwkSignKey[] | Error;
changePassword: { sub: string } | Error;
createUser: string | ConflictError | Error;
getUser: Aadb2cUser | Error;
};
export type SendGridMockValue = {
createMailContentFromEmailConfirm: {
subject: string;
text: string;
html: string;
};
createMailContentFromEmailConfirmForNormalUser:
| { subject: string; text: string; html: string }
| Error;
sendMail: undefined | Error;
};
export const makeUsersServiceMock = async (
cryptoMockValue: CryptoMockValue,
usersRepositoryMockValue: UsersRepositoryMockValue,
adB2cMockValue: AdB2cMockValue,
sendGridMockValue: SendGridMockValue,
configMockValue: ConfigMockValue,
sortCriteriaRepositoryMockValue: SortCriteriaRepositoryMockValue,
): Promise<UsersService> => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService],
imports: [
ConfigModule.forRoot({
ignoreEnvFile: true,
ignoreEnvVars: true,
}),
],
})
.useMocker((token) => {
switch (token) {
case CryptoService:
return makeCryptoServiceMock(cryptoMockValue);
case UsersRepositoryService:
return makeUsersRepositoryMock(usersRepositoryMockValue);
case AdB2cService:
return makeAdB2cServiceMock(adB2cMockValue);
case SendGridService:
return makeSendGridMock(sendGridMockValue);
case ConfigService:
return makeConfigMock(configMockValue);
case SortCriteriaRepositoryService:
return makeSortCriteriaRepositoryMock(
sortCriteriaRepositoryMockValue,
);
}
})
.compile();
return module.get<UsersService>(UsersService);
};
export const makeSortCriteriaRepositoryMock = (
value: SortCriteriaRepositoryMockValue,
) => {
const { updateSortCriteria } = value;
return {
updateSortCriteria:
updateSortCriteria instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(updateSortCriteria)
: jest
.fn<Promise<SortCriteria>, []>()
.mockResolvedValue(updateSortCriteria),
};
};
export const makeSendGridServiceMock = (value: SendGridMockValue) => {
const { createMailContentFromEmailConfirm, sendMail } = value;
return {
createMailContentFromEmailConfirm:
createMailContentFromEmailConfirm instanceof Error
? jest
.fn<Promise<void>, []>()
.mockRejectedValue(createMailContentFromEmailConfirm)
: jest
.fn<Promise<{ subject: string; text: string; html: string }>, []>()
.mockResolvedValue(createMailContentFromEmailConfirm),
sendMail:
sendMail instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(sendMail)
: jest.fn<Promise<void>, []>().mockResolvedValue(sendMail),
};
};
export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
const { getMetaData, getSignKeySets, changePassword, createUser, getUser } =
value;
return {
getMetaData:
getMetaData instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getMetaData)
: jest.fn<Promise<B2cMetadata>, []>().mockResolvedValue(getMetaData),
getSignKeySets:
getSignKeySets instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getSignKeySets)
: jest
.fn<Promise<JwkSignKey[]>, []>()
.mockResolvedValue(getSignKeySets),
changePassword:
changePassword instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(changePassword)
: jest
.fn<Promise<{ sub: string }>, []>()
.mockResolvedValue(changePassword),
createUser:
createUser instanceof Error
? jest.fn<Promise<ConflictError>, []>().mockRejectedValue(createUser)
: jest
.fn<Promise<string | ConflictError>, []>()
.mockResolvedValue(createUser),
getUser:
getUser instanceof Error
? jest
.fn<Promise<Aadb2cUser | undefined>, []>()
.mockRejectedValue(getUser)
: jest
.fn<Promise<Aadb2cUser | undefined>, []>()
.mockResolvedValue(getUser),
};
};
export type ConfigMockValue = {
get: string | Error;
};
export const makeCryptoServiceMock = (value: CryptoMockValue) => {
const { getPublicKey } = value;
return {
getPublicKey:
getPublicKey instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getPublicKey)
: jest.fn<Promise<string>, []>().mockResolvedValue(getPublicKey),
};
};
class authorIdError extends Error {
constructor(public code: string, e?: string) {
super(e);
}
}
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
const {
updateUserVerified,
findUserById,
createNormalUser,
findSameAccountUsers,
findUserByExternalId,
existsAuthorId,
} = value;
const aIdError = new authorIdError('ER_DUP_ENTRY');
return {
updateUserVerified:
updateUserVerified instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(updateUserVerified)
: jest.fn<Promise<void>, []>().mockResolvedValue(updateUserVerified),
findUserById:
findUserById instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(findUserById)
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserById),
createNormalUser:
createNormalUser instanceof Error
? createNormalUser.name == 'ER_DUP_ENTRY'
? jest.fn<Promise<void>, []>().mockRejectedValue(aIdError)
: jest.fn<Promise<void>, []>().mockRejectedValue(createNormalUser)
: jest.fn<Promise<User>, []>().mockResolvedValue(createNormalUser),
findSameAccountUsers:
findSameAccountUsers instanceof Error
? jest
.fn<Promise<User[] | undefined>, []>()
.mockRejectedValue(findSameAccountUsers)
: jest
.fn<Promise<User[] | undefined>, []>()
.mockResolvedValue(findSameAccountUsers),
findUserByExternalId:
findUserByExternalId instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(findUserByExternalId)
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserByExternalId),
existsAuthorId:
existsAuthorId instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(existsAuthorId)
: jest.fn<Promise<boolean>, []>().mockResolvedValue(existsAuthorId),
};
};
export const makeSendGridMock = (value: SendGridMockValue) => {
const { sendMail, createMailContentFromEmailConfirmForNormalUser } = value;
return {
sendMail:
sendMail instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(sendMail)
: jest.fn<Promise<void>, []>().mockResolvedValue(sendMail),
createMailContentFromEmailConfirmForNormalUser:
createMailContentFromEmailConfirmForNormalUser instanceof Error
? jest
.fn<Promise<void>, []>()
.mockRejectedValue(createMailContentFromEmailConfirmForNormalUser)
: jest
.fn<Promise<{ subject: string; text: string; html: string }>, []>()
.mockResolvedValue(createMailContentFromEmailConfirmForNormalUser),
};
};
export const makeConfigMock = (value: ConfigMockValue) => {
const { get } = value;
return {
get:
get instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(get)
: jest.fn<Promise<string>, []>().mockResolvedValue(get),
};
};
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
return {
getPublicKey: [
'-----BEGIN PUBLIC KEY-----',
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
'OQIDAQAB',
'-----END PUBLIC KEY-----',
].join('\n'),
};
};
export const makeDefaultSendGridlValue = (): SendGridMockValue => {
return {
sendMail: undefined,
createMailContentFromEmailConfirm: { subject: '', text: '', html: '' },
createMailContentFromEmailConfirmForNormalUser: {
subject: 'test',
text: 'test',
html: 'test',
},
};
};
export const makeDefaultConfigValue = (): ConfigMockValue => {
return {
get: `test@example.co.jp`,
};
};
export const makeDefaultSortCriteriaRepositoryMockValue =
(): SortCriteriaRepositoryMockValue => {
const sortCriteria = new SortCriteria();
{
sortCriteria.id = 1;
sortCriteria.direction = 'ASC';
sortCriteria.parameter = 'JOB_NUMBER';
sortCriteria.user_id = 1;
}
return {
updateSortCriteria: sortCriteria,
};
};
export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => {
return {
getMetaData: {
issuer: 'issuer',
},
getSignKeySets: [
{
kid: 'kid',
nbf: 1111111111,
use: 'sig',
kty: 'RSA',
e: 'e',
n: 'n',
},
],
changePassword: {
sub: 'TEST9999',
},
createUser: '001',
getUser: {
displayName: 'Hanako Sato',
mail: 'hanako@sample.com',
},
};
};
// 個別のテストケースに対応してそれぞれのMockを用意するのは無駄が多いのでテストケース内で個別の値を設定する
export const makeDefaultUsersRepositoryMockValue =
(): UsersRepositoryMockValue => {
const newUser = new User();
newUser.id = 111;
const user1 = new User();
user1.id = 2;
user1.external_id = 'ede66c43-9b9d-4222-93ed-5f11c96e08e2';
user1.account_id = 1234567890123456;
user1.role = 'none';
user1.author_id = '6cce347f-0cf1-a15e-19ab-d00988b643f9';
user1.accepted_terms_version = '1.0';
user1.email_verified = true;
user1.auto_renew = false;
user1.license_alert = false;
user1.notification = false;
user1.deleted_at = null;
user1.created_by = 'test';
user1.created_at = new Date();
user1.updated_by = null;
user1.updated_at = null;
const user2 = new User();
user2.id = 3;
user2.external_id = '698176dc-4028-4638-a452-f00bf62a7781';
user2.account_id = 1234567890123456;
user2.role = 'none';
user2.author_id = '551c4077-5b55-a38c-2c55-cd1edd537aa8';
user2.accepted_terms_version = '1.0';
user2.email_verified = true;
user2.auto_renew = false;
user2.license_alert = false;
user2.notification = false;
user2.deleted_at = null;
user2.created_by = 'test';
user2.created_at = new Date();
user2.updated_by = null;
user2.updated_at = null;
return {
updateUserVerified: undefined,
findUserById: newUser,
createNormalUser: newUser,
findSameAccountUsers: [user1, user2],
findUserByExternalId: newUser,
existsAuthorId: false,
};
};