Merge pull request #338 from Safelite/feature/digital/SSR-505

Feature/digital/ssr 505
This commit is contained in:
michaela-brydon-safelite 2023-06-29 12:12:42 -04:00 committed by GitHub
commit 5a764218d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1123 additions and 496 deletions

6
package-lock.json generated
View file

@ -3250,9 +3250,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.7.15", "version": "20.3.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz",
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==", "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==",
"dev": true "dev": true
}, },
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {

View file

@ -0,0 +1,7 @@
const coverageStatuses = {
PENDING: "Pending",
NO_COMP: "No Comp",
VERIFIED: "Verified",
};
export { coverageStatuses };

View file

@ -0,0 +1,9 @@
const endorsementOptions = {
EDUCATOR: "Educator",
OEM_APPROVED: "OEM Approved",
FULL_GLASS: "Full Glass Coverage",
PARKING_GUARD: "Parking Guard",
REPAIR_WAIVED: "Repair Waived"
};
export { endorsementOptions };

View file

@ -125,7 +125,11 @@ const endpoints = {
CoveragePolicyInfo: { CoveragePolicyInfo: {
url: '/coverage/api/v1/coverage/get-policy-information', url: '/coverage/api/v1/coverage/get-policy-information',
method: 'POST' method: 'POST'
} },
RegisterClaim: {
url: '/coverage/api/v1/coverage/register-claim',
method: 'POST'
}
}; };
export { endpoints }; export { endpoints };

View file

@ -0,0 +1,28 @@
import { randomUUID } from "crypto";
export function getRandomString(minLength = 1, maxLength = 100) {
const length = getRandomInt(minLength, maxLength + 1);
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];
}

View file

@ -10,6 +10,8 @@ import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { applicationConfig } from "@/constants/application-config"; import { applicationConfig } from "@/constants/application-config";
import { fetchCmsContentForPage, setupModalLinks } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage, setupModalLinks } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper.js"; import { settleAllPromises } from "@/helpers/layout-helper.js";
import { createTestingPinia } from '@pinia/testing';
import { getRandomString } from '@/helpers/data-generation.js';
jest.mock("@/helpers/damage-helper", () => ({ jest.mock("@/helpers/damage-helper", () => ({
getDamageString: jest.fn(), getDamageString: jest.fn(),
@ -31,6 +33,7 @@ describe("coverage-statement.vue...", () => {
test("Should return true for valid page requisites if vin exists", () => { test("Should return true for valid page requisites if vin exists", () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
useMainStore().order.vehicle.vin = getRandomString(5,20);
// Act // Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
@ -76,7 +79,7 @@ describe("coverage-statement.vue...", () => {
useMainStore().order.damage.isRepair = true; useMainStore().order.damage.isRepair = true;
// Assert // Assert
expect(wrapper.vm.unverifiedNonADASRepairBodyText).toEqual("NonADASRepairTestReturn"); expect(wrapper.vm.bodyText).toEqual("NonADASRepairTestReturn");
}) })
test("If damage is NonADAS Replace, display NonADASReplace coverage statement", async () => { test("If damage is NonADAS Replace, display NonADASReplace coverage statement", async () => {
@ -85,8 +88,16 @@ describe("coverage-statement.vue...", () => {
mixins: [mockMixin], mixins: [mockMixin],
}); });
useMainStore().lineItems.glassParts =
[
{
requiresRecalibration: false,
}
];
useMainStore().order.damage.isRepair = false;
// Assert // Assert
expect(wrapper.vm.unverifiedNonADASNextStepsBodyText).toEqual("NonADASReplaceTestReturn"); expect(wrapper.vm.bodyText).toEqual("NonADASReplaceTestReturn");
}) })
test("If damage is ADAS Replace, display ADASReplace coverage statement", async () => { test("If damage is ADAS Replace, display ADASReplace coverage statement", async () => {
@ -94,12 +105,55 @@ describe("coverage-statement.vue...", () => {
const wrapper = shallowMount(coverageStatement, { const wrapper = shallowMount(coverageStatement, {
mixins: [mockMixin], mixins: [mockMixin],
}); });
useMainStore().lineItems.glassParts = [
useMainStore().order.lineItems.requiresRecalibration = true; {
requiresRecalibration: true,
}
];
useMainStore().order.damage.isRepair = false;
// Assert // Assert
expect(wrapper.vm.unverifiedADASNextStepsBodyText).toEqual("ADASReplaceTestReturn"); expect(wrapper.vm.bodyText).toEqual("ADASReplaceTestReturn");
}) })
});
describe("claim registration api call", () => {
it("claim registration not required => method not called", async () => {
// Arrange
const wrapper = setupMocks({});
const store = useMainStore();
store.isClaimRegistrationRequired = false;
const to = {
query: { issPage: getRandomString(4,10) }
};
const next = jest.fn();
// SUT
coverageStatement.beforeRouteEnter.call(wrapper.vm, to, undefined, next)
// Assert
expect(store.registerClaim).not.toHaveBeenCalled();
});
it("claim registration required => register claim method called", async () => {
// Arrange
const wrapper = setupMocks({});
const store = useMainStore();
store.isClaimRegistrationRequired = true;
const to = {
query: { issPage: getRandomString(4,10) }
};
const next = jest.fn();
// SUT
coverageStatement.beforeRouteEnter.call(wrapper.vm, to, undefined, next)
// Assert
expect(store.registerClaim).toHaveBeenCalled();
});
}) })
}); });
@ -142,30 +196,6 @@ mountOptionsMockData = {},
}, },
}; };
useMainStore().order = {
vehicle: {
vin: "TESTVIN",
},
lineItems: {
glassParts: [
{
canSafeliteRecalibrate: false,
childParts: null,
color: "Green Tint",
description: "solar, driver side, encap",
partNumber: "DQ12204GTYNOEM",
partType: "DRIVER REAR QUARTER GLASS",
recalibrationType: null,
requiresCapabilityQuestions: false,
requiresRecalibration: false,
}
]
},
damage: {
isRepair: false,
}
};
const apiPromise = Promise.resolve(apiResponses); const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise); settleAllPromises.mockImplementation(() => apiPromise);
@ -174,12 +204,14 @@ mountOptionsMockData = {},
const mountOptions = getMountOptions({}); const mountOptions = getMountOptions({});
mountOptions.mixins = [baseMixin, vehicleQuestionsMixin]; mountOptions.mixins = [baseMixin, vehicleQuestionsMixin];
mountOptions.global = {
plugins: [createTestingPinia()]
}
const wrapper = shallowMount(coverageStatement, mountOptions); const wrapper = shallowMount(coverageStatement, mountOptions);
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
return { wrapper }; return { wrapper };
} }

