diff --git a/src/constants/coverage-statuses.js b/src/constants/coverage-statuses.js index 5f794cc9..4142121a 100644 --- a/src/constants/coverage-statuses.js +++ b/src/constants/coverage-statuses.js @@ -1,7 +1,7 @@ const coverageStatuses = Object.freeze({ - PENDING: 'Pending', - NO_COMP: 'No Comp', - VERIFIED: 'Verified' + PENDING: 0, + NO_COMP: 1, + VERIFIED: 2 }); export default coverageStatuses; diff --git a/src/router/index.js b/src/router/index.js index 44e5e5a8..5f8f3cdc 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -82,13 +82,19 @@ const router = createRouter({ } }); -router.afterEach((to, from) => { +router.afterEach(async (to, from) => { /*eslint-disable-line*/ - const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); - store.saveSession(); + await store.saveSession()?.catch(() => { + console.log("failed :("); + if(from.name === issPageValues.WELCOME_PAGE) { + console.log("welcome!"); + router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) + // TODO bail out if save session fails + } + }); if (to.query.issPage !== issPageValues.ENTRY_PAGE) { // Push page view to GA diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index f732786a..6fb510d2 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -11,6 +11,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_POLICY_UNVERIFIED: 'CLICKED_FORWARD_POLICY_UNVERIFIED', CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES: 'CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES', CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES: 'CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', + SAVE_SESSION_FAILED: 'SAVE_SESSION_FAILED', // YMMS SELECTED_YEAR: 'SELECTED_YEAR', @@ -63,7 +64,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES', // Bailout - CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' + CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT', }); export default navigationScenarios; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 4af22d4f..e2a0dc85 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -354,6 +354,10 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, destinationIssPageValue: issPageValues.POLICY_VEHICLES + }, + { + scenario: navigationScenarios.SAVE_SESSION_FAILED, + destinationIssPageValue: issPageValues.BAILOUT_PAGE } ] }, diff --git a/src/store/index.js b/src/store/index.js index e89cdb27..2765a5f2 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -685,22 +685,22 @@ export const useMainStore = defineStore({ }, saveSession() { - const { vehicle, damage, policy, customer, contactInfo, payment, applicationUser, + const { vehicle, damage, policy, customer, contactInfo, payment, lineItems, serviceLocation, schedule } = this.order; const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); - return globalMethods.callHttpClient({ - method: endpoints.SaveSession.method, - endpoint: endpoints.SaveSession.url, - payload: { - applicationUser: { - crmCustomerId: applicationUser.crmCustomerId, - experiments: applicationUser.experiments, - lastPage: applicationUser.lastPageVisited, - pageData: applicationUser.pageData, - savedSessionId: applicationUser.savedSessionId - }, - order: { + return new Promise((resolve, reject) => { + globalMethods.callHttpClient({ + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: { + applicationUser: { + crmCustomerId: this.applicationUser.crmCustomerId, + experiments: this.applicationUser.experiments, + lastPage: this.applicationUser.lastPageVisited, + pageData: this.applicationUser.pageData, + savedSessionId: this.applicationUser.savedSessionId + }, vehicle: { year: vehicle.year, make: vehicle.make, @@ -708,7 +708,7 @@ export const useMainStore = defineStore({ style: vehicle.style, vin: vehicle.vin, carId: vehicle.carId, - licensePlateNumber: vehicle.registration.licensePlate + licensePlateNumber: vehicle.registration?.licensePlate }, damage: { numberOfChips: damage.numberOfChips, @@ -739,11 +739,11 @@ export const useMainStore = defineStore({ }, customer: { address: { - streetAddress: customer.address.streetAddress, - streetAddress2: customer.address.streetAddress2, - city: customer.address.city, - state: customer.address.state, - zipCode: customer.address.zipCode + streetAddress: customer.address?.streetAddress, + streetAddress2: customer.address?.streetAddress2, + city: customer.address?.city, + state: customer.address?.state, + zipCode: customer.address?.zipCode }, emailAddress: contactInfo.emailAddress, firstName: contactInfo.firstName, @@ -758,8 +758,8 @@ export const useMainStore = defineStore({ }, payment: { InsuranceCoverage: { - isVerified: payment.insuranceCoverage.isVerified ?? false, - coverageStatus: payment.insuranceCoverage.coverageStatus + isVerified: payment.insuranceCoverage?.isVerified ?? false, + coverageStatus: payment.insuranceCoverage?.coverageStatus }, isInsurance: payment.isInsurance ?? true, parentAccountNumber: this.issConfig.accountNumber @@ -775,18 +775,22 @@ export const useMainStore = defineStore({ techNotes: contactInfo.notesForTechnician }, schedule: { - date: schedule?.date, - startTime: schedule?.startTime, - endTime: schedule?.endTime, - routeCode: schedule?.routeCode, - jobMaxMinutes: schedule?.jobMaxMinutes + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes }, referralDate: this.order.referralDate, referralNumber: this.order.referralNumber?.toString() - } - }, - additionalSuccessEventDataHandler: (response) => - `Email provided: ${customer.emailAddress ? 'true' : 'false'}` + }, + additionalSuccessEventDataHandler: (response) => + `Email provided: ${customer.emailAddress ? 'true' : 'false'}` + }).then((response) => { + return resolve(response); + }).catch((error) => { + return reject(error); + }); }); }, diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 6a7339ef..bbaf7dc1 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -3,6 +3,7 @@ import { setActivePinia, createPinia } from 'pinia'; import globalMethods from '@/global-methods.js'; import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js'; import coverageStatuses from '@/constants/coverage-statuses.js'; +import { endpoints } from '@/constants/endpoints'; describe('Store', () => { let store; @@ -478,6 +479,510 @@ describe('Store', () => { expect(store.contactInfo.notesForTechnician).toEqual(''); }); }); - // TODO add tests - describe('saveSession method', () => {}); + + describe('saveSession method', () => { + describe('successful method call', () => { + it('calls save session api endpoint', () => { + // Arrange + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url + } + )); + }); + it('Returns expected response object', async () => { + // Arrange + var response = { ReferralNumber: getRandomString(6, 6) }; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); + + // Act + const result = store.saveSession(); + + // Asserts + await expect(result).resolves.toBe(response); + }) + it('calls api with expected application user data', () => { + // Arrange + var applicationUser = { + crmCustomerId: getRandomString(6, 6), + experiments: getRandomString(6, 6), + lastPageVisited: getRandomString(6, 6), + pageData: getRandomString(6, 6), + savedSessionId: getRandomString(6, 6) + }; + store.applicationUser = applicationUser; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + const result = store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + applicationUser: expect.objectContaining({ + crmCustomerId: applicationUser.crmCustomerId, + experiments: applicationUser.experiments, + lastPage: applicationUser.lastPageVisited, + pageData: applicationUser.pageData, + savedSessionId: applicationUser.savedSessionId + }) + }) + }) + ); + }); + it('calls api with expected vehicle', () => { + var vehicle = { + year: getRandomString(6, 6), + make: getRandomString(6, 6), + model: getRandomString(6, 6), + style: getRandomString(6, 6), + carId: getRandomString(6, 6), + vin: getRandomString(6, 6), + registration: { licensePlate: getRandomString(6, 6) } + }; + store.order.vehicle = vehicle; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + vehicle: expect.objectContaining({ + year: vehicle.year, + make: vehicle.make, + model: vehicle.model, + style: vehicle.style, + carId: vehicle.carId, + vin: vehicle.vin, + licensePlateNumber: vehicle.registration.licensePlate + }) + }) + }) + } + )); + }); + it('calls api with expected damage', () => { + // Arrange + var damage = { + isRepair: getRandomString(6, 6), + numberOfChips: getRandomString(6, 6), + glassToReplace: [], + partQuestionAnswers: getRandomString(6, 6), + moldingQuestionAnswers: getRandomString(6, 6), + capabilityQuestionAnswers: getRandomString(6, 6) + }; + var policy = { + dateOfLoss: getRandomString(6, 6), + damageCause: getRandomString(6, 6), + damageState: getRandomString(6, 6), + damageCity: getRandomString(6, 6), + isDamageGlassOnly: getRandomString(6, 6) + }; + store.order.damage = damage; + store.order.policy = policy; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + numberOfChips: damage.numberOfChips, + isRepair: damage.isRepair, + partQuestionAnswers: damage.partQuestionAnswers, + moldingQuestionAnswers: damage.moldingQuestionAnswers, + capabilityQuestionAnswers: damage.capabilityQuestionAnswers, + dateOfLoss: policy.dateOfLoss, + damageCause: policy.damageCause, + damageState: policy.damageState, + damageCity: policy.damageCity, + isDamageGlassOnly: policy.isDamageGlassOnly + }) + }) + }) + }) + ); + }); + it('calls api with expected policy', () => { + // Arrange + var customer = { + firstName: getRandomString(6, 6), + lastName: getRandomString(6, 6), + emailAddress: getRandomString(6, 6), + phoneNumber: getRandomString(6, 6) + }; + var policy = { + policyNumber: getRandomString(6, 6), + policyZipCode: getRandomString(6, 6), + policyLookupSuccessful: getRandomString(6, 6), + noCoverage: getRandomString(6, 6) + }; + var originalDeductible = getRandomString(6, 6); + var currentDeductible = getRandomString(6, 6); + store.order.originalDeductible = originalDeductible; + store.order.currentDeductible = currentDeductible; + store.order.customer = customer; + store.order.policy = policy; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + policy: expect.objectContaining({ + policyHolder: expect.objectContaining({ + policyFirstName: customer.firstName, + policyLastName: customer.lastName, + policyPhoneNumber: customer.phoneNumber, + policyEmail: customer.emailAddress + }), + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, + noCoverage: policy.noCoverage, + policyLookupSuccessful: policy.policyLookupSuccessful, + originalDeductible, + currentDeductible + }) + }) + }) + }) + ); + }); + it('calls api with expected customer', () => { + // Arrange + var customer = { + address: { + streetAddress: getRandomString(6, 6), + streetAddress2: getRandomString(6, 6), + city: getRandomString(6, 6), + state: getRandomString(6, 6), + zipCode: getRandomString(6, 6) + } + }; + var contactInfo = { + firstName: getRandomString(6, 6), + lastName: getRandomString(6, 6), + emailAddress: getRandomString(6, 6), + phoneNumber: getRandomString(6, 6), + requestTextUpdates: getRandomBoolean() + }; + store.order.contactInfo = contactInfo; + store.order.customer = customer; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + customer: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: customer.address.streetAddress, + streetAddress2: customer.address.streetAddress2, + city: customer.address.city, + state: customer.address.state, + zipCode: customer.address.zipCode + }), + emailAddress: contactInfo.emailAddress, + firstName: contactInfo.firstName, + lastName: contactInfo.lastName, + phoneNumber: contactInfo.phoneNumber, + optInSms: contactInfo.requestTextUpdates + }) + }) + }) + }) + ); + }); + it('calls api with expected lineItems', () => { + // Arrange + var lineItems = { + glassParts: getRandomString(6, 6), + supportingItems: getRandomString(6, 6), + vaps: getRandomString(6, 6) + }; + store.order.lineItems = lineItems; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + lineItems: expect.objectContaining({ + glassParts: lineItems.glassParts, + supportingItems: lineItems.supportingItems, + vaps: lineItems.vaps + }) + }) + }) + }) + ); + }); + it.each([ + [coverageStatuses.PENDING], + [coverageStatuses.NO_COMP], + [coverageStatuses.VERIFIED] + ])('calls api with expected payment', (coverageStatus) => { + // Arrange + const accountNumber = getRandomString(6, 6); + const payment = { + isInsurance: getRandomBoolean(), + insuranceCoverage: { + isVerified: getRandomBoolean(), + coverageStatus + } + }; + store.issConfig.accountNumber = accountNumber; + store.order.payment = payment; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + payment: expect.objectContaining({ + InsuranceCoverage: expect.objectContaining({ + isVerified: payment.insuranceCoverage.isVerified, + coverageStatus: coverageStatus + }), + isInsurance: payment.isInsurance, + parentAccountNumber: accountNumber + }) + }) + }) + }) + ); + }); + it('calls api with expected service location', () => { + // Arrange + var notesForTechnician = getRandomString(6, 6); + var serviceLocation = { + address: getRandomString(6, 6), + city: getRandomString(6, 6), + state: getRandomString(6, 6), + zipCode: getRandomString(6, 6), + zipCodeCtu: getRandomString(6, 6) + }; + store.order.contactInfo.notesForTechnician = notesForTechnician; + store.order.serviceLocation = serviceLocation; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + serviceLocation: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: serviceLocation.address, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu + }), + techNotes: notesForTechnician + }) + }) + }) + }) + ); + }); + it('calls api with expected schedule', () => { + // Arrange + var schedule = { + date: getRandomString(6, 6), + startTime: getRandomString(6, 6), + endTime: getRandomString(6, 6), + routeCode: getRandomString(6, 6), + jobMaxMinutes: getRandomString(6, 6) + }; + store.order.schedule = schedule; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + schedule: expect.objectContaining({ + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes + }) + }) + }) + }) + ); + }); + it('calls api with expected referral date', () => { + // Arrange + var referralDate = getRandomString(6, 6); + store.order.referralDate = referralDate; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ referralDate: referralDate }) + }) + }) + ); + }); + it('calls api with expected referral number', () => { + // Arrange + var referralNumber = getRandomString(6, 6); + store.order.referralNumber = referralNumber; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ referralNumber: referralNumber }) + }) + } + )); + }); + }); + it('No glassArray => empty list', async () => { + store.damage.glassToReplace = null; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: [] + }) + }) + }) + }) + ); + }); + it('glassArray empty => empty list', async () => { + store.damage.glassToReplace = []; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: [] + }) + }) + }) + }) + ); + }); + it('Nonempty glass array => expected glass array sent', async () => { + const location1 = getRandomString(5); + const location2 = getRandomString(5); + const name1 = getRandomString(10); + const name2 = getRandomString(10); + store.damage.glassToReplace = [ + {glassLocation: location1, glassName: name1}, + {glassLocation: location2, glassName: name2} + ], + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: expect.arrayContaining([ + {location: location1, name: name1}, + {location: location2, name: name2} + ]) + }) + }) + }) + }) + ); + }); + it('api call throws exception', async () => { + expect.assertions(2); + const error = 'this is the error'; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); + + // Act + await store.saveSession().catch((e) => { + expect(e).toEqual(error); + }); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url + }) + ); + }); + }); });