Merge pull request #480 from Safelite/feature/SSR-735

conditionally show endorsement questions
This commit is contained in:
katiekroell 2023-10-13 15:24:13 -04:00 committed by GitHub
commit 3ecd2222e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 276 additions and 28 deletions

View file

@ -7,6 +7,24 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
import navigationScenarios from '@/router/router-constants/navigation-scenarios'; import navigationScenarios from '@/router/router-constants/navigation-scenarios';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { getRandomString } from '@/helpers/data-generation';
function getMountedComponent(mainInitialState = {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
}
});
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const wrapper = shallowMount(policyEndorsements, mountOptions);
return { wrapper };
}
describe('policyEndorsements.vue', () => { describe('policyEndorsements.vue', () => {
describe('Rendering', () => { describe('Rendering', () => {
@ -30,26 +48,70 @@ describe('policyEndorsements.vue', () => {
// Assert // Assert
expect(siteSubHeader.exists()).toBe(true); expect(siteSubHeader.exists()).toBe(true);
}); });
test('Should render schoolProperty buttonQuestion component', () => { test('Should render schoolProperty buttonQuestion component if policy vehicle has Educator endorsement', () => {
// Arrange // Arrange
const wrapper = shallowMount(policyEndorsements, getMountOptions()); const mainInitialState = {
order: {
// Act policy: {
endorsements: ['Educator']
}
}
};
const { wrapper } = getMountedComponent(mainInitialState);
const buttonQuestion = wrapper.findComponent({ ref: 'schoolPropertyQuestion' }); const buttonQuestion = wrapper.findComponent({ ref: 'schoolPropertyQuestion' });
// Assert // Assert
expect(wrapper.vm.educatorEndorsement).toBeTruthy();
expect(buttonQuestion.exists()).toBe(true); expect(buttonQuestion.exists()).toBe(true);
}); });
test('Should render parkingLot buttonQuestion component', () => { test('Should not render schoolProperty buttonQuestion component if policy vehicle does not have Educator endorsement', () => {
// Arrange // Arrange
const wrapper = shallowMount(policyEndorsements, getMountOptions()); const mainInitialState = {
order: {
policy: {
endorsements: [getRandomString(20, 30)]
}
}
};
const { wrapper } = getMountedComponent(mainInitialState);
const buttonQuestion = wrapper.findComponent({ ref: 'schoolPropertyQuestion' });
// Act // Assert
expect(wrapper.vm.educatorEndorsement).toBeFalsy();
expect(buttonQuestion.exists()).toBe(false);
});
test('Should render parkingLot buttonQuestion component if policy vehicle has Parking Guard endorsement', () => {
// Arrange
const mainInitialState = {
order: {
policy: {
endorsements: ['Parking Guard']
}
}
};
const { wrapper } = getMountedComponent(mainInitialState);
const buttonQuestion = wrapper.findComponent({ ref: 'parkingLotQuestion' }); const buttonQuestion = wrapper.findComponent({ ref: 'parkingLotQuestion' });
// Assert // Assert
expect(wrapper.vm.parkingGuardEndorsement).toBeTruthy();
expect(buttonQuestion.exists()).toBe(true); expect(buttonQuestion.exists()).toBe(true);
}); });
test('Should not render parkingLot buttonQuestion component if policy vehicle does not have Parking Guard endorsement', () => {
// Arrange
const mainInitialState = {
order: {
policy: {
endorsements: [getRandomString(20, 30)]
}
}
};
const { wrapper } = getMountedComponent(mainInitialState);
const buttonQuestion = wrapper.findComponent({ ref: 'parkingLotQuestion' });
// Assert
expect(wrapper.vm.parkingGuardEndorsement).toBeFalsy();
expect(buttonQuestion.exists()).toBe(false);
});
test('Should render site footer', () => { test('Should render site footer', () => {
// Arrange // Arrange
const wrapper = shallowMount(policyEndorsements, getMountOptions()); const wrapper = shallowMount(policyEndorsements, getMountOptions());

View file

@ -16,6 +16,7 @@
cmsWidgetName="SiteSubHeaderWidget" cmsWidgetName="SiteSubHeaderWidget"
class="mt-5" /> class="mt-5" />
<buttonQuestion <buttonQuestion
v-if="educatorEndorsement"
ref="schoolPropertyQuestion" ref="schoolPropertyQuestion"
v-model="schoolPropertyAnswer" v-model="schoolPropertyAnswer"
class="radioQuestion windshield-chip-count-question mb-4" class="radioQuestion windshield-chip-count-question mb-4"
@ -29,6 +30,7 @@
:validationRules="rules.selectionRequired"> :validationRules="rules.selectionRequired">
</buttonQuestion> </buttonQuestion>
<buttonQuestion <buttonQuestion
v-if="parkingGuardEndorsement"
ref="parkingLotQuestion" ref="parkingLotQuestion"
v-model="parkingLotAnswer" v-model="parkingLotAnswer"
class="radioQuestion windshield-chip-count-question" class="radioQuestion windshield-chip-count-question"
@ -43,7 +45,6 @@
</buttonQuestion> </buttonQuestion>
<siteFooter <siteFooter
ref="siteFooter" ref="siteFooter"
class="pt-5"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@forwardClicked="forwardButtonAction" @forwardClicked="forwardButtonAction"
@ -117,6 +118,12 @@ export default {
}, },
parkingLotAnswersFromCms() { parkingLotAnswersFromCms() {
return this.getCmsContent('ParkingLotQuestion', 'Answers'); return this.getCmsContent('ParkingLotQuestion', 'Answers');
},
educatorEndorsement() {
return useMainStore().order.policy.endorsements?.includes('Educator') ?? false;
},
parkingGuardEndorsement() {
return useMainStore().order.policy.endorsements?.includes('Parking Guard') ?? false;
} }
}, },
methods: methods:
@ -126,18 +133,24 @@ export default {
}, },
async forwardButtonAction() { async forwardButtonAction() {
// TO DO: remove hard coding and update data format once service returns endorsement questions // TO DO: remove hard coding and update data format once service returns endorsement questions
this.questionAnswersArray.push( if (this.educatorEndorsement) {
this.questionAnswersArray.push(
{ {
questionNum: 1, questionNum: 1,
endorsement: 'Educator',
questionText: this.schoolPropertyQuestionText, questionText: this.schoolPropertyQuestionText,
selectedAnswer: this.schoolPropertyAnswer selectedAnswer: this.schoolPropertyAnswer
}, });
};
if (this.parkingGuardEndorsement) {
this.questionAnswersArray.push(
{ {
questionNum: 2, questionNum: 2,
endorsement: 'Parking Guard',
questionText: this.parkingLotQuestionText, questionText: this.parkingLotQuestionText,
selectedAnswer: this.parkingLotAnswer selectedAnswer: this.parkingLotAnswer
} });
); };
// save answers to store as order.policy.endorsementQuestionAnswers // save answers to store as order.policy.endorsementQuestionAnswers
useMainStore().saveEndorsementQuestionAnswers(this.questionAnswersArray); useMainStore().saveEndorsementQuestionAnswers(this.questionAnswersArray);

View file

@ -117,7 +117,8 @@ describe('policy-vehicles.vue', () => {
vin, vin,
noCoverage: true, noCoverage: true,
deductible: 0, deductible: 0,
repairWaived: false repairWaived: false,
endorsements: []
}; };
// Act // Act
@ -135,6 +136,55 @@ describe('policy-vehicles.vue', () => {
} }
); );
test(
// eslint-disable-next-line max-len
'Selected VIN matches vehicle listed in system and policy vehicle has endorsements => update vehicle and navigate forward with CLICKED_FORWARD_WITH_ENDORSEMENTS scenario.',
async () => {
// Arrange
const { wrapper } = setupMocks({});
const vin = getRandomString(17, 17);
const endorsements = [getRandomString(10, 20)];
await wrapper.setData({
selectedVehicleVin: vin,
policyVehicles: [
{
vin,
endorsements
}
]
});
const year = getRandomInt(1998, 2023);
const lookupVehicleResponse = {
data: {
year
}
};
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.resolve(lookupVehicleResponse));
const expectedInput = {
year,
vin,
noCoverage: true,
deductible: 0,
repairWaived: false,
endorsements
};
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(store.updateVehicle).toHaveBeenCalledWith(expectedInput);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
undefined
);
}
);
test( test(
'Error in lookupVehicleByVin call => bailout true and navigate forward with CLICKED_FORWARD_WITH_BAILOUT scenario.', 'Error in lookupVehicleByVin call => bailout true and navigate forward with CLICKED_FORWARD_WITH_BAILOUT scenario.',
async () => { async () => {
@ -408,6 +458,120 @@ describe('policy-vehicles.vue', () => {
}); });
}); });
describe('endorsementsForSelectedVehicle computed property', () => {
it('policyVehicles is null => empty endorsements array returned', () => {
// Arrange
const testValues = {
policyVehicles: null
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
const expected = [];
// Assert
expect(result).toStrictEqual(expected);
});
it('policyVehicles is empty => empty endorsements array returned', () => {
// Arrange
const testValues = {
policyVehicles: []
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
const expected = [];
// Assert
expect(result).toStrictEqual(expected);
});
it('selectedVehicleVin does not match any vin in policyVehicles => empty endorsements array returned', () => {
// Arrange
const selectedVin = getRandomString(17, 17);
const otherVin = getRandomString(17, 17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin
}
]
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
const expected = [];
// Assert
expect(result).toStrictEqual(expected);
});
it('vehicle VIN match with endorsements null => empty endorsements array returned', () => {
// Arrange
const vin = getRandomString(17, 17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin,
endorsements: null
}
]
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
const expected = [];
// Assert
expect(result).toStrictEqual(expected);
});
it('vehicle VIN match with empty endorsements => empty endorsements array returned', () => {
// Arrange
const vin = getRandomString(17, 17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin,
endorsements: []
}
]
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
const expected = [];
// Assert
expect(result).toStrictEqual(expected);
});
it('vehicle VIN match with endorsements => endorsements array returned', () => {
// Arrange
const vin = getRandomString(17, 17);
const endorsements = [getRandomString(10, 20)];
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin,
endorsements
}
]
};
// Act
const result = policyVehicles.computed.endorsementsForSelectedVehicle.call(testValues);
// Assert
expect(result).toStrictEqual(endorsements);
});
});
test('first vehicle is auto-selected if only one vehicle on policy', async () => { test('first vehicle is auto-selected if only one vehicle on policy', async () => {
// Arrange // Arrange
const vin = getRandomString(17, 17); const vin = getRandomString(17, 17);

View file

@ -102,12 +102,12 @@ export default {
return mappedData; return mappedData;
}, },
noCoverageForSelectedVehicle() { noCoverageForSelectedVehicle() {
const vehicle = this.policyVehicles.find((policyVehicle) => const vehicle = this.policyVehicles?.find((policyVehicle) =>
policyVehicle.vin === this.selectedVehicleVin); policyVehicle.vin === this.selectedVehicleVin);
return (vehicle?.coverages?.length ?? 0) === 0; return (vehicle?.coverages?.length ?? 0) === 0;
}, },
deductibleForSelectedVehicle() { deductibleForSelectedVehicle() {
const vehicle = this.policyVehicles.find((policyVehicle) => const vehicle = this.policyVehicles?.find((policyVehicle) =>
policyVehicle?.vin === this.selectedVehicleVin); policyVehicle?.vin === this.selectedVehicleVin);
if (!vehicle) { if (!vehicle) {
return undefined; return undefined;
@ -117,16 +117,16 @@ export default {
? vehicle?.coverages[0].deductible ? vehicle?.coverages[0].deductible
: 0; : 0;
}, },
selectedVehicleHasEndorsements() { endorsementsForSelectedVehicle() {
const vehicle = this.policyVehicles.find((policyVehicle) => const vehicle = this.policyVehicles?.find((policyVehicle) =>
policyVehicle?.vin === this.selectedVehicleVin); policyVehicle?.vin === this.selectedVehicleVin);
if (!vehicle) { if (vehicle?.endorsements?.length > 0) {
return false; return vehicle.endorsements;
} }
return vehicle.endorsements?.length > 0; return [];
}, },
repairWaivedForSelectedVehicle() { repairWaivedForSelectedVehicle() {
const vehicle = this.policyVehicles.find((policyVehicle) => const vehicle = this.policyVehicles?.find((policyVehicle) =>
policyVehicle.vin === this.selectedVehicleVin); policyVehicle.vin === this.selectedVehicleVin);
return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false; return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false;
}, },
@ -161,7 +161,7 @@ export default {
}, },
beforeMount() { beforeMount() {
if (this.policyVehicles?.length === 1) { if (this.policyVehicles?.length === 1) {
this.selectedVehicleVin = this.policyVehicles[0].vin; this.selectedVehicleVin = this.policyVehicles[0]?.vin;
} }
}, },
methods: methods:
@ -182,7 +182,8 @@ export default {
vin: this.selectedVehicleVin, vin: this.selectedVehicleVin,
noCoverage: this.noCoverageForSelectedVehicle, noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle, deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle repairWaived: this.repairWaivedForSelectedVehicle,
endorsements: this.endorsementsForSelectedVehicle
}); });
useMainStore().updateVehicle(this.vehicleFromLookup); useMainStore().updateVehicle(this.vehicleFromLookup);
@ -205,7 +206,7 @@ export default {
{}, {},
{} {}
); );
} else if (this.selectedVehicleHasEndorsements) { } else if (this.endorsementsForSelectedVehicle?.length > 0) {
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS, this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
this.$route this.$route

View file

@ -76,6 +76,7 @@ const getDefaultState = () => ({
}, },
isITAC: null, isITAC: null,
vehicles: [], vehicles: [],
endorsements: [],
endorsementQuestionAnswers: null endorsementQuestionAnswers: null
}, },
customer: { customer: {
@ -1168,6 +1169,7 @@ export const useMainStore = defineStore({
: coverageStatuses.PENDING; : coverageStatuses.PENDING;
this.order.policy.deductible.replace = vehicle.deductible; this.order.policy.deductible.replace = vehicle.deductible;
this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible; this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible;
this.order.policy.endorsements = vehicle?.endorsements;
// TODO logic should be more complicated later on // TODO logic should be more complicated later on
this.order.originalDeductible = parseFloat(vehicle.deductible); this.order.originalDeductible = parseFloat(vehicle.deductible);

View file

@ -153,10 +153,12 @@ describe('Store', () => {
// Arrange // Arrange
const noCoverage = getRandomBoolean(); const noCoverage = getRandomBoolean();
const deductible = getRandomInt(1, 500); const deductible = getRandomInt(1, 500);
const endorsements = [getRandomString(10, 20)];
const vehicle = { const vehicle = {
noCoverage, noCoverage,
deductible, deductible,
repairWaived: true repairWaived: true,
endorsements
}; };
const expectedPolicy = { const expectedPolicy = {
@ -164,7 +166,8 @@ describe('Store', () => {
deductible: { deductible: {
replace: deductible, replace: deductible,
repair: 0 repair: 0
} },
endorsements
}; };
// Act // Act
@ -178,10 +181,12 @@ describe('Store', () => {
// Arrange // Arrange
const noCoverage = getRandomBoolean(); const noCoverage = getRandomBoolean();
const deductible = getRandomInt(1, 500); const deductible = getRandomInt(1, 500);
const endorsements = [getRandomString(10, 20)];
const vehicle = { const vehicle = {
noCoverage, noCoverage,
deductible, deductible,
repairWaived: false repairWaived: false,
endorsements
}; };
const expectedPolicy = { const expectedPolicy = {
@ -189,7 +194,8 @@ describe('Store', () => {
deductible: { deductible: {
replace: deductible, replace: deductible,
repair: deductible repair: deductible
} },
endorsements
}; };
// Act // Act