View file

@ -76,14 +76,14 @@ export default {
}, },
computed: { computed: {
bodyText() { bodyText() {
if (useMainStore().order.damage.isRepair) { if (useMainStore().damage.isRepair) {
return this.unverifiedNonADASRepairBodyText; return this.unverifiedNonADASRepairBodyText;
} }
else { else {
let parts = useMainStore().order.lineItems.glassParts; let parts = useMainStore().lineItems.glassParts;
// if ADAS, display ADASNextSteps // if ADAS, display ADASNextSteps
if (parts.filter(part => part.requiresRecalibration).length > 0) { if (parts != null && parts.filter(part => part.requiresRecalibration).length > 0) {
return this.unverifiedADASNextStepsBodyText; return this.unverifiedADASNextStepsBodyText;
} }
// if non-ADAS, display NonADASNextSteps // if non-ADAS, display NonADASNextSteps
@ -121,15 +121,23 @@ export default {
}, },
]; ];
if (useMainStore().isClaimRegistrationRequired){
const registerClaimResponse = await useMainStore().registerClaim();
promiseResultMap.push({
resultKey: 'registerClaim',
promise: registerClaimResponse,
});
}
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
}); });
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.vin) { if (useMainStore().vehicle.vin) {
return true; return true;
} }
return false; return false;

View file

