diff --git a/strr-web/lang/en.json b/strr-web/lang/en.json index 7a59df2d..62549ce1 100644 --- a/strr-web/lang/en.json +++ b/strr-web/lang/en.json @@ -153,6 +153,8 @@ "principalResidenceNotApplies": "Principal residence does not apply or my property is exempt", "principalResidenceApplies": "Principal residence does apply", "proof": "Proof of Principal Residence", + "paymentDueBannerMessage": "Payment has failed. Submit payment to complete your registration application.", + "paymentDueBannerTitle": "Important", "ltsaInfo": "LTSA Information", "ltsaDetails": "View LTSA Details", "autoApprovalLogic": "Auto-Approval Logic", diff --git a/strr-web/pages/application-details/[id]/index.vue b/strr-web/pages/application-details/[id]/index.vue index 598ac0af..38fcb6eb 100644 --- a/strr-web/pages/application-details/[id]/index.vue +++ b/strr-web/pages/application-details/[id]/index.vue @@ -28,7 +28,22 @@ -
+
+
+ + {{ tApplicationDetails('paymentDueBannerTitle') }}: + {{ tApplicationDetails('paymentDueBannerMessage') }} +
+
+

{{ tApplicationDetails('applicationStatus') }} @@ -353,12 +368,13 @@ const tApplicationDetails = (translationKey: string) => t(`applicationDetails.${ const tStatuses = (translationKey: string) => t(`statuses.${translationKey}`) const tPropertyForm = (translationKey: string) => t(`createAccount.propertyForm.${translationKey}`) const tReview = (translationKey: string) => t(`createAccount.review.${translationKey}`) -const { isExaminer } = useBcrosKeycloak() +const { isExaminer } = storeToRefs(useBcrosKeycloak()) const { getChipFlavour } = useChipFlavour() const regionNamesInEnglish = new Intl.DisplayNames(['en'], { type: 'region' }) -const applicationNumber = route.params.id.toString() +// Modified for unit tests, unable to mock route params in tests +const applicationNumber = route.params.id?.toString() || '' const { getApplication, @@ -366,9 +382,7 @@ const { getDocument } = useApplications() -const { - setupBreadcrumbData -} = useBreadcrumb() +const { setupBreadcrumbData } = useBreadcrumb() const [application, applicationHistory]: [ApplicationI, FilingHistoryEventI[]] = await Promise.all([ getApplication(applicationNumber), @@ -382,7 +396,7 @@ const applicationDetails: HostApplicationDetailsI = application.registration // Get Supporting Documents from the Application response const documents: DocumentUploadI[] = applicationDetails.documents || [] const examinerOrHostStatus = computed(() => { - if (isExaminer) { + if (isExaminer.value) { return application?.header.examinerStatus } else { return application?.header.hostStatus @@ -390,6 +404,7 @@ const examinerOrHostStatus = computed(() => { }) const applicationStatus = application?.header.status const flavour = application ? getChipFlavour(examinerOrHostStatus.value || applicationStatus) : null +const isPaymentDue = computed(() => applicationStatus === ApplicationStatusE.PAYMENT_DUE) const getApplicationStatusTranslation = (status) => { const commonStatusMap = { diff --git a/strr-web/tests/mocks/mockApplication.ts b/strr-web/tests/mocks/mockApplication.ts index f92ec2c5..a72a2c70 100644 --- a/strr-web/tests/mocks/mockApplication.ts +++ b/strr-web/tests/mocks/mockApplication.ts @@ -94,75 +94,111 @@ export const mockApplicationDetails: HostApplicationDetailsI = { }, unitDetails: { ownershipType: 'OWN', - propertyType: 'SECONDARY', - rentalUnitSpaceType: '', - isUnitOnPrincipalResidenceProperty: false, - hostResidence: undefined, - numberOfRoomsForRent: 0 + propertyType: 'SINGLE_FAMILY_HOME', + rentalUnitSpaceType: 'ENTIRE_HOME', + isUnitOnPrincipalResidenceProperty: true, + hostResidence: 'SAME_UNIT', + numberOfRoomsForRent: 1 }, registrationType: RegistrationTypeE.HOST, propertyManager: mockPropertyManager } -export const mockApplicationApproved: ApplicationI = { - header: { - applicationNumber: '41447512384286', - applicationDateTime: '2024-08-14T22:24:42.006030+00:00', - decisionDate: '2024-08-16T11:08:40.948148+00:00', - name: 'registration', - paymentAccount: '1699', - paymentStatus: 'CREATED', - paymentToken: 39363, - registrationEndDate: '2025-08-16T11:08:40.935161', - registrationId: 1, - registrationNumber: 'BCH24527283787', - registrationStartDate: '2024-08-16T11:08:40.935161+00:00', - registrationStatus: RegistrationStatusE.ACTIVE, - isCertificateIssued: true, - reviewer: { - displayName: 'Joe Smith', - username: 'joes@idir' - }, - status: ApplicationStatusE.AUTO_APPROVED, - submitter: { - displayName: 'BCREGTEST TWENTYFIVE', - username: 'bcsc/sdfasdfasdf' - }, - hostActions: [], - examinerActions: [ExaminerActionsE.ISSUE_CERTIFICATE], - hostStatus: HostApplicationStatusE.AUTO_APPROVED, - examinerStatus: ExaminerApplicationStatusE.FULL_REVIEW_APPROVED +const mockApplicationHeader: ApplicationHeaderI = { + applicationNumber: '41447512384286', + applicationDateTime: '2024-08-14T22:24:42.006030+00:00', + decisionDate: '2024-08-16T11:08:40.948148+00:00', + name: 'registration', + paymentAccount: '1699', + paymentStatus: 'CREATED', + paymentToken: 39363, + registrationEndDate: '2025-08-16T11:08:40.935161', + registrationId: 1, + registrationNumber: 'BCH24527283787', + registrationStartDate: '2024-08-16T11:08:40.935161+00:00', + reviewer: { + displayName: 'Joe Smith', + username: 'joes@idir' }, + submitter: { + displayName: 'BCREGTEST TWENTYFIVE', + username: 'bcsc/sdfasdfasdf' + }, + registrationStatus: RegistrationStatusE.ACTIVE, + status: ApplicationStatusE.AUTO_APPROVED, + isCertificateIssued: true, + hostActions: [], + examinerActions: [ExaminerActionsE.ISSUE_CERTIFICATE], + hostStatus: HostApplicationStatusE.AUTO_APPROVED, + examinerStatus: ExaminerApplicationStatusE.FULL_REVIEW_APPROVED +} + +export const mockApplicationApproved: ApplicationI = { + header: mockApplicationHeader, registration: mockApplicationDetails, selectedAccount: { sbc_account_id: '12345' } } +export const mockApplicationApprovedWithSecondaryContact: ApplicationI = { + header: mockApplicationHeader, + registration: { + ...mockApplicationDetails, + secondaryContact: { + details: { + emailAddress: 'secondary@email.com', + faxNumber: '', + phoneNumber: '2505551234', + preferredName: 'Jane Smith', + extension: '' + }, + name: { + firstName: 'Jane', + lastName: 'Smith', + middleName: '' + }, + socialInsuranceNumber: '', + businessNumber: '', + dateOfBirth: '1990-01-01', + mailingAddress: { + address: '789 Test', + addressLineTwo: '', + city: 'Victoria', + country: 'CA', + postalCode: 'V8V3V3', + province: 'BC' + } + } + }, + selectedAccount: { + sbc_account_id: '12345' + } +} + +export const mockApplicationApprovedWithDocuments: ApplicationI = { + header: mockApplicationHeader, + registration: { + ...mockApplicationDetails, + documents: [ + { + fileKey: '809bf24f-a2b9-4740-af84-8297bc346f1d', + fileName: 'Test_test', + fileType: 'application/octet-stream' + } + ] + }, + selectedAccount: { + sbc_account_id: '12345' + } +} + export const mockApplicationPaymentDue: ApplicationI = { header: { - applicationNumber: '41447512384286', - applicationDateTime: '2024-08-14T22:24:42.006030+00:00', - decisionDate: '2024-08-16T11:08:40.948148+00:00', - name: 'registration', - paymentAccount: '1699', - paymentStatus: 'CREATED', - paymentToken: 39363, - registrationEndDate: '2025-08-16T11:08:40.935161', - registrationId: 1, - registrationNumber: 'BCH24527283787', - registrationStartDate: '2024-08-16T11:08:40.935161+00:00', + ...mockApplicationHeader, registrationStatus: RegistrationStatusE.ACTIVE, - isCertificateIssued: false, - reviewer: { - displayName: 'Joe Smith', - username: 'joes@idir' - }, status: ApplicationStatusE.PAYMENT_DUE, - submitter: { - displayName: 'BCREGTEST TWENTYFIVE', - username: 'bcsc/sdfasdfasdf' - }, + isCertificateIssued: false, hostActions: [HostActionsE.SUBMIT_PAYMENT], examinerActions: [], hostStatus: HostApplicationStatusE.PAYMENT_DUE, @@ -176,28 +212,10 @@ export const mockApplicationPaymentDue: ApplicationI = { export const mockApplicationFullReview: ApplicationI = { header: { - applicationNumber: '41447512384286', - applicationDateTime: '2024-08-14T22:24:42.006030+00:00', - decisionDate: '2024-08-16T11:08:40.948148+00:00', - name: 'registration', - paymentAccount: '1699', - paymentStatus: 'COMPLETED', - paymentToken: 34253, - registrationEndDate: '2025-08-16T11:08:40.935161', - registrationId: 1, - registrationNumber: 'BCH24527283787', - registrationStartDate: '2024-08-16T11:08:40.935161+00:00', + ...mockApplicationHeader, registrationStatus: RegistrationStatusE.ACTIVE, + status: ApplicationStatusE.FULL_REVIEW, isCertificateIssued: false, - reviewer: { - displayName: 'Joe Smith', - username: 'joes@idir' - }, - status: ApplicationStatusE.PAYMENT_DUE, - submitter: { - displayName: 'BCREGTEST TWENTYFIVE', - username: 'bcsc/sdfasdfasdf' - }, hostActions: [], examinerActions: [ExaminerActionsE.APPROVE, ExaminerActionsE.REJECT], hostStatus: HostApplicationStatusE.FULL_REVIEW, diff --git a/strr-web/tests/unit/pages/application-details.spec.ts b/strr-web/tests/unit/pages/application-details.spec.ts index 27fc8cdb..c4d3ef78 100644 --- a/strr-web/tests/unit/pages/application-details.spec.ts +++ b/strr-web/tests/unit/pages/application-details.spec.ts @@ -1,258 +1,129 @@ -import { mount } from '@vue/test-utils' -import { describe, it, expect, vi } from 'vitest' -import { mockFilingHistory } from '../../mocks/mockFilingHistory' -import { mockApplicationApproved } from '../../mocks/mockApplication' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import { ref } from 'vue' import ApplicationDetails from '@/pages/application-details/[id]/index.vue' +import { + mockApplicationApproved, + mockApplicationPaymentDue, + mockApplicationApprovedWithSecondaryContact, + mockApplicationApprovedWithDocuments +} from '~/tests/mocks/mockApplication' + +const { t } = useTranslation() +const tApplicationDetails = (key: string) => t(`applicationDetails.${key}`) +const tStatuses = (key: string) => t(`statuses.${key}`) vi.mock('~/composables/useApplications', () => ({ - useApplications: vi.fn(() => ({ - getApplication: vi.fn(), - getApplicationHistory: vi.fn(), - getDocument: vi.fn() - })) + useApplications: vi.fn() })) -vi.mock('~/composables/useBreadcrumb', () => ({ - useBreadcrumb: vi.fn(() => ({ - setupBreadcrumbData: vi.fn() +const mockUseApplications = (applicationData: any = mockApplicationApproved) => { + // @ts-ignore: Ignore TypeScript error for mockImplementation + useApplications.mockImplementation(() => ({ + getApplication: vi.fn().mockResolvedValue(applicationData), + getApplicationHistory: vi.fn().mockResolvedValue([]) })) -})) +} -vi.mock('~/composables/useChipFlavour', () => ({ - useChipFlavour: vi.fn(() => ({ - getChipFlavour: vi.fn() - })) +vi.mock('@/stores/keycloak', () => ({ + useBcrosKeycloak: vi.fn() })) -const mockRoute = { - params: { - id: '1' - } +const mockUseBcrosKeycloak = (isExaminer: boolean = false) => { + // @ts-ignore: Ignore TypeScript error for mockImplementation + useBcrosKeycloak.mockImplementation(() => ({ + isExaminer: ref(isExaminer) + })) } -describe('ApplicationDetails', () => { - it('renders application details correctly', () => { - const wrapper = mount(ApplicationDetails, { - global: { - mocks: { - $route: mockRoute, - useApplications: vi.fn(() => ({ - getApplication: vi.fn().mockResolvedValue(mockApplicationApproved), - getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - getDocument: vi.fn() - })), - useBreadcrumb: vi.fn(() => ({ - setupBreadcrumbData: vi.fn() - })), - useChipFlavour: vi.fn(() => ({ - getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - })) - }, - stubs: [ - 'BcrosBanner', - 'BcrosTypographyH1', - 'BcrosChip', - 'BcrosFormSectionReviewItem', - 'UTable', - 'UButton', - 'FilingHistory' - ] - } +vi.mock('~/composables/useChipFlavour', () => ({ + useChipFlavour: () => ({ + getChipFlavour: () => ({ + text: 'success', + color: 'bg-green-100' }) - expect(wrapper.vm).toBeTruthy() - - // await wrapper.vm.$nextTick() - // expect(wrapper.find('[data-test-id="application-title"]').text()).toContain('BCH24527283787') - // expect(wrapper.find('[data-test-id="application-status-chip"]').text()).toBe('Auto Approved') - // expect(wrapper.find('[data-test-id="unit-address"]').text()).toContain('123 Main St') - // expect(wrapper.find('[data-test-id="business-license"]').text()).toBe('-') - // expect(wrapper.find('[data-test-id="ownership-type"]').text()).toBe('Own') - // expect(wrapper.find('[data-test-id="property-type"]').text()).toBe('Secondary Suite') - // expect(wrapper.find('[data-test-id="primary-contact-name"]').text()).toContain('BCREGTEST TWENTYFIVE') - // expect(wrapper.find('[data-test-id="primary-contact-email"]').text()).toBe('test1@email.com') - // expect(wrapper.find('[data-test-id="primary-contact-phone"]').text()).toBe('5554443322') - // }) - - // it('displays correct application status', async () => { - // const wrapper = mount(ApplicationDetails, { - // global: { - // mocks: { - // $route: mockRoute, - // useApplications: vi.fn(() => ({ - // getApplication: vi.fn().mockResolvedValue(mockApplicationApproved), - // getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - // getDocument: vi.fn() - // })), - // useBreadcrumb: vi.fn(() => ({ - // setupBreadcrumbData: vi.fn() - // })), - // useChipFlavour: vi.fn(() => ({ - // getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - // })) - // }, - // stubs: [ - // 'BcrosBanner', - // 'BcrosTypographyH1', - // 'BcrosChip', - // 'BcrosFormSectionReviewItem', - // 'UTable', - // 'UButton', - // 'FilingHistory' - // ] - // } - // }) + }) +})) - // await wrapper.vm.$nextTick() +describe('Application Details Page', () => { + let wrapper: any - // expect(wrapper.find('[data-test-id="application-status-text"]').text()).toBe('hostStatuses.autoApproved') - // }) + beforeEach(() => { + vi.resetAllMocks() + mockUseApplications() + mockUseBcrosKeycloak() + }) - // it('renders filing history correctly', async () => { - // const wrapper = mount(ApplicationDetails, { - // global: { - // mocks: { - // $route: mockRoute, - // useApplications: vi.fn(() => ({ - // getApplication: vi.fn().mockResolvedValue(mockApplicationApproved), - // getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - // getDocument: vi.fn() - // })), - // useBreadcrumb: vi.fn(() => ({ - // setupBreadcrumbData: vi.fn() - // })), - // useChipFlavour: vi.fn(() => ({ - // getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - // })) - // }, - // stubs: [ - // 'BcrosBanner', - // 'BcrosTypographyH1', - // 'BcrosChip', - // 'BcrosFormSectionReviewItem', - // 'UTable', - // 'UButton' - // ] - // } - // }) + it('renders the application details page correctly', async () => { + wrapper = await mountSuspended(ApplicationDetails) + expect(wrapper.findTestId('application-details').exists()).toBe(true) + expect(wrapper.findTestId('application-header').exists()).toBe(true) + expect(wrapper.findTestId('application-title').exists()).toBe(true) + }) - // await wrapper.vm.$nextTick() + it('displays application status correctly', async () => { + wrapper = await mountSuspended(ApplicationDetails) + const statusSection = wrapper.findTestId('application-status') + expect(statusSection.exists()).toBe(true) + expect(statusSection.find('h2').text()).toBe(tApplicationDetails('applicationStatus')) + }) - // const filingHistory = wrapper.findComponent({ name: 'FilingHistory' }) - // expect(filingHistory.exists()).toBe(true) - // expect(filingHistory.props('history')).toEqual(mockFilingHistory) - // }) + it('displays rental unit information correctly', async () => { + wrapper = await mountSuspended(ApplicationDetails) + expect(wrapper.findTestId('unit-nickname').exists()).toBe(true) + expect(wrapper.findTestId('ownership-type').exists()).toBe(true) + expect(wrapper.findTestId('unit-address').exists()).toBe(true) + expect(wrapper.findTestId('parcel-identifier').exists()).toBe(true) + expect(wrapper.findTestId('property-type').exists()).toBe(true) + const statusText = wrapper.findTestId('application-status-text') + expect(statusText.text()).toBe(tStatuses('hostStatuses.fullReviewApproved')) + }) - // it('handles application without documents', async () => { - // const applicationWithoutDocuments = { - // ...mockApplicationApproved, - // registration: { ...mockApplicationApproved.registration, documents: [] } - // } - // const wrapper = mount(ApplicationDetails, { - // global: { - // mocks: { - // $route: mockRoute, - // useApplications: vi.fn(() => ({ - // getApplication: vi.fn().mockResolvedValue(applicationWithoutDocuments), - // getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - // getDocument: vi.fn() - // })), - // useBreadcrumb: vi.fn(() => ({ - // setupBreadcrumbData: vi.fn() - // })), - // useChipFlavour: vi.fn(() => ({ - // getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - // })) - // }, - // stubs: [ - // 'BcrosBanner', - // 'BcrosTypographyH1', - // 'BcrosChip', - // 'BcrosFormSectionReviewItem', - // 'UTable', - // 'UButton', - // 'FilingHistory' - // ] - // } - // }) + it('displays primary contact information correctly', async () => { + wrapper = await mountSuspended(ApplicationDetails) + const primaryContact = wrapper.findTestId('primary-contact') + expect(primaryContact.exists()).toBe(true) + expect(wrapper.findTestId('primary-contact-name').exists()).toBe(true) + expect(wrapper.findTestId('primary-contact-email').exists()).toBe(true) + expect(wrapper.findTestId('primary-contact-phone').exists()).toBe(true) + expect(wrapper.findTestId('primary-contact-address').exists()).toBe(true) + }) - // await wrapper.vm.$nextTick() + it('displays payment due banner when payment is due', async () => { + mockUseApplications(mockApplicationPaymentDue) - // expect(wrapper.find('[data-test-id="documents-section"]').exists()).toBe(false) - // }) + wrapper = await mountSuspended(ApplicationDetails) + const statusText = wrapper.findTestId('application-status-text') + expect(statusText.text()).toBe(tStatuses('paymentDue')) + const banner = wrapper.findTestId('payment-due-banner') + expect(banner.exists()).toBe(true) + expect(banner.text()).toContain(tApplicationDetails('paymentDueBannerTitle')) + }) - // it('displays LTSA and auto-approval sections for examiner', async () => { - // const wrapper = mount(ApplicationDetails, { - // global: { - // mocks: { - // $route: mockRoute, - // useApplications: vi.fn(() => ({ - // getApplication: vi.fn().mockResolvedValue(mockApplicationApproved), - // getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - // getDocument: vi.fn() - // })), - // useBreadcrumb: vi.fn(() => ({ - // setupBreadcrumbData: vi.fn() - // })), - // useChipFlavour: vi.fn(() => ({ - // getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - // })), - // useBcrosKeycloak: vi.fn(() => ({ - // isExaminer: true - // })) - // }, - // stubs: [ - // 'BcrosBanner', - // 'BcrosTypographyH1', - // 'BcrosChip', - // 'BcrosFormSectionReviewItem', - // 'UTable', - // 'UButton', - // 'FilingHistory' - // ] - // } - // }) + it('displays documents section when documents exist', async () => { + mockUseApplications(mockApplicationApprovedWithDocuments) - // await wrapper.vm.$nextTick() + wrapper = await mountSuspended(ApplicationDetails) + const documentId = wrapper.vm.documents[0].fileKey + const documents = wrapper.findTestId(`document-${documentId}`) + expect(documents.exists()).toBe(true) + const documentsSection = wrapper.findTestId('documents-section') + expect(documentsSection.exists()).toBe(true) + }) - // expect(wrapper.find('[data-test-id="ltsa-info-section"]').exists()).toBe(true) - // expect(wrapper.find('[data-test-id="auto-approval-section"]').exists()).toBe(true) - // }) + it('displays examiner-specific sections when user is examiner', async () => { + mockUseBcrosKeycloak(true) - // it('does not display LTSA and auto-approval sections for non-examiner', async () => { - // const wrapper = mount(ApplicationDetails, { - // global: { - // mocks: { - // $route: mockRoute, - // useApplications: vi.fn(() => ({ - // getApplication: vi.fn().mockResolvedValue(mockApplicationApproved), - // getApplicationHistory: vi.fn().mockResolvedValue(mockFilingHistory), - // getDocument: vi.fn() - // })), - // useBreadcrumb: vi.fn(() => ({ - // setupBreadcrumbData: vi.fn() - // })), - // useChipFlavour: vi.fn(() => ({ - // getChipFlavour: vi.fn().mockReturnValue({ text: 'Auto Approved' }) - // })), - // useBcrosKeycloak: vi.fn(() => ({ - // isExaminer: false - // })) - // }, - // stubs: [ - // 'BcrosBanner', - // 'BcrosTypographyH1', - // 'BcrosChip', - // 'BcrosFormSectionReviewItem', - // 'UTable', - // 'UButton', - // 'FilingHistory' - // ] - // } - // }) + wrapper = await mountSuspended(ApplicationDetails) + expect(wrapper.findTestId('ltsa-info-section').exists()).toBe(true) + expect(wrapper.findTestId('auto-approval-section').exists()).toBe(true) + }) - // await wrapper.vm.$nextTick() + it('displays secondary contact information when available', async () => { + mockUseApplications(mockApplicationApprovedWithSecondaryContact) - // expect(wrapper.find('[data-test-id="ltsa-info-section"]').exists()).toBe(false) - // expect(wrapper.find('[data-test-id="auto-approval-section"]').exists()).toBe(false) + wrapper = await mountSuspended(ApplicationDetails) + const secondaryContact = wrapper.findTestId('secondary-contact') + expect(secondaryContact.exists()).toBe(true) + expect(wrapper.findTestId('secondary-contact-email').text()).toContain('secondary@email.com') }) })