Merge pull request #484 from Safelite/feature/digital/SSR-462

SSR-462 VIN passed or input doesn't match a CarID in our system
This commit is contained in:
Josh Dassinger 2023-10-18 09:53:56 -05:00 committed by GitHub
commit da8f2e2776
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 203 additions and 25 deletions

View file

@ -243,7 +243,7 @@ function mapStringToState(str) {
// Reset store state for each match.
const valueFromStore = getStoreValueFromString(match[2]);
if (!valueFromStore) {
console.warning('Unable to resolve global state data.');
console.warn('Unable to resolve global state data.');
return ''; // if we can't map our string to state data, return an empty string.
}
const stringWithReplacement = str.replace(match[0], valueFromStore);

View file

@ -140,7 +140,7 @@ describe('policyEndorsements.vue', () => {
expect(wrapper.vm.$router.navigate)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK, undefined);
});
test('Forward button clicked triggers navigation', () => {
test('Forward button clicked with valid car id triggers navigation', () => {
// Arrange
const wrapper = shallowMount(policyEndorsements, getMountOptions({
router: {
@ -148,6 +148,10 @@ describe('policyEndorsements.vue', () => {
}
}));
wrapper.setData({
hasValidCarId: true
});
// Act
wrapper.vm.forwardButtonAction();
wrapper.vm.navigateForward();
@ -157,6 +161,27 @@ describe('policyEndorsements.vue', () => {
expect(wrapper.vm.$router.navigate)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD, undefined);
});
test('Forward button clicked with invalid car id triggers navigation scenario CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND', () => {
// Arrange
const wrapper = shallowMount(policyEndorsements, getMountOptions({
router: {
navigate: jest.fn()
}
}));
wrapper.setData({
hasValidCarId: false,
});
// Act
wrapper.vm.forwardButtonAction();
wrapper.vm.navigateForward();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
expect(wrapper.vm.$router.navigate)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND, undefined);
});
test('Forward button clicked saves endorsement question answers', () => {
// Arrange
const mountOptions = getMountOptions({

View file

@ -96,11 +96,17 @@ export default {
});
},
emits: ['update:modelValue'],
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
questionAnswersArray: [],
schoolPropertyAnswer: '',
parkingLotAnswer: '',
hasValidCarId: this.mainStore.vehicle.carId && this.mainStore.vehicle.carId !== '0',
rules: {
selectionRequired: globalRules.OPTION_REQUIRED
}
@ -158,10 +164,17 @@ export default {
return this.navigateForward();
},
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
if (!this.hasValidCarId) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
}
}
}
};

View file

@ -100,7 +100,8 @@ describe('policy-vehicles.vue', () => {
policyVehicles: [
{ vin }
],
bailout: false
bailout: false,
policyVinFound: true
});
const year = getRandomInt(1998, 2023);
@ -126,6 +127,7 @@ describe('policy-vehicles.vue', () => {
// Assert
expect(wrapper.vm.bailout).toBeFalsy();
expect(wrapper.vm.policyVinFound).toBeTruthy();
expect(store.updateVehicle).toHaveBeenCalledWith(expectedInput);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
@ -190,6 +192,7 @@ describe('policy-vehicles.vue', () => {
async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.lookupVehicleByVin = jest.fn().mockReturnValue({ error: true, status: 500 });
const vin = getRandomString(17, 17);
await wrapper.setData({
@ -197,9 +200,6 @@ describe('policy-vehicles.vue', () => {
bailout: false
});
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.reject());
// Act
await wrapper.vm.forwardButtonAction();
@ -214,6 +214,43 @@ describe('policy-vehicles.vue', () => {
}
);
test(
// eslint-disable-next-line max-len
'Vehicle not found in lookupVehicleByVin call => policyVinFound false and navigate forward with CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND scenario.',
async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.lookupVehicleByVin = jest.fn().mockReturnValue({ error: true, status: 404 });
const vin = getRandomString(17, 17);
await wrapper.setData({
selectedVehicleVin: vin,
bailout: false,
policyVinFound: true,
policyVehicles: [{
vin,
vehicleYear: getRandomInt(2000, 2100),
vehicleMake: getRandomString(5, 10),
vehicleMode: getRandomString(5, 10),
vehicleStyle: getRandomString(5, 10)
}]
});
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.bailout).toBeFalsy();
expect(wrapper.vm.policyVinFound).toBeFalsy();
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
undefined,
{},
{}
);
}
);
test('vehicle not listed => navigate forward with CLICKED_FORWARD_NON_LISTED_VEHICLE scenario.', async () => {
// Arrange
const { wrapper } = setupMocks({});

View file

@ -77,6 +77,7 @@ export default {
policyVehicles,
selectedVehicleVin: '',
displayGeneric: true,
policyVinFound: true,
bailout: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
@ -174,6 +175,26 @@ export default {
if (this.selectedVehicleVin !== vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin);
if (vehicleLookupResponse.error) {
if (vehicleLookupResponse.status === 404) {
const vehicle = this.policyVehicles.find((pv) => pv.vin === this.selectedVehicleVin);
this.mainStore.resetVehicleState();
useMainStore().updateVehicle({
carId: '0',
category: '',
year: vehicle.vehicleYear || '',
make: vehicle.vehicleMake || '',
model: vehicle.vehicleModel || '',
style: vehicle.vehicleStyle || '',
vin: vehicle.vin,
noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle
});
this.policyVinFound = false;
return this.navigateForward();
}
this.bailout = true;
return this.navigateForward();
}
@ -192,12 +213,13 @@ export default {
},
navigateForward() {
if (this.bailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route,
{},
{}
);
this.$router
.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route,
{},
{}
);
} else if (this.selectedVehicleVin === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
this.$router
.navigate(
@ -211,6 +233,13 @@ export default {
this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
this.$route
);
} else if (!this.policyVinFound) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
this.$route,
{},
{}
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
@ -225,7 +254,8 @@ export default {
return await useMainStore().lookupVehicleByVin(vin);
} catch (responseError) {
return {
error: true
error: true,
status: responseError.status
};
}
}

View file

@ -477,6 +477,43 @@ describe('vin-lookup.vue', () => {
);
});
});
// eslint-disable-next-line max-len
test('Policy Vehicle with invalid vin corrected. Click "Continue", execute navigate with navigationScenario.CORRECTED_VIN_FROM_POLICY_VEHICLE', async () => {
const user = userEvent.setup();
mountOptions.global.stubs.vinQuestion = false;
mountOptions.data = () => ({
vinWithNonMatchingCarId: true,
isCarIdDifferentFromTheStore: false,
vin: mockValidVin
});
getPartsOrQuestions.mockResponse = vehicleWithNoAdditionalPartsOrQuestionsMockResponse;
jest.spyOn(VinLookupComponent.methods, lookupVehicleByVin.methodName)
.mockResolvedValue(lookupVehicleByVin.mockResponse);
jest.spyOn(vehicleQuestionsMixin.methods, getPartsOrQuestions.methodName)
.mockResolvedValue(getPartsOrQuestions.mockResponse);
const { container } = render(VinLookupComponent, mountOptions);
const vinInput = container.querySelector(vinInputSelector);
await user.type(vinInput, mockValidVin);
const continueButton = container.querySelector(continueButtonQuerySelector);
await user.click(continueButton);
await flushPromises();
await waitFor(() => {
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
expect(mockRouter.navigate)
.toHaveBeenCalledWith(
navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
mockRoute
);
});
});
});
});
});