@ -1,28 +1,34 @@
import policyVehicles from "@/layouts/policy-vehicles/policy-vehicles"; import policyVehicles from '@/layouts/policy-vehicles/policy-vehicles.vue';
import { settleAllPromises } from "@/helpers/layout-helper.js"; import { settleAllPromises } from '@/helpers/layout-helper';
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { getMountOptions } from '@/helpers/unit-test-helper';
import { useMainStore } from "@/store"; import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
import baseMixin from '@/mixins/base-mixin';
import { getRandomString, getRandomInt } from '@/helpers/data-generation';
import { endorsementOptions } from '@/constants/endorsement-options';
import { createTestingPinia } from '@pinia/testing';
import { issPageValues } from "@/router/router-constants/issPage-values";
import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
// Mock fetchCmsContentForPage // Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({ jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn(), fetchCmsContentForPage: jest.fn(),
doesCopyContainRouterLink: jest.fn(), doesCopyContainRouterLink: jest.fn(),
splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => "test"), splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => 'test'),
getRouterLinkRouteFromCopy: jest.fn(), getRouterLinkRouteFromCopy: jest.fn(),
getRouterLinkDisplayTextFromCopy: jest.fn(), getRouterLinkDisplayTextFromCopy: jest.fn(),
splitCMSCopyOnParagraphTag: jest.fn(), splitCMSCopyOnParagraphTag: jest.fn(),
})); }));
// Mock our module for promises. // Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({ jest.mock('@/helpers/layout-helper.js', () => ({
settleAllPromises: jest.fn(), settleAllPromises: jest.fn(),
})); }));
describe("policy-vehicles.vue", () => { describe('policy-vehicles.vue', () => {
test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => { test('Should navigate to CLICKED_BACK if backButtonAction is run', async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -32,126 +38,376 @@ describe("policy-vehicles.vue", () => {
//Assert //Assert
expect(wrapper.vm.$router.navigate).toBeCalled(); expect(wrapper.vm.$router.navigate).toBeCalled();
}); });
test("Selected vehicle VIN do match vehicles listed in our system (CarIDs) found then navigate forward to vehicle-damage page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
// Act describe('forwardButtonAction', () => {
await wrapper.setData({
selectedVehicleVin: "5NMS3CADXLH233004" test('Selected VIN matches vehicle listed in system => update vehicle and navigate forward with CLICKED_FORWARD_LISTED_VEHICLE scenario.', async () => {
//Arrange
const { wrapper } = setupMocks({});
const vin = getRandomString(17,17);
await wrapper.setData({
selectedVehicleVin: vin,
policyVehicles: [
{ vin: vin },
],
bailout: false
});
const year = getRandomInt(1998, 2023);
const lookupVehicleResponse = {
data: {
year: year,
}
};
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.resolve(lookupVehicleResponse));
const expectedInput = {
year: year,
vin: vin,
noCompensation: true,
deductible: 0,
repairWaived: false
}
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.bailout).toBeFalsy();
expect(store.updateVehicle).toHaveBeenCalledWith(expectedInput);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
undefined,
{},
{}
);
}); });
await wrapper.vm.forwardButtonAction();
// Assert test('Error in lookupVehicleByVin call => bailout true and navigate forward with CLICKED_FORWARD_WITH_BAILOUT scenario.', async () => {
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( //Arrange
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, const { wrapper } = setupMocks({});
undefined,
{},
{}
);
});
test("Selected vehicle VIN do not match vehicles listed in our system (CarIDs) found then navigate forward to bailout page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
// Act const vin = getRandomString(17,17);
await wrapper.setData({ await wrapper.setData({
selectedVehicleVin: "5NMS3CADXLH233004", selectedVehicleVin: vin,
bailout: true bailout: false
});
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.reject());
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.bailout).toBeTruthy();
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
undefined,
{},
{}
);
}); });
await wrapper.vm.forwardButtonAction();
// Assert test('vehicle not listed => navigate forward with CLICKED_FORWARD_NON_LISTED_VEHICLE scenario.', async () => {
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( // Arrange
navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, const { wrapper } = setupMocks({});
undefined,
{},
{}
);
});
test("if user select vehicle not listed option then navigate forward to vehicle-selection page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
// Act await wrapper.setData({
await wrapper.setData({ selectedVehicleVin: vehicleSelectionOptions.VEHICLE_NOT_LISTED,
selectedVehicleVin: "Vehicle not listed", });
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
undefined,
{},
{}
);
}); });
await wrapper.vm.forwardButtonAction(); })
// Assert describe('noCompensationForSelectedVehicle computed property', () => {
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( it('No vehicle match => returns true', async () => {
navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, // Arrange
undefined, const selectedVin = getRandomString(17,17);
{}, const otherVin = getRandomString(17,17);
{} const testValues = {
); selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeTruthy();
});
it('Coverages list empty => true', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: []
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeTruthy();
});
it('Coverages list non-empty => false', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: [
{
deductible: 0
}
]
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeFalsy();
});
})
describe('deductibleForSelectedVehicle computed property', () => {
it('No vehicle match => undefined returned', () => {
// Arrange
const selectedVin = getRandomString(17,17);
const otherVin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(undefined);
});
it('Vehicle match with empty coverages list => 0 returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: []
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(0);
});
it('Coverages list non empty => deductible from first coverage returned', () => {
// Arrange
const vin = getRandomString(17,17);
const firstDeductible = getRandomInt(1,1000);
const secondDeductible = getRandomInt(1,1000);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: [
{
deductible: firstDeductible
},
{
deductible: secondDeductible
}
]
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(firstDeductible);
});
}); });
test("first vehicle is auto-selected if only one vehicle on policy", async () => {
//Arrange describe('repairWaivedForSelectedVehicle computed property', () => {
const { wrapper } = setupMocks({});
it('No vehicle match => false returned', () => {
// Arrange
const selectedVin = getRandomString(17,17);
const otherVin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list empty => false returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: []
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list non-empty, not containing repair waived => false returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: [ endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD ]
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list contains repair waived => true returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: [
endorsementOptions.EDUCATOR,
endorsementOptions.REPAIR_WAIVED,
endorsementOptions.PARKING_GUARD
]
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(true);
});
});
test('first vehicle is auto-selected if only one vehicle on policy', async () => {
// Arrange
const vin = getRandomString(17,17);
useMainStore().applicationUser = {
pageData: {
[issPageValues.POLICY_VEHICLES]: [ { vin: vin } ],
}
};
const { wrapper } = setupMocks();
// Act // Act
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
// Assert // Assert
expect(wrapper.vm.selectedVehicleVin).toBe("5NMS3CADXLH233004"); expect(wrapper.vm.selectedVehicleVin).toBe(vin);
}); });
}); });
function setupMocks({ const mockMixin = {
route = null, methods: {
lookupVehicleByVinResponse getCmsContent: jest.fn(),
}) },
computed: {
dynamicStrings() {
return { ROUTER_LINK: 'routerLink:' };
},
},
};
function setupMocks()
{ {
useMainStore().applicationUser = {
pageData: {
"policy-vehicles":
[
{
vehicleMake: "Hyundai",
vehicleModel: "Santa Fe",
vehicleStyle: "4 door utility",
vehicleYear: 2020,
vin: "5NMS3CADXLH233004",
},
],
}
};
useMainStore().lookupVehicleByVin = jest.fn().mockImplementation(() => {
return Promise.resolve({
data: lookupVehicleByVinResponse
? lookupVehicleByVinResponse : {
vehicle: {
carId: "CARID"
},
},
})
});
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
route: route ? route : undefined,
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
}, },
mainStore: { mixins: [mockMixin],
order: { global: {
vehicle: { mocks: {
carId: "CR00069309", $route: {
category: "SUV", params: {
imageUrl: id: 1
"https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg", }
imageVifColor: "white",
imageVifNumber: "13769",
make: "Hyundai",
model: "Santa Fe",
style: "4 door utility",
year: 2020,
}, },
vin: "5NMS3CADXLH233004", $router: {
navigate: jest.fn()
}
}, },
}, plugins: [createTestingPinia()]
}, }
); });
const apiResponses = { const apiResponses = {
cmsContent: {}, cmsContent: {},
@ -160,23 +416,10 @@ function setupMocks({
settleAllPromises.mockImplementation(() => apiResponses); settleAllPromises.mockImplementation(() => apiResponses);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const wrapper = shallowMount(policyVehicles, mountOptions);
//Mock props wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
const mockMixin = {
methods: {
getCmsContent: jest.fn(),
},
computed: {
dynamicStrings() {
return { ROUTER_LINK: "routerLink:" };
},
},
};
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(policyVehicles,mountOptions);
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.setCmsContent = jest.fn(); wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn(); wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
return { wrapper }; return { wrapper };

View file

@ -41,7 +41,8 @@ import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { issPageValues } from "@/router/router-constants/issPage-values"; import { issPageValues } from "@/router/router-constants/issPage-values";
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import {vehicleSelectionOptions} from "@/constants/vehicle-selection-options"; import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
import { endorsementOptions } from "@/constants/endorsement-options";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
@ -49,14 +50,15 @@ export default {
name: "policy-vehicles", name: "policy-vehicles",
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
data() { data() {
return { const policyVehicles = useMainStore().pageData(issPageValues.POLICY_VEHICLES);
selectedVehicleVin: "", return {
displayGeneric: true, policyVehicles: policyVehicles,
bailout: false selectedVehicleVin: (policyVehicles?.length ?? 0) == 1
} ? policyVehicles[0].vin
}, : "",
mounted() { displayGeneric: true,
this.autoSelectIfOneVehicle(); bailout: false
}
}, },
async beforeRouteEnter(to, from, next) async beforeRouteEnter(to, from, next)
{ {
@ -67,28 +69,36 @@ export default {
{ {
resultKey: "cmsContent", resultKey: "cmsContent",
promise: cmsContentPromise, promise: cmsContentPromise,
},]; },
//use resultMap to populate layout content. ];
let resultMap = await settleAllPromises(promiseResultMap); //use resultMap to populate layout content.
next((vm) => { let resultMap = await settleAllPromises(promiseResultMap);
vm.setCmsContent(resultMap.cmsContent); next((vm) => {
}); vm.setCmsContent(resultMap.cmsContent);
}, });
},
methods: methods:
{ {
backButtonAction() { backButtonAction() {
this.mainStore.issConfig.disabledFields.policyNumber = true; useMainStore().issConfig.disabledFields.policyNumber = true;
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
}, },
async forwardButtonAction() { async forwardButtonAction() {
if(this.selectedVehicleVin != vehicleSelectionOptions.VEHICLE_NOT_LISTED){ if (this.selectedVehicleVin != vehicleSelectionOptions.VEHICLE_NOT_LISTED){
const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin); const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin);
if (vehicleLookupResponse.error) { if (vehicleLookupResponse.error) {
this.bailout = true; this.bailout = true;
return this.navigateForward(); return this.navigateForward();
} }
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.selectedVehicleVin });
this.mainStore.updateVehicle(this.vehicleFromLookup); this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
vin: this.selectedVehicleVin,
noCompensation: this.noCompensationForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle
});
useMainStore().updateVehicle(this.vehicleFromLookup);
} }
return this.navigateForward(); return this.navigateForward();
}, },
@ -116,28 +126,21 @@ export default {
); );
}, },
async lookupVehicleByVin(vin) { async lookupVehicleByVin(vin) {
try { try {
return await this.mainStore.lookupVehicleByVin(vin); return await useMainStore().lookupVehicleByVin(vin);
} }
catch (responseError) { catch (responseError) {
return { return {
error: { error: true,
status: responseError.status, };
}, }
};
}
}, },
autoSelectIfOneVehicle() {
if (this.VehiclesFromApi.length == 1) {
this.selectedVehicleVin = this.VehiclesFromApi[0].vin;
}
}
}, },
computed:{ computed:{
VehiclesForQuestions() { VehiclesForQuestions() {
// Map API result data, to address-vehicles data structure // Map API result data, to address-vehicles data structure
const vehicles = this.VehiclesFromApi; const vehicles = this.policyVehicles;
const mappedData = vehicles.map((v) => { const mappedData = vehicles?.map((v) => {
const maskSymbol = "X"; const maskSymbol = "X";
const vinStart = maskSymbol.repeat(v.vin.length - 6); const vinStart = maskSymbol.repeat(v.vin.length - 6);
const vinEnd = v.vin.substring(v.vin.length - 6); const vinEnd = v.vin.substring(v.vin.length - 6);
@ -148,9 +151,27 @@ export default {
Name: v.vin, Name: v.vin,
SubText: "VIN " + vinStart + vinEnd, SubText: "VIN " + vinStart + vinEnd,
}; };
}); }) ?? [];
return mappedData; return mappedData;
}, },
noCompensationForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; });
return (vehicle?.coverages?.length ?? 0) == 0;
},
deductibleForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle?.vin == this.selectedVehicleVin; });
if (!vehicle){
return undefined;
}
return vehicle.coverages?.length ?? false
? vehicle?.coverages[0].deductible
: 0;
},
repairWaivedForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; });
return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false;
},
VehiclesFromApi() { VehiclesFromApi() {
return useMainStore().pageData(issPageValues.POLICY_VEHICLES); return useMainStore().pageData(issPageValues.POLICY_VEHICLES);
}, },
@ -161,7 +182,7 @@ export default {
}, },
watch: { watch: {
async selectedVehicleVin(value) { async selectedVehicleVin(value) {
if (value === "Vehicle not listed") { if (value === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
// clear previously selected vehicle and image // clear previously selected vehicle and image
this.mainStore.resetVehicleState(); this.mainStore.resetVehicleState();
this.displayGeneric = true; this.displayGeneric = true;
@ -172,9 +193,10 @@ export default {
const vehicle = await this.lookupVehicleByVin(value); const vehicle = await this.lookupVehicleByVin(value);
// handle error in case vehicle info doesn't come back for selected VIN // handle error in case vehicle info doesn't come back for selected VIN
if (vehicle.error) { if (vehicle?.error ?? true) {
this.mainStore.resetVehicleState(); this.mainStore.resetVehicleState();
this.displayGeneric = true; this.displayGeneric = true;
return;
} }
// save selected vehicle to the store // save selected vehicle to the store
@ -189,13 +211,7 @@ export default {
) )
// if there is more than 1 style for the selected vehicle, display generic/blurred image // if there is more than 1 style for the selected vehicle, display generic/blurred image
if (styleOptions?.data?.length > 1) { this.displayGeneric = styleOptions?.data?.length > 1;
this.displayGeneric = true;
}
else {
// display clear image of vehicle
this.displayGeneric = false;
}
} }
} }
}, },

