From 37e09406448ce2f9bc4ac1e41e4d0cd6b9b437c1 Mon Sep 17 00:00:00 2001 From: Kevin Foong <55353265+kevin9foong@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:54:46 +0800 Subject: [PATCH] feat: add tc for delete form fields controller and service --- .../admin-form.assistance.service.spec.ts | 52 ++++++++ .../__tests__/admin-form.service.spec.ts | 126 ++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/src/app/modules/form/admin-form/__tests__/admin-form.assistance.service.spec.ts b/src/app/modules/form/admin-form/__tests__/admin-form.assistance.service.spec.ts index aa602db774..c3e97eff33 100644 --- a/src/app/modules/form/admin-form/__tests__/admin-form.assistance.service.spec.ts +++ b/src/app/modules/form/admin-form/__tests__/admin-form.assistance.service.spec.ts @@ -194,6 +194,58 @@ describe('admin-form.assistance.service', () => { expect(calledNewFields[0].description).toBeTruthy() expect(calledNewFields[0].description.trim()).not.toBe('') }) + + it('should return created field ids provided by return value of AdminFormService.createFormFields', async () => { + // Arrange + const VALID_ALL_FIELDS_INCLUDED_RESPONSE = + '[{"title":"Cat Information","fieldType":"Section","required":false},{"title":"Please provide the name of your cat.","fieldType":"Statement","required":true,"description":"This information is needed to identify your pet."},{"title":"Your Email Address","fieldType":"Email","required":true},{"title":"Your Mobile Number","fieldType":"Mobile","required":true},{"title":"Your Home Phone Number","fieldType":"HomeNo","required":false},{"title":"How many cats do you have?","fieldType":"Number","required":true},{"title":"How much do you spend on cat care monthly?","fieldType":"Decimal","required":true},{"title":"Cat\'s Name (Short)","fieldType":"ShortText","required":true},{"title":"Tell us more about your cat (Long)","fieldType":"LongText","required":false},{"title":"Select your favorite cat breed","fieldType":"Dropdown","required":true,"fieldOptions":["Siamese","Persian","Maine Coon","Bengal","Sphynx"]},{"title":"Country/Region","fieldType":"CountryRegion","required":true},{"title":"Do you agree to share your cat\'s name for our records?","fieldType":"YesNo","required":true},{"title":"Do you want to receive updates about cat care?","fieldType":"Checkbox","required":false,"fieldOptions":["Yes, send me emails","No, thank you"]},{"title":"Select your preferred communication method","fieldType":"Radio","required":true,"fieldOptions":["Email","Phone","SMS"]},{"title":"Upload a picture of your cat","fieldType":"Attachment","required":false},{"title":"Select the date of your cat\'s birthday","fieldType":"Date","required":true},{"title":"Rate your satisfaction with our cat services (1-5)","fieldType":"Rating","required":true},{"title":"Your NRIC Number","fieldType":"Nric","required":true},{"title":"Your Business UEN (if applicable)","fieldType":"Uen","required":false},{"title":"Cat Care Records","fieldType":"Table","required":true,"columns":["Date","Activity","Notes"],"minimumRows":1,"addMoreRows":true}]' + + MockedAiModel.sendUserTextPrompt = jest + .fn() + .mockReturnValue(okAsync(VALID_ALL_FIELDS_INCLUDED_RESPONSE)) + + const CREATED_FIELD_SCHEMAS = [ + { _id: '507f1f77bcf86cd799439011' }, + { _id: '507f1f77bcf86cd799439012' }, + { _id: '507f1f77bcf86cd799439013' }, + { _id: '507f1f77bcf86cd799439014' }, + { _id: '507f1f77bcf86cd799439015' }, + { _id: '507f1f77bcf86cd799439016' }, + { _id: '507f1f77bcf86cd799439017' }, + { _id: '507f1f77bcf86cd799439018' }, + { _id: '507f1f77bcf86cd799439019' }, + { _id: '507f1f77bcf86cd799439020' }, + { _id: '507f1f77bcf86cd799439021' }, + { _id: '507f1f77bcf86cd799439022' }, + { _id: '507f1f77bcf86cd799439023' }, + { _id: '507f1f77bcf86cd799439024' }, + { _id: '507f1f77bcf86cd799439025' }, + { _id: '507f1f77bcf86cd799439026' }, + { _id: '507f1f77bcf86cd799439027' }, + { _id: '507f1f77bcf86cd799439028' }, + { _id: '507f1f77bcf86cd799439029' }, + { _id: '507f1f77bcf86cd799439030' }, + ] + + const mockedCreateFormFields = + AdminFormService.createFormFields as jest.Mock + mockedCreateFormFields.mockReturnValueOnce( + okAsync(CREATED_FIELD_SCHEMAS as FormFieldSchema[]), + ) + + // Act + const createdFieldIds = await createFormFieldsUsingTextPrompt({ + form: mockForm, + userPrompt: mockUserPrompt, + }) + + // Assert + expect(AdminFormService.createFormFields).toHaveBeenCalledTimes(1) + expect(createdFieldIds.isOk()).toBe(true) + expect(createdFieldIds._unsafeUnwrap()).toEqual( + CREATED_FIELD_SCHEMAS.map((field) => field._id), + ) + }) }) describe('model errors', () => { diff --git a/src/app/modules/form/admin-form/__tests__/admin-form.service.spec.ts b/src/app/modules/form/admin-form/__tests__/admin-form.service.spec.ts index 22c7f37093..d103c7c28f 100644 --- a/src/app/modules/form/admin-form/__tests__/admin-form.service.spec.ts +++ b/src/app/modules/form/admin-form/__tests__/admin-form.service.spec.ts @@ -33,6 +33,7 @@ import { CreatePresignedPostError } from 'src/app/utils/aws-s3' import { formatErrorRecoveryMessage } from 'src/app/utils/handle-mongo-error' import { EditFieldActions } from 'src/shared/constants' import { + FormFieldSchema, FormLogicSchema, IEmailFormSchema, IFormDocument, @@ -2428,6 +2429,131 @@ describe('admin-form.service', () => { }) }) + describe('deleteFormFields', () => { + const deleteFormFieldsSpy = jest.spyOn(FormModel, 'deleteFormFieldsByIds') + + it('should return updated form when all fields to delete are found and deleted successfully', async () => { + // Arrange + const fieldsToDelete = [ + generateDefaultField(BasicField.Mobile), + generateDefaultField(BasicField.Image), + ] + + const mockUpdatedForm = { + title: 'some mock form', + form_fields: [generateDefaultField(BasicField.Nric)], + } as IFormSchema + + const mockForm = { + ...mockUpdatedForm, + form_fields: [ + ...fieldsToDelete, + ...(mockUpdatedForm.form_fields as FormFieldSchema[]), + ], + } as unknown as IPopulatedForm + + deleteFormFieldsSpy.mockResolvedValueOnce(mockUpdatedForm) + + // Act + const actual = await AdminFormService.deleteFormFields( + mockForm, + fieldsToDelete.map((f) => String(f._id)), + ) + + // Assert + expect(actual._unsafeUnwrap()).toEqual(mockUpdatedForm) + expect(deleteFormFieldsSpy).toHaveBeenCalledWith( + mockForm._id, + fieldsToDelete.map((f) => f._id), + ) + }) + + it('should return FormNotFoundError when form cannot be found', async () => { + // Arrange + const mockForm = { + _id: new ObjectId(), + form_fields: [generateDefaultField(BasicField.Mobile)], + } as unknown as IPopulatedForm + + deleteFormFieldsSpy.mockResolvedValueOnce(null) + + // Act + const actual = await AdminFormService.deleteFormFields(mockForm, [ + mockForm.form_fields[0]._id, + ]) + + // Assert + expect(actual._unsafeUnwrapErr()).toEqual(new FormNotFoundError()) + expect(deleteFormFieldsSpy).toHaveBeenCalledWith(mockForm._id, [ + mockForm.form_fields[0]._id, + ]) + }) + + it('should return updated form when some fields to delete are found and some are not found', async () => { + // Arrange + const fieldsToDelete = [ + generateDefaultField(BasicField.Mobile), + generateDefaultField(BasicField.Image), + ] + + const mockUpdatedForm = { + title: 'some mock form', + form_fields: [generateDefaultField(BasicField.Nric)], + } as IFormSchema + + const mockForm = { + ...mockUpdatedForm, + form_fields: [ + ...fieldsToDelete, + ...(mockUpdatedForm.form_fields as FormFieldSchema[]), + ], + } as unknown as IPopulatedForm + + deleteFormFieldsSpy.mockResolvedValueOnce(mockUpdatedForm) + + // Act + const actual = await AdminFormService.deleteFormFields( + mockForm, + fieldsToDelete.map((f) => String(f._id)), + ) + + // Assert + expect(actual._unsafeUnwrap()).toEqual(mockUpdatedForm) + expect(deleteFormFieldsSpy).toHaveBeenCalledWith( + mockForm._id, + fieldsToDelete.map((f) => f._id), + ) + }) + + it('should return unchanged form when no fields to delete are found', async () => { + // Arrange + const mockForm = { + title: 'some mock form', + form_fields: [generateDefaultField(BasicField.Nric)], + _id: new ObjectId(), + } as unknown as IPopulatedForm + + const mockUpdatedForm = { + ...mockForm, + } as IFormSchema + + deleteFormFieldsSpy.mockResolvedValueOnce(mockUpdatedForm) + + const nonExistentFieldId = new ObjectId().toHexString() + + // Act + const actual = await AdminFormService.deleteFormFields(mockForm, [ + nonExistentFieldId, + ]) + + // Assert + expect(actual._unsafeUnwrap()).toEqual(mockUpdatedForm) + expect(deleteFormFieldsSpy).toHaveBeenCalledWith(mockForm._id, [ + nonExistentFieldId, + ]) + }) + }) + describe('updateEndPage', () => { const updateSpy = jest.spyOn(FormModel, 'updateEndPageById') const MOCK_FORM_ID = new ObjectId().toHexString()