diff --git a/src/helpers/coverage-statement-helper.js b/src/helpers/coverage-statement-helper.js index 187f1ea7..772f3149 100644 --- a/src/helpers/coverage-statement-helper.js +++ b/src/helpers/coverage-statement-helper.js @@ -1,37 +1,27 @@ import { useMainStore } from '@/store'; import { coverageStatuses } from '@/constants/coverage-statuses'; -// TODO description export async function getRegisterClaimResponse() { - try { - const registerClaimResponse = await useMainStore().registerClaim(); - const promiseResultMap = [ - { - resultKey: 'registerClaimResponse', - promise: registerClaimResponse - }, - ]; + const registerClaimResponse = await useMainStore().registerClaim(); + const promiseResultMap = [ + { + resultKey: 'registerClaimResponse', + promise: registerClaimResponse + }, + ]; - const resultMap = await settleAllPromises(promiseResultMap); - return resultMap.registerClaimResponse; - } - catch(responseError) { - return { - error: { - status: responseError.status - } - } - } + const resultMap = await settleAllPromises(promiseResultMap); + return resultMap.registerClaimResponse; } -// Deductible/ITAC, No Comp, and Not Verified -// Still need No Comp, ITAC, and Deductible export function setInsuranceCoverageValues(registerClaimResponse) { - const registerClaimFailed = registerClaimResponse.error; + const registerClaimFailed = registerClaimResponse.isError; if (useMainStore().isClaimRegistrationRequired) { useMainStore().payment.insuranceCoverage.isVerified = !registerClaimFailed; useMainStore().payment.insuranceCoverage.coverageStatus = registerClaimFailed ? coverageStatuses.PENDING - : coverageStatuses.VERIFIED; + : useMainStore().policy.noCoverage + ? coverageStatuses.NO_COMP + : coverageStatuses.VERIFIED; } } diff --git a/src/helpers/data-generation.js b/src/helpers/data-generation.js new file mode 100644 index 00000000..b1371713 --- /dev/null +++ b/src/helpers/data-generation.js @@ -0,0 +1,28 @@ +import { randomUUID } from "node:crypto"; + +export function getRandomString(minLength = 1, maxLength = 100) { + const length = getRandomInt(minLength, maxLength); + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} + +export function getRandomInt(min = 0, max = 1000) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive +} + +export function getRandomGuid() { + return randomUUID(); +} + +export function getRandomBoolean() { + const bools = [true, false]; + const index = getRandomInt(0,2); + return bools[index]; +} \ No newline at end of file diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index c0aa9e33..1e5c766e 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -98,7 +98,6 @@ export default { // If they go backwards select vehicle => forward => one deductible => back to vehicle selection => forward again => right info // backwards => vehicle unverified => clear coverage info // keep this in mind - console.log("Going to update vehicle"); this.mainStore.updateVehicle(this.vehicleFromLookup); } return this.navigateForward(); @@ -160,13 +159,20 @@ export default { }, noCoverageForSelectedVehicle() { const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; }); - return vehicle.coverages.length == 0; + return vehicle.coverages?.length == 0 ?? true; }, deductibleForSelectedVehicle() { - const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; }); - return vehicle?.coverages?.length == 0 ?? true - ? 0 - : vehicle.coverages[0].deductible; + const vehicle = this.policyVehicles.find((vehicle) => { return vehicle?.vin == this.selectedVehicleVin; }); + if (!vehicle){ + return undefined; + } + // return 0 in (vehicle.coverages ?? []) + // ? vehicle?.coverages[0].deductible + // : 0; + + return vehicle.coverages?.length ?? false + ? vehicle?.coverages[0].deductible + : 0; }, repairWaivedForSelectedVehicle() { const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; }); diff --git a/src/store/index.js b/src/store/index.js index 9beed8c2..4b2a0f69 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -134,6 +134,7 @@ export const useMainStore = defineStore({ damage: (state) => state.order.damage, lineItems: (state) => state.order.lineItems, payment: (state) => state.order.payment, + policy: (state) => state.order.policy, hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly, isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired, eventBusItem: (state) => ( eventCategory, eventSubCategory) => { @@ -414,11 +415,9 @@ export const useMainStore = defineStore({ }); return response; } catch (responseError) { - return { - error: { - status: responseError.status - } - }; + return Promise.resolve({ + isError: true + }) } }, async lookupVinByPlate(licensePlate, licenseState) { @@ -554,7 +553,7 @@ export const useMainStore = defineStore({ console.error(error); return []; }); - }, + }, async getRainDefense() { return globalMethods @@ -664,18 +663,18 @@ export const useMainStore = defineStore({ } }); }, - // TODO when is this called? + setVehicle() { return globalMethods - .callHttpClient({ - methods: endpoints.GetVehicle.method, - endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`, - payload: {} - }) - .then((response) => { - this.updateVehicle(response.data); - return response; - }); + .callHttpClient({ + methods: endpoints.GetVehicle.method, + endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`, + payload: {} + }) + .then((response) => { + this.updateVehicle(response.data); + return response; + }); }, saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { @@ -752,7 +751,7 @@ export const useMainStore = defineStore({ updateVehicle(vehicle) { // Assuming that the method caller pass all the properties. // otherwise need to check for undefined for every property. - this.order.vehicle.carId = vehicle.carId; + this.vehicle.carId = vehicle.carId; this.order.vehicle.category = vehicle.category; this.order.vehicle.year = vehicle.year; this.order.vehicle.make = vehicle.make; diff --git a/src/store/store.spec.js b/src/store/store.spec.js index e282f849..e8d9a3b2 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1,8 +1,9 @@ import { useMainStore } from '@/store'; import { createApp } from 'vue'; -import { createPinia } from "pinia"; +import { setActivePinia, createPinia } from "pinia"; import globalMethods from "@/global-methods"; import App from '@/App.vue'; +import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '../helpers/data-generation'; describe("Store", () => { @@ -14,6 +15,7 @@ describe("Store", () => { vueApp.use(pinia); beforeEach(() => { + setActivePinia(createPinia()); store = useMainStore(); store.applicationUser.eventBus = []; jest.resetAllMocks(); @@ -27,31 +29,47 @@ describe("Store", () => { }); it("Should add events to the bus", () => { + // Arrange + const category = getRandomString(1, 25); + const subCategory = getRandomString(5, 20); + const isDismissible = getRandomBoolean(); + const copy = getRandomString(5, 25); + const headline = getRandomString(5, 25); + const type = getRandomString(5, 15); let event = { - category: "TestCategory", - subCategory: "TestSubCategory", + category: category, + subCategory: subCategory, eventValue: { - isDismissible: true, - messageCopy: "You can get a quote by starting on this page.", - messageHeadline: "We're sorry, something went wrong.", - type: "testType", + isDismissible: isDismissible, + messageCopy: copy, + messageHeadline: headline, + type: type, }, }; + // Act store.addEventToBus(event); + // Assert expect(store.applicationUser.eventBus[0]).toEqual(event); }); it("Should remove events from the bus", () => { + // Arrange + const category = getRandomString(1, 25); + const subCategory = getRandomString(5, 20); + const isDismissible = getRandomBoolean(); + const copy = getRandomString(5, 25); + const headline = getRandomString(5, 25); + const type = getRandomString(5, 15); let event = { - category: "TestCategory", - subCategory: "TestSubCategory", + category: category, + subCategory: subCategory, eventValue: { - isDismissible: true, - messageCopy: "You can get a quote by starting on this page.", - messageHeadline: "We're sorry, something went wrong.", - type: "testType", + isDismissible: isDismissible, + messageCopy: copy, + messageHeadline: headline, + type: type, }, }; @@ -59,164 +77,324 @@ describe("Store", () => { expect(store.applicationUser.eventBus.length).toBe(1); + // Act store.removeEventFromBus({ category: event.category, subCategory: event.subCategory }) + // Assert expect(store.applicationUser.eventBus.length).toBe(0); }); it("Should return correct event using the getter function eventBusItem", () => { + // Arrange + const category = getRandomString(1, 25); + const subCategory = getRandomString(5, 20); + const isDismissible = getRandomBoolean(); + const copy = getRandomString(5, 25); + const headline = getRandomString(5, 25); + const type = getRandomString(5, 15); let event = { - category: "TestCategory", - subCategory: "TestSubCategory", + category: category, + subCategory: subCategory, eventValue: { - isDismissible: true, - messageCopy: "You can get a quote by starting on this page.", - messageHeadline: "We're sorry, something went wrong.", - type: "testType", + isDismissible: isDismissible, + messageCopy: copy, + messageHeadline: headline, + type: type, }, }; store.addEventToBus(event); + // Act const actual = store.eventBusItem(event.category, event.subCategory) + // Assert expect(actual).toEqual(event.eventValue); }); it("UpdateVehicle should merge vehicle with response object", () => { - store.order.vehicle = { - year: 2020, - make: "Honda", - model: "Civic", - style: "4 door sedan", - carId: null, - category: null, - vin: null, - imageUrl: null, - imageVifNumber: null, - imageColor: null, + // Arrange + const carId = getRandomString(10,14); + const category = getRandomString(3,7); + const year = getRandomInt(1960, 2023); + const make = getRandomString(4,10); + const model = getRandomString(4,10); + const style = getRandomString(4,15); + const imageUrl = getRandomString(50,100); + const imageVifNumber = getRandomInt(10000,99999).toString(); + const imageColor = getRandomString(4,10); + const providedVehicle = { + carId: carId, + category: category, + year: year, + make: make, + model: model, + style: style, + imageUrl: imageUrl, + imageVifNumber: imageVifNumber, + imageVifColor: imageColor }; - const response = {data: { - "carId": "CR00069299", - "category": "CAR", - "year": 2020, - "make": "Honda", - "model": "Civic", - "style": "4 door sedan", - "imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg", - "imageVifNumber": "13996", - "imageVifColor": "white" + const expectedVehicle = { + carId: carId, + category: category, + year: year, + make: make, + model: model, + style: style, + imageUrl: imageUrl, + imageVifNumber: imageVifNumber, + imageColor: imageColor + } + + // Act + store.updateVehicle(providedVehicle); + + // Assert + expect(store.order.vehicle).toMatchObject(expectedVehicle); + }); + + it("UpdateVehicle should set policy values appropriately with repair waived", () => { + // Arrange + const noCoverage = getRandomBoolean(); + const deductible = getRandomInt(1,500); + const vehicle = { + noCoverage: noCoverage, + deductible: deductible, + repairWaived: true + }; + + const expectedPolicy = { + noCoverage: noCoverage, + deductible: { + replace: deductible, + repair: 0 } }; - store.updateVehicle(response.data); + // Act + store.updateVehicle(vehicle); - expect(store.order.vehicle.imageUrl).toEqual(response.data.imageUrl); - expect(store.order.vehicle.imageVifNumber).toEqual(response.data.imageVifNumber); - expect(store.order.vehicle.style).toEqual(response.data.style); + // Assert + expect(store.order.policy).toMatchObject(expectedPolicy); }); - it("setVehicle should call globalMethods.callHttpClient", () => { - store.order.vehicle = jest.fn(); + it("UpdateVehicle should set policy values appropriately with repair not waived", () => { + // Arrange + const noCoverage = getRandomBoolean(); + const deductible = getRandomInt(1,500); + const vehicle = { + noCoverage: noCoverage, + deductible: deductible, + repairWaived: false + }; - const response = {data: { - "carId": "CR00069299", - "category": "CAR", - "year": 2020, - "make": "Honda", - "model": "Civic", - "style": "4 door sedan", - "imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg", - "imageVifNumber": "13996", - "imageVifColor": "white" + const expectedPolicy = { + noCoverage: noCoverage, + deductible: { + replace: deductible, + repair: deductible + } + }; + + // Act + store.updateVehicle(vehicle); + + // Assert + expect(store.order.policy).toMatchObject(expectedPolicy); + }); + + // TODO update test to work also checking store values + it("setVehicle should call globalMethods.callHttpClient", () => { + // Arrange + const carId = getRandomString(10,14); + const category = getRandomString(3,7); + const year = getRandomInt(1960, 2023); + const make = getRandomString(4,10); + const model = getRandomString(4,10); + const style = getRandomString(4,15); + const imageUrl = getRandomString(50,100); + const imageVifNumber = getRandomInt(10000,99999).toString(); + const imageColor = getRandomString(4,10); + const response = { + data: { + carId: carId, + category: category, + year: year, + make: make, + model: model, + style: style, + imageUrl: imageUrl, + imageVifNumber: imageVifNumber, + imageVifColor: imageColor } }; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); - - store.setVehicle(); - - expect(globalMethods.callHttpClient).toHaveBeenCalled(); - }); - - it("saveVehicleDamage, should update damage", () => { - // Arrange - store.order.damage = { - glassToReplace: [{ glassName: "Single", glassLocation: "Windshield" }], - }; // Act - store.saveVehicleDamage( false, - [{ glassName: "Rear", glassLocation: "quarter" }], - 0); + const returned = store.setVehicle(); // Assert - expect(store.order.damage.glassToReplace).toEqual([{ glassName: "Rear", glassLocation: "quarter" }]); - expect(store.order.damage.isRepair).toEqual(false); - expect(store.order.damage.numberOfChips).toEqual(null); + expect(globalMethods.callHttpClient).toHaveBeenCalled(); + expect(returned).resolves.toMatchObject(response); + }); + + it("saveVehicleDamage with windshield repair should update damage with number of chips not null", () => { + // Arrange + const glassName = getRandomString(4,10); + const glassLocation = getRandomString(5,15); + const isWindshieldRepair = true; + const selectedGlassToReplace = [{ + glassName: glassName, + glassLocation: glassLocation + }]; + const chipCount = getRandomInt(0,3).toString(); + + // Act + store.saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, chipCount); + + // Assert + expect(store.order.damage.glassToReplace).toEqual(selectedGlassToReplace); + expect(store.order.damage.isRepair).toEqual(isWindshieldRepair); + expect(store.order.damage.numberOfChips).toEqual(chipCount); + }); + + it("saveVehicleDamage without windshield repair should update damage with number of chips null", () => { + // Arrange + const glassName = getRandomString(4,10); + const glassLocation = getRandomString(5,15); + const isWindshieldRepair = false; + const selectedGlassToReplace = [{ + glassName: glassName, + glassLocation: glassLocation + }]; + const chipCount = getRandomInt(0,3); + + const expectedChipCount = null; + + // Act + store.saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, chipCount); + + // Assert + expect(store.order.damage.glassToReplace).toEqual(selectedGlassToReplace); + expect(store.order.damage.isRepair).toEqual(isWindshieldRepair); + expect(store.order.damage.numberOfChips).toEqual(expectedChipCount); }); it("should return registration data if available", () => { //Arrange + const streetAddress = getRandomString(5,15); + const city = getRandomString(5,15); + const state = getRandomString(5,10); + const zipCode = getRandomInt(10000,99999).toString(); + const firstName = getRandomString(5,20); + const lastName = getRandomString(5,20); const expected = { addressQuestions: { - streetAddress: "test", - city: "city", - state: "state", - zipCode: "zip", + streetAddress: streetAddress, + city: city, + state: state, + zipCode: zipCode, }, - firstName: "1stName", - lastName: "Surname", + firstName: firstName, + lastName: lastName, } store.order.vehicle.registration = { licensePlate: null, - address: "test", - city: "city", - state: "state", - zipCode: "zip", - firstName: "1stName", - lastName: "Surname", + address: streetAddress, + city: city, + state: state, + zipCode: zipCode, + firstName: firstName, + lastName: lastName, }; //Act const actual = store.customerData; - //Assert + //Assert expect(actual).toEqual(expected); }); it("should return customer data if registration data unavailable", () => { //Arrange + const address = getRandomString(1,25); + const city = getRandomString(5,20); + const state = getRandomString(4,20); + const zipCode = getRandomInt(10000, 99999).toString(); + const firstName = getRandomString(5,25); + const lastName = getRandomString(5,25); const expected = { addressQuestions: { - streetAddress: "test", - city: "city", - state: "state", - zipCode: "zip", + streetAddress: address, + city: city, + state: state, + zipCode: zipCode, }, - firstName: "1stName", - lastName: "Surname", + firstName: firstName, + lastName: lastName, } store.order.vehicle.registration.address = null; store.order.customer = { - licensePlate: null, - address: "test", - city: "city", - state: "state", - zipCode: "zip", - firstName: "1stName", - lastName: "Surname", + address: { + streetAddress: address, + city: city, + state: state, + zipCode: zipCode + }, + firstName: firstName, + lastName: lastName }; //Act const actual = store.customerData; - //Assert - expect(actual).toEqual(expected); + //Assert + expect(actual).toMatchObject(expected); }); + describe("registerClaim method", () => { + it("successful response results in expected data returned", () => { + // Arrange + const response = { + data: { + claimantId: null, + claimNumber: getRandomString(9, 9), + correlationId: getRandomGuid(), + isSuccess: true, + isError: false, + successMessage: getRandomString(9, 9), + deductible: 0 + } + }; + + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); + + // Act + const registerClaimPromise = store.registerClaim(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalled(); + expect(registerClaimPromise).resolves.toMatchObject(response); + expect(registerClaimPromise).resolves.not.toHaveProperty('error'); + }); + + it("Call to client returns exception, resulting in object with error property being returned", () => { + // Arrange + globalMethods.callHttpClient = jest.fn().mockImplementation(() => { + throw new Error('Register claim call failed'); + }); + + // Act + const registerClaimPromise = store.registerClaim(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalled(); + expect(registerClaimPromise).resolves.toHaveProperty('error'); + }); + }) }); \ No newline at end of file