View file

@ -316,170 +316,170 @@ export default {
this.selectedGlassToReplace(), this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount); this.selectedWindshieldOptions.selectedWindshieldChipCount);
return this.navigateForward(); return this.navigateForward();
}, },
navigateForward() { navigateForward() {
if (this.mainStore.damage.isRepair) { if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
}
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route this.$route
); );
} }
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
}
},
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
}
);
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
});
}
return selectedGlassToReplace;
},
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
});
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
});
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
});
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedDriverSide) => {
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
});
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) => {
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
});
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => {
return (
selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase()
);
}
))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
} }
}, },
components: { selectedGlassToReplace() {
siteHeader, const selectedGlassToReplace = [];
siteFooter, if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
vehicleBanner, this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
siteSubHeader, (wsItem) => {
sideDoorOptions, selectedGlassToReplace.push({
damageLocationQuestion, glassLocation: damageLocationsSelected.WINDSHIELD,
windshieldOptions, glassName: wsItem,
replaceOptionsQuestion, });
Form, }
alert, );
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
});
}
return selectedGlassToReplace;
}, },
}; },
</script> computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
});
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
});
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
});
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedDriverSide) => {
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
});
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) => {
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
});
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => {
return (
selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase()
);
}
))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
Form,
alert,
},
};
</script>

