diff --git a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.controller.spec.ts b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.controller.spec.ts index 1c998ad9c..fb2d59f16 100644 --- a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.controller.spec.ts +++ b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.controller.spec.ts @@ -1,19 +1,31 @@ import { Test, TestingModule } from '@nestjs/testing'; import { NoticeOfIntentTagController } from './notice-of-intent-tag.controller'; import { NoticeOfIntentTagService } from './notice-of-intent-tag.service'; -import { DeepMocked } from '@golevelup/nestjs-testing'; +import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { ClsService } from 'nestjs-cls'; import { mockKeyCloakProviders } from '../../../../test/mocks/mockTypes'; +import { + initNoticeOfIntentMockEntity, + initNoticeOfIntentWithTagsMockEntity, + initTagMockEntity, +} from '../../../../test/mocks/mockEntities'; +import { NoticeOfIntentTagDto } from './notice-of-intent-tag.dto'; describe('NoticeOfIntentTagController', () => { let controller: NoticeOfIntentTagController; - let tagService: DeepMocked; + let noiTagService: DeepMocked; + + const mockNoticeOfIntentEntityWithoutTags = initNoticeOfIntentMockEntity(); + mockNoticeOfIntentEntityWithoutTags.tags = []; + const mockNoticeOfIntentEntityWithTags = initNoticeOfIntentWithTagsMockEntity(); + const mockTagEntity = initTagMockEntity(); beforeEach(async () => { + noiTagService = createMock(); const module: TestingModule = await Test.createTestingModule({ controllers: [NoticeOfIntentTagController], providers: [ - { provide: NoticeOfIntentTagService, useValue: tagService }, + { provide: NoticeOfIntentTagService, useValue: noiTagService }, { provide: ClsService, useValue: {}, @@ -28,4 +40,31 @@ describe('NoticeOfIntentTagController', () => { it('should be defined', () => { expect(controller).toBeDefined(); }); + + it('should return tags for the noi', async () => { + noiTagService.getNoticeOfIntentTags.mockResolvedValue([mockTagEntity]); + + const result = await controller.getApplicationTags('noi_1'); + expect(noiTagService.getNoticeOfIntentTags).toHaveBeenCalledTimes(1); + expect(result[0].name).toEqual('tag-name'); + }); + + it('should create tags', async () => { + noiTagService.addTagToNoticeOfIntent.mockResolvedValue(mockNoticeOfIntentEntityWithTags); + + const mockTagDto = new NoticeOfIntentTagDto(); + mockTagDto.tagName = 'tag-name'; + + const result = await controller.addTagToApplication('noi_1', mockTagDto); + expect(noiTagService.addTagToNoticeOfIntent).toHaveBeenCalledTimes(1); + expect(result.tags[0].name).toEqual('tag-name'); + }); + + it('should remove tags', async () => { + noiTagService.removeTagFromNoticeOfIntent.mockResolvedValue(mockNoticeOfIntentEntityWithoutTags); + + const result = await controller.removeTagFromApplication('noi_1', 'tag-name'); + expect(noiTagService.removeTagFromNoticeOfIntent).toHaveBeenCalledTimes(1); + expect(result.tags.length).toEqual(0); + }); }); diff --git a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.service.spec.ts b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.service.spec.ts index f03153fc7..5e50ecc0a 100644 --- a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.service.spec.ts +++ b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent-tag/notice-of-intent-tag.service.spec.ts @@ -5,24 +5,42 @@ import { NoticeOfIntent } from '../notice-of-intent.entity'; import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Repository } from 'typeorm'; import { Tag } from '../../tag/tag.entity'; +import { + initNoticeOfIntentMockEntity, + initNoticeOfIntentWithTagsMockEntity, + initTagMockEntity, +} from '../../../../test/mocks/mockEntities'; +import { ServiceNotFoundException, ServiceValidationException } from '@app/common/exceptions/base.exception'; describe('NoticeOfIntentTagService', () => { let service: NoticeOfIntentTagService; - let noiRepository: DeepMocked>; - let tagRepository: DeepMocked>; + let noiRepositoryMock: DeepMocked>; + let tagRepositoryMock: DeepMocked>; + + let mockNoiEntityWithoutTags: NoticeOfIntent; + let mockNoiEntityWithTags: NoticeOfIntent; + let mockNoiEntityWithDifferentTags: NoticeOfIntent; + let mockTagEntity: Tag; beforeEach(async () => { - noiRepository = createMock(); + tagRepositoryMock = createMock(); + noiRepositoryMock = createMock(); + mockNoiEntityWithoutTags = initNoticeOfIntentMockEntity(); + mockNoiEntityWithTags = initNoticeOfIntentWithTagsMockEntity(); + mockNoiEntityWithDifferentTags = initNoticeOfIntentWithTagsMockEntity(); + mockNoiEntityWithDifferentTags.tags[0].name = 'tag-name-2'; + mockNoiEntityWithDifferentTags.tags[0].uuid = 'tag-uuid-2'; + mockTagEntity = initTagMockEntity(); const module: TestingModule = await Test.createTestingModule({ providers: [ NoticeOfIntentTagService, { provide: getRepositoryToken(NoticeOfIntent), - useValue: noiRepository, + useValue: noiRepositoryMock, }, { provide: getRepositoryToken(Tag), - useValue: tagRepository, + useValue: tagRepositoryMock, }, ], }).compile(); @@ -33,4 +51,75 @@ describe('NoticeOfIntentTagService', () => { it('should be defined', () => { expect(service).toBeDefined(); }); + + it('should add tag to the noi if not existing', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithoutTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + noiRepositoryMock.save.mockResolvedValue(mockNoiEntityWithTags); + + await service.addTagToNoticeOfIntent('app_1', 'tag-name'); + expect(mockNoiEntityWithoutTags.tags.length).toEqual(1); + expect(noiRepositoryMock.save).toHaveBeenCalledTimes(1); + }); + + it('should raise an error if noi is not found', async () => { + noiRepositoryMock.findOne.mockResolvedValue(null); + + await expect(service.addTagToNoticeOfIntent('noi-1', 'tag-name')).rejects.toThrow(ServiceNotFoundException); + }); + + it('should throw an error if tag is not found', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithoutTags); + tagRepositoryMock.findOne.mockResolvedValue(null); + + await expect(service.addTagToNoticeOfIntent('noi-1', 'tag-name')).rejects.toThrow(ServiceNotFoundException); + }); + + it('should raise an error if the noi already has the tag', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + + await expect(service.addTagToNoticeOfIntent('noi-1', 'tag-name')).rejects.toThrow(ServiceValidationException); + }); + + it('should throw an error if the noi does not have any tags when deleting', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithoutTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + + await expect(service.removeTagFromNoticeOfIntent('noi-1', 'tag-name')).rejects.toThrow(ServiceValidationException); + }); + + it('should throw an error if the noi does not have the tag requested when deleting', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithDifferentTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + + await expect(service.removeTagFromNoticeOfIntent('noi-1', 'tag-name')).rejects.toThrow(ServiceValidationException); + }); + + it('should delete the tag from noi if exists', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + noiRepositoryMock.save.mockResolvedValue(mockNoiEntityWithoutTags); + + await service.removeTagFromNoticeOfIntent('noi-1', 'tag-name'); + expect(mockNoiEntityWithTags.tags.length).toEqual(0); + expect(noiRepositoryMock.save).toHaveBeenCalledTimes(1); + }); + + it('should return noi tags', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithTags); + tagRepositoryMock.findOne.mockResolvedValue(mockTagEntity); + + const result = await service.getNoticeOfIntentTags('noi-1'); + expect(result).toBeTruthy(); + expect(result.length).toEqual(1); + }); + + it('should return empty array if noi does not have tags', async () => { + noiRepositoryMock.findOne.mockResolvedValue(mockNoiEntityWithoutTags); + + const result = await service.getNoticeOfIntentTags('noi-1'); + expect(result).toEqual([]); + expect(result.length).toEqual(0); + }); }); diff --git a/services/apps/alcs/test/mocks/mockEntities.ts b/services/apps/alcs/test/mocks/mockEntities.ts index 33077d062..6906650d9 100644 --- a/services/apps/alcs/test/mocks/mockEntities.ts +++ b/services/apps/alcs/test/mocks/mockEntities.ts @@ -24,6 +24,8 @@ import { AssigneeDto, UserDto } from '../../src/user/user.dto'; import { User } from '../../src/user/user.entity'; import { TagCategory } from '../../src/alcs/tag/tag-category/tag-category.entity'; import { Tag } from '../../src/alcs/tag/tag.entity'; +import { NoticeOfIntent } from '../../src/alcs/notice-of-intent/notice-of-intent.entity'; +import { NoticeOfIntentType } from '../../src/alcs/notice-of-intent/notice-of-intent-type/notice-of-intent-type.entity'; const initCardStatusMockEntity = (): CardStatus => { const cardStatus = new CardStatus(); @@ -115,6 +117,19 @@ const initApplicationTypeMockEntity = (): ApplicationType => { return applicationType; }; +const initNoticeOfIntentTypeMockEntity = (): NoticeOfIntentType => { + const noticeOfIntentType = new NoticeOfIntentType(); + noticeOfIntentType.code = 'type_1'; + noticeOfIntentType.description = 'noi desc 1'; + noticeOfIntentType.label = 'noi_label'; + noticeOfIntentType.shortLabel = 'short_label'; + noticeOfIntentType.auditDeletedDateAt = new Date(1, 1, 1, 1, 1, 1, 1); + noticeOfIntentType.auditCreatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + noticeOfIntentType.auditUpdatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + + return noticeOfIntentType; +}; + const initUserMockEntity = (): User => { const user = new User(); user.familyName = 'familyName'; @@ -207,6 +222,28 @@ const initApplicationMockEntity = (fileNumber?: string): Application => { return applicationEntity; }; +const initNoticeOfIntentMockEntity = (fileNumber?: string): NoticeOfIntent => { + const noticeOfIntentEntity = new NoticeOfIntent(); + noticeOfIntentEntity.fileNumber = fileNumber ?? 'app_1'; + noticeOfIntentEntity.applicant = 'applicant 1'; + noticeOfIntentEntity.uuid = '1111-1111-1111-1111'; + noticeOfIntentEntity.auditDeletedDateAt = new Date(1, 1, 1, 1, 1, 1, 1); + noticeOfIntentEntity.auditCreatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + noticeOfIntentEntity.auditUpdatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + noticeOfIntentEntity.card = initCardMockEntity(); + noticeOfIntentEntity.cardUuid = noticeOfIntentEntity.card.uuid; + noticeOfIntentEntity.type = initNoticeOfIntentTypeMockEntity(); + noticeOfIntentEntity.card.highPriority = false; + noticeOfIntentEntity.region = { + code: 'fake', + label: 'fake', + auditCreatedAt: new Date(1, 1, 1, 1, 1, 1, 1), + auditUpdatedAt: new Date(1, 1, 1, 1, 1, 1, 1), + } as ApplicationRegion; + + return noticeOfIntentEntity; +}; + const initApplicationWithTagsMockEntity = (): Application => { const applicationEntity = initApplicationMockEntity(); const tagEntity = initTagMockEntity(); @@ -215,6 +252,14 @@ const initApplicationWithTagsMockEntity = (): Application => { return applicationEntity; }; +const initNoticeOfIntentWithTagsMockEntity = (): NoticeOfIntent => { + const noticeOfIntentEntity = initNoticeOfIntentMockEntity(); + const tagEntity = initTagMockEntity(); + noticeOfIntentEntity.tags = []; + noticeOfIntentEntity.tags.push(tagEntity); + return noticeOfIntentEntity; +}; + const initMockUserDto = (assignee?: User): UserDto => { const userEntity = assignee ?? initUserMockEntity(); const userDto = new UserDto(); @@ -369,4 +414,6 @@ export { initTagCategoryMockEntity, initTagMockEntity, initApplicationWithTagsMockEntity, + initNoticeOfIntentMockEntity, + initNoticeOfIntentWithTagsMockEntity, };