import { Injectable } from '@angular/core'; import { GCMockModule } from '@core/mocks/gc-module.mock'; import { ReferenceFieldAPI } from '@core/typings/api/reference-fields.typing'; import { ApplicantFormForUI, ApplicantFormFromApi, ApplicationFromApi } from '@core/typings/application.typing'; import { User, UserTypes } from '@core/typings/client-user.typing'; import { ProcessingTypes } from '@core/typings/payment.typing'; import { ProgramApplicantType } from '@core/typings/program.typing'; import { ApplicationStatuses } from '@core/typings/status.typing'; import { ReferenceFieldsUI } from '@core/typings/ui/reference-fields.typing'; import { ApplicationViewFormForUI, ApplicationViewFormFromApi, AvailabilityOptions, CompletionRequirementType, FormAudience, FormDecisionTypes, FormDueEmailModalResponse, FormForApplicantForUI, FormReminderForApi, FormRequirements, FormResponse, FormStatuses, FormTypes, ResponseVisibilityOptions, SaveFormResponse } from '@features/configure-forms/form.typing'; import { OrganizationEligibleForGivingStatus } from '@yourcause/common'; import { AfterEach, BeforeEach, Spec, TestCase } from '@yourcause/test-decorators'; import { DescribeAngularService } from '@yourcause/test-decorators/angular'; import { expect, spy } from 'chai'; import { cloneDeep } from 'lodash'; import { ApplicationFormService } from './application-forms.service'; @Injectable({ providedIn: 'root' }) @DescribeAngularService(ApplicationFormService, { imports: [ GCMockModule ] }) export class ApplicationFormServiceSpec implements Spec { formId = 2353; appId = 44; revisionId = 7563; applicantForms: FormForApplicantForUI[] = [{ formId: this.formId, formRevisionId: this.revisionId, formData: {}, isDraft: true, applicationFormId: 5, dueDate: '03/22/2022', revisionNotes: '', formName: '', submittedDate: '', createdBy: '', updatedBy: '', submittedBy: '', statusUpdatedDate: '', updatedDate: '', createdDate: '', applicationFormStatusId: FormStatuses.DraftSaved, isOverdue: false }]; applicationFormId = 10; textFieldKey = 'textFieldKey'; formResponse: FormResponse = { applicationFormId: this.applicationFormId, isDraft: true, revisionNotes: '', formComments: '', submittedBy: { firstName: 'Tina', lastName: 'Conway', email: 'asdf@email.com', userType: UserTypes.APPLICANT, impersonatedBy: '' }, applicationFormStatusId: FormStatuses.Submitted, submittedDate:'2022-06-30T06:00:00.000Z', formData: {}, formDefinition: [{ logic: null, index: 0, tabName: '', components: [{ key: this.textFieldKey, type: `referenceFields-${this.textFieldKey}` }] }], formRevisionId: this.revisionId, workflowLevelName: '', revisionLastSentDate: '', decision: FormDecisionTypes.Decline, dueDate: null, reviewerRecommendedFundingAmount: null }; applicantFormsForUi: ApplicantFormForUI[] = [{ applicationFormId: this.applicationFormId, canApproveApplicaitonForm: true, canDeclineApplicationForm: true, canRequestRevision: true, formComments: [{ workflowLevelId: 1, workflowLevelName: '', firstName: '', lastName: '', profileImageUrl: '', notes: '', createdDate: '' }], formData: {}, formDefinition: [{ logic: null, index: 0, tabName: '', components: [{ key: this.textFieldKey, type: `referenceFields-${this.textFieldKey}` }] }], formDescription: '', formId: this.formId, formName: '', formRevisionId: this.revisionId, formStatus: FormStatuses.Sent, formSubmittedOn: '', createdBy: '', submittedBy: '', formTypeId: FormTypes.REQUEST, myCommentInCurrentLevel: '', statusUpdatedBy: '', statusUpdatedByClientUser: null, statusUpdatedDate: '', totalCommentsInCurrentWorkflow: 1, isDefault: true, portalFormAvailabilityInfo: null, updatedBy: '', updatedDate: '', impersonatedBy: '', userType: UserTypes.APPLICANT, dueDate: '03/05/2020', isOverdue: true, formResponse: { ...this.formResponse }, name: '', programApplicantType: ProgramApplicantType.ORGS, createImpersonatedBy: '', isDraft: false, requireSignature: false, signatureDescription: '' }]; grantProgramCycle = { id: 633, name: 'Cycle name', startDate: '', endDate: '', grantProgramId: 1235, isArchived: false, clientOrganizationsProcessingTypeId: ProcessingTypes.YourCause, isClientProcessing: false }; applicationFromApi: ApplicationFromApi = { reservedFunds: false, budgetId: null, fundingSourceId: null, applicationGuid: 'abc-123', applicationId: this.appId, applicationStatus: ApplicationStatuses.Approved, submittedDate: '', applicantId: 65, applicantFirstName: 'Lukie', applicantCanReceiveEmails: true, applicantLastName: 'Smith', applicantEmail: 'lukie@mailinator.com', applicantPhoneNumber: '', applicationProfileImageUrl: '', applicantAddress: '', programName: 'Program name', programId: 4575, grantProgramTimezone: 'UTC', organizationId: 7476, charityId: 5, organizationName: 'Org name', orgnizationImageUrl: '', organizationIdentification: '12-3415', organizationAddress: '', isPrivateOrg: false, daysInReview: 0, isApplicationInClientUserWorkflowLevel: true, workflowLevelApplicationReview: null, reviewRuleType: null, totalWorkflowLevelReviews: 4, totalWorkflowLevelUsers: 4, majorityReviewed: false, currentWorkflowName: 'WFL name', currentWorkFlowLevelName: 'WF name', parentWorkFlowLevelName: 'Parent WFL name', parentWorkFlowLevelId: 1, canRouteApplication: true, canArchiveAndUnarchiveApplication: true, canApproveApplication: true, canAwardApplication: true, canDeclineApplication: true, canArchiveApplication: true, canExtendFormDueDate: true, canRecommendFunding: true, hasNonPaidPayments: true, workflowLevelUsersWithoutReviews: [], workflowLevelRoutes: [], managerWillComplete: true, isDraft: true, programAllowCollaboration: true, programSendEmailsToCollaborators: true, amountRequested: 500, paymentDesignation: 'payment designation', careOf: null, createdBy: null, lastUpdatedBy: null, updatedDate: '', createdDate: '', nonprofitGuid: 'guid', currentWorkFlowLevelId: 96, currentWorkFlowId: 464, isArchived: true, nominee: null, nominationApplicationId: 6, canAccessNominationApplication: true, isMasked: true, canViewMaskedApplicantInfo: false, specialHandlingAddress1: 'Address 1', specialHandlingAddress2: 'Address 2', specialHandlingCity: 'City', specialHandlingCountry: 'US', specialHandlingName: 'Special Handling name', specialHandlingPostalCode: '32690', specialHandlingStateProvinceRegion: 'SC', specialHandlingNotes: '', specialHandlingFileUrl: null, specialHandlingReason: '', currencyRequestedAmountEquivalent: 0, currencyRequested: 'USD', inKindAmountRequested: 0, inKindItems: [], isProgramArchived: true, meetsVettingRequirement: true, grantProgramCycle: this.grantProgramCycle, hasAwards: false, hasPayments: false, hasCashAward: false, organizationEligibleForGivingStatus: OrganizationEligibleForGivingStatus.ELIGIBLE, recommendedFundingAmount: 0, orgIsInternational: false, applicantIsSSO: false, currentWorkflowLevelShowBudgetSummaryInfo: true, currentWorkflowLevelAllowUserToViewAwardsAndPayments: true, currentWorkflowLevelAllowAward: true }; textFieldId = 757; tableId = 3464; tableKey = 'tableKey'; tableField: ReferenceFieldAPI.ReferenceFieldDisplayModel = { isEncrypted: false, isMasked: false, aggregateType: null, referenceFieldId: this.tableId, parentReferenceFieldId: null, formCount: 0, usedOnReports: false, createdBy: '', createDate: '', updatedBy: '', updateDate: '', customDataTableGuid: '', name: 'Table field', description: '', type: ReferenceFieldsUI.ReferenceFieldTypes.Table, key: this.tableKey, supportsMultiple: false, categoryId: 0, formAudience: FormAudience.APPLICANT, isSingleResponse: true, tableAllowsImport: false, isTableField: false, aggregateTableReferenceFieldId: null, referenceFieldTableId: null, standardComponentIsPublished: true, isStandardProductField: false, subsetCollectionType: null }; tableRowUpdatePayload: ReferenceFieldsUI.AdaptRefChangesResponse = { needToSaveFileIds: false, standardChangeValues: [], tableChangeValues: { updates: [{ values: [{ referenceFieldKey: this.textFieldKey, referenceFieldId: this.textFieldId, value: '2', numericValue: null, currencyValue: '' }], rowId: null, isNewRecord: true, tableReferenceFieldId: this.tableId, index: 0 }], deletions: [] }, tableChangeMap: { [this.tableKey]: [{ rowId: null, columns: [{ referenceFieldKey: this.textFieldKey, referenceFieldId: this.textFieldId, value: '2', numericValue: null, dateValue: '', currencyValue: '', file: null, files: [], applicationFormId: 1, applicationId: 2 }] }] } }; textField: ReferenceFieldAPI.ReferenceFieldDisplayModel = { isEncrypted: false, isMasked: false, aggregateType: null, referenceFieldId: this.textFieldId, parentReferenceFieldId: null, formCount: 1, usedOnReports: false, createdBy: '', createDate: '', updateDate: '', updatedBy: '', customDataTableGuid: '', name: 'Text Field', description: '', type: ReferenceFieldsUI.ReferenceFieldTypes.TextField, key: this.textFieldKey, supportsMultiple: false, categoryId: 2, formAudience: FormAudience.APPLICANT, isSingleResponse: true, tableAllowsImport: false, isTableField: false, aggregateTableReferenceFieldId: null, referenceFieldTableId: null, standardComponentIsPublished: true, isStandardProductField: false, subsetCollectionType: null }; tableRowId = 64; reviewForm: ApplicationViewFormFromApi = { audience: FormAudience.MANAGER, formId: 5325, formRevisionId: 25332, grantManagerActionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, responses: [], otherLevelResponses: [], nominationResponses: [], name: '', formType: FormTypes.REVIEW, comments: [], actionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, completionRequirementType: CompletionRequirementType.ALL_USERS, specificNumberForCompletion: null, managersCount: 4, portalAvailabilityDetails: { portalFormAvailabilityType: AvailabilityOptions.AUTO, portalFormAvailabilityDateOption: null, portalFormAvailabilityDateOffset: '', portalFormAvailabilityDate: '', portalFormAvailabilityDynamicDateApplicationApproval: '', portalFormAvailabilityDynamicDateAwardCreation: '', portalFormAvailabilityDynamicDateApplicationSubmission: '', portalFormAvailabilityDynamicDateWorkflowLevelEntry: '' }, dueDate: '', sortOrder: 1, requireSignature: false, signatureDescription: '' }; requestForm: ApplicationViewFormFromApi = { audience: FormAudience.APPLICANT, formId: 23531, formRevisionId: 95959, grantManagerActionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, responses: [], otherLevelResponses: [], nominationResponses: [], name: '', formType: FormTypes.REQUEST, comments: [], actionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, completionRequirementType: CompletionRequirementType.ALL_USERS, specificNumberForCompletion: null, managersCount: 4, portalAvailabilityDetails: { portalFormAvailabilityType: AvailabilityOptions.AUTO, portalFormAvailabilityDateOption: null, portalFormAvailabilityDateOffset: '', portalFormAvailabilityDate: '', portalFormAvailabilityDynamicDateApplicationApproval: '', portalFormAvailabilityDynamicDateAwardCreation: '', portalFormAvailabilityDynamicDateApplicationSubmission: '', portalFormAvailabilityDynamicDateWorkflowLevelEntry: '' }, dueDate: '', sortOrder: 1, requireSignature: false, signatureDescription: '' }; appViewFormsFromApi = [ this.reviewForm, this.requestForm ]; applicationForms: ApplicantFormFromApi[] = [{ updatedBy: '', updatedDate: '', createdBy: '', impersonatedBy: '', createImpersonatedBy: '', formTypeId: FormTypes.REQUEST, applicationFormId: this.applicationFormId, formId: 12, formRevisionId: 5, formName: 'Form name', formDescription: '', formStatus: FormStatuses.Submitted, statusUpdatedDate: '', statusUpdatedBy: '', formSubmittedOn: '', totalCommentsInCurrentWorkflow: 0, canRequestRevision: false, canApproveApplicaitonForm: false, canDeclineApplicationForm: false, formData: {}, statusUpdatedByClientUser: null, formComments: [], myCommentInCurrentLevel: '', programApplicantType: ProgramApplicantType.ORGS, isDefault: true, portalFormAvailabilityInfo: null, dueDate: '01/12/2022', submittedBy: '', isDraft: false, formDefinition: [], requireSignature: false, signatureDescription: '' }, { updatedBy: '', updatedDate: '', createdBy: '', impersonatedBy: '', createImpersonatedBy: '', formTypeId: FormTypes.REVIEW, applicationFormId: 13253, formId: 124, formRevisionId: 5, formName: 'Form 2', formDescription: '', formStatus: FormStatuses.DraftSaved, statusUpdatedDate: '', statusUpdatedBy: '', formSubmittedOn: '', totalCommentsInCurrentWorkflow: 0, canRequestRevision: false, canApproveApplicaitonForm: false, canDeclineApplicationForm: false, formData: {}, statusUpdatedByClientUser: null, formComments: [], myCommentInCurrentLevel: '', programApplicantType: ProgramApplicantType.ORGS, isDefault: true, portalFormAvailabilityInfo: null, dueDate: '', submittedBy: '', isDraft: false, formDefinition: [], requireSignature: false, signatureDescription: '' }]; applicantViewForm: ApplicationViewFormForUI = { audience: FormAudience.APPLICANT, formId: 53542, formRevisionId: 8657, grantManagerActionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, name: 'Request form', formType: FormTypes.REQUEST, comments: [], actionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, completionRequirementType: CompletionRequirementType.NONE, specificNumberForCompletion: null, managersCount: null, portalAvailabilityDetails: { portalFormAvailabilityDate: null, portalFormAvailabilityDateOffset: '0', portalFormAvailabilityDateOption: null, portalFormAvailabilityDynamicDateApplicationApproval: null, portalFormAvailabilityDynamicDateApplicationSubmission: '2022-06-14T16:27:36.1964069Z', portalFormAvailabilityDynamicDateAwardCreation: null, portalFormAvailabilityDynamicDateWorkflowLevelEntry: '2022-06-14T16:27:38.5732807Z', portalFormAvailabilityType: 1 }, dueDate: '10/08/2022', sortOrder: 1, requireSignature: true, signatureDescription: '', isOverdue: false, responses: [{ ...this.formResponse, applicationFormStatusId: FormStatuses.DraftSaved }], otherLevelResponses: [], nominationResponses: [] }; managerViewForm: ApplicationViewFormForUI = { audience: FormAudience.MANAGER, formId: 5341532, formRevisionId: 85657, grantManagerActionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, name: 'Review form', formType: FormTypes.REVIEW, comments: [], actionType: ResponseVisibilityOptions.VIEW_AT_ALL_WORKFLOW, completionRequirementType: CompletionRequirementType.ALL_USERS, specificNumberForCompletion: null, managersCount: 2, portalAvailabilityDetails: { portalFormAvailabilityDate: null, portalFormAvailabilityDateOffset: '0', portalFormAvailabilityDateOption: null, portalFormAvailabilityDynamicDateApplicationApproval: null, portalFormAvailabilityDynamicDateApplicationSubmission: '2022-06-14T16:27:36.1964069Z', portalFormAvailabilityDynamicDateAwardCreation: null, portalFormAvailabilityDynamicDateWorkflowLevelEntry: '2022-06-14T16:27:38.5732807Z', portalFormAvailabilityType: 1 }, dueDate: '', sortOrder: 2, requireSignature: true, signatureDescription: '', isOverdue: false, responses: [{ ...this.formResponse, applicationFormStatusId: FormStatuses.Submitted }], otherLevelResponses: [], nominationResponses: [] }; applicationViewForms: ApplicationViewFormForUI[] = [ this.applicantViewForm, this.managerViewForm ]; userEmail = 'tina.conway@gmail.com'; @BeforeEach() mock (service: ApplicationFormService) { service['applicationFormResources'].getAllApplicantForms = async () => { return this.applicantForms; }; service['applicationFormResources'].sendReviewReminder = async () => {}; service['applicationFormResources'].saveReferenceFields = async () => { return { rowId: this.tableRowId }; }; service['referenceFieldsService'].setAllReferenceFields([ this.tableField, this.textField ]); service['applicationFormResources'].getAllApplicationForms = async () => { return { formDetails: this.appViewFormsFromApi, applicationReferenceFieldResponses: [] }; }; service['applicationFormResources'].getApplicationForms = async () => { return this.applicationForms; }; service['statusService'].getFormStatusMap(); } @AfterEach() restore () { spy.restore(); } @TestCase('should be able to set editing form') setEditingForm (service: ApplicationFormService) { service.setEditingForm(true); expect(service.editingForm).to.be.true; service.setEditingForm(false); expect(service.editingForm).to.be.false; } @TestCase('should be able to set forms for user') setFormsForUser (service: ApplicationFormService) { const forms = ['form1', 'form2']; service.setFormsForUser(forms); expect(service.formsForUser).to.deep.equal(forms); service.setFormsForUser(undefined); const noForms = !service.formsForUser; expect(noForms).to.be.true; } @TestCase('should be able to set optional forms for user') setOptionalFormsForUser (service: ApplicationFormService) { const forms = ['optional1', 'optional2']; service.setOptionalFormsForUser(forms); expect(service.optionalFormsForUser).to.deep.equal(forms); service.setOptionalFormsForUser(undefined); const noForms = !service.optionalFormsForUser; expect(noForms).to.be.true; } @TestCase('should be able to get all applicant forms - due date relevant') async getAllApplicantForms (service: ApplicationFormService) { spy.on(service['applicationFormResources'], 'getAllApplicantForms'); await service.getAllApplicantForms(12, ApplicationStatuses.AwaitingReview); expect(service['applicationFormResources']['getAllApplicantForms']).to.have.been.called.once; } @TestCase('should be able to get all applicant forms - due date not relevant') async getAllApplicantForms2 (service: ApplicationFormService) { spy.on(service['applicationFormResources'], 'getAllApplicantForms', () => { return [{ ...this.applicantForms[0], applicationFormStatusId: FormStatuses.Submitted }]; }); await service.getAllApplicantForms(12, ApplicationStatuses.AwaitingReview); expect(service['applicationFormResources']['getAllApplicantForms']).to.have.been.called.once; } @TestCase('should be able to get due date from responses array - applicant form') getDueDateFromResponseArray (service: ApplicationFormService) { const dueDate = '01/01/2021'; const isManagerForm = false; const isInMyWfl = false; const result = service.getDueDateFromResponseArray( [{ ...this.formResponse, applicationFormStatusId: FormStatuses.DraftSaved, dueDate, isOverdue: true }], isManagerForm, isInMyWfl, dueDate, ApplicationStatuses.Draft ); expect(result.dueDate).to.be.equal(dueDate); expect(result.isOverdue).to.be.true; } @TestCase('should be able to get due date from responses array - manager form') getDueDateFromResponseArray2 (service: ApplicationFormService) { const isManagerForm = true; const isInMyWfl = true; const dueDate = '03/22/2022'; const result = service.getDueDateFromResponseArray( [{ ...this.formResponse, createdBy: { firstName: 'Tina', lastName: 'Conway', userType: UserTypes.MANAGER, impersonatedBy: '', email: this.userEmail } }], isManagerForm, isInMyWfl, dueDate, ApplicationStatuses.Approved ); expect(result.dueDate).to.be.equal(dueDate); expect(result.isOverdue).to.be.true; } @TestCase('should be able to get due date from responses array - no response') getDueDateFromResponseArray3 (service: ApplicationFormService) { const isManagerForm = true; const isInMyWfl = true; const dueDate = '03/22/2022'; const result = service.getDueDateFromResponseArray( [], isManagerForm, isInMyWfl, dueDate, ApplicationStatuses.Approved ); expect(result.dueDate).to.be.equal(dueDate); expect(result.isOverdue).to.be.true; } @TestCase('should be able to get due date from responses array - no due date') getDueDateFromResponseArray4 (service: ApplicationFormService) { const isManagerForm = false; const isInMyWfl = true; const dueDate = '03/22/2022'; const result = service.getDueDateFromResponseArray( [{ ...this.formResponse, applicationFormStatusId: FormStatuses.Submitted, createdBy: { firstName: 'Tina', lastName: 'Conway', userType: UserTypes.APPLICANT, impersonatedBy: '', email: this.userEmail } }], isManagerForm, isInMyWfl, dueDate, ApplicationStatuses.Approved ); const noDueDate = !result.dueDate; expect(noDueDate).to.be.true; expect(result.isOverdue).to.be.false; } @TestCase('should be able to get form due string') getFormDueString (service: ApplicationFormService) { const result = service.getFormDueString('03/01/2020'); expect(result).to.be.equal('Form due on Mar 1, 2020'); } @TestCase('should be able to get if due date is relevant') isDueDateRelevant (service: ApplicationFormService) { let isRelevant = service.isDueDateRelevant( FormStatuses.DraftSaved, ApplicationStatuses.AwaitingReview ); expect(isRelevant).to.be.true; isRelevant = service.isDueDateRelevant( FormStatuses.DraftSaved, ApplicationStatuses.Hold ); expect(isRelevant).to.be.false; } @TestCase('should be able to get all application forms') async getAllApplicationForms (service: ApplicationFormService) { spy.on(service, 'setIsOverdueOnFormResponsesAndAdaptTabs'); spy.on(service, 'getDueDateFromResponseArray'); const response = await service.getAllApplicationForms( this.appId, false, ApplicationStatuses.AwaitingReview ); expect(response.length).to.be.equal(this.appViewFormsFromApi.length); // We call "setIsOverdueOnFormResponsesAndAdaptTabs" 3 times for every form const numberOfCalls = this.appViewFormsFromApi.length * 3; expect(service['setIsOverdueOnFormResponsesAndAdaptTabs']).to.have.been.called.exactly(numberOfCalls); // We call "getDueDateFromResponseArray" once for each form expect(service['getDueDateFromResponseArray']).to.have.been.called.exactly(this.appViewFormsFromApi.length); } @TestCase('should be able to se is overdue on form responses and adapt tabs') setIsOverdueOnFormResponsesAndAdaptTabs (service: ApplicationFormService) { const dueDate = '01/01/2021'; let result = service.setIsOverdueOnFormResponsesAndAdaptTabs( [{ ...this.formResponse, applicationFormStatusId: FormStatuses.DraftSaved, dueDate, isOverdue: null }], 1, 2 ); const isOverdue = result[0].isOverdue; expect(isOverdue).to.be.true; result = service.setIsOverdueOnFormResponsesAndAdaptTabs( [{ ...this.formResponse, applicationFormStatusId: FormStatuses.Submitted, dueDate, isOverdue: null }], 1, 2 ); const notOverdue = !result[0].isOverdue; expect(notOverdue).to.be.true; } @TestCase('should be able to get applicant forms for application') async getApplicantFormsForApplication (service: ApplicationFormService) { const forms = cloneDeep(this.applicationForms); spy.on(service['applicationFormResources'], 'getApplicationForms', async () => { return forms; }); spy.on(service, 'isDueDateRelevant'); spy.on(service['formLogicService'], 'adaptFormDefinitionForTabs'); spy.on(service, 'getIsFormOverdue'); spy.on(service, 'adaptApplicantFormToResponse'); await service.getApplicantFormsForApplication( this.appId, this.applicationFromApi.applicationStatus ); expect(service['applicationFormResources']['getApplicationForms']).to.have.been.called.once; const numberOfFormsWithDueDate = this.applicationForms.filter((form) => !!form.dueDate).length; expect(service['isDueDateRelevant']).to.have.been.called.exactly(numberOfFormsWithDueDate); const numberOfForms = this.applicationForms.length; expect(service['formLogicService']['adaptFormDefinitionForTabs']).to.have.been.called.exactly(numberOfForms); expect(service['getIsFormOverdue']).to.have.been.called.exactly(numberOfForms); expect(service['adaptApplicantFormToResponse']).to.have.been.called.exactly(numberOfForms); } @TestCase('should be able to adapt applicant form to view form response') async adaptApplicantFormToViewFormResponse (service: ApplicationFormService) { const adapted = service.adaptApplicantFormToViewFormResponse( this.applicantFormsForUi[0] ); expect(adapted.formStatus).to.be.equal(this.applicantFormsForUi[0].formStatus); expect(adapted.applicationFormId).to.be.equal(this.applicationFormId); } @TestCase('should be able to adapt form response to view form repsonse') async adaptFormResponseToViewFormResponse (service: ApplicationFormService) { const adapted = service.adaptFormResponseToViewFormResponse( this.formResponse, this.formId, FormTypes.REQUEST, 'Form name', [{ comment: 'Comment', commentor: { firstName: 'Tina', lastName: 'Conway', email: 'asdf@email.com', userType: UserTypes.MANAGER, impersonatedBy: '' }, commentDate: '04/24/2022' }] ); expect(adapted.formStatus).to.be.equal(this.formResponse.applicationFormStatusId); expect(adapted.applicationFormId).to.be.equal(this.applicationFormId); } @TestCase('should be able to adapt form response to view form repsonse - use created by') async adaptFormResponseToViewFormResponseUseCreatedBy (service: ApplicationFormService) { const formResponse: FormResponse = { ...this.formResponse, submittedBy: null, createdBy: this.formResponse.submittedBy }; const adapted = service.adaptFormResponseToViewFormResponse( formResponse, this.formId, FormTypes.REQUEST, 'Form name', [] ); const expectedSubmittedBy = `${formResponse.createdBy.firstName} ${formResponse.createdBy.lastName}`; expect(adapted.formSubmittedBy).to.be.equal(expectedSubmittedBy); expect(adapted.formStatus).to.be.equal(this.formResponse.applicationFormStatusId); expect(adapted.applicationFormId).to.be.equal(this.applicationFormId); } @TestCase('should be able to save form response') async saveFormResponse (service: ApplicationFormService) { spy.on(service['applicationFormResources'], 'saveFormResponse', async () => {}); const data = {} as SaveFormResponse; await service.saveFormResponse(data, 1); expect(service['applicationFormResources']['saveFormResponse']).to.have.been.called.once; } @TestCase('should be able to get all application forms panels - manager tests') getAllApplicationFormsPanelsManagerTests (service: ApplicationFormService) { // Manager forms should be calling: getRequiredCount, getPanelDescription, getPanelIconAndClass // Applicant forms should not be calling these let gotRequiredCountForManager = false; let gotRequiredCountForApplicant = false; spy.on(service, 'getRequiredCount', (form: ApplicationViewFormForUI) => { if (form.formId === this.managerViewForm.formId) { gotRequiredCountForManager = true; } if (form.formId === this.applicantViewForm.formId) { gotRequiredCountForApplicant = true; } }); let gotPanelDescriptionForManager = false; let gotPanelDescriptionForApplicant = false; spy.on(service, 'getPanelDescription', (form: ApplicationViewFormForUI) => { if (form.formId === this.managerViewForm.formId) { gotPanelDescriptionForManager = true; } if (form.formId === this.applicantViewForm.formId) { gotPanelDescriptionForApplicant = true; } }); let gotPanelIconForManager = false; let gotPanelIconForApplicant = false; spy.on(service, 'getPanelIconAndClass', (_, completionRequirementType: CompletionRequirementType) => { const isManagerForm = this.managerViewForm.completionRequirementType === completionRequirementType; if (isManagerForm) { gotPanelIconForManager = true; } if (!isManagerForm) { gotPanelIconForApplicant = true; } return { icon: 'check-circle', iconClass: 'success' }; }); service.getAllApplicationFormsPanels(this.applicationViewForms); expect(gotRequiredCountForManager).to.be.true; expect(gotRequiredCountForApplicant).to.be.false; expect(gotPanelDescriptionForManager).to.be.true; expect(gotPanelDescriptionForApplicant).to.be.false; expect(gotPanelIconForManager).to.be.true; expect(gotPanelIconForApplicant).to.be.false; } @TestCase('should be able to get all application forms panels - applicant tests') getAllApplicationFormsPanelsApplicantTests (service: ApplicationFormService) { // Applicant forms should be calling getDynamicStatusString, while manager forms should not // We call getFormDueString on any form with a due date (manager form in this case) let gotDynamicStatusStringForManager = false; let gotDynamicStatusStringForApplicant = false; spy.on(service, 'getDynamicStatusString', (applicationFormStatusId: number) => { if (applicationFormStatusId === this.managerViewForm.responses[0].applicationFormStatusId) { gotDynamicStatusStringForManager = true; } if (applicationFormStatusId === this.applicantViewForm.responses[0].applicationFormStatusId) { gotDynamicStatusStringForApplicant = true; } }); let dueDateToEvaluate; spy.on(service, 'getFormDueString', (dueDate: string) => { dueDateToEvaluate = dueDate; }); service.getAllApplicationFormsPanels(this.applicationViewForms); expect(gotDynamicStatusStringForManager).to.be.false; expect(gotDynamicStatusStringForApplicant).to.be.true; expect(dueDateToEvaluate).to.be.equal(this.applicantViewForm.dueDate); } @TestCase('should be able to get all application forms panels - handle no response') getAllApplicationFormPanelsNoResponse (service: ApplicationFormService) { const forms = service.getAllApplicationFormsPanels([{ ...this.applicantViewForm, responses: [], dueDate: '' }]); const applicantViewForm = forms[0]; // No responses exist, so description should be "No response" expect(applicantViewForm.description).to.be.equal('No response'); } @TestCase('should be able to get required count - all users') getRequiredCountAllUsers (service: ApplicationFormService) { const result = service.getRequiredCount({ ...this.managerViewForm, managersCount: 2, completionRequirementType: CompletionRequirementType.ALL_USERS, responses: [{ decision: FormDecisionTypes.Recused, isDraft: false } as FormResponse, { decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse], otherLevelResponses: [{ decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse] }); // 2 managers in WFL, one recused, one approved // All users requirement met expect(result.countComplete).to.be.equal(1); expect(result.countOtherWorkflows).to.be.equal(1); expect(result.countRequired).to.be.equal(1); expect(result.metRequirement).to.be.true; } @TestCase('should be able to get required count - majority') getRequiredCountMajority (service: ApplicationFormService) { const result = service.getRequiredCount({ ...this.managerViewForm, managersCount: 4, completionRequirementType: CompletionRequirementType.MAJORITY, responses: [{ decision: FormDecisionTypes.Recused, isDraft: false } as FormResponse, { decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse], otherLevelResponses: [{ decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse] }); // 4 managers in WFL, one recused, one approved, two didn't answer // Majority requirement not met expect(result.countComplete).to.be.equal(1); expect(result.countOtherWorkflows).to.be.equal(1); expect(result.countRequired).to.be.equal(2); expect(result.metRequirement).to.be.false; } @TestCase('should be able to get required count - specific count') getRequiredCountSpecificCount (service: ApplicationFormService) { const result = service.getRequiredCount({ ...this.managerViewForm, managersCount: 3, specificNumberForCompletion: 2, completionRequirementType: CompletionRequirementType.SPECIFIC_COUNT, responses: [{ decision: FormDecisionTypes.Recused, isDraft: false } as FormResponse, { decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse], otherLevelResponses: [{ decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse] }); // 3 managers in WFL, one recused, one approved, one didn't answer // Specific count requirement (2) not met expect(result.countComplete).to.be.equal(1); expect(result.countOtherWorkflows).to.be.equal(1); expect(result.countRequired).to.be.equal(2); expect(result.metRequirement).to.be.false; } @TestCase('should be able to get required count - view only') getRequiredCountViewOnly (service: ApplicationFormService) { const result = service.getRequiredCount({ ...this.managerViewForm, managersCount: 3, completionRequirementType: CompletionRequirementType.VIEW_ONLY, responses: [{ decision: FormDecisionTypes.Recused, isDraft: false } as FormResponse, { decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse], otherLevelResponses: [{ decision: FormDecisionTypes.Approve, isDraft: false } as FormResponse] }); // View only has no requirements expect(result.countComplete).to.be.equal(1); expect(result.countOtherWorkflows).to.be.equal(1); expect(result.countRequired).to.be.equal(0); expect(result.metRequirement).to.be.true; } @TestCase('should be able to get panel icon and class - did not meet req') getPanelIconAndClass1 (service: ApplicationFormService) { const requirements: FormRequirements = { countComplete: 0, countRequired: 1, metRequirement: false, countOtherWorkflows: 0 }; const { icon, iconClass } = service.getPanelIconAndClass(requirements, CompletionRequirementType.ALL_USERS); // Did not met requirements expect(icon).to.be.equal('exclamation-circle'); expect(iconClass).to.be.equal('warning'); } @TestCase('should be able to get panel icon and class - met req') getPanelIconAndClass2 (service: ApplicationFormService) { const requirements: FormRequirements = { countComplete: 1, countRequired: 1, metRequirement: true, countOtherWorkflows: 0 }; const { icon, iconClass } = service.getPanelIconAndClass(requirements, CompletionRequirementType.ALL_USERS); // Did meet requirements expect(icon).to.be.equal('check-circle'); expect(iconClass).to.be.equal('success'); } @TestCase('should be able to get panel icon and class - view only') getPanelIconAndClass3 (service: ApplicationFormService) { const requirements: FormRequirements = { countComplete: 1, countRequired: 1, metRequirement: true, countOtherWorkflows: 0 }; const { icon, iconClass } = service.getPanelIconAndClass(requirements, CompletionRequirementType.VIEW_ONLY); expect(icon).to.be.equal('ban'); expect(iconClass).to.be.equal('danger'); } @TestCase('should be able to get panel icon and class - none') getPanelIconAndClass4 (service: ApplicationFormService) { const requirements: FormRequirements = { countComplete: 1, countRequired: 1, metRequirement: true, countOtherWorkflows: 0 }; const { icon, iconClass } = service.getPanelIconAndClass(requirements, CompletionRequirementType.NONE); expect(icon).to.be.equal('exclamation-circle'); expect(iconClass).to.be.equal('warning'); } @TestCase('should be able to get panel description - 1st if') getPanelDescription (service: ApplicationFormService) { const reqs: FormRequirements = { countRequired: 1, countComplete: 1, metRequirement: true, countOtherWorkflows: 0 }; const desc = service.getPanelDescription(this.managerViewForm, reqs); expect(desc).to.be.equal('1 out of 1 complete in this level'); } @TestCase('should be able to get panel description - 2nd if') getPanelDescription2 (service: ApplicationFormService) { const reqs: FormRequirements = { countRequired: 0, countComplete: 1, metRequirement: true, countOtherWorkflows: 0 }; const desc = service.getPanelDescription(this.managerViewForm, reqs); expect(desc).to.be.equal('1 submitted responses'); } @TestCase('should be able to get panel description - else') getPanelDescription3 (service: ApplicationFormService) { spy.on(service, 'getFormDueString'); const reqs: FormRequirements = { countRequired: 0, countComplete: 0, metRequirement: true, countOtherWorkflows: 0 }; const desc = service.getPanelDescription({ ...this.managerViewForm, dueDate: '04/24/2022' }, reqs); expect(desc).to.be.equal('No submitted responses
Form due on Apr 24, 2022'); expect(service['getFormDueString']).to.have.been.called.once; } @TestCase('should be able to get my application form panels - optional not submitted') getMyApplicationFormPanels1 (service: ApplicationFormService) { service['userService']['set']('user', { email: this.userEmail } as User); const form = { ...this.managerViewForm, completionRequirementType: CompletionRequirementType.NONE, dueDate: '04/23/2022', responses: [{ ...this.formResponse, isDraft: true, createdBy: { email: this.userEmail, firstName: 'Tina', lastName: 'Conway', impersonatedBy: '', userType: UserTypes.MANAGER } }] }; const panels = service.getMyApplicationFormPanels([form]); const myForm = panels[0]; const hasDesc = myForm.description.includes('Not submitted as of') && myForm.description.includes('Optional'); expect(hasDesc).to.be.true; expect(myForm.icon).to.be.equal('hourglass-half'); expect(myForm.iconClass).to.be.equal('warning'); } @TestCase('should be able to get my application form panels - optional not submitted') getMyApplicationFormPanels2 (service: ApplicationFormService) { const email = 'tina.conway@gmail.com'; service['userService']['set']('user', { email } as User); spy.on(service['statusService'], 'getDynamicStatusString'); const form = { ...this.managerViewForm, completionRequirementType: CompletionRequirementType.ALL_USERS, responses: [{ ...this.formResponse, isDraft: false, applicationFormStatusId: FormStatuses.Submitted, createdBy: { email, firstName: 'Tina', lastName: 'Conway', impersonatedBy: '', userType: UserTypes.MANAGER } }] }; const panels = service.getMyApplicationFormPanels([form]); const myForm = panels[0]; expect(service['statusService']['getDynamicStatusString']).to.have.been.called.once; expect(myForm.iconClass).to.be.equal('success'); expect(myForm.icon).to.be.equal('check-circle'); expect(myForm.description).to.be.equal('Submitted on Jun 30, 2022'); } @TestCase('should be able to get applicant form panels') getApplicantFormPanels (service: ApplicationFormService) { spy.on(service, 'getDynamicStatusString'); const result = service.getApplicantFormPanels(this.applicantFormsForUi); const numberOfForms = this.applicantFormsForUi.length; const myForm = result[0]; expect(service['getDynamicStatusString']).to.have.been.called.exactly(numberOfForms); expect(myForm.iconClass).to.be.equal('danger'); expect(myForm.icon).to.be.equal('hourglass-half'); const hasCorrectDesc = myForm.description === 'Submitted on Jun 30, 2022
Form due on Mar 5, 2020'; expect(hasCorrectDesc).to.be.true; } @TestCase('should be able to get can edit form - view only') getCanEditForm (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.MANAGER, FormTypes.REVIEW, CompletionRequirementType.VIEW_ONLY, ApplicationStatuses.AwaitingReview, false, false, false, false ); // This is a view only manager form, so can't edit expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - editing') getCanEditForm2 (service: ApplicationFormService) { const editing = true; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.REQUEST, null, ApplicationStatuses.AwaitingReview, false, false, false, false ); // We are already editing, so no expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - declined') getCanEditForm3 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.REQUEST, null, ApplicationStatuses.Declined, false, false, false, false ); // App is declined, so no expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - cannot edit applicant forms') getCanEditForm4 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = false; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.REQUEST, null, ApplicationStatuses.AwaitingReview, false, false, false, false ); // Can't edit applicant forms, so no expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - is routing form') getCanEditForm5 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.ROUTING, null, ApplicationStatuses.AwaitingReview, false, false, false, false ); // Can't edit routing form, so no expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - is hold but is on edit view') getCanEditForm6 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.REQUEST, null, ApplicationStatuses.Hold, false, false, true, false ); // Is on hold, but we are on edit app view so we can expect(canEdit).to.be.true; } @TestCase('should be able to get can edit form - is nomination form but not on nomination') getCanEditForm7 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, this.formResponse, FormAudience.APPLICANT, FormTypes.NOMINATION, null, ApplicationStatuses.AwaitingReview, true, false, false, false ); // Is nomintion form, but not on a nomiation record, so false expect(canEdit).to.be.false; } @TestCase('should be able to get can edit form - not sent') getCanEditForm8 (service: ApplicationFormService) { const editing = false; const canEditApplicantForms = true; const canEdit = service.getCanEditForm( editing, canEditApplicantForms, { ...this.formResponse, applicationFormStatusId: FormStatuses.NotSent }, FormAudience.APPLICANT, FormTypes.REQUEST, null, ApplicationStatuses.AwaitingReview, false, false, false, false ); // Is not sent, so can't edit expect(canEdit).to.be.false; } @TestCase('should be able to send form reminder') async sendFormReminder (service: ApplicationFormService) { service['applicationFormResources']['sendFormReminder'] = async () => { return { passed: true, endpointResponse: null }; }; spy.on(service['confirmAndTakeActionService'], 'genericTakeAction'); await service.sendFormReminder({ applicationId: 235 } as FormReminderForApi); expect(service['confirmAndTakeActionService']['genericTakeAction']).to.have.been.called.once; } @TestCase('should be able to check revision request criteria - not resend') checkRevisionRequestCriteria (service: ApplicationFormService) { let formAudience = FormAudience.APPLICANT; let applicationStatus = ApplicationStatuses.Approved; let applicationFormStatus = FormStatuses.Submitted; const forResend = false; let canRequestRevision = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // Meets requirements expect(canRequestRevision).to.be.true; formAudience = FormAudience.MANAGER; canRequestRevision = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // manager forms don't support expect(canRequestRevision).to.be.false; formAudience = FormAudience.APPLICANT; applicationStatus = ApplicationStatuses.Declined; canRequestRevision = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // Can't request revision bc app was declined expect(canRequestRevision).to.be.false; applicationStatus = ApplicationStatuses.Approved; applicationFormStatus = FormStatuses.RevisionRequested; canRequestRevision = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // can't request when revision already requested expect(canRequestRevision).to.be.false; } @TestCase('should be able to check revision request criteria - resend') checkRevisionRequestCriteriaResend (service: ApplicationFormService) { let formAudience = FormAudience.APPLICANT; let applicationStatus = ApplicationStatuses.Hold; let applicationFormStatus = FormStatuses.RevisionRequested; const forResend = true; let canResend = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // Meets requirements expect(canResend).to.be.true; formAudience = FormAudience.MANAGER; canResend = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // manager forms don't support expect(canResend).to.be.false; formAudience = FormAudience.APPLICANT; applicationStatus = ApplicationStatuses.Declined; canResend = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // Can't resend bc it's not on hold expect(canResend).to.be.false; applicationStatus = ApplicationStatuses.Hold; applicationFormStatus = FormStatuses.Submitted; canResend = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // can't resend bc it's already submitted expect(canResend).to.be.false; applicationFormStatus = FormStatuses.DraftSaved; canResend = service.checkRevisionRequestCriteria( formAudience, applicationStatus, applicationFormStatus, forResend ); // can resend bc it's in draft and on hold expect(canResend).to.be.true; } @TestCase('should be able to handle recall application form') async handleRecallApplicationForm (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: { automaticallyRouted: true } }; }); let calledAutoRouteFunc = false; service['showAutomaticallyRoutedToaster'] = () => { calledAutoRouteFunc = true; }; await service.handleRecallApplicationForm( 1, 2, 0, null, true ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; expect(calledAutoRouteFunc).to.be.true; } @TestCase('should be able to handle request revision') async handleRequestRevision (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); await service.handleRequestRevision( this.appId, this.applicationFormId, { emailOptionsRequest: null, notes: '', clientEmailTemplateId: 0 } ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle send form due is overdue') async handleSendFormDueOverdue (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); const modalResponse: FormDueEmailModalResponse = { clientEmailTemplateId: null, applicationFormId: 12, applicationId: 2, formId: 53, workflowLevelId: 77, userId: 123, emailOptionsModel: null }; const isOverdue = true; await service.handleSendFormDue(modalResponse, isOverdue); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle send form due - not overdue') async handleSendFormDueNotOverdue (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); const modalResponse: FormDueEmailModalResponse = { clientEmailTemplateId: null, applicationFormId: 12, applicationId: 2, formId: 53, workflowLevelId: 77, userId: 123, emailOptionsModel: null }; const isOverdue = false; await service.handleSendFormDue(modalResponse, isOverdue); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle extend form due date') async handleExtendFormDueDate (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); await service.handleExtendFormDueDate(1, 2, 3, 4, '', true); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle bulk request revision') async handleBulkRequestRevision (service: ApplicationFormService) { service['applicationFormResources']['requestBulkApplicationFormRevision'] = async () => { return { passed: true, endpointResponse: null }; }; spy.on(service['confirmAndTakeActionService'], 'genericTakeAction'); await service.handleBulkRequestRevision( [this.appId], this.formId, { emailOptionsRequest: null, notes: '', clientEmailTemplateId: 0 }, 46 ); expect(service['confirmAndTakeActionService']['genericTakeAction']).to.have.been.called.once; } @TestCase('should be able to add comment to form') async addCommentToApplicationForm (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); await service.addCommentToApplicationForm( 2, 3, { notes: 'notes', formRevisionId: 23 } ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to show automatically routed toastr') showAutomaticallyRoutedToaster (service: ApplicationFormService) { spy.on(service['notifier'], 'success'); service.showAutomaticallyRoutedToaster(true); expect(service['notifier']['success']).to.have.been.called.once; } @TestCase('should be able to handle revision reminder') async handleRevisionReminder (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); await service.handleRevisionReminder( this.appId, this.formId, '', 0, null ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle bulk revision reminder') async handleBulkRevisionReminder (service: ApplicationFormService) { service['applicationFormResources']['sendBulkRevisionReminder'] = async () => { return { passed: true, endpointResponse: null }; }; spy.on(service['confirmAndTakeActionService'], 'genericTakeAction'); await service.handleBulkRevisionReminder( [this.appId], this.formId, '', null, 235 ); expect(service['confirmAndTakeActionService']['genericTakeAction']).to.have.been.called.once; } @TestCase('should be able to handle cancel revision') async handleCancelRevision (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: null }; }); await service.handleCancelRevision( { clientEmailTemplateId: 0, emailOptionsModel: { ccEmails: [], bccEmails: [], attachments: [] } }, this.appId, this.applicationFormId ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; } @TestCase('should be able to handle send form to applicant') async handleSendFormToApplicant (service: ApplicationFormService) { spy.on(service['confirmAndTakeActionService'], 'takeAction', () => { return { passed: true, endpointResponse: { automaticallyRouted: true } }; }); let calledAutoRouteFunc = false; service['showAutomaticallyRoutedToaster'] = () => { calledAutoRouteFunc = true; }; await service.handleSendFormToApplicant( this.appId, this.applicationFormId, { ccEmails: [], bccEmails: [], attachments: [] }, 0, false ); expect(service['confirmAndTakeActionService']['takeAction']).to.have.been.called.once; expect(calledAutoRouteFunc).to.be.true; } @TestCase('should be able to save table field values') async saveTableFieldValues (service: ApplicationFormService) { const response = await service.saveTableFieldValues( { ...this.tableRowUpdatePayload.tableChangeValues, updates: [{ values: [{ referenceFieldKey: this.textFieldKey, referenceFieldId: this.textFieldId, value: '2', numericValue: null, currencyValue: '' }], rowId: null, isNewRecord: true, tableReferenceFieldId: this.tableId, index: 0 }] }, this.appId, this.formId, this.revisionId, this.applicationFormId, false ); const addedRowId = response.rowsToUpdate[0].rowId === this.tableRowId; expect(addedRowId).to.be.true; } @TestCase('should be able to save table field values - fail') async saveTableFieldValuesFail (service: ApplicationFormService) { spy.on(service['notifier'], 'error'); spy.on(service['logger'], 'error'); spy.on(service['applicationFormResources'], 'saveReferenceFields', async () => { // eslint-disable-next-line no-throw-literal throw { error: { message: 'error' } }; }); const response = await service.saveTableFieldValues( { ...this.tableRowUpdatePayload.tableChangeValues, updates: [{ values: [{ referenceFieldKey: this.textFieldKey, referenceFieldId: this.textFieldId, value: '2', numericValue: null, currencyValue: '' }], rowId: null, isNewRecord: true, tableReferenceFieldId: this.tableId, index: 0 }] }, this.appId, this.formId, this.revisionId, this.applicationFormId, false ); expect(service['notifier']['error']).to.have.been.called.once; expect(service['logger']['error']).to.have.been.called.once; } @TestCase('should be able to send review reminder') async sendReviewReminder (service: ApplicationFormService) { let successMessage = ''; service['notifier']['success'] = (message: string) => { successMessage = message; }; await service.sendReviewReminder( this.appId, { users: [4], clientEmailTemplateId: 0, emailOptionsModel: null } ); expect(successMessage).to.be.equal( 'Successfully sent reminder email to user' ); } @TestCase('should be able to send review reminder - fail') async sendReviewReminderFail (service: ApplicationFormService) { let errorMessage = ''; service['notifier']['error'] = (message: string) => { errorMessage = message; }; service['applicationFormResources']['sendReviewReminder'] = async () => { // eslint-disable-next-line no-throw-literal throw { error: { message: 'error' } }; }; await service.sendReviewReminder( this.appId, { users: [4], clientEmailTemplateId: 0, emailOptionsModel: null } ); expect(errorMessage).to.be.equal('There was an error sending the selected user a reminder'); } @TestCase('should be able to save ref field values') async saveReferenceFieldValues (service: ApplicationFormService) { spy.on(service['applicationFormResources'], 'saveReferenceFields'); const passed = await service.saveReferenceFieldValues( this.appId, this.formId, this.revisionId, this.applicationFormId, [], false, false ); expect(service['applicationFormResources']['saveReferenceFields']).to.have.been.called.once; expect(passed).to.be.true; } @TestCase('should be able to save ref field values - fail') async saveReferenceFieldValuesFail (service: ApplicationFormService) { spy.on(service['notifier'], 'error'); spy.on(service['logger'], 'error'); spy.on(service['applicationFormResources'], 'saveReferenceFields', async () => { // eslint-disable-next-line no-throw-literal throw { error: { message: 'error' } }; }); const passed = await service.saveReferenceFieldValues( this.appId, this.formId, this.revisionId, this.applicationFormId, [], false, false ); expect(service['applicationFormResources']['saveReferenceFields']).to.have.been.called.once; expect(service['notifier']['error']).to.have.been.called.once; expect(service['logger']['error']).to.have.been.called.once; expect(passed).to.be.false; } @TestCase('should be able to do table row updates') async doTableRowUpdates (service: ApplicationFormService) { let setApplicationFormTableRows = false; service['referenceFieldsService'].setApplicationFormTableRowsMap = async () => { setApplicationFormTableRows = true; }; await service.doTableRowUpdates( this.tableRowUpdatePayload, this.appId, this.formId, this.revisionId, this.applicationFormId ); expect(setApplicationFormTableRows).to.be.true; } @TestCase('should be able to handle save of all fields') async handleSaveOfAllFields (service: ApplicationFormService) { const result = await service.handleSaveOfChangedFields( this.tableRowUpdatePayload, this.appId, this.formId, this.revisionId, this.applicationFormId, false, false ); expect(result.standardPassed).to.be.true; expect(result.tablePassed).to.be.true; } @TestCase('should be able to handle save of all fields - standard') async handleSaveOfAllFieldsStandard (service: ApplicationFormService) { spy.on(service, 'saveReferenceFieldValues', () => { return true; }); const standardChangeValues: ReferenceFieldAPI.ApplicationRefFieldResponseForApi[] = [{ referenceFieldKey: this.textField.key, referenceFieldId: this.textField.referenceFieldId, value: 'asdf', numericValue: null, currencyValue: '' }, { referenceFieldKey: 'checkbox', referenceFieldId: 2353, value: 'true', numericValue: null, currencyValue: '' }]; await service.handleSaveOfChangedFields( { ...this.tableRowUpdatePayload, standardChangeValues, tableChangeValues: { updates: [], deletions: [] } }, this.appId, this.formId, this.revisionId, this.applicationFormId, false, false ); expect(service['saveReferenceFieldValues']).to.have.been.called.once; } @TestCase('should be able to get is form overdue') getIsFormOverdue (service: ApplicationFormService) { const isOverdue = service.getIsFormOverdue('03/01/2020'); expect(isOverdue).to.be.true; } }