View file

@ -15,7 +15,7 @@
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
:displayGenericVehicleImage="carIdIsValid" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<vinLookupAlerts
class="mt-5"
@ -106,23 +106,28 @@ export default {
return { mainStore };
},
data() {
const vin = this.getVinFromStore();
return {
activeVehicleLookupAlertType: null,
activeVehicleLookupAlertType: vin?.length > 0 && !this.hasValidCarId() ? vehicleLookupAlertTypes.NOT_FOUND : null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vin: this.getVinFromStore(),
vinWithNonMatchingCarId: vin?.length > 0 && !this.hasValidCarId(),
vin,
forwardButtonCarStyle: '',
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0
vinPopulatedOnPageLoad: vin?.length > 0 && this.hasValidCarId()
};
},
computed: {
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null
this.vehicleFromLookup !== null && this.hasValidCarId()
&& this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
},
isTwoIdenticalYMMVehicleFound() {
if (this.vehicleFromLookup === null) {
return false;
}
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected =
`${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
@ -138,6 +143,9 @@ export default {
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
return 'XXXXXXXXXXXXXXXXX';
},
carIdIsValid() {
return this.hasValidCarId();
}
},
watch: {
@ -155,10 +163,13 @@ export default {
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
hasValidCarId() {
return this.mainStore.vehicle.carId && this.mainStore.vehicle.carId !== '0';
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
@ -228,6 +239,14 @@ export default {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
if (this.vinWithNonMatchingCarId) {
this.$router.navigate(
this.navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
this.$route
);
return null;
}
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here

View file

@ -25,6 +25,7 @@ const navigationScenarios = Object.freeze({
// Policy Vehicle
CLICKED_FORWARD_LISTED_VEHICLE: 'CLICKED_FORWARD_LISTED_VEHICLE',
CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND: 'CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND',
CLICKED_FORWARD_NON_LISTED_VEHICLE: 'CLICKED_FORWARD_NON_LISTED_VEHICLE',
CLICKED_FORWARD_WITH_ENDORSEMENTS: 'CLICKED_FORWARD_WITH_ENDORSEMENTS',
@ -36,6 +37,7 @@ const navigationScenarios = Object.freeze({
CLICKED_FORWARD_WITHOUT_VIN: 'CLICKED_FORWARD_WITHOUT_VIN',
CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES: 'CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES',
SELECTED_VIN_WITH_MISMATCHED_GLASS: 'SELECTED_VIN_WITH_MISMATCHED_GLASS',
CORRECTED_VIN_FROM_POLICY_VEHICLE: 'CORRECTED_VIN_FROM_POLICY_VEHICLE',
SELECTED_MANUAL_VIN: 'SELECTED_MANUAL_VIN',
SELECTED_LICENSE_PLATE: 'SELECTED_LICENSE_PLATE',
SELECTED_HOME_ADDRESS: 'SELECTED_HOME_ADDRESS',

View file

@ -86,6 +86,10 @@ const routingTable = () => [
scenario: navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
},
{
scenario: navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
destinationIssPageValue: issPageValues.PART_QUESTIONS
@ -110,6 +114,10 @@ const routingTable = () => [
scenario: issPageValues.VEHICLE_LOOKUP,
destinationIssPageValue: issPageValues.VEHICLE_LOOKUP
},
{
scenario: issPageValues.BAILOUT_PAGE,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
@ -447,6 +455,10 @@ const routingTable = () => [
scenario: navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
destinationIssPageValue: issPageValues.VEHICLE_SELECTION
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
destinationIssPageValue: issPageValues.VIN_LOOKUP
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
@ -455,7 +467,6 @@ const routingTable = () => [
scenario: navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
destinationIssPageValue: issPageValues.POLICY_ENDORSEMENTS
}
]
},
{
@ -681,6 +692,10 @@ const routingTable = () => [
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
destinationIssPageValue: issPageValues.VIN_LOOKUP
}
]
}