From 7c946ab114d8f7ef2c4d6934d045c5b6fc6bd49b Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 14 Feb 2024 09:30:43 -0500 Subject: [PATCH 1/7] lint fix --- src/layouts/welcome-page/welcome-page.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/welcome-page/welcome-page.spec.js b/src/layouts/welcome-page/welcome-page.spec.js index 38733d63..efd1c924 100644 --- a/src/layouts/welcome-page/welcome-page.spec.js +++ b/src/layouts/welcome-page/welcome-page.spec.js @@ -69,7 +69,7 @@ function setupMocks({ } }; - mountOptionsMockData = { + const mockDataMountOptions = { ...mountOptionsMockData, router: { navigate: jest.fn() @@ -81,7 +81,7 @@ function setupMocks({ settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions(mountOptionsMockData); + const mountOptions = getMountOptions(mockDataMountOptions); const wrapper = shallowMount(welcomePage, mountOptions); From 51e612d50a207a52179448ccf23fc5b0562855a7 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 14 Feb 2024 14:25:52 -0500 Subject: [PATCH 2/7] validation updates. --- src/constants/error-messages.js | 4 ++ src/layouts/welcome-page/welcome-page.vue | 75 +++++++++++++++++++---- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 0c8d4719..39543b5f 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -32,17 +32,21 @@ const errorMessages = Object.freeze({ OPTION_REQUIRED: 'Please select an option', VEHICLE_REQUIRED: 'Please select a vehicle', POLICY_NUMBER_REQUIRED: 'Please enter your policy number', + POLICY_NUMBER_FORMAT: 'Please enter an alpha-numeric string', PHONE_NUMBER_REQUIRED: 'Please enter phone number', PHONE_NUMBER_FORMAT: 'Please enter your phone number. The format must be ###-###-####', POLICY_ZIP_REQUIRED: 'Please enter your policy ZIP', POLICY_ZIP_FORMAT: 'Please enter a valid ZIP', LOSS_CAUSE_REQUIRED: 'Please enter loss cause', LOSS_CITY_REQUIRED: 'Please enter a city', + LOSS_CITY_FORMAT: 'Please enter only alpha characters', LOSS_STATE_REQUIRED: 'Please select an option', LOSS_DATE_REQUIRED: 'Please select a date. Format must be MM/DD/YYYY and the date must be not in the future', DAMAGE_DATE_REQUIREMENT: 'Damage date must be within the past 10 years', + DAMAGE_DATE_NO_FUTURE_DATE: + 'Damage date may not be in the future', DAMAGE_OPTION_REQUIRED: 'Please select an option', POLICYHOLDER_FIRST_NAME_REQUIRED: 'Please enter the policyholder first name', diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 77a60a5f..b9cac195 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -85,7 +85,7 @@ cmsWidgetName="PhoneNumberQuestion" :validationRules="rules.phoneNumber" isRequired - mask="###-###-####" + :mask="mask" disableAutoFill /> @@ -153,7 +153,15 @@ id="welcomeFooter" class="row position-sticky top-100">
+ { return true; }); +defineRule('loss-date-lt-tomorrow', (value) => { + const lossDate = new Date(Date.parse(`${value}T00:00:00`)); + const today = new Date(); + const tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0, 0); + if (lossDate >= tomorrow) { + return errorMessages.DAMAGE_DATE_NO_FUTURE_DATE; + } + + return true; +}); export default { name: 'welcome-page', components: { siteHeader, siteSubHeader, + alert, buttonQuestion, textboxQuestion, dropdownQuestion, @@ -260,15 +288,16 @@ export default { data() { return { welcomePageModel: this.getWelcomePageModelFromStore(), + displayInvalidZipAlert: false, duplicates: [], rules: { - policyNumber: 'policy-number-required', + policyNumber: 'policy-number-required|policy-number-format', policyZip: 'policy-zip-required|policy-zip-format', - lossDate: 'loss-date-required|loss-date-gt-10-years', + lossDate: 'loss-date-required|loss-date-gt-10-years|loss-date-lt-tomorrow', damageOption: 'damage-option-required', phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`, email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`, - lossCity: 'loss-city-required', + lossCity: 'loss-city-required|loss-city-format', lossState: 'loss-state-required' } }; @@ -319,20 +348,42 @@ export default { }, maxCoverageLookupAttemptsReached() { return this.mainStore.applicationUser.coverageLookupAttempts >= 11; + }, + mask() { + return { + mask: 'x##-###-####', + tokens: { + x: { + pattern: /[2-9]/ + } + } + }; } }, methods: { async forwardButtonAction() { - this.mainStore.updatePolicyData(this.welcomePageModel); - await this.mainStore.getDuplicateReferrals() - .then(() => {}, () => {}) - .finally(async () => { - if (this.isCoverageEnabled && !this.maxCoverageLookupAttemptsReached) { - await this.mainStore.getCoveragePolicyInfo()?.then(() => {}, () => {}); + console.log('zip code...'); + console.log(this.welcomePageModel.policyZipCode); + await this.mainStore.validateZip({ zip: this.welcomePageModel.policyZipCode }) + .then(async (zipInfo) => { + if (zipInfo?.data?.isValid === true) { + this.mainStore.updatePolicyData(this.welcomePageModel); + await this.mainStore.getDuplicateReferrals() + .then(() => {}, () => {}) + .finally(async () => { + if (this.isCoverageEnabled && !this.maxCoverageLookupAttemptsReached) { + await this.mainStore.getCoveragePolicyInfo()?.then(() => {}, () => {}); + } else { + this.mainStore.order.policy.policyLookupSuccessful = false; + } + return this.navigateForward(); + }); } else { - this.mainStore.order.policy.policyLookupSuccessful = false; + // set manual error message + console.log('zip invalid...'); + this.displayInvalidZipAlert = true; + return this.$refs.siteFooter.removeLoader(); } - this.navigateForward(); }); }, navigateForward() { From 0eaa9786a607522bc7ecd6f66977790a75c75215 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 15 Feb 2024 15:51:27 -0500 Subject: [PATCH 3/7] Updates to welcome page validation Added updated validators Moved validators to globalrules A couple of small linting upates --- src/constants/global-rules.js | 10 + .../textbox-question/textbox-question.vue | 2 +- src/helpers/global-rule-definer.js | 61 +++ src/layouts/welcome-page/welcome-page.spec.js | 350 +++++++++++------- src/layouts/welcome-page/welcome-page.vue | 62 +--- 5 files changed, 295 insertions(+), 190 deletions(-) diff --git a/src/constants/global-rules.js b/src/constants/global-rules.js index da36b822..70c5834a 100644 --- a/src/constants/global-rules.js +++ b/src/constants/global-rules.js @@ -7,8 +7,18 @@ const globalRules = Object.freeze({ POLICYHOLDER_FIRST_NAME_REQUIRED: 'policyholder-first-name-required', POLICYHOLDER_LAST_NAME_REQUIRED: 'policyholder-last-name-required', + POLICY_NUMBER_FORMAT: 'policy-number-format', + POLICY_NUMBER_REQUIRED: 'policy-number-required', + POLICY_ZIP_FORMAT: 'policy-zip-format', + POLICY_ZIP_REQUIRED: 'policy-zip-required', FIRST_NAME_REQUIRED: 'first-name-required', LAST_NAME_REQUIRED: 'last-name-required', + DATE_OF_LOSS_CITY_FORMAT: 'loss-city-format', + DATE_OF_LOSS_CITY_REQUIRED: 'loss-city-required', + DATE_OF_LOSS_STATE_REQUIRED: 'loss-state-required', + DATE_OF_LOSS_NOT_FUTURE: 'loss-date-lt-tomorrow', + DATE_OF_LOSS_NOT_TEN_YEARS_PAST: 'loss-date-gt-10-years', + DATE_OF_LOSS_REQUIRED: 'loss-date-required', EMAIL_ADDRESS_REQUIRED: 'email-required', EMAIL_ADDRESS_FORMAT: 'email-address-format', PHONE_NUMBER_REQUIRED: 'phone-number-required', diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 31d912a0..2ba8d5b9 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -102,7 +102,7 @@ export default { }, validationRules: String, cmsWidgetName: { - String, + type: String, default: '' }, maxLength: String, diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js index daee0de3..def671e4 100644 --- a/src/helpers/global-rule-definer.js +++ b/src/helpers/global-rule-definer.js @@ -33,6 +33,39 @@ function defineGlobalEmailRules() { ); } +/** + * @summary Define global rules related to date/location of loss information + */ +function defineGlobalDateOfLossRules() { + defineRule(globalRules.DATE_OF_LOSS_REQUIRED, required(errorMessages.LOSS_DATE_REQUIRED)); + defineRule(globalRules.DATE_OF_LOSS_NOT_TEN_YEARS_PAST, (value) => { + const lossDate = new Date(Date.parse(`${value}T00:00:00`)); + const today = new Date(); + const tenYearsAgo = new Date(today.getFullYear() - 10, today.getMonth(), today.getDate(), 0, 0, 0, 0); + if (lossDate < tenYearsAgo) { + return errorMessages.DAMAGE_DATE_REQUIREMENT; + } + + return true; + }); + defineRule(globalRules.DATE_OF_LOSS_NOT_FUTURE, (value) => { + const lossDate = new Date(Date.parse(`${value}T00:00:00`)); + const today = new Date(); + const tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0, 0); + if (lossDate >= tomorrow) { + return errorMessages.DAMAGE_DATE_NO_FUTURE_DATE; + } + + return true; + }); + defineRule(globalRules.DATE_OF_LOSS_CITY_REQUIRED, required(errorMessages.LOSS_CITY_REQUIRED)); + defineRule( + globalRules.DATE_OF_LOSS_CITY_FORMAT, + regex(/^[a-zA-Z .'-]+$/, errorMessages.LOSS_CITY_FORMAT) + ); + defineRule(globalRules.DATE_OF_LOSS_STATE_REQUIRED, required(errorMessages.LOSS_STATE_REQUIRED)); +} + /** * @summary Define global rules related to phone numbers */ @@ -47,6 +80,31 @@ function defineGlobalPhoneNumberRules() { ); } +/** + * @summary Define global rules related to policy numbers + */ +function defineGlobalPolicyNumberRules() { + defineRule(globalRules.POLICY_NUMBER_REQUIRED, required(errorMessages.POLICY_NUMBER_REQUIRED)); + defineRule( + globalRules.POLICY_NUMBER_FORMAT, + regex( + /^~?[a-zA-Z0-9]+$/, + errorMessages.POLICY_NUMBER_FORMAT + ) + ); +} + +/** + * @summary Define global rules related to policy zip codes + */ +function defineGlobalPolicyZipCodeRules() { + defineRule(globalRules.POLICY_ZIP_REQUIRED, required(errorMessages.POLICY_ZIP_REQUIRED)); + defineRule( + globalRules.POLICY_ZIP_FORMAT, + regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT) + ); +} + /** * @summary Define global rules related to zip codes */ @@ -61,8 +119,11 @@ function defineGlobalZipCodeRules() { */ export default function defineGlobalRules() { defineGlobalNameRules(); + defineGlobalDateOfLossRules(); defineGlobalEmailRules(); defineGlobalPhoneNumberRules(); + defineGlobalPolicyNumberRules(); + defineGlobalPolicyZipCodeRules(); defineGlobalZipCodeRules(); defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED)); diff --git a/src/layouts/welcome-page/welcome-page.spec.js b/src/layouts/welcome-page/welcome-page.spec.js index efd1c924..f84bb7bc 100644 --- a/src/layouts/welcome-page/welcome-page.spec.js +++ b/src/layouts/welcome-page/welcome-page.spec.js @@ -87,6 +87,7 @@ function setupMocks({ wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ''); + wrapper.vm.$refs.siteFooter.removeLoader = jest.fn(); return { wrapper, apiPromise }; } @@ -175,170 +176,243 @@ describe('welcome-page.vue', () => { }); describe('navigation', () => { - test('if duplicates found, navigate to duplicate check page', async () => { - // Arrange - const { wrapper } = getMountedComponent({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().applicationUser.duplicateOrders = [{ test: 'a' }]; + describe('When zip code check fails', () => { + test('Navigation should not happen', async () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().applicationUser.duplicateOrders = [{ test: 'a' }]; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: false + } + })); - // Act - await wrapper.vm.forwardButtonAction(); + // Act + await wrapper.vm.forwardButtonAction(); - // Assert - expect(wrapper.vm.mainStore.getDuplicateReferrals).toHaveBeenCalled(); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); + // Assert + expect(wrapper.vm.mainStore.getDuplicateReferrals).toHaveBeenCalledTimes(0); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(0); + }); }); - test('if isCoverageEnabled is false, then getCoveragePolicyInfo not called', async () => { - // Arrange - const { wrapper } = getMountedComponent({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().issConfig.isCoverageEnabled = false; - // Act - await wrapper.vm.forwardButtonAction(); + describe('When zip code check succeeds', () => { + test('if duplicates found, navigate to duplicate check page', async () => { + // Arrange + const { wrapper } = getMountedComponent({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().applicationUser.duplicateOrders = [{ test: 'a' }]; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Assert - expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); - expect(wrapper.vm.mainStore.getCoveragePolicyInfo).not.toHaveBeenCalled(); - }); - test('if isCoverageEnabled is true, then getCoveragePolicyInfo called', async () => { - // Arrange - const { wrapper } = getMountedComponent({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().issConfig.isCoverageEnabled = true; + // Act + await wrapper.vm.forwardButtonAction(); - // Act - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.mainStore.getDuplicateReferrals).toHaveBeenCalled(); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + ); + }); + test('if isCoverageEnabled is false, then getCoveragePolicyInfo not called', async () => { + // Arrange + const { wrapper } = getMountedComponent({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().issConfig.isCoverageEnabled = false; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Assert - expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); - expect(wrapper.vm.mainStore.getCoveragePolicyInfo).toHaveBeenCalled(); - }); - test('if maxCoverageLookupAttemptsReached is true, then getCoveragePolicyInfo not called', async () => { - // Arrange - const { wrapper } = getMountedComponent({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().applicationUser.coverageLookupAttempts = 11; + // Act + await wrapper.vm.forwardButtonAction(); - // Act - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); + expect(wrapper.vm.mainStore.getCoveragePolicyInfo).not.toHaveBeenCalled(); + }); + test('if isCoverageEnabled is true, then getCoveragePolicyInfo called', async () => { + // Arrange + const { wrapper } = getMountedComponent({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().issConfig.isCoverageEnabled = true; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Assert - expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); - expect(wrapper.vm.mainStore.getCoveragePolicyInfo).not.toHaveBeenCalled(); - }); - test('if maxCoverageLookupAttemptsReached is false, then getCoveragePolicyInfo called', async () => { - // Arrange - const { wrapper } = getMountedComponent({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().applicationUser.coverageLookupAttempts = 10; + // Act + await wrapper.vm.forwardButtonAction(); - // Act - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); + expect(wrapper.vm.mainStore.getCoveragePolicyInfo).toHaveBeenCalled(); + }); + test('if maxCoverageLookupAttemptsReached is true, then getCoveragePolicyInfo not called', async () => { + // Arrange + const { wrapper } = getMountedComponent({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().applicationUser.coverageLookupAttempts = 11; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Assert - expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); - expect(wrapper.vm.mainStore.getCoveragePolicyInfo).toHaveBeenCalled(); - }); - test('if policy and vehicles are found but no duplicates, navigate to policy-vehicle page', async () => { - // Arrange - const { wrapper } = setupMocks({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + // Act + await wrapper.vm.forwardButtonAction(); - useMainStore().applicationUser.duplicateOrders = []; - useMainStore().order.policy.policyLookupSuccessful = true; - useMainStore().order.policy.vehicles = [ - { vin: 'TEST_VIN' }, - { vin: 'TEST_VIN2' } - ]; + // Assert + expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); + expect(wrapper.vm.mainStore.getCoveragePolicyInfo).not.toHaveBeenCalled(); + }); + test('if maxCoverageLookupAttemptsReached is false, then getCoveragePolicyInfo called', async () => { + // Arrange + const { wrapper } = getMountedComponent({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().applicationUser.coverageLookupAttempts = 10; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Act - await wrapper.vm.forwardButtonAction(); + // Act + await wrapper.vm.forwardButtonAction(); - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('if policy is found, but no vehicles and no duplicates, navigate to vehicle-selection page', async () => { - // Arrange - const { wrapper } = setupMocks({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + // Assert + expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled(); + expect(wrapper.vm.mainStore.getCoveragePolicyInfo).toHaveBeenCalled(); + }); + test('if policy and vehicles are found but no duplicates, navigate to policy-vehicle page', async () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - useMainStore().applicationUser.duplicateOrders = []; - useMainStore().order.policy.policyLookupSuccessful = true; - useMainStore().order.policy.vehicles = []; + useMainStore().applicationUser.duplicateOrders = []; + useMainStore().order.policy.policyLookupSuccessful = true; + useMainStore().order.policy.vehicles = [ + { vin: 'TEST_VIN' }, + { vin: 'TEST_VIN2' } + ]; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Act + // Act + await wrapper.vm.forwardButtonAction(); - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + ); + }); + test('if policy is found, but no vehicles and no duplicates, navigate to vehicle-selection page', async () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('if policy is found, but null vehicles and no duplicates, navigate to vehicle-selection page', async () => { - // Arrange - const { wrapper } = setupMocks({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + useMainStore().applicationUser.duplicateOrders = []; + useMainStore().order.policy.policyLookupSuccessful = true; + useMainStore().order.policy.vehicles = []; + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - useMainStore().applicationUser.duplicateOrders = []; - useMainStore().order.policy.policyLookupSuccessful = true; - useMainStore().order.policy.vehicles = null; + // Act + await wrapper.vm.forwardButtonAction(); - // Act + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + ); + }); + test('if policy is found, but null vehicles and no duplicates, navigate to vehicle-selection page', async () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - await wrapper.vm.forwardButtonAction(); + useMainStore().applicationUser.duplicateOrders = []; + useMainStore().order.policy.policyLookupSuccessful = true; + useMainStore().order.policy.vehicles = null; - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('if policy is not found and no duplicates, navigate to policy-holder-details page', async () => { - // Arrange - const { wrapper } = setupMocks({}); - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - useMainStore().order.policy.policyLookupSuccessful = false; - useMainStore().applicationUser.duplicateOrders = []; + // Act + await wrapper.vm.forwardButtonAction(); - // Act - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + ); + }); + test('if policy is not found and no duplicates, navigate to policy-holder-details page', async () => { + // Arrange + const { wrapper } = setupMocks({}); + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({})); - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('getDuplicateReferrals throws rejected promise => navigate called', async () => { - // Arrange - const { wrapper } = setupMocks({}); - const error = 'duplicate referrals error'; - useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.reject(error)); + useMainStore().order.policy.policyLookupSuccessful = false; + useMainStore().applicationUser.duplicateOrders = []; - // Act - await wrapper.vm.forwardButtonAction(); + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); - // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + ); + }); + test('getDuplicateReferrals throws rejected promise => navigate called', async () => { + // Arrange + const { wrapper } = setupMocks({}); + const error = 'duplicate referrals error'; + useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.reject(error)); + wrapper.vm.mainStore.validateZip = jest.fn().mockImplementation(() => Promise.resolve({ + data: { + isValid: true + } + })); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + }); }); }); diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index b9cac195..05afc1e2 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -165,7 +165,6 @@ class="mt-3" cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" - @backClicked="backButtonAction" @ForwardClicked="forwardButtonAction" />
@@ -190,7 +189,7 @@ import textBlock from '@/digital-components/text-block/text-block.vue'; // Supporting files import { fetchCmsContentForPage, fetchGlobalCmsContent, updateCmsSiteHeader } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper'; -import { required, regex } from '@/helpers/validation-rules'; +import { required } from '@/helpers/validation-rules'; import errorMessages from '@/constants/error-messages'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; @@ -199,44 +198,7 @@ import globalRules from '@/constants/global-rules'; import routerParams from '@/router/router-constants/router-params'; // define validation rules -defineRule('loss-date-required', required(errorMessages.LOSS_DATE_REQUIRED)); -defineRule('policy-number-required', required(errorMessages.POLICY_NUMBER_REQUIRED)); -defineRule( - 'policy-number-format', - regex(/^~?[a-zA-Z0-9]+$/, errorMessages.POLICY_NUMBER_FORMAT) -); -defineRule('loss-state-required', required(errorMessages.LOSS_STATE_REQUIRED)); -defineRule( - 'loss-city-format', - regex(/^[a-zA-Z .]+$/, errorMessages.LOSS_CITY_FORMAT) -); -defineRule('loss-city-required', required(errorMessages.LOSS_CITY_REQUIRED)); defineRule('damage-option-required', required(errorMessages.DAMAGE_OPTION_REQUIRED)); -defineRule('policy-zip-required', required(errorMessages.POLICY_ZIP_REQUIRED)); -defineRule( - 'policy-zip-format', - regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT) -); -defineRule('loss-date-gt-10-years', (value) => { - const lossDate = new Date(Date.parse(`${value}T00:00:00`)); - const today = new Date(); - const tenYearsAgo = new Date(today.getFullYear() - 10, today.getMonth(), today.getDate(), 0, 0, 0, 0); - if (lossDate < tenYearsAgo) { - return errorMessages.DAMAGE_DATE_REQUIREMENT; - } - - return true; -}); -defineRule('loss-date-lt-tomorrow', (value) => { - const lossDate = new Date(Date.parse(`${value}T00:00:00`)); - const today = new Date(); - const tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0, 0); - if (lossDate >= tomorrow) { - return errorMessages.DAMAGE_DATE_NO_FUTURE_DATE; - } - - return true; -}); export default { name: 'welcome-page', @@ -291,14 +253,15 @@ export default { displayInvalidZipAlert: false, duplicates: [], rules: { - policyNumber: 'policy-number-required|policy-number-format', - policyZip: 'policy-zip-required|policy-zip-format', - lossDate: 'loss-date-required|loss-date-gt-10-years|loss-date-lt-tomorrow', damageOption: 'damage-option-required', - phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`, email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`, - lossCity: 'loss-city-required|loss-city-format', - lossState: 'loss-state-required' + lossCity: `${globalRules.DATE_OF_LOSS_CITY_REQUIRED}|${globalRules.DATE_OF_LOSS_CITY_FORMAT}`, + // eslint-disable-next-line max-len + lossDate: `${globalRules.DATE_OF_LOSS_REQUIRED}|${globalRules.DATE_OF_LOSS_NOT_TEN_YEARS_PAST}|${globalRules.DATE_OF_LOSS_NOT_FUTURE}`, + lossState: `${globalRules.DATE_OF_LOSS_STATE_REQUIRED}`, + policyNumber: `${globalRules.POLICY_NUMBER_REQUIRED}|${globalRules.POLICY_NUMBER_FORMAT}`, + policyZip: `${globalRules.POLICY_ZIP_REQUIRED}|${globalRules.POLICY_ZIP_FORMAT}`, + phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}` } }; }, @@ -362,8 +325,6 @@ export default { }, methods: { async forwardButtonAction() { - console.log('zip code...'); - console.log(this.welcomePageModel.policyZipCode); await this.mainStore.validateZip({ zip: this.welcomePageModel.policyZipCode }) .then(async (zipInfo) => { if (zipInfo?.data?.isValid === true) { @@ -376,13 +337,12 @@ export default { } else { this.mainStore.order.policy.policyLookupSuccessful = false; } - return this.navigateForward(); + this.navigateForward(); }); } else { - // set manual error message - console.log('zip invalid...'); + // display alert, remove button loader this.displayInvalidZipAlert = true; - return this.$refs.siteFooter.removeLoader(); + this.$refs.siteFooter.removeLoader(); } }); }, From 3ba5bee4a96bff4d2dc53f8263dbe18d63f5edcf Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Fri, 16 Feb 2024 10:57:44 -0500 Subject: [PATCH 4/7] removed comment --- src/layouts/welcome-page/welcome-page.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 05afc1e2..70005db2 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -340,7 +340,6 @@ export default { this.navigateForward(); }); } else { - // display alert, remove button loader this.displayInvalidZipAlert = true; this.$refs.siteFooter.removeLoader(); } From 6d4ef194965e0a436cb961a5e8798b2f038aaa06 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Fri, 16 Feb 2024 15:24:16 -0500 Subject: [PATCH 5/7] Checked with Janet after card comment, update to policy zip validation --- src/helpers/global-rule-definer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js index def671e4..eed5e381 100644 --- a/src/helpers/global-rule-definer.js +++ b/src/helpers/global-rule-definer.js @@ -101,7 +101,7 @@ function defineGlobalPolicyZipCodeRules() { defineRule(globalRules.POLICY_ZIP_REQUIRED, required(errorMessages.POLICY_ZIP_REQUIRED)); defineRule( globalRules.POLICY_ZIP_FORMAT, - regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT) + regex(/^\d{5}$/, errorMessages.POLICY_ZIP_FORMAT) ); } From d85829f83e643c3e2ec3b82c22caf0ba6a0443df Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Fri, 16 Feb 2024 16:19:47 -0500 Subject: [PATCH 6/7] Add Mask to phone number fields in app Prevents 1 and 0 from starting a phone number. --- src/layouts/bailout-page/bailout-page.vue | 12 +++++++++++- src/layouts/contact-details/contact-details.vue | 11 +++++++++++ .../contact-details-drawer.vue | 12 +++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/layouts/bailout-page/bailout-page.vue b/src/layouts/bailout-page/bailout-page.vue index 87797893..4a60c8e9 100644 --- a/src/layouts/bailout-page/bailout-page.vue +++ b/src/layouts/bailout-page/bailout-page.vue @@ -39,7 +39,7 @@ inputId="phoneNumberField" cmsWidgetName="PhoneNumberQuestion" isRequired - mask="###-###-####" + :mask="mask" disableAutoFill :validationRules="rules.phoneNumber" /> @@ -101,6 +101,16 @@ export default { }, footerButtonText() { return this.getCmsContent(this.widget.drawerFooter, widgetFields.FOOTER_WIDGET.FORWARD_BUTTON_TEXT); + }, + mask() { + return { + mask: 'x##-###-####', + tokens: { + x: { + pattern: /[2-9]/ + } + } + }; } }, methods: { From cd36ee81c11cdd1b7bf3780062d099f6f649f4d5 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 19 Feb 2024 13:02:55 -0500 Subject: [PATCH 7/7] mask zip input --- src/layouts/welcome-page/welcome-page.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 70005db2..df58619e 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -34,6 +34,7 @@ inputId="policyZipCode" cmsWidgetName="PolicyZipQuestion" isRequired + mask="#####" :isDisabled="isPolicyZipDisabled" :validationRules="rules.policyZip" />