View file

@ -1,12 +1,11 @@
/* eslint-env jest */ /* eslint-env jest */
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios'; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
import { issPageValues } from '@/router/router-constants/issPage-values';
import { queryStrings } from '@/constants/query-strings'; import { queryStrings } from '@/constants/query-strings';
import { GaActions } from "@/constants/analytics"; import { GaActions } from "@/constants/analytics";
import VehicleLookup from './vehicle-lookup.vue'; import VehicleLookup from './vehicle-lookup.vue';
import {vinLookupMethodSelections} from '@/constants/vin-lookup-methods'; import {vinLookupMethodSelections} from '@/constants/vin-lookup-methods';
import { useMainStore } from '../../store'; import { useMainStore } from '@/store';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import { mapStores } from "pinia"; import { mapStores } from "pinia";

View file

@ -6,6 +6,7 @@ import { experimentTriggers } from '@/constants/experiments';
import { applicationConfig } from '@/constants/application-config'; import { applicationConfig } from '@/constants/application-config';
import { issPageValues } from '@/router/router-constants/issPage-values'; import { issPageValues } from '@/router/router-constants/issPage-values';
import { damageLocationsSelected } from '@/constants/damage-locations-selected'; import { damageLocationsSelected } from '@/constants/damage-locations-selected';
import { coverageStatuses } from '@/constants/coverage-statuses';
const storeId = 'main'; const storeId = 'main';
@ -48,7 +49,12 @@ const getDefaultState = () => {
damageCause: null, damageCause: null,
damageState: null, damageState: null,
damageCity: null, damageCity: null,
isDamageGlassOnly: null isDamageGlassOnly: null,
noCompensation: null,
deductible: {
repair: null, // numerical value; how much customer owes on deductible in repair case
replace: null // numerical value; how much customer owes on deductible in replace case,
}
}, },
customer: { customer: {
address: { address: {
@ -79,7 +85,8 @@ const getDefaultState = () => {
payment: { payment: {
isInsurance: true, isInsurance: true,
insuranceCoverage: { insuranceCoverage: {
isVerified: false isVerified: false,
coverageStatus: coverageStatuses.PENDING
} }
}, },
referralNumber: null, referralNumber: null,
@ -125,7 +132,10 @@ export const useMainStore = defineStore({
vehicle: (state) => state.order.vehicle, vehicle: (state) => state.order.vehicle,
damage: (state) => state.order.damage, damage: (state) => state.order.damage,
lineItems: (state) => state.order.lineItems, lineItems: (state) => state.order.lineItems,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly, hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly,
isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired,
eventBusItem: (state) => ( eventCategory, eventSubCategory) => { eventBusItem: (state) => ( eventCategory, eventSubCategory) => {
const matchedEvent = state.applicationUser.eventBus.find( const matchedEvent = state.applicationUser.eventBus.find(
@ -327,7 +337,7 @@ export const useMainStore = defineStore({
} }
}, },
getCoveragePolicyInfo({accountNumber, policyNumber, dateOfLoss, zipCode}){ getCoveragePolicyInfo({accountNumber, policyNumber, dateOfLoss, zipCode}){
//todo: replace place holder correlationId with the real thing //TODO: replace place holder correlationId with the real thing
const placeHolderCorrelationId = "00000000-0000-0000-0000-000000000000"; const placeHolderCorrelationId = "00000000-0000-0000-0000-000000000000";
try{ try{
const response = globalMethods.callHttpClient({ const response = globalMethods.callHttpClient({
@ -350,6 +360,69 @@ export const useMainStore = defineStore({
}; };
} }
}, },
registerClaim() {
// TODO: replace place holder correlationId with the real thing
const placeHolderCorrelationId = "00000000-0000-0000-0000-000000000000";
globalMethods.callHttpClient({
method: endpoints.RegisterClaim.method,
endpoint: endpoints.RegisterClaim.url,
payload:
{
correlationId: placeHolderCorrelationId,
accountNumber: this.issConfig.accountNumber?.toString() ?? "",
insured: {
firstName: this.order.customer.firstName,
lastName: this.order.customer.lastName,
address: {
addressLine1: this.order.customer.address.streetAddress,
addressLine2: this.order.customer.address.streetAddress2,
city: this.order.customer.address.city,
state: this.order.customer.address.state,
zipCode: this.order.customer.address.zipCode,
country: "US" // TODO set from store
},
homePhone: {
number: this.order.customer.phoneNumber
}
},
caller: {
homePhone: {}
},
policyInfo: {
policyNumber: this.order.policy.policyNumber,
safelitePolicy: {
policies: []
}
},
lossInfo: {
dateOfLoss: this.order.policy.dateOfLoss,
location: {
city: this.order.policy.damageCity,
state: this.order.policy.damageState,
country: "US" // TODO set from store
},
vehicle: {
year: this.order.vehicle.year?.toString() ?? "",
make: this.order.vehicle.make,
model: this.order.vehicle.model,
vin: this.order.vehicle.vin
},
},
damageDescription: this.order.policy.damageCause
}
}).then((response) => {
const registerClaimFailed = response.data.isError;
this.order.payment.insuranceCoverage.isVerified = !registerClaimFailed;
this.order.payment.insuranceCoverage.coverageStatus = registerClaimFailed
? coverageStatuses.PENDING
: this.policy.noCompensation
? coverageStatuses.NO_COMP
: coverageStatuses.VERIFIED;
},(error) => {
this.order.payment.insuranceCoverage.isVerified = false;
this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING;
});
},
async lookupVinByPlate(licensePlate, licenseState) { async lookupVinByPlate(licensePlate, licenseState) {
try { try {
const response = await globalMethods.callHttpClient({ const response = await globalMethods.callHttpClient({
@ -483,7 +556,7 @@ export const useMainStore = defineStore({
console.error(error); console.error(error);
return []; return [];
}); });
}, },
async getRainDefense() { async getRainDefense() {
return globalMethods return globalMethods
@ -596,15 +669,15 @@ export const useMainStore = defineStore({
setVehicle() { setVehicle() {
return globalMethods return globalMethods
.callHttpClient({ .callHttpClient({
methods: endpoints.GetVehicle.method, methods: endpoints.GetVehicle.method,
endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`, endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`,
payload: {} payload: {}
}) })
.then((response) => { .then((response) => {
this.updateVehicle(response.data); this.updateVehicle(response.data);
return response; return response;
}); });
}, },
saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) {
@ -681,8 +754,7 @@ export const useMainStore = defineStore({
updateVehicle(vehicle) { updateVehicle(vehicle) {
// Assuming that the method caller pass all the properties. // Assuming that the method caller pass all the properties.
// otherwise need to check for undefined for every property. // otherwise need to check for undefined for every property.
this.vehicle.carId = vehicle.carId;
this.order.vehicle.carId = vehicle.carId;
this.order.vehicle.category = vehicle.category; this.order.vehicle.category = vehicle.category;
this.order.vehicle.year = vehicle.year; this.order.vehicle.year = vehicle.year;
this.order.vehicle.make = vehicle.make; this.order.vehicle.make = vehicle.make;
@ -693,6 +765,11 @@ export const useMainStore = defineStore({
this.order.vehicle.imageVifNumber = vehicle.imageVifNumber; this.order.vehicle.imageVifNumber = vehicle.imageVifNumber;
this.order.vehicle.imageColor = vehicle.imageVifColor; this.order.vehicle.imageColor = vehicle.imageVifColor;
// These could be undefined
this.order.policy.noCompensation = vehicle.noCoverage;
this.order.policy.deductible.replace = vehicle.deductible;
this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible;
this.resetSupportingItemsState(); this.resetSupportingItemsState();
this.resetVapsState(); this.resetVapsState();
}, },

View file

@ -1,19 +1,21 @@
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { createApp } from 'vue'; import { createApp } from 'vue';
import { createPinia } from "pinia"; import { setActivePinia, createPinia } from "pinia";
import globalMethods from "@/global-methods"; import globalMethods from "@/global-methods";
import App from '@/App.vue'; import App from '@/App.vue';
import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation';
import { coverageStatuses } from "@/constants/coverage-statuses.js";
describe("Store", () => { describe("Store", () => {
let store; let store;
const vueApp = createApp(App); const vueApp = createApp(App);
const pinia = createPinia();
vueApp.use(pinia);
beforeEach(() => { beforeEach(() => {
const pinia = createPinia();
setActivePinia(pinia);
vueApp.use(pinia);
store = useMainStore(); store = useMainStore();
store.applicationUser.eventBus = []; store.applicationUser.eventBus = [];
jest.resetAllMocks(); jest.resetAllMocks();
@ -27,31 +29,47 @@ describe("Store", () => {
}); });
it("Should add events to the bus", () => { 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 = { let event = {
category: "TestCategory", category: category,
subCategory: "TestSubCategory", subCategory: subCategory,
eventValue: { eventValue: {
isDismissible: true, isDismissible: isDismissible,
messageCopy: "You can get a quote by starting on this page.", messageCopy: copy,
messageHeadline: "We're sorry, something went wrong.", messageHeadline: headline,
type: "testType", type: type,
}, },
}; };
// Act
store.addEventToBus(event); store.addEventToBus(event);
// Assert
expect(store.applicationUser.eventBus[0]).toEqual(event); expect(store.applicationUser.eventBus[0]).toEqual(event);
}); });
it("Should remove events from the bus", () => { 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 = { let event = {
category: "TestCategory", category: category,
subCategory: "TestSubCategory", subCategory: subCategory,
eventValue: { eventValue: {
isDismissible: true, isDismissible: isDismissible,
messageCopy: "You can get a quote by starting on this page.", messageCopy: copy,
messageHeadline: "We're sorry, something went wrong.", messageHeadline: headline,
type: "testType", type: type,
}, },
}; };
@ -59,164 +77,350 @@ describe("Store", () => {
expect(store.applicationUser.eventBus.length).toBe(1); expect(store.applicationUser.eventBus.length).toBe(1);
// Act
store.removeEventFromBus({ category: event.category, subCategory: event.subCategory }) store.removeEventFromBus({ category: event.category, subCategory: event.subCategory })
// Assert
expect(store.applicationUser.eventBus.length).toBe(0); expect(store.applicationUser.eventBus.length).toBe(0);
}); });
it("Should return correct event using the getter function eventBusItem", () => { 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 = { let event = {
category: "TestCategory", category: category,
subCategory: "TestSubCategory", subCategory: subCategory,
eventValue: { eventValue: {
isDismissible: true, isDismissible: isDismissible,
messageCopy: "You can get a quote by starting on this page.", messageCopy: copy,
messageHeadline: "We're sorry, something went wrong.", messageHeadline: headline,
type: "testType", type: type,
}, },
}; };
store.addEventToBus(event); store.addEventToBus(event);
// Act
const actual = store.eventBusItem(event.category, event.subCategory) const actual = store.eventBusItem(event.category, event.subCategory)
// Assert
expect(actual).toEqual(event.eventValue); expect(actual).toEqual(event.eventValue);
}); });
it("UpdateVehicle should merge vehicle with response object", () => { it("UpdateVehicle should merge vehicle with response object", () => {
store.order.vehicle = { // Arrange
year: 2020, const carId = getRandomString(10,14);
make: "Honda", const category = getRandomString(3,7);
model: "Civic", const year = getRandomInt(1960, 2023);
style: "4 door sedan", const make = getRandomString(4,10);
carId: null, const model = getRandomString(4,10);
category: null, const style = getRandomString(4,15);
vin: null, const imageUrl = getRandomString(50,100);
imageUrl: null, const imageVifNumber = getRandomInt(10000,99999).toString();
imageVifNumber: null, const imageColor = getRandomString(4,10);
imageColor: null, const providedVehicle = {
carId: carId,
category: category,
year: year,
make: make,
model: model,
style: style,
imageUrl: imageUrl,
imageVifNumber: imageVifNumber,
imageVifColor: imageColor
}; };
const response = {data: { const expectedVehicle = {
"carId": "CR00069299", carId: carId,
"category": "CAR", category: category,
"year": 2020, year: year,
"make": "Honda", make: make,
"model": "Civic", model: model,
"style": "4 door sedan", style: style,
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg", imageUrl: imageUrl,
"imageVifNumber": "13996", imageVifNumber: imageVifNumber,
"imageVifColor": "white" 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 noCompensation = getRandomBoolean();
const deductible = getRandomInt(1,500);
const vehicle = {
noCoverage: noCompensation,
deductible: deductible,
repairWaived: true
};
const expectedPolicy = {
noCompensation: noCompensation,
deductible: {
replace: deductible,
repair: 0
} }
}; };
store.updateVehicle(response.data); // Act
store.updateVehicle(vehicle);
expect(store.order.vehicle.imageUrl).toEqual(response.data.imageUrl); // Assert
expect(store.order.vehicle.imageVifNumber).toEqual(response.data.imageVifNumber); expect(store.order.policy).toMatchObject(expectedPolicy);
expect(store.order.vehicle.style).toEqual(response.data.style);
}); });
it("setVehicle should call globalMethods.callHttpClient", () => { it("UpdateVehicle should set policy values appropriately with repair not waived", () => {
store.order.vehicle = jest.fn(); // Arrange
const noCompensation = getRandomBoolean();
const deductible = getRandomInt(1,500);
const vehicle = {
noCoverage: noCompensation,
deductible: deductible,
repairWaived: false
};
const response = {data: { const expectedPolicy = {
"carId": "CR00069299", noCompensation: noCompensation,
"category": "CAR", deductible: {
"year": 2020, replace: deductible,
"make": "Honda", repair: deductible
"model": "Civic", }
"style": "4 door sedan", };
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg",
"imageVifNumber": "13996", // Act
"imageVifColor": "white" 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)); 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 // Act
store.saveVehicleDamage( false, const returned = store.setVehicle();
[{ glassName: "Rear", glassLocation: "quarter" }],
0);
// Assert // Assert
expect(store.order.damage.glassToReplace).toEqual([{ glassName: "Rear", glassLocation: "quarter" }]); expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.order.damage.isRepair).toEqual(false); expect(returned).resolves.toMatchObject(response);
expect(store.order.damage.numberOfChips).toEqual(null); });
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);
// 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", () => { it("should return registration data if available", () => {
//Arrange //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 = { const expected = {
addressQuestions: { addressQuestions: {
streetAddress: "test", streetAddress: streetAddress,
city: "city", city: city,
state: "state", state: state,
zipCode: "zip", zipCode: zipCode,
}, },
firstName: "1stName", firstName: firstName,
lastName: "Surname", lastName: lastName,
} }
store.order.vehicle.registration = { store.order.vehicle.registration = {
licensePlate: null, licensePlate: null,
address: "test", address: streetAddress,
city: "city", city: city,
state: "state", state: state,
zipCode: "zip", zipCode: zipCode,
firstName: "1stName", firstName: firstName,
lastName: "Surname", lastName: lastName,
}; };
//Act //Act
const actual = store.customerData; const actual = store.customerData;
//Assert
//Assert
expect(actual).toEqual(expected); expect(actual).toEqual(expected);
}); });
it("should return customer data if registration data unavailable", () => { it("should return customer data if registration data unavailable", () => {
//Arrange //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 = { const expected = {
addressQuestions: { addressQuestions: {
streetAddress: "test", streetAddress: address,
city: "city", city: city,
state: "state", state: state,
zipCode: "zip", zipCode: zipCode,
}, },
firstName: "1stName", firstName: firstName,
lastName: "Surname", lastName: lastName,
} }
store.order.vehicle.registration.address = null; store.order.vehicle.registration.address = null;
store.order.customer = { store.order.customer = {
licensePlate: null, address: {
address: "test", streetAddress: address,
city: "city", city: city,
state: "state", state: state,
zipCode: "zip", zipCode: zipCode
firstName: "1stName", },
lastName: "Surname", firstName: firstName,
lastName: lastName
}; };
//Act //Act
const actual = store.customerData; const actual = store.customerData;
//Assert
expect(actual).toEqual(expected); //Assert
expect(actual).toMatchObject(expected);
}); });
describe("registerClaim method", () => {
it("successful response with no coverage => isVerified true and coverage status no comp", async () => {
// Arrange
const response = {
data: {
claimantId: null,
claimNumber: getRandomString(9, 9),
correlationId: getRandomGuid(),
isSuccess: true,
isError: false,
successMessage: getRandomString(9, 9),
deductible: 0
}
};
store.policy.noCompensation = true;
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(true);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.NO_COMP);
});
it("successful response with coverage => isVerified true and coverage status verified", async () => {
// Arrange
const response = {
data: {
claimantId: null,
claimNumber: getRandomString(9, 9),
correlationId: getRandomGuid(),
isSuccess: true,
isError: false,
successMessage: getRandomString(9, 9),
deductible: 0
}
};
store.policy.noCompensation = false;
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(true);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.VERIFIED);
})
it("Call to client returns exception, resulting in object with error property being returned", async () => {
// Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject());
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(false);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.PENDING);
});
})
}); });