first commit
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
/**
|
||||
* Copyright 2025 LY Corporation
|
||||
*
|
||||
* LY Corporation licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Server } from 'net';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import type { INestApplication } from '@nestjs/common';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import type { TestingModule } from '@nestjs/testing';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { getDataSourceToken } from '@nestjs/typeorm';
|
||||
import { Client } from '@opensearch-project/opensearch';
|
||||
import type { Indices_Get_Response } from '@opensearch-project/opensearch/api/indices/get';
|
||||
import request from 'supertest';
|
||||
import type { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import { AppModule } from '@/app.module';
|
||||
import {
|
||||
FieldFormatEnum,
|
||||
FieldPropertyEnum,
|
||||
FieldStatusEnum,
|
||||
} from '@/common/enums';
|
||||
import { HttpExceptionFilter } from '@/common/filters';
|
||||
import { ChannelEntity } from '@/domains/admin/channel/channel/channel.entity';
|
||||
import { ChannelService } from '@/domains/admin/channel/channel/channel.service';
|
||||
import {
|
||||
CreateChannelRequestDto,
|
||||
UpdateChannelRequestDto,
|
||||
} from '@/domains/admin/channel/channel/dtos/requests';
|
||||
import type { CreateChannelResponseDto } from '@/domains/admin/channel/channel/dtos/responses/create-channel-response.dto';
|
||||
import type { FindChannelByIdResponseDto } from '@/domains/admin/channel/channel/dtos/responses/find-channel-by-id-response.dto';
|
||||
import type { FindChannelsByProjectIdResponseDto } from '@/domains/admin/channel/channel/dtos/responses/find-channels-by-id-response.dto';
|
||||
import { FieldEntity } from '@/domains/admin/channel/field/field.entity';
|
||||
import { FIELD_TYPES_TO_MAPPING_TYPES } from '@/domains/admin/channel/field/field.service';
|
||||
import { OptionEntity } from '@/domains/admin/channel/option/option.entity';
|
||||
import { ProjectEntity } from '@/domains/admin/project/project/project.entity';
|
||||
import { createFieldDto, optionSort } from '@/test-utils/fixtures';
|
||||
import {
|
||||
clearEntities,
|
||||
DEFAULT_FIELD_COUNT,
|
||||
} from '@/test-utils/util-functions';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let dataSource: DataSource;
|
||||
|
||||
let channelRepo: Repository<ChannelEntity>;
|
||||
let projectRepo: Repository<ProjectEntity>;
|
||||
let fieldRepo: Repository<FieldEntity>;
|
||||
let optionRepo: Repository<OptionEntity>;
|
||||
|
||||
let osService: Client;
|
||||
let channelService: ChannelService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
app.useGlobalFilters(new HttpExceptionFilter());
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({ transform: true, whitelist: true }),
|
||||
);
|
||||
|
||||
await app.init();
|
||||
|
||||
dataSource = module.get(getDataSourceToken());
|
||||
|
||||
channelRepo = dataSource.getRepository(ChannelEntity);
|
||||
projectRepo = dataSource.getRepository(ProjectEntity);
|
||||
fieldRepo = dataSource.getRepository(FieldEntity);
|
||||
optionRepo = dataSource.getRepository(OptionEntity);
|
||||
osService = module.get(Client);
|
||||
channelService = module.get(ChannelService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await dataSource.destroy();
|
||||
await app.close();
|
||||
});
|
||||
|
||||
let project: ProjectEntity;
|
||||
|
||||
beforeEach(async () => {
|
||||
await clearEntities([projectRepo, channelRepo, fieldRepo, optionRepo]);
|
||||
|
||||
project = await projectRepo.save({
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
});
|
||||
});
|
||||
|
||||
it('/projects/:projectId/channels (POST)', () => {
|
||||
const fieldCount = faker.number.int({ min: 1, max: 10 });
|
||||
|
||||
const dto = new CreateChannelRequestDto();
|
||||
dto.name = faker.string.sample();
|
||||
dto.description = faker.string.sample();
|
||||
dto.fields = Array.from({ length: fieldCount }).map((_) =>
|
||||
createFieldDto({}),
|
||||
);
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.post(`/projects/${project.id}/channels`)
|
||||
.send(dto)
|
||||
.expect(201)
|
||||
.then(async ({ body }: { body: CreateChannelResponseDto }) => {
|
||||
expect(body.id).toBeDefined();
|
||||
|
||||
const channel = await channelRepo.findOneBy({
|
||||
id: body.id,
|
||||
});
|
||||
expect(channel).toBeDefined();
|
||||
if (channel === null) {
|
||||
throw new Error('Channel not found');
|
||||
}
|
||||
expect(channel.name).toEqual(dto.name);
|
||||
expect(channel.description).toEqual(dto.description);
|
||||
|
||||
const fields = await fieldRepo.find({
|
||||
where: { channel: { id: body.id } },
|
||||
relations: { options: true },
|
||||
});
|
||||
|
||||
expect(fields).toHaveLength(fieldCount + DEFAULT_FIELD_COUNT);
|
||||
|
||||
expect(fields.map(fieldEntityToDto2)).toEqual(
|
||||
dto.fields
|
||||
.concat({
|
||||
name: 'createdAt',
|
||||
key: 'createdAt',
|
||||
format: FieldFormatEnum.date,
|
||||
property: FieldPropertyEnum.READ_ONLY,
|
||||
status: FieldStatusEnum.ACTIVE,
|
||||
options: undefined,
|
||||
description: '',
|
||||
})
|
||||
.concat({
|
||||
name: 'updatedAt',
|
||||
key: 'updatedAt',
|
||||
format: FieldFormatEnum.date,
|
||||
property: FieldPropertyEnum.READ_ONLY,
|
||||
status: FieldStatusEnum.ACTIVE,
|
||||
options: undefined,
|
||||
description: '',
|
||||
}),
|
||||
);
|
||||
|
||||
const result: Indices_Get_Response = await osService.indices.get({
|
||||
index: body.id.toString(),
|
||||
});
|
||||
expect(Object.keys(result.body)[0]).toEqual(body.id);
|
||||
|
||||
Object.entries<Record<string, { type: string }>>(
|
||||
result.body[body.id].mappings?.properties as
|
||||
| Record<string, Record<string, { type: string }>>
|
||||
| ArrayLike<Record<string, { type: string }>>,
|
||||
).forEach(([fieldId, { type }]) => {
|
||||
const field =
|
||||
fields.find(({ id }) => id === parseInt(fieldId)) ??
|
||||
new FieldEntity();
|
||||
expect(field).toBeDefined();
|
||||
expect(FIELD_TYPES_TO_MAPPING_TYPES[field.format]).toEqual(type);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('/projects/:projectId/channels (GET)', async () => {
|
||||
const total = faker.number.int(10);
|
||||
|
||||
await channelRepo.save(
|
||||
Array.from({ length: total }).map(() => ({
|
||||
name: faker.word.noun(),
|
||||
description: faker.lorem.lines(1),
|
||||
project: { id: project.id },
|
||||
})),
|
||||
);
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.get(`/projects/${project.id}/channels`)
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toHaveProperty('items');
|
||||
expect(body).toHaveProperty('meta');
|
||||
|
||||
expect(
|
||||
Array.isArray((body as FindChannelsByProjectIdResponseDto).items),
|
||||
).toEqual(true);
|
||||
for (const channel of (body as FindChannelsByProjectIdResponseDto)
|
||||
.items) {
|
||||
expect(channel).toHaveProperty('id');
|
||||
expect(channel).toHaveProperty('name');
|
||||
expect(channel).toHaveProperty('description');
|
||||
}
|
||||
expect(
|
||||
(body as FindChannelsByProjectIdResponseDto).meta.totalItems,
|
||||
).toEqual(total);
|
||||
});
|
||||
});
|
||||
|
||||
it('/channels/:id (GET)', async () => {
|
||||
const channel = await channelRepo.save({
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
});
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.get('/channels/' + channel.id)
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect((body as FindChannelByIdResponseDto).id).toEqual(channel.id);
|
||||
expect((body as FindChannelByIdResponseDto).name).toEqual(channel.name);
|
||||
expect((body as FindChannelByIdResponseDto).description).toEqual(
|
||||
channel.description,
|
||||
);
|
||||
});
|
||||
});
|
||||
it('/channels/:id (PUT)', async () => {
|
||||
const fieldCount = faker.number.int({ min: 1, max: 10 });
|
||||
|
||||
const { id: channelId } = await channelService.create({
|
||||
projectId: project.id,
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
fields: Array.from({ length: fieldCount }).map((_) => createFieldDto({})),
|
||||
feedbackSearchMaxDays: faker.number.int({ min: 1, max: 30 }),
|
||||
imageConfig: null,
|
||||
});
|
||||
|
||||
const originalFields = await fieldRepo.find({
|
||||
where: { channel: { id: channelId } },
|
||||
relations: { options: true },
|
||||
});
|
||||
|
||||
// const existingFields = originalFields
|
||||
// .map(fieldEntityToDto)
|
||||
// .filter((v) => v.name !== 'createdAt' && v.name !== 'updatedAt');
|
||||
|
||||
const newfields = Array.from({ length: fieldCount }).map((_) =>
|
||||
createFieldDto({}),
|
||||
);
|
||||
|
||||
const dto = new UpdateChannelRequestDto();
|
||||
dto.name = faker.string.sample();
|
||||
dto.description = faker.string.sample();
|
||||
// dto.fields = [...existingFields, ...newfields];
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.put(`/channels/${channelId}`)
|
||||
.send(dto)
|
||||
.expect(200)
|
||||
.then(async () => {
|
||||
const updatedchannel = await channelRepo.findOneBy({ id: channelId });
|
||||
expect(updatedchannel?.name).toEqual(dto.name);
|
||||
expect(updatedchannel?.description).toEqual(dto.description);
|
||||
|
||||
const updatedFields = await fieldRepo.find({
|
||||
where: { channel: { id: channelId } },
|
||||
relations: { options: true },
|
||||
});
|
||||
expect(updatedFields).toHaveLength(
|
||||
originalFields.length + newfields.length,
|
||||
);
|
||||
|
||||
// const activeFields = updatedFields.filter(
|
||||
// (v) =>
|
||||
// v.status === FieldStatusEnum.ACTIVE &&
|
||||
// v.name !== 'updatedAt' &&
|
||||
// v.name !== 'createdAt',
|
||||
// );
|
||||
// expect(activeFields.length).toEqual(dto.fields.length);
|
||||
|
||||
// activeFields.forEach((activeField) => {
|
||||
// const fieldDto = dto.fields.find((v) => v.name === activeField.name);
|
||||
|
||||
// expect(fieldDto).toBeDefined();
|
||||
// expect(activeField.name).toEqual(fieldDto.name);
|
||||
// expect(activeField.type).toEqual(fieldDto.type);
|
||||
|
||||
// if (activeField.format === FieldFormatEnum.select) {
|
||||
// expect(
|
||||
// activeField.options.map((v) => v.name).sort(strSort),
|
||||
// ).toEqual(fieldDto.options?.map((v) => v.name).sort(strSort));
|
||||
// }
|
||||
// });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// const fieldEntityToDto = (field: FieldEntity) => ({
|
||||
// id: field.id,
|
||||
// name: field.name,
|
||||
// key: field.key,
|
||||
// format: field.format,
|
||||
// type: field.type,
|
||||
// status: field.status,
|
||||
// description: field.description,
|
||||
// options: field.format === FieldFormatEnum.select ? field.options : undefined,
|
||||
// });
|
||||
|
||||
const fieldEntityToDto2 = (field: FieldEntity) => ({
|
||||
name: field.name,
|
||||
format: field.format,
|
||||
property: field.property,
|
||||
status: field.status,
|
||||
description: field.description,
|
||||
options:
|
||||
field.format === FieldFormatEnum.select ?
|
||||
(field.options ?? []).map(({ name }) => ({ name })).sort(optionSort)
|
||||
: undefined,
|
||||
});
|
||||
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* Copyright 2025 LY Corporation
|
||||
*
|
||||
* LY Corporation licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Server } from 'net';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import type { INestApplication } from '@nestjs/common';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import type { TestingModule } from '@nestjs/testing';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { Client } from '@opensearch-project/opensearch';
|
||||
import request from 'supertest';
|
||||
import type { Repository } from 'typeorm';
|
||||
|
||||
import { AppModule } from '@/app.module';
|
||||
import { FieldFormatEnum } from '@/common/enums';
|
||||
import { HttpExceptionFilter } from '@/common/filters';
|
||||
import { ChannelEntity } from '@/domains/admin/channel/channel/channel.entity';
|
||||
import { ChannelService } from '@/domains/admin/channel/channel/channel.service';
|
||||
import { FieldEntity } from '@/domains/admin/channel/field/field.entity';
|
||||
import { FeedbackService } from '@/domains/admin/feedback/feedback.service';
|
||||
import { ProjectEntity } from '@/domains/admin/project/project/project.entity';
|
||||
import { ProjectService } from '@/domains/admin/project/project/project.service';
|
||||
import { createFieldDto, getRandomValue } from '@/test-utils/fixtures';
|
||||
import { clearEntities } from '@/test-utils/util-functions';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let projectService: ProjectService;
|
||||
let channelService: ChannelService;
|
||||
let feedbackService: FeedbackService;
|
||||
|
||||
let projectRepo: Repository<ProjectEntity>;
|
||||
let channelRepo: Repository<ChannelEntity>;
|
||||
let fieldRepo: Repository<FieldEntity>;
|
||||
let osService: Client;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({ transform: true, whitelist: true }),
|
||||
);
|
||||
|
||||
app.useGlobalFilters(new HttpExceptionFilter());
|
||||
|
||||
await app.init();
|
||||
|
||||
projectService = module.get(ProjectService);
|
||||
channelService = module.get(ChannelService);
|
||||
feedbackService = module.get(FeedbackService);
|
||||
|
||||
projectRepo = module.get(getRepositoryToken(ProjectEntity));
|
||||
channelRepo = module.get(getRepositoryToken(ChannelEntity));
|
||||
fieldRepo = module.get(getRepositoryToken(FieldEntity));
|
||||
osService = module.get(Client);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
let channel: ChannelEntity = new ChannelEntity();
|
||||
let fields: FieldEntity[];
|
||||
beforeEach(async () => {
|
||||
await clearEntities([projectRepo, channelRepo, fieldRepo]);
|
||||
const { id: projectId } = await projectService.create({
|
||||
name: faker.word.noun(),
|
||||
description: faker.lorem.lines(1),
|
||||
timezone: {
|
||||
countryCode: 'KR',
|
||||
name: 'Asia/Seoul',
|
||||
offset: '+09:00',
|
||||
},
|
||||
});
|
||||
|
||||
const { id: channelId } = await channelService.create({
|
||||
projectId,
|
||||
name: faker.word.noun(),
|
||||
description: faker.lorem.lines(1),
|
||||
fields: Array.from({
|
||||
length: faker.number.int({ min: 1, max: 10 }),
|
||||
}).map(createFieldDto),
|
||||
feedbackSearchMaxDays: faker.number.int({ min: 1, max: 30 }),
|
||||
imageConfig: null,
|
||||
});
|
||||
|
||||
channel = await channelService.findById({ channelId });
|
||||
|
||||
fields = await fieldRepo.find({
|
||||
where: { channel: { id: channel.id } },
|
||||
relations: { options: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('/channels/:channelId/feedbacks (POST)', () => {
|
||||
const dto: Record<string, string | number | string[] | number[]> = {};
|
||||
fields
|
||||
.filter(({ name }) => name !== 'createdAt' && name !== 'updatedAt')
|
||||
.forEach(({ name, format, options }) => {
|
||||
dto[name] = getRandomValue(format, options);
|
||||
});
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.post(`/channels/${channel.id}/feedbacks`)
|
||||
.send(dto)
|
||||
.expect(201)
|
||||
.then(
|
||||
async ({
|
||||
body,
|
||||
}: {
|
||||
body: Record<string, any> & { issueNames?: string[] };
|
||||
}) => {
|
||||
expect(body.id).toBeDefined();
|
||||
const esResult = await osService.get({
|
||||
id: body.id as string,
|
||||
index: channel.id.toString(),
|
||||
});
|
||||
|
||||
delete esResult.body._source?.[
|
||||
(fields.find((v) => v.name === 'createdAt') ?? { id: 0 }).id
|
||||
];
|
||||
expect(toApi(dto, fields)).toMatchObject(esResult.body._source ?? {});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('/channels/:channelId/feedbacks (GET)', async () => {
|
||||
const feedbackCount = faker.number.int({ min: 1, max: 10 });
|
||||
const dataset: Record<string, any>[] = [];
|
||||
for (let i = 0; i < feedbackCount; i++) {
|
||||
const data: Record<string, any> = {};
|
||||
fields
|
||||
.filter(({ name }) => name !== 'createdAt' && name !== 'updatedAt')
|
||||
.forEach(({ name, format, options }) => {
|
||||
data[name] = getRandomValue(format, options);
|
||||
});
|
||||
await feedbackService.create({ channelId: channel.id, data });
|
||||
dataset.push(data);
|
||||
}
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.get(`/channels/${channel.id}/feedbacks`)
|
||||
.expect(200)
|
||||
.then(({ body }) => {
|
||||
expect(Array.isArray(body)).toEqual(true);
|
||||
expect(body).toHaveLength(feedbackCount);
|
||||
});
|
||||
});
|
||||
|
||||
it('/channels/:channelId/feedbacks/:feedbackId/field/:fieldId (PUT)', async () => {
|
||||
const data = {};
|
||||
const targetFields = fields.filter(
|
||||
({ name }) => name !== 'createdAt' && name !== 'updatedAt',
|
||||
);
|
||||
|
||||
targetFields.forEach(({ name, format, options }) => {
|
||||
data[name] = getRandomValue(format, options);
|
||||
});
|
||||
|
||||
const { id: feedbackId } = await feedbackService.create({
|
||||
channelId: channel.id,
|
||||
data,
|
||||
});
|
||||
|
||||
const targetField = targetFields[faker.number.int(targetFields.length - 1)];
|
||||
|
||||
const newValue = getRandomValue(targetField.format, targetField.options);
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.put(
|
||||
`/channels/${channel.id}/feedbacks/${feedbackId}/field/${targetField.id}`,
|
||||
)
|
||||
.send({ value: newValue })
|
||||
.expect(200)
|
||||
.then(async () => {
|
||||
const { body } = await osService.get({
|
||||
id: feedbackId.toString(),
|
||||
index: channel.id.toString(),
|
||||
});
|
||||
|
||||
expect(body._source?.[targetField.id]).toEqual(
|
||||
targetField.format === FieldFormatEnum.select ?
|
||||
((targetField.options ?? []).find((v) => v.name === newValue) ??
|
||||
{ id: 0 }.id)
|
||||
: newValue,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// const channel = await channelModel.create({
|
||||
// name: faker.string.sample(),
|
||||
// description: faker.string.sample(),
|
||||
// });
|
||||
|
||||
// return request(app.getHttpServer())
|
||||
// .get('/channels/' + channel.id)
|
||||
// .expect(200)
|
||||
// .expect(({ body }) => {
|
||||
// expect(body.id).toEqual(channel.id);
|
||||
// expect(body.name).toEqual(channel.name);
|
||||
// expect(body.description).toEqual(channel.description);
|
||||
// });
|
||||
// });
|
||||
// it('/channels/:id (PUT)', async () => {
|
||||
// const channel = await channelModel.create({
|
||||
// name: faker.string.sample(),
|
||||
// description: faker.string.sample(),
|
||||
// });
|
||||
|
||||
// await fieldModel.create(
|
||||
// Array.from({ length: faker.number.int({ min: 1, max: 5 }) })
|
||||
// .map(createField)
|
||||
// .map((v) => ({ ...v, channel: { _id: channel.id } })),
|
||||
// );
|
||||
|
||||
// const dto = new UpdateChannelRequestDto();
|
||||
// dto.name = faker.string.sample();
|
||||
// dto.description = faker.string.sample();
|
||||
// dto.fields = [];
|
||||
|
||||
// return request(app.getHttpServer())
|
||||
// .put(`/channels/${channel.id}`)
|
||||
// .send(dto)
|
||||
// .expect(200)
|
||||
// .then(async () => {
|
||||
// const updatedchannel = await channelModel.findById(channel.id);
|
||||
// expect(updatedchannel.name).toEqual(dto.name);
|
||||
// expect(updatedchannel.description).toEqual(dto.description);
|
||||
|
||||
// const fields = await fieldModel.find({ channel: { _id: channel.id } });
|
||||
// expect(fields).toHaveLength(dto.fields.length);
|
||||
// });
|
||||
// });
|
||||
// it('/channels/:id (DELETE)', async () => {
|
||||
// const channel = await channelModel.create({
|
||||
// name: faker.string.sample(),
|
||||
// description: faker.string.sample(),
|
||||
// });
|
||||
|
||||
// await request(app.getHttpServer())
|
||||
// .delete(`/channels/${channel.id}`)
|
||||
// .expect(200)
|
||||
// .then(async () => {
|
||||
// expect(await channelModel.findById(channel.id)).toBeNull();
|
||||
// });
|
||||
// expect(await channelModel.findById(channel.id)).toBeNull();
|
||||
// });
|
||||
});
|
||||
|
||||
const toApi = (
|
||||
data: Record<string, string | number | string[] | number[]>,
|
||||
fields: FieldEntity[],
|
||||
) => {
|
||||
return Object.entries(data).reduce((prev, [key, value]) => {
|
||||
const field: FieldEntity =
|
||||
fields.find((v) => v.name === key) ?? new FieldEntity();
|
||||
return Object.assign(prev, {
|
||||
[field.id]:
|
||||
field.format === FieldFormatEnum.select ?
|
||||
(
|
||||
(field.options ?? []).find((v) => v.name === value) ??
|
||||
new FieldEntity()
|
||||
).id
|
||||
: value,
|
||||
});
|
||||
}, {});
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright 2025 LY Corporation
|
||||
*
|
||||
* LY Corporation licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Server } from 'net';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import type { INestApplication } from '@nestjs/common';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import type { TestingModule } from '@nestjs/testing';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { getDataSourceToken } from '@nestjs/typeorm';
|
||||
import request from 'supertest';
|
||||
import type { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import { AppModule } from '@/app.module';
|
||||
import { HttpExceptionFilter } from '@/common/filters';
|
||||
import { CreateProjectRequestDto } from '@/domains/admin/project/project/dtos/requests';
|
||||
import type { FindProjectByIdResponseDto } from '@/domains/admin/project/project/dtos/responses/find-project-by-id-response.dto';
|
||||
import type { FindProjectsResponseDto } from '@/domains/admin/project/project/dtos/responses/find-projects-response.dto';
|
||||
import { ProjectEntity } from '@/domains/admin/project/project/project.entity';
|
||||
import { clearEntities } from '@/test-utils/util-functions';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let dataSource: DataSource;
|
||||
let projectRepo: Repository<ProjectEntity>;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
|
||||
app.useGlobalFilters(new HttpExceptionFilter());
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({ transform: true, whitelist: true }),
|
||||
);
|
||||
|
||||
await app.init();
|
||||
|
||||
dataSource = module.get(getDataSourceToken());
|
||||
projectRepo = dataSource.getRepository(ProjectEntity);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await dataSource.destroy();
|
||||
await app.close();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await clearEntities([projectRepo]);
|
||||
});
|
||||
|
||||
it('/projects (GET)', async () => {
|
||||
const total = faker.number.int(10);
|
||||
|
||||
await projectRepo.save(
|
||||
Array.from({ length: total }).map(() => ({
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
})),
|
||||
);
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.get('/projects')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toHaveProperty('items');
|
||||
expect(body).toHaveProperty('meta');
|
||||
|
||||
expect(Array.isArray((body as FindProjectsResponseDto).items)).toEqual(
|
||||
true,
|
||||
);
|
||||
for (const project of (body as FindProjectsResponseDto).items) {
|
||||
expect(project).toHaveProperty('id');
|
||||
expect(project).toHaveProperty('name');
|
||||
expect(project).toHaveProperty('description');
|
||||
}
|
||||
expect((body as FindProjectsResponseDto).meta.totalItems).toEqual(
|
||||
total,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('/projects (POST)', () => {
|
||||
const dto = new CreateProjectRequestDto();
|
||||
dto.name = faker.string.sample();
|
||||
dto.description = faker.string.sample();
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.post('/projects')
|
||||
.send(dto)
|
||||
.expect(201);
|
||||
});
|
||||
|
||||
it('/projects/:id (GET)', async () => {
|
||||
const project = await projectRepo.save({
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
});
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.get('/projects/' + project.id)
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect((body as FindProjectByIdResponseDto).id).toEqual(project.id);
|
||||
expect((body as FindProjectByIdResponseDto).name).toEqual(project.name);
|
||||
expect((body as FindProjectByIdResponseDto).description).toEqual(
|
||||
project.description,
|
||||
);
|
||||
});
|
||||
});
|
||||
it('/projects/:id (PUT)', async () => {
|
||||
const project = await projectRepo.save({
|
||||
name: faker.string.sample(),
|
||||
description: faker.string.sample(),
|
||||
});
|
||||
|
||||
const name = faker.string.sample();
|
||||
const description = faker.string.sample();
|
||||
|
||||
return request(app.getHttpServer() as Server)
|
||||
.put(`/projects/${project.id}`)
|
||||
.send({ name, description })
|
||||
.expect(200)
|
||||
.then(async () => {
|
||||
const updatedproject = await projectRepo.findOneBy({ id: project.id });
|
||||
expect(updatedproject?.name).toEqual(name);
|
||||
expect(updatedproject?.description).toEqual(description);
|
||||
});
|
||||
});
|
||||
// it('/projects/:id (DELETE)', async () => {
|
||||
// const project = await projectModel.create({
|
||||
// name: faker.string.sample(),
|
||||
// description: faker.string.sample(),
|
||||
// });
|
||||
|
||||
// await request(app.getHttpServer())
|
||||
// .delete(`/projects/${project.id}`)
|
||||
// .expect(200)
|
||||
// .then(async () => {
|
||||
// expect(await projectModel.findById(project.id)).toBeNull();
|
||||
// });
|
||||
// expect(await projectModel.findById(project.id)).toBeNull();
|
||||
// });
|
||||
});
|
||||
Reference in New Issue
Block a user