From c13ae07b6cbff3315e7883d1abad161e5f479e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=98=81=EC=9A=B0?= Date: Tue, 30 Jul 2024 15:07:51 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=97=90=ED=94=BD=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?,=20=EC=88=98=EC=A0=95=20API=EC=97=90=20=EC=9A=B0=EC=84=A0?= =?UTF-8?q?=EC=88=9C=EC=9C=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0(rankValue)?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - lexorank 패키지 설치 - epic 엔티티 - rankValue 프로퍼티 추가 - 에픽의 rankValue가 project에서 고유하도록 유니크 제약조건 추가 - project 레포지토리, project 서비스, epic컨트롤러에 rankValue 정보 추가 - Epic DTO에 rankValue 정보 추가 - LexoRank형식인지 검증할 수 있는 IsLexoRankValue 데코레이터 추가 - E2E 테스트 - 에픽, 스토리, 태스크, 백로그 테스트에 rankValue정보 추가 - 에픽 테스트에 rankValue update테스트 추가 --- backend/package-lock.json | 67 ++++++++++++------- backend/package.json | 1 + .../src/common/decorator/IsLexoRankValue.ts | 18 +++++ .../project/dto/epic/EpicCreateNotify.dto.ts | 9 ++- .../project/dto/epic/EpicCreateRequest.dto.ts | 6 ++ .../project/dto/epic/EpicUpdateNotify.dto.ts | 8 ++- .../project/dto/epic/EpicUpdateRequest.dto.ts | 8 ++- backend/src/project/entity/epic.entity.ts | 13 +++- backend/src/project/project.repository.ts | 5 ++ .../src/project/service/project.service.ts | 24 +++++-- .../ws-project-epic.controller.ts | 10 ++- .../ws-backlog-page/ws-epic.e2e-spec.ts | 66 ++++++++++++++++-- .../ws-init-backlog.e2e-spec.ts | 8 +-- .../ws-backlog-page/ws-story.e2e-spec.ts | 15 +++-- .../ws-backlog-page/ws-task.e2e-spec.ts | 14 ++-- 15 files changed, 212 insertions(+), 60 deletions(-) create mode 100644 backend/src/common/decorator/IsLexoRankValue.ts diff --git a/backend/package-lock.json b/backend/package-lock.json index dd3fbbe..9145877 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -20,6 +20,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cookie-parser": "^1.4.6", + "lexorank": "^1.0.5", "mysql2": "^3.9.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", @@ -3044,6 +3045,14 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", + "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -3271,12 +3280,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4187,9 +4196,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -4200,22 +4209,22 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" } }, "node_modules/engine.io-client": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", - "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0", + "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.0.0" } }, @@ -4785,9 +4794,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -6551,6 +6560,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lexorank": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lexorank/-/lexorank-1.0.5.tgz", + "integrity": "sha512-K1B/Yr/gIU0wm68hk/yB0p/mv6xM3ShD5aci42vOwcjof8slG8Kpo3Q7+1WTv7DaRHKWRgLPqrFDt+4GtuFAtA==" + }, "node_modules/libphonenumber-js": { "version": "1.10.58", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.58.tgz", @@ -6892,10 +6906,11 @@ "dev": true }, "node_modules/mysql2": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.1.tgz", - "integrity": "sha512-3njoWAAhGBYy0tWBabqUQcLtczZUxrmmtc2vszQUekg3kTJyZ5/IeLC3Fo04u6y6Iy5Sba7pIIa2P/gs8D3ZeQ==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz", + "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==", "dependencies": { + "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", @@ -8214,12 +8229,12 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dependencies": { "debug": "~4.3.4", - "ws": "~8.11.0" + "ws": "~8.17.1" } }, "node_modules/socket.io-client": { @@ -9481,15 +9496,15 @@ "dev": true }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { diff --git a/backend/package.json b/backend/package.json index 9328e96..58c3b18 100644 --- a/backend/package.json +++ b/backend/package.json @@ -33,6 +33,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cookie-parser": "^1.4.6", + "lexorank": "^1.0.5", "mysql2": "^3.9.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", diff --git a/backend/src/common/decorator/IsLexoRankValue.ts b/backend/src/common/decorator/IsLexoRankValue.ts new file mode 100644 index 0000000..362b848 --- /dev/null +++ b/backend/src/common/decorator/IsLexoRankValue.ts @@ -0,0 +1,18 @@ +import { registerDecorator } from 'class-validator'; + +export function IsLexoRankValue() { + return function (object: Object, propertyName: string) { + registerDecorator({ + name: 'IsLexoRankValue', + target: object.constructor, + propertyName: propertyName, + options: { message: 'invalid LexoRank format' }, + validator: { + validate(value: any) { + const lexorankPattern = new RegExp(`^[012]\\|.*`, 'i'); + return lexorankPattern.test(value); + }, + }, + }); + }; +} diff --git a/backend/src/project/dto/epic/EpicCreateNotify.dto.ts b/backend/src/project/dto/epic/EpicCreateNotify.dto.ts index f3f730b..c90c4b8 100644 --- a/backend/src/project/dto/epic/EpicCreateNotify.dto.ts +++ b/backend/src/project/dto/epic/EpicCreateNotify.dto.ts @@ -4,11 +4,14 @@ class Epic { id: number; name: string; color: EpicColor; - static of(id: number, name: string, color: EpicColor) { + rankValue: string; + + static of(id: number, name: string, color: EpicColor, rankValue: string) { const dto = new Epic(); dto.id = id; dto.name = name; dto.color = color; + dto.rankValue = rankValue; return dto; } } @@ -18,11 +21,11 @@ export class EpicCreateNotifyDto { action: string; content: Epic; - static of(id: number, name: string, color: EpicColor) { + static of(id: number, name: string, color: EpicColor, rankValue: string) { const dto = new EpicCreateNotifyDto(); dto.domain = 'epic'; dto.action = 'create'; - dto.content = Epic.of(id, name, color); + dto.content = Epic.of(id, name, color, rankValue); return dto; } } diff --git a/backend/src/project/dto/epic/EpicCreateRequest.dto.ts b/backend/src/project/dto/epic/EpicCreateRequest.dto.ts index 4acff8f..07a1f6e 100644 --- a/backend/src/project/dto/epic/EpicCreateRequest.dto.ts +++ b/backend/src/project/dto/epic/EpicCreateRequest.dto.ts @@ -7,6 +7,7 @@ import { Matches, ValidateNested, } from 'class-validator'; +import { IsLexoRankValue } from 'src/common/decorator/IsLexoRankValue'; import { EpicColor } from 'src/project/entity/epic.entity'; class Epic { @@ -16,6 +17,11 @@ class Epic { @IsEnum(EpicColor) color: EpicColor; + + @IsString() + @IsLexoRankValue() + @Length(2, 255) + rankValue: string; } export class EpicCreateRequestDto { diff --git a/backend/src/project/dto/epic/EpicUpdateNotify.dto.ts b/backend/src/project/dto/epic/EpicUpdateNotify.dto.ts index 9e76b9a..fe58e93 100644 --- a/backend/src/project/dto/epic/EpicUpdateNotify.dto.ts +++ b/backend/src/project/dto/epic/EpicUpdateNotify.dto.ts @@ -4,11 +4,13 @@ class Epic { id: number; name?: string; color?: EpicColor; - static of(id: number, name: string, color: EpicColor) { + rankValue?: string; + static of(id: number, name: string, color: EpicColor, rankValue: string) { const dto = new Epic(); dto.id = id; if (name !== undefined) dto.name = name; if (color !== undefined) dto.color = color; + if (rankValue !== undefined) dto.rankValue = rankValue; return dto; } } @@ -18,11 +20,11 @@ export class EpicUpdateNotifyDto { action: string; content: Epic; - static of(id: number, name: string, color: EpicColor) { + static of(id: number, name: string, color: EpicColor, rankValue: string) { const dto = new EpicUpdateNotifyDto(); dto.domain = 'epic'; dto.action = 'update'; - dto.content = Epic.of(id, name, color); + dto.content = Epic.of(id, name, color, rankValue); return dto; } } diff --git a/backend/src/project/dto/epic/EpicUpdateRequest.dto.ts b/backend/src/project/dto/epic/EpicUpdateRequest.dto.ts index d77c847..57f18f2 100644 --- a/backend/src/project/dto/epic/EpicUpdateRequest.dto.ts +++ b/backend/src/project/dto/epic/EpicUpdateRequest.dto.ts @@ -9,13 +9,14 @@ import { ValidateNested, Length, } from 'class-validator'; +import { IsLexoRankValue } from 'src/common/decorator/IsLexoRankValue'; import { EpicColor } from 'src/project/entity/epic.entity'; import { AtLeastOneProperty } from 'src/project/util/validation.util'; class Epic { @IsNotEmpty() @IsInt() - @AtLeastOneProperty(['name', 'color']) + @AtLeastOneProperty(['name', 'color', 'rankValue']) id: number; @IsOptional() @@ -26,6 +27,11 @@ class Epic { @IsOptional() @IsEnum(EpicColor) color?: EpicColor; + + @IsOptional() + @IsLexoRankValue() + @Length(2, 255) + rankValue?: string; } export class EpicUpdateRequestDto { diff --git a/backend/src/project/entity/epic.entity.ts b/backend/src/project/entity/epic.entity.ts index d0acec1..63fa4e7 100644 --- a/backend/src/project/entity/epic.entity.ts +++ b/backend/src/project/entity/epic.entity.ts @@ -6,6 +6,7 @@ import { ManyToOne, OneToMany, PrimaryGeneratedColumn, + Unique, UpdateDateColumn, } from 'typeorm'; import { Project } from './project.entity'; @@ -22,6 +23,7 @@ export enum EpicColor { } @Entity() +@Unique(['rankValue', 'projectId']) export class Epic { @PrimaryGeneratedColumn('increment', { type: 'int' }) id: number; @@ -51,11 +53,20 @@ export class Epic { @OneToMany(() => Story, (story) => story.epic) storyList: Story[]; - static of(project: Project, name: string, color: EpicColor) { + @Column({ type: 'varchar', length: 255, nullable: false, name: 'rank_value' }) + rankValue: string; + + static of( + project: Project, + name: string, + color: EpicColor, + rankValue: string, + ) { const newEpic = new Epic(); newEpic.project = project; newEpic.name = name; newEpic.color = color; + newEpic.rankValue = rankValue; return newEpic; } } diff --git a/backend/src/project/project.repository.ts b/backend/src/project/project.repository.ts index 30cbe54..a5a3245 100644 --- a/backend/src/project/project.repository.ts +++ b/backend/src/project/project.repository.ts @@ -134,6 +134,7 @@ export class ProjectRepository { id: number, name?: string, color?: EpicColor, + rankValue?: string, ): Promise { const updateData: any = {}; @@ -144,6 +145,10 @@ export class ProjectRepository { updateData.color = color; } + if (rankValue !== undefined) { + updateData.rankValue = rankValue; + } + const result = await this.epicRepository.update( { id, project: { id: project.id } }, updateData, diff --git a/backend/src/project/service/project.service.ts b/backend/src/project/service/project.service.ts index 2b727bf..9090f4b 100644 --- a/backend/src/project/service/project.service.ts +++ b/backend/src/project/service/project.service.ts @@ -95,8 +95,13 @@ export class ProjectService { return result ? true : false; } - createEpic(project: Project, name: string, color: EpicColor) { - const newEpic = Epic.of(project, name, color); + createEpic( + project: Project, + name: string, + color: EpicColor, + rankValue: string, + ) { + const newEpic = Epic.of(project, name, color, rankValue); return this.projectRepository.createEpic(newEpic); } @@ -110,8 +115,15 @@ export class ProjectService { id: number, name?: string, color?: EpicColor, + rankValue?: string, ): Promise { - return this.projectRepository.updateEpic(project, id, name, color); + return this.projectRepository.updateEpic( + project, + id, + name, + color, + rankValue, + ); } async createStory( @@ -211,8 +223,8 @@ export class ProjectService { assignedMemberId, ); } - - getProjectBacklog(project: Project){ - return this.projectRepository.getProjectBacklog(project); + + getProjectBacklog(project: Project) { + return this.projectRepository.getProjectBacklog(project); } } diff --git a/backend/src/project/ws-controller/ws-project-epic.controller.ts b/backend/src/project/ws-controller/ws-project-epic.controller.ts index 4841438..fc3dcfe 100644 --- a/backend/src/project/ws-controller/ws-project-epic.controller.ts +++ b/backend/src/project/ws-controller/ws-project-epic.controller.ts @@ -26,6 +26,7 @@ export class WsProjectEpicController { client.project, content.name, content.color, + content.rankValue, ); client.nsp .to('backlog') @@ -35,6 +36,7 @@ export class WsProjectEpicController { createdEpic.id, createdEpic.name, createdEpic.color, + createdEpic.rankValue, ), ); } @@ -71,6 +73,7 @@ export class WsProjectEpicController { content.id, content.name, content.color, + content.rankValue, ); if (isUpdated) { @@ -78,7 +81,12 @@ export class WsProjectEpicController { .to('backlog') .emit( 'backlog', - EpicUpdateNotifyDto.of(content.id, content.name, content.color), + EpicUpdateNotifyDto.of( + content.id, + content.name, + content.color, + content.rankValue, + ), ); } } diff --git a/backend/test/project/ws-backlog-page/ws-epic.e2e-spec.ts b/backend/test/project/ws-backlog-page/ws-epic.e2e-spec.ts index beccb4a..4d4a83a 100644 --- a/backend/test/project/ws-backlog-page/ws-epic.e2e-spec.ts +++ b/backend/test/project/ws-backlog-page/ws-epic.e2e-spec.ts @@ -1,3 +1,5 @@ +import { LexoRank } from 'lexorank'; +import { resolve } from 'path'; import { Socket } from 'socket.io-client'; import { app, appInit } from 'test/setup'; import { @@ -20,20 +22,21 @@ describe('WS epic', () => { await Promise.all([initBacklog(socket1), initBacklog(socket2)]); const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); const requestData = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket1.emit('epic', requestData); await Promise.all([ - expectCreateEpic(socket1, name, color), - expectCreateEpic(socket2, name, color), + expectCreateEpic(socket1, name, color, rankValue), + expectCreateEpic(socket2, name, color, rankValue), ]); socket1.close(); socket2.close(); }); - const expectCreateEpic = (socket, name, color) => { + const expectCreateEpic = (socket, name, color, rankValue) => { return new Promise((resolve) => { socket.once('backlog', async (data) => { const { content, action, domain } = data; @@ -42,6 +45,7 @@ describe('WS epic', () => { expect(content?.id).toBeDefined(); expect(content?.name).toBe(name); expect(content?.color).toBe(color); + expect(content?.rankValue).toBe(rankValue); resolve(); }); }); @@ -56,9 +60,10 @@ describe('WS epic', () => { await Promise.all([initBacklog(socket1), initBacklog(socket2)]); const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket1.emit('epic', requestData); @@ -99,9 +104,10 @@ describe('WS epic', () => { await initBacklog(socket); const name = '회원'; let color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const id = await getEpicId(socket); @@ -137,9 +143,10 @@ describe('WS epic', () => { await initBacklog(socket); let name = '회원'; let color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const id = await getEpicId(socket); @@ -170,6 +177,51 @@ describe('WS epic', () => { }); }); }; + + it('should return updated epic data when update rankValue', async () => { + const socket = await getMemberJoinedLandingPage(); + socket.emit('joinBacklog'); + await initBacklog(socket); + const name1 = '회원'; + const color1 = 'yellow'; + const rankValue1 = LexoRank.middle().toString(); + const requestData1: any = { + action: 'create', + content: { name: name1, color: color1, rankValue: rankValue1 }, + }; + socket.emit('epic', requestData1); + const id1 = await getEpicId(socket); + + const name2 = '회원'; + const color2 = 'yellow'; + const rankValue2 = LexoRank.parse(rankValue1).genNext().toString(); + const requestData2: any = { + action: 'create', + content: { name: name2, color: color2, rankValue: rankValue2 }, + }; + socket.emit('epic', requestData2); + const id2 = await getEpicId(socket); + + const updateRankValue = LexoRank.parse(rankValue2).genNext().toString(); + const requestData3 = { + action: 'update', + content: { id: id1, rankValue: updateRankValue }, + }; + + socket.emit('epic', requestData3); + await new Promise((resolve) => { + socket.once('backlog', async (data) => { + const { content, action, domain } = data; + expect(domain).toBe('epic'); + expect(action).toBe('update'); + expect(content?.id).toBe(id1); + expect(content?.rankValue).toBe(updateRankValue); + resolve(); + }); + }); + + socket.close(); + }); }); }); diff --git a/backend/test/project/ws-backlog-page/ws-init-backlog.e2e-spec.ts b/backend/test/project/ws-backlog-page/ws-init-backlog.e2e-spec.ts index 5886ad5..7e09c7d 100644 --- a/backend/test/project/ws-backlog-page/ws-init-backlog.e2e-spec.ts +++ b/backend/test/project/ws-backlog-page/ws-init-backlog.e2e-spec.ts @@ -1,8 +1,7 @@ +import { LexoRank } from 'lexorank'; import { Socket } from 'socket.io-client'; import { app, appInit } from 'test/setup'; -import { - getTwoMemberJoinedLandingPage, -} from '../ws-common'; +import { getTwoMemberJoinedLandingPage } from '../ws-common'; describe('WS epic', () => { beforeEach(async () => { @@ -18,9 +17,10 @@ describe('WS epic', () => { await initBacklog(socket1); const epicName = '회원'; const epicColor = 'yellow'; + const epicRankValue = LexoRank.middle().toString(); socket1.emit('epic', { action: 'create', - content: { name: epicName, color: epicColor }, + content: { name: epicName, color: epicColor, rankValue: epicRankValue }, }); const epicId = await getEpicId(socket1); const storyTitle = '타이틀'; diff --git a/backend/test/project/ws-backlog-page/ws-story.e2e-spec.ts b/backend/test/project/ws-backlog-page/ws-story.e2e-spec.ts index 8fa0e84..b94294c 100644 --- a/backend/test/project/ws-backlog-page/ws-story.e2e-spec.ts +++ b/backend/test/project/ws-backlog-page/ws-story.e2e-spec.ts @@ -1,3 +1,4 @@ +import { LexoRank } from 'lexorank'; import { Socket } from 'socket.io-client'; import { app, appInit } from 'test/setup'; import { @@ -21,9 +22,10 @@ describe('WS story', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket1.emit('epic', requestData); const [epicId] = await Promise.all([ @@ -72,9 +74,11 @@ describe('WS story', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); + let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]); @@ -119,9 +123,11 @@ describe('WS story', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); + let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]); @@ -167,9 +173,10 @@ describe('WS story', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]); diff --git a/backend/test/project/ws-backlog-page/ws-task.e2e-spec.ts b/backend/test/project/ws-backlog-page/ws-task.e2e-spec.ts index 2118840..329da68 100644 --- a/backend/test/project/ws-backlog-page/ws-task.e2e-spec.ts +++ b/backend/test/project/ws-backlog-page/ws-task.e2e-spec.ts @@ -1,3 +1,4 @@ +import { LexoRank } from 'lexorank'; import { Socket } from 'socket.io-client'; import { app, appInit } from 'test/setup'; import { @@ -21,9 +22,10 @@ describe('WS task', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket1.emit('epic', requestData); const [epicId] = await Promise.all([ @@ -178,9 +180,11 @@ describe('WS task', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); + let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]); @@ -245,9 +249,10 @@ describe('WS task', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]); @@ -353,9 +358,10 @@ describe('WS task', () => { const name = '회원'; const color = 'yellow'; + const rankValue = LexoRank.middle().toString(); let requestData: any = { action: 'create', - content: { name, color }, + content: { name, color, rankValue }, }; socket.emit('epic', requestData); const [epicId] = await Promise.all([getEpicId(socket)]);