Merging from develop

This commit is contained in:
Leah Schumann 2022-06-10 15:21:27 -04:00
commit b1328b7cdc
24 changed files with 2294 additions and 255 deletions

View file

@ -19,11 +19,9 @@ module.exports = {
"!src/layouts/part-questions/**/*.vue", "!src/layouts/part-questions/**/*.vue",
"!src/layouts/reveal/**/*.vue", "!src/layouts/reveal/**/*.vue",
"!src/layouts/estimate/**/*.vue", "!src/layouts/estimate/**/*.vue",
"!src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue", // there are limitations of async script loading and third party scripts that prevent full coverage from being met for this component.
// TODO REMOVE THESE AFTER WRITING UNIT TESTS // TODO REMOVE THESE AFTER WRITING UNIT TESTS
"!src/layouts/address-vehicles/address-vehicles.vue",
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue", "!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
"!src/ux-components/alert\alert.vue", "!src/ux-components/alert/alert.vue",
"!src/helpers/validation-rules.js", "!src/helpers/validation-rules.js",
// END // END
], // ! means exclude from coverage. ], // ! means exclude from coverage.

View file

@ -6,6 +6,7 @@
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit --coverage --ci", "test:unit": "vue-cli-service test:unit --coverage --ci",
"test:unit:lite": "vue-cli-service test:unit --ci",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {

View file

@ -80,7 +80,7 @@ export default {
.bar3 { .bar3 {
width: 14px; width: 14px;
height: 2px; height: 2px;
background-color: $blue-400; background-color: $blue;
margin: 1px 0; margin: 1px 0;
transition: 0.25s; transition: 0.25s;
} }

View file

@ -77,7 +77,7 @@ export default {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 1055; z-index: 1057;
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow-x: hidden; overflow-x: hidden;

View file

@ -55,9 +55,11 @@ export function getMountOptions(mockData) {
mocks.$store = mockData.store; mocks.$store = mockData.store;
mocks.$router = mockData.router; mocks.$router = mockData.router;
mocks.$route = mockData.route; mocks.$route = mockData.route;
mocks.$loadScript = mockData.loadScript;
const global = { const global = {
mocks: mocks, mocks: mocks,
mixins: mockData.mixins,
stubs: { Form } stubs: { Form }
}; };

View file

@ -322,7 +322,6 @@ describe("address-lookup.vue", () => {
// Assert // Assert
expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled(); expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled();
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalled(); expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
}); });
test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => { test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => {
@ -371,17 +370,17 @@ describe("address-lookup.vue", () => {
}) })
const carsFound = [{ const carsFound = [{
vin: "TEST_VIN", vin: "TEST_VIN",
vehicle: { vehicle: {
carId: "CARID" carId: "CARID"
} }
}, },
{ {
vin: "TEST_VIN2", vin: "TEST_VIN2",
vehicle: { vehicle: {
carId: "CARID2" carId: "CARID2"
} }
}] }]
await wrapper.setData({ await wrapper.setData({
customerQuestions: { customerQuestions: {
@ -396,7 +395,6 @@ describe("address-lookup.vue", () => {
// Assert // Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, carsFound); expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, carsFound);
}); });
test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => { test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => {
@ -520,13 +518,74 @@ describe("address-lookup.vue", () => {
await wrapper.vm.navigateForward(carEntered, carsFound); await wrapper.vm.navigateForward(carEntered, carsFound);
// Assert // Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS, undefined, {}, {"displayVehicleChangeAlert": true}, {}); expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, undefined, {}, { "displayVehicleChangeAlert": true }, {});
}); });
test("single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const carEntered = {
carId: "CARID2"
};
const carsFound = [
{
vin: "TEST_VIN_2",
vehicle: {
carId: "CARID2"
}
}
];
const { wrapper } = setupMocks({}, {});
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act
wrapper.vm.navigateForward(carEntered, carsFound);
// Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
});
test("multiple cars were found and one matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const carEntered = {
carId: "CARID2"
};
const carsFound = [
{
vin: "TEST_VIN_1",
vehicle: {
carId: "CARID1"
}
},
{
vin: "TEST_VIN_2",
vehicle: {
carId: "CARID2"
}
},
{
vin: "TEST_VIN_3",
vehicle: {
carId: "CARID3"
}
}
];
const { wrapper } = setupMocks({}, {});
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act
wrapper.vm.navigateForward(carEntered, carsFound);
// Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
});
}); });
describe("reseting dependent state", () => { describe("resetting dependent state", () => {
test("when reseting dependent state, license plate is set to null and parts state and dependencies are reset", async () => { test("when reseting dependent state, license plate is set to null and parts state and dependencies are reset", async () => {
// Arrange // Arrange
const commitSpy = jest.spyOn(store, "commit"); const commitSpy = jest.spyOn(store, "commit");
@ -556,7 +615,7 @@ describe("address-lookup.vue", () => {
zipCode: "43215" zipCode: "43215"
} }
const { wrapper } = setupMocks(addressLookup,{ const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: true isZipServiceable: true
}); });
@ -572,7 +631,7 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
// Assert // Assert
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
}); });
}); });
@ -619,8 +678,8 @@ describe("address-lookup.vue", () => {
} }
const { wrapper } = setupMocks(addressLookup, { const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: false isZipServiceable: false
} }
); );
expect(wrapper.vm.showServiceZipField).toBeFalsy(); expect(wrapper.vm.showServiceZipField).toBeFalsy();
@ -651,8 +710,8 @@ describe("address-lookup.vue", () => {
} }
const { wrapper } = setupMocks(addressLookup, { const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: false isZipServiceable: false
} }
); );
store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
@ -735,7 +794,7 @@ describe("address-lookup.vue", () => {
}); });
}); });
function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) { function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse, partsOrQuestions = [] }) {
store.commit(storeMutations.RESET_STATE); store.commit(storeMutations.RESET_STATE);
const wrapper = shallowMount(addressLookup, getMountOptions({ const wrapper = shallowMount(addressLookup, getMountOptions({
...mountOptions, ...mountOptions,
@ -757,7 +816,13 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
} }
}] }]
} }
} },
{
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
data: {
partsOrQuestions: partsOrQuestions
}
},
], ],
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
@ -772,6 +837,5 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
wrapper.vm.$refs.loadingModal.showModal = jest.fn(); wrapper.vm.$refs.loadingModal.showModal = jest.fn();
return { wrapper }; return { wrapper };
} }

View file

@ -85,12 +85,14 @@ import { storeMutations } from "@/constants/store-mutations";
import baseMixin from "@/mixins/base-mixin"; import baseMixin from "@/mixins/base-mixin";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper"; import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
export default { export default {
name: "address-lookup", name: "address-lookup",
mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@ -291,26 +293,23 @@ export default {
this.$router.navigateAfterSave( this.$router.navigateAfterSave(
// then navigate back to "vehicle-damage", and display vehicle changed alert // then navigate back to "vehicle-damage", and display vehicle changed alert
// on that page // on that page
this.navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS, this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
this.$route, {}, { this.$route, {}, {
displayVehicleChangeAlert: true displayVehicleChangeAlert: true
}, {} }, {}
); );
} else { } else {
// otherwise // otherwise
this.$refs.loadingModal.showModal(); this.navigateForwardWithSingleCarMatch();
navigateAfterSaveToHeritageFunnel(this.$route);
} }
} else if (carsFound.length > 1) { } else if (carsFound.length > 1) {
// if multiple cars were found // if multiple cars were found
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId); let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
if (matchingCars.length === 1) { if (matchingCars.length === 1) {
this.$refs.loadingModal.showModal();
// and one and only of them matches the car id entered // and one and only of them matches the car id entered
const matchingCar = matchingCars[0]; const matchingCar = matchingCars[0];
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle); this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
navigateAfterSaveToHeritageFunnel(this.$route); this.navigateForwardWithSingleCarMatch();
} else { } else {
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page // if there are no matches or there are multiple matches, navigate to "address-vehicles" page
this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound); this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
@ -330,7 +329,7 @@ export default {
licenseLastName: lastName, licenseLastName: lastName,
licenseStreetAddress: streetAddress, licenseStreetAddress: streetAddress,
licenseZip: zip, licenseZip: zip,
licenseState: state, licenseState: state
}, false }, false
); );
}, },
@ -361,9 +360,7 @@ export default {
const serviceLocation = store.getters.order.serviceLocation; const serviceLocation = store.getters.order.serviceLocation;
if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) { if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) {
baseMixin.methods.dispatchStoreAction( this.dispatchStoreAction(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION
);
} }
} }
}, },

View file

@ -1,130 +1,630 @@
import { shallowMount } from "@vue/test-utils"; // Components
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
import alert from "@/ux-components/alert/alert";
const addressModel = { // Supporting Files
streetAddress: "", import { mount, shallowMount } from "@vue/test-utils";
city: "", import { getMountOptions } from "@/helpers/unit-test-helper.js";
state: "", import { storeActions } from "@/constants/store-actions";
zipCode: "", import { storeMutations } from "@/constants/store-mutations";
import store from "@/store";
let autocompleteElement;
describe("address-questions.vue", () => {
beforeEach(() => {
// Create the `addressField1` element (autocomplete's input)
autocompleteElement = document.createElement("input")
autocompleteElement.getPlace = jest.fn();
document.getElementById = jest.fn().mockReturnValue(autocompleteElement);
})
describe("initial state", () => {
test("only street address field is shown", () => {
// Arrange
const { wrapper } = setupMocks({});
// Assert
const streetAddressField = wrapper.findComponent({ ref: "autocomplete" });
const cityField = wrapper.findComponent({ ref: "city" });
const stateField = wrapper.findComponent({ ref: "state" });
const zipCodeField = wrapper.findComponent({ ref: "zipCode" });
expect(streetAddressField.exists()).toBe(true);
expect(streetAddressField.isVisible()).toBe(true);
expect(cityField.exists()).toBe(true);
expect(cityField.isVisible()).toBe(false);
expect(stateField.exists()).toBe(true);
expect(stateField.isVisible()).toBe(false);
expect(zipCodeField.exists()).toBe(true);
expect(zipCodeField.isVisible()).toBe(false);
const alerts = wrapper.findAllComponents(alert);
expect(alerts.length).toEqual(0);
})
test("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const streetAddress = wrapper.findComponent({ ref: 'autocomplete' });
const city = wrapper.findComponent({ ref: 'city' });
const state = wrapper.findComponent({ ref: 'state' });
const zipCode = wrapper.findComponent({ ref: 'zipCode' });
// Assert
expect(streetAddress.exists()).toBe(true);
expect(city.exists()).toBe(true);
expect(state.exists()).toBe(true);
expect(zipCode.exists()).toBe(true);
});
test("Should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
// Arrange
const newAddressModel = {
streetAddress: "foo",
city: "foo",
state: "foo",
zipCode: "55555",
};
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: newAddressModel,
},
});
await wrapper.setData({
displayNoMatchWarning: true
})
expect(wrapper.vm.displayNoMatchWarning).toBeTruthy();
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, wrapper.vm.addressModel);
// Assert
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
});
test("Should it set this.showAddressFields to true when the model is prepopulated", async () => {
// Arrange
// Act
const newAddressModel = {
streetAddress: "foo",
city: "foo",
state: "foo",
zipCode: "55555",
};
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: newAddressModel,
},
});
// Act
wrapper.vm.setupAddressLookup();
// Assert
expect(wrapper.vm.showAddressFields).toBe(true);
});
});
describe("happy paths", () => {
test("full street address is passed in => address fields are displayed", async () => {
// Arrange/Act
const { wrapper } = setupMocks({
props: {
modelValue: {
streetAddress: "12345 Test Road",
city: "Tests",
state: "OH",
zipCode: "12312"
}
}
});
await wrapper.vm.$nextTick();
// Assert
const cityField = wrapper.findComponent({ ref: "city" });
const stateField = wrapper.findComponent({ ref: "state" });
const zipField = wrapper.findComponent({ ref: "zipCode" });
expect(cityField.exists()).toBeTruthy();
expect(cityField.isVisible()).toBeTruthy();
expect(stateField.exists()).toBeTruthy();
expect(cityField.isVisible()).toBeTruthy();
expect(zipField.exists()).toBeTruthy();
expect(cityField.isVisible()).toBeTruthy();
});
test("full street address is passed in => don't load Google Autocomplete script", async () => {
// Arrange/Act
const { wrapper } = setupMocks({
props: {
modelValue: {
streetAddress: "12345 Test Road",
city: "Tests",
state: "OH",
zipCode: "12312"
}
}
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.$loadScript).not.toHaveBeenCalled();
});
test("address field is focused => disable autocomplete", async () => {
// Arrange
let focusEventCallbackFunction;
autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
if (eventName == "focus") {
focusEventCallbackFunction = callbackFunction;
}
});
const { wrapper } = setupMocks({});
await wrapper.vm.$nextTick();
// Act
focusEventCallbackFunction();
await wrapper.vm.$nextTick();
// Assert
expect(autocompleteElement.getAttribute("autocomplete")).toEqual("do-not-autofill");
});
test("street address is entered, user chooses good result from autocomplete results => other fields are filled in", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
addressModel: {
streetAddress: "123 Test Street"
}
})
const selectedPlace = {
address_components: [
{
long_name: "1234",
short_name: "1234",
types: ["street_number"]
},
{
long_name: "Test Road",
short_name: "Test Road",
types: ["route"]
},
{
long_name: "East Columbus",
short_name: "Columbus",
types: ["neighborhood", "political"]
},
{
long_name: "Columbus",
short_name: "Columbus",
types: ["locality", "political"]
},
{
long_name: "Franklin County",
short_name: "Franklin County",
types: ["administrative_area_level_2", "political"]
},
{
long_name: "Ohio",
short_name: "OH",
types: ["administrative_area_level_1", "political"]
},
{
long_name: "United States",
short_name: "US",
types: ["country", "political"]
},
{
long_name: "43215",
short_name: "43215",
types: ["postal_code"]
},
]
}
// Act
autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
// Assert
const addressModel = wrapper.vm.addressModel;
expect(addressModel.streetAddress).toEqual("1234 Test Road");
expect(addressModel.city).toEqual("Columbus");
expect(addressModel.state).toEqual("OH");
expect(addressModel.zipCode).toEqual("43215");
})
test("street address is entered, user chooses good result from autocomplete results => alerts are cleared", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
addressModel: {
streetAddress: "123 Test Street"
},
displayVerificationWarning: true,
displayNoMatchWarning: true
})
let alerts = wrapper.findAllComponents(alert);
alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy());
const selectedPlace = {
address_components: [
{
long_name: "1234",
short_name: "1234",
types: ["street_number"]
},
{
long_name: "Test Road",
short_name: "Test Road",
types: ["route"]
},
{
long_name: "East Columbus",
short_name: "Columbus",
types: ["neighborhood", "political"]
},
{
long_name: "Columbus",
short_name: "Columbus",
types: ["locality", "political"]
},
{
long_name: "Franklin County",
short_name: "Franklin County",
types: ["administrative_area_level_2", "political"]
},
{
long_name: "Ohio",
short_name: "OH",
types: ["administrative_area_level_1", "political"]
},
{
long_name: "United States",
short_name: "US",
types: ["country", "political"]
},
{
long_name: "43215",
short_name: "43215",
types: ["postal_code"]
},
]
}
// Act
autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
await wrapper.vm.$nextTick();
// Assert
alerts = wrapper.findAllComponents(alert);
alerts.forEach(alert => expect(alert.exists()).toBeFalsy());
});
test("street address is entered, but user clicks away => first result is selected and other fields are filled in", async () => {
// Arrange
let changeEventCallbackFunction;
autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
if (eventName == "change") {
changeEventCallbackFunction = callbackFunction;
}
});
const { wrapper } = setupMocks({
querySelectorFunction: function (query) {
if (query == ".pac-container .pac-item") {
let element = document.createElement("div");
element.textContent = "123 Test Street"
return element;
}
},
geocoderResult: {
address_components: [
{
long_name: "1234",
short_name: "1234",
types: ["street_number"]
},
{
long_name: "Test Road",
short_name: "Test Road",
types: ["route"]
},
{
long_name: "East Columbus",
short_name: "Columbus",
types: ["neighborhood", "political"]
},
{
long_name: "Columbus",
short_name: "Columbus",
types: ["locality", "political"]
},
{
long_name: "Franklin County",
short_name: "Franklin County",
types: ["administrative_area_level_2", "political"]
},
{
long_name: "Ohio",
short_name: "OH",
types: ["administrative_area_level_1", "political"]
},
{
long_name: "United States",
short_name: "US",
types: ["country", "political"]
},
{
long_name: "43215",
short_name: "43215",
types: ["postal_code"]
},
]
}
});
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
expect(verificationAlert.exists()).toBeFalsy();
await wrapper.vm.$nextTick();
// Act
changeEventCallbackFunction();
await wrapper.vm.$nextTick();
// Assert
const addressModel = wrapper.vm.addressModel;
expect(addressModel.streetAddress).toEqual("1234 Test Road");
expect(addressModel.city).toEqual("Columbus");
expect(addressModel.state).toEqual("OH");
expect(addressModel.zipCode).toEqual("43215");
});
});
describe("alerts", () => {
const places = [null, { address_components: null }, undefined, {}];
test.each(places)("selected place/place properties is null => display verification alert", async (place) => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
addressModel: {
streetAddress: "123 Test Street"
},
displayVerificationWarning: true,
displayNoMatchWarning: true
})
let alerts = wrapper.findAllComponents(alert);
alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy());
const selectedPlace = place;
// Act
autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
await wrapper.vm.$nextTick();
// Assert
const verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
expect(verificationAlert.exists()).toBe(true);
expect(verificationAlert.isVisible()).toBe(true);
const noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBe(false);
});
test("user enters address that yields no autocomplete results => show noMatch alert", async () => {
// Arrange
let changeEventCallbackFunction;
autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
if (eventName == "change") {
changeEventCallbackFunction = callbackFunction;
}
});
const { wrapper } = setupMocks({});
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
await wrapper.vm.$nextTick();
// Act
changeEventCallbackFunction();
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.displayNoMatchWarning).toBeTruthy();
noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeTruthy();
expect(noMatchAlert.isVisible()).toBeTruthy();
});
test("user enters address that yields autocomplete results, but doesn't select => show verification alert", async () => {
// Arrange
let changeEventCallbackFunction;
autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
if (eventName == "change") {
changeEventCallbackFunction = callbackFunction;
}
});
const { wrapper } = setupMocks({
querySelectorFunction: function (query) {
if (query == ".pac-container .pac-item") {
let element = document.createElement("div");
element.textContent = "123 Test Street"
return element;
}
}
});
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
expect(verificationAlert.exists()).toBeFalsy();
await wrapper.vm.$nextTick();
// Act
changeEventCallbackFunction();
await wrapper.vm.$nextTick();
// Assert
verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
expect(wrapper.vm.displayVerificationWarning).toBeTruthy();
expect(verificationAlert.exists()).toBeTruthy();
expect(verificationAlert.isVisible()).toBeTruthy();
noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
expect(noMatchAlert.exists()).toBeFalsy();
});
describe("noMatch alert is cleared on address change", () => {
test("user sees noMatch warning and enters city => noMatch warning is removed", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.setData({
displayNoMatchWarning: true
});
await wrapper.vm.$nextTick();
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeTruthy();
expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
city: "Somewhere"
})
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
});
test("user sees noMatch warning and enters state => noMatch warning is removed", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.setData({
displayNoMatchWarning: true
});
await wrapper.vm.$nextTick();
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeTruthy();
expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
state: "KO"
})
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
});
test("user sees noMatch warning and enters zip code => noMatch warning is removed", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.setData({
displayNoMatchWarning: true
});
await wrapper.vm.$nextTick();
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeTruthy();
expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
zipCode: "12345"
})
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
expect(noMatchAlert.exists()).toBeFalsy();
});
});
});
});
function setupMocks({ mountOptions, props, isShallowMount = true, querySelectorFunction, geocoderResult = ["1234 Test Street"] }) {
store.commit(storeMutations.RESET_STATE);
const resultingMountOptions = getMountOptions({
...mountOptions,
router: {
navigate: jest.fn(),
navigateAfterSave: jest.fn()
},
loadScript: jest.fn().mockResolvedValue()
});
window.google = {
maps: {
event: {
addListener: jest.fn().mockImplementation((element, eventName, callbackFunction) => {
function interceptedCallbackFunction(e) {
callbackFunction(e.detail);
}
// selectedPlace = "Woogly";
element.addEventListener(eventName, interceptedCallbackFunction);
}),
removeListener: jest.fn(),
clearInstanceListeners: jest.fn()
},
places: {
Autocomplete: jest.fn().mockImplementation((el) => el)
},
Geocoder: class Geocoder {
// constructor();
geocode(request, callback) {
callback([geocoderResult], true)
}
},
GeocoderStatus: {
OK: true
}
}
};
if (props)
resultingMountOptions.propsData = props;
const wrapper = isShallowMount ? shallowMount(addressQuestions, resultingMountOptions) : mount(addressQuestions, resultingMountOptions);
document.querySelector = jest.fn().mockImplementation(query => {
let result = null;
if (query == ".pac-container")
result = document.createElement("div");
else if (querySelectorFunction) {
result = querySelectorFunction(query);
}
return result ?? null;
});
return { wrapper };
} }
describe("addressQuestions.vue", () => {
it("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => {
// Arrange
const wrapper = shallowMount(addressQuestions);
// Act
const streetAddress = wrapper.findComponent({ ref: 'autocomplete' });
const city = wrapper.findComponent({ ref: 'city' });
const state = wrapper.findComponent({ ref: 'state' });
const zipCode = wrapper.findComponent({ ref: 'zipCode' });
// Assert
expect(streetAddress.exists()).toBe(true);
expect(city.exists()).toBe(true);
expect(state.exists()).toBe(true);
expect(zipCode.exists()).toBe(true);
});
it("Should call the watch handler for the address model when the addressModel is changed", async () => {
// Arrange
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: addressModel,
},
});
wrapper.vm.displayNoMatchWarning = true;
// Act
const newAddressModel = {
streetAddress: "foo",
city: "foo",
state: "foo",
zipCode: "55555",
};
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
// Assert
expect(wrapper.vm.addressModel.handler).toHaveBeenCalled;
});
it("Should set this.displayNoMatchWarning to false, if the model changes when it is set to true", async () => {
// Arrange
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: addressModel,
},
});
wrapper.vm.displayNoMatchWarning = true;
// Act
const newAddressModel = {
streetAddress: "foo",
city: "",
state: "",
zipCode: "",
};
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
// Assert
expect(wrapper.vm.displayNoMatchWarning === false);
});
it("Should it not should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
// Arrange
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: addressModel,
},
});
wrapper.vm.displayNoMatchWarning = true;
// Act
const newAddressModel = {
streetAddress: "foo",
city: "foo",
state: "foo",
zipCode: "55555",
};
// Act
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
// Assert
expect(wrapper.vm.displayNoMatchWarning === true);
});
it("Should it set this.showAddressFields to true when the model is prepopulated", async () => {
// Arrange
const wrapper = shallowMount(addressQuestions, {
propsData: {
modelValue: addressModel,
},
});
wrapper.vm.displayNoMatchWarning = true;
// Act
const newAddressModel = {
streetAddress: "foo",
city: "foo",
state: "foo",
zipCode: "55555",
};
// Act
wrapper.vm.setupAddressLookup();
// Assert
expect(wrapper.vm.showAddressFields).toBe(true);
});
})

View file

@ -185,11 +185,10 @@ export default ({
}, },
methods: { methods: {
setupAddressLookup() { setupAddressLookup() {
if (this.addressModel.streetAddress &&
if (this.addressModel.streetAddress !== null & this.addressModel.city &&
this.addressModel.city !== null & this.addressModel.state &&
this.addressModel.state !== null & this.addressModel.zipCode) {
this.addressModel.zipCode !== null) {
this.showAddressFields = true; this.showAddressFields = true;
return; return;
@ -228,10 +227,9 @@ export default ({
if (autocompleteResultsContainer) { if (autocompleteResultsContainer) {
streetAddressField.appendChild(autocompleteResultsContainer); streetAddressField.appendChild(autocompleteResultsContainer);
} }
}) })
addressField1.onchange = function() { addressField1.addEventListener("change", () => {
const hover = document.querySelector(".pac-container .pac-item:hover"); const hover = document.querySelector(".pac-container .pac-item:hover");
// if an item has been clicked, do nothing, otherwise get first solution and use Geocoder to get the place // if an item has been clicked, do nothing, otherwise get first solution and use Geocoder to get the place
if (hover === null) { if (hover === null) {
@ -258,7 +256,7 @@ export default ({
self.displayNoMatchWarning = true; self.displayNoMatchWarning = true;
} }
} }
}; });
function fillInAddress(place) { function fillInAddress(place) {
if (!place) { if (!place) {
@ -310,7 +308,6 @@ export default ({
addressField1.onchange = null; addressField1.onchange = null;
const pacContainer = document.querySelector(".pac-container"); const pacContainer = document.querySelector(".pac-container");
pacContainer.remove(); pacContainer.remove();
} }
}) })
.catch(() => { .catch(() => {
@ -325,14 +322,8 @@ export default ({
watch: { watch: {
addressModel: { addressModel: {
handler(newValue) { handler(newValue) {
// The first time the address model changes is when the page first loads // Clear no match warning on address change
if (!newValue.city && if (newValue.city || newValue.state || newValue.zipCode) {
!newValue.state &&
!newValue.zipCode) {
return;
}
if (this.displayNoMatchWarning === true) {
this.displayNoMatchWarning = false; this.displayNoMatchWarning = false;
} }
}, },

View file

@ -7,7 +7,6 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store"; import store from "@/store";
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper"; import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
// Mock our module for promises. // Mock our module for promises.
jest.mock("@/helpers/damage-helper", () => ({ jest.mock("@/helpers/damage-helper", () => ({
isGlassAvailableForCarId: () => { isGlassAvailableForCarId: () => {
@ -17,7 +16,6 @@ jest.mock("@/helpers/damage-helper", () => ({
describe("addressVehicles.vue", () => { describe("addressVehicles.vue", () => {
test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => { test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -225,40 +223,32 @@ describe("addressVehicles.vue", () => {
wrapper.unmount(); wrapper.unmount();
}); });
test("Should navigate to navigateAfterSaveToHeritageFunnel if carId is not different on navigateForward", async () => { test("carId is not different on navigateForward (car was found) => Should handle navigating forward with car match", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn(); wrapper.vm.$refs.loadingModal.showModal = jest.fn();
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act // Act
wrapper.setData({ wrapper.setData({
selectedVehicleVin: ['5NMS3CADXLH233004'],
isSelectedGlassAvailableForVehicle: true,
isCarIdDifferent: false, isCarIdDifferent: false,
}); });
await wrapper.vm.navigateForward(); await wrapper.vm.navigateForward();
//Assert //Assert
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toBeCalledTimes(1); expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
wrapper.unmount(); wrapper.unmount();
}); });
}); });
function setupMocks({}) {
function setupMocks({
// modelValueProp = "1900",
cmsQuestionText = "CMS text goes here",
// dataFromStoreApi = [],
}) {
//Mock store //Mock store
store.dispatch = jest.fn(() => {}); store.dispatch = jest.fn(() => {});
store.getters = { store.getters = {
pageData: jest.fn((pageName) => { pageData: jest.fn((pageName) => {
// console.log('pageName: ', pageName) // address-vehicles
return [ return [
{ {
vehicle: { vehicle: {
@ -295,9 +285,6 @@ function setupMocks({
} }
}; };
// baseMixin.methods.dispatchStoreAction = jest.fn();
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
store: { store: {
dispatch: store.dispatch, dispatch: store.dispatch,
@ -320,16 +307,6 @@ function setupMocks({
} }
return null; return null;
}), }),
// dispatchStoreAction: jest.fn(() => {
// console.log("23424243")
// }),
// isGlassAvailableForCarId: () => {
// console.log("%%%%%%%%%%%%%%%")
// return Promise.resolve(true)
// }
// lookupVin: jest.fn(() => Promise.resolve(lookupVinResponse)),
}, },
computed: { computed: {
dynamicStrings() { dynamicStrings() {
@ -337,18 +314,10 @@ function setupMocks({
} }
} }
} }
// mountOptions.propsData = {
// modelValue: modelValueProp,
// };
mountOptions.mixins = [mockMixin]; mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(addressVehicles, mountOptions); const wrapper = shallowMount(addressVehicles, mountOptions);
//Mock CMS content
const cmsContent = {
QuestionText: cmsQuestionText,
};
return { wrapper }; return { wrapper };
} }

View file

@ -71,13 +71,15 @@ import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
import { doesCopyContainRouterLink, import { doesCopyContainRouterLink,
splitCopyOnCMSPlaceHolder, splitCopyOnCMSPlaceHolder,
getRouterLinkRouteFromCopy, getRouterLinkRouteFromCopy,
getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper" getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED)); defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED));
export default { export default {
name: "address-vehicles", name: "address-vehicles",
mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@ -188,8 +190,7 @@ export default {
); );
return; return;
} else { } else {
this.$refs.loadingModal.showModal(); this.navigateForwardWithSingleCarMatch();
navigateAfterSaveToHeritageFunnel(this.$route);
return; return;
} }
}, },

View file

@ -0,0 +1,187 @@
//Components
import estimate from "@/layouts/estimate/estimate.vue";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
//Supporting files
import { storeKey } from "vuex";
import store from "@/store";
import { storeMutations } from "@/constants/store-mutations";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "../../mixins/base-mixin";
import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js";
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
describe("estimate.vue", () => {
test("Selected vin option is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: ["Provide my VIN manually most specific to your vehicle"] });
//Act
wrapper.setValue({ modelValue: ["Provide my license plate # Most accurate VIN match"] });
await wrapper.vm.$nextTick();
//Assesrt
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: ["Provide my license plate # Most accurate VIN match"] }]);
});
test("isRepair is set to true, arePagePrerequisitesValid should return true", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, true );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("isRepair is set to false, arePagePrerequisitesValid should return true", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, false );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("isRepair is set to null, arePagePrerequisitesValid should return false", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, null );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(false);
});
test("After selecting provide my home address on ForwardButtonAction triggers a router.navigate", async () => {
//Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
selectedValues: [vinLookupMethodSelections.HOMEADDRESS]
})
//Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
test("After selecting provide my manual vin on ForwardButtonAction triggers a router.navigate", async () => {
//Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
selectedValues: [vinLookupMethodSelections.MANUALVIN]
})
//Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
test("BackButtonAction triggers a router.navigate change", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
estimate.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "estimate" } },
undefined,
(c) => c(wrapper.vm)
);
wrapper.vm.backButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
test("Provide my license plate on ForwardButtonAction triggers a router.navigate", async () => {
//Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
selectedValues: [vinLookupMethodSelections.LICENSEPLATE]
})
//Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
});
function setupMocks({
modelValueProp = ["Provide my VIN manually most specific to your vehicle"],
isMultiSelect = false,
groupName = "estimate",
cmsQuestionText = "Let's get your VIN. Or we can look it up for you!",
cmsAnswers = [{ Name: "Provide my VIN manually Most specific to your vehicle" }, { Name: "Provide my license plate # Most accurate VIN match" }, { Name: "Provide my home address Most convenient VIN match" }],
dataFromApi = [],
mountOptionsMockData = {
router: {
navigate: jest.fn(),
},
},
}) {
//Mock CMS Content
const cmsContent = {
groupName: groupName,
QuestionText: cmsQuestionText,
Answers: cmsAnswers
};
//Mock props
const mockMixin = {
methods: {
getCmsContent: jest.fn()
}
}
const apiPromise = Promise.resolve(cmsContent);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [baseMixin] });
mountOptions['attachTo'] = document.body;
const wrapper = shallowMount(estimate, mountOptions);
return { wrapper, apiPromise };
}

View file

@ -9,6 +9,7 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-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.js";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import store from "@/store"; import store from "@/store";
@ -223,7 +224,7 @@ describe("license-plate-lookup.vue", () => {
}); });
describe("navigateForward", () => { describe("navigateForward", () => {
test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => { test("navigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -259,6 +260,38 @@ describe("license-plate-lookup.vue", () => {
//Assert //Assert
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled(); expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
}); });
test("carId matches returned vehicle => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
isCarIdDifferent: false
})
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act
await wrapper.vm.navigateForward();
//Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
});
test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
isSelectedGlassAvailableForVehicle: true
})
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act
await wrapper.vm.navigateForward();
//Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
});
}); });
}); });
@ -484,7 +517,7 @@ describe("license-plate-lookup.vue", () => {
expect(store.dispatch).toHaveBeenCalled(); expect(store.dispatch).toHaveBeenCalled();
}) })
test("dispatch non blocking store action called on validate zip", async () => { test("dispatchStoreAction called on validate zip", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -497,7 +530,7 @@ describe("license-plate-lookup.vue", () => {
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled(); expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
}); });
test("dispatch non blocking store action called on lookup vin", async () => { test("dispatchStoreAction called on lookup vin", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -514,11 +547,8 @@ describe("license-plate-lookup.vue", () => {
function setupMocks({ function setupMocks({
pageHeaderWidgetHeaderText = {}, pageHeaderWidgetHeaderText = {},
mountOptionsMockData = { mountOptionsMockData = {},
router: { partsOrQuestions = []
navigate: jest.fn(),
},
},
}) { }) {
store.commit(storeMutations.RESET_STATE); store.commit(storeMutations.RESET_STATE);
//Mock api responses //Mock api responses
@ -537,6 +567,21 @@ function setupMocks({
}, },
}; };
mountOptionsMockData = {
...mountOptionsMockData,
router: {
navigate: jest.fn(),
},
actionList: [
{
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
data: {
partsOrQuestions: partsOrQuestions
}
},
]
}
const apiPromise = Promise.resolve(apiResponses); const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise); settleAllPromises.mockImplementation(() => apiPromise);

View file

@ -98,10 +98,10 @@ import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper"; import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper";
import { required, regex, } from "@/helpers/validation-rules"; import { required, regex, } from "@/helpers/validation-rules";
import { Form, defineRule, } from "vee-validate"; import { Form, defineRule, } from "vee-validate";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED)); defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
@ -112,6 +112,7 @@ defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+
export default { export default {
name: "license-plate-lookup", name: "license-plate-lookup",
mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@ -297,8 +298,7 @@ export default {
); );
return; return;
} else { } else {
this.$refs.loadingModal.showModal(); this.navigateForwardWithSingleCarMatch();
navigateAfterSaveToHeritageFunnel(this.$route);
return; return;
} }
}, },
@ -312,7 +312,7 @@ export default {
}, },
updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) { updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) {
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
} }
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin); store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year); store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year);

View file

@ -5,9 +5,7 @@
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall"> <div class="fade-on-route-transition sub-container make-tall">
<h1>Part Questions Page Placeholder</h1> <h1>Part Questions Page Placeholder</h1>
<funnel-footer <funnel-footer cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction" />
cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction"
/>
</div> </div>
</div> </div>
</template> </template>
@ -65,10 +63,7 @@ export default {
); );
}, },
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
if (Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length !== 0) { return Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length !== 0;
return true;
}
return false;
}, },
resetDependentState() { resetDependentState() {
// Set // Set

View file

@ -168,7 +168,7 @@ export default {
// Check if only a single part is present for the tint and set the v-model if it is. // Check if only a single part is present for the tint and set the v-model if it is.
AutoSelectIfSinglePart() { AutoSelectIfSinglePart() {
// Check if the selected tint only has a single feature // Check if the selected tint only has a single feature
Object.keys(this.PartDataFromApi.partsOrQuestions).forEach((key) => { Object.keys(this.PartDataFromApi.partsOrQuestions ?? {}).forEach((key) => {
const currentGlassSelection = const currentGlassSelection =
this.PartDataFromApi.partsOrQuestions[key]; this.PartDataFromApi.partsOrQuestions[key];

View file

@ -1 +1,261 @@
test.todo("some test to be written in the future"); import { shallowMount } from "@vue/test-utils";
import vinLookup from "./vin-lookup.vue";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js";
import store from "@/store";
jest.mock("@/store", () => ({
commit: jest.fn(),
dispatch: jest.fn(),
getters: {
vehicle: {
year: 2019,
carId: 'initial carId'
},
order: {
serviceLocation: {
zipCode: "45253"
},
customer: {
emailAddress: "builddigitaltest@safelite.com"
}
},
payment: {
insuranceCoverage: {
isVerified: true
}
},
damage: {
glassToReplace: "windshield"
}
},
}));
import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper";
jest.mock("@/helpers/damage-helper", () => ({
isGlassAvailableForCarId: jest.fn(() => {
return Promise.resolve();
}),
getIsWindshieldOnly: jest.fn(),
getDamageString: jest.fn(),
}));
describe("vin-lookup.vue", () => {
it("Should update the funnel-footer forward button when VIN is changed", (done) => {
//Arrange
const { wrapper } = setupMocks({});
//Act
wrapper.setData({ vin: "newValue" });
//Assert
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled();
done();
});
});
it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
});
it("Should not call navigateForward() if the store carId does not match the vin response carId and forward button is clicked", async () => {
// Arrange
const { wrapper } = setupMocks({});
const vehicleLookupApiResponse = {
data: {
carId: 'new carId' // does not match the store value
}
};
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
});
it("Should call navigateForward() if the store carId does not match the vin response carId but does match previously enterted carId and forward button is clicked", async () => {
// Arrange
const { wrapper } = setupMocks({});
const vehicleLookupApiResponse = {
data: {
carId: 'new carId' // does not match the store value
}
};
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.previouslyEnteredCarId = 'new carId';
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
});
it("Should not call navigateForward() if zip service returns a non-serviceable flag", async () => {
// Arrange
const { wrapper } = setupMocks({});
const zipValidationApiResponse = {
data: {
isServiceable: false
}
};
const zipPromise = Promise.resolve(zipValidationApiResponse);
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.previouslyEnteredCarId = 'new carId';
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
});
it("Should not call navigateForward() when forward button is clicked but lookupVehicle errors out.", async () => {
// Arrange
const { wrapper } = setupMocks({});
const vehicleLookupApiResponse = {
data: {
carId: 'new carId' // does not match the store value
}
};
const vinPromise = Promise.reject(vehicleLookupApiResponse);
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.previouslyEnteredCarId = 'new carId';
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
});
describe("navigateForward", () => {
test("carId is different from returned vehicle and selected glass isn't available => continue with different glass", async () => {
// Arrange
const { wrapper } = setupMocks({
customMountOptions: {
router: {
navigateAfterSave: jest.fn()
}
}
});
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
wrapper.setData({
isCarIdDifferent: true,
isSelectedGlassAvailableForVehicle: false
});
// Act
await wrapper.vm.navigateForward();
//Assert
expect(wrapper.vm.$router.navigateAfterSave).toBeCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, wrapper.vm.$route, expect.anything(), expect.anything(), expect.anything());
})
test("carId matches => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
wrapper.setData({
isCarIdDifferent: false,
});
// Act
await wrapper.vm.navigateForward();
//Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
})
test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
wrapper.setData({
isSelectedGlassAvailableForVehicle: true,
});
// Act
await wrapper.vm.navigateForward();
//Assert
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
})
})
});
function setupMocks({ customMountOptions }) {
const mountOptions = getMountOptions({
...customMountOptions
});
// Modify/augment default mount options
mountOptions.global.mocks["$store"] = store;
mountOptions.global.mixins = [mockMixin];
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
const wrapper = shallowMount(vinLookup, mountOptions);
mockOutPromises(wrapper);
mockOutStubFunctions(wrapper);
return { wrapper };
}
function mockOutPromises(wrapper) {
const zipValidationApiResponse = {
data: {
isServiceable: true
}
};
const vehicleLookupApiResponse = {
data: {
carId: 'initial carId'
}
};
const zipPromise = Promise.resolve(zipValidationApiResponse);
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
}
function mockOutStubFunctions(wrapper) {
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
}
const mockMixin = {
methods: {
getCmsContent: jest.fn(() => "placeholder CMS content"),
}
}

View file

@ -134,7 +134,6 @@ import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import store from "@/store"; import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
@ -143,6 +142,7 @@ import { required, regex } from "@/helpers/validation-rules";
import { Form, defineRule } from "vee-validate"; import { Form, defineRule } from "vee-validate";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
@ -154,6 +154,7 @@ defineRule("vin-format", regex(/^[a-hA-Hj-nJ-NpPr-zR-Z0-9]{17}$/, errorMessages.
export default { export default {
name: "vin-lookup", name: "vin-lookup",
mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@ -313,9 +314,13 @@ export default {
this.vinNotFound = true; this.vinNotFound = true;
this.$refs.funnelFooter.removeLoader(); this.$refs.funnelFooter.removeLoader();
this.noServiceZip = false; this.noServiceZip = false;
return; return false;
}); });
if (!vehicleLookupResponse) {
return;
}
if (!zipValidationResponse.data.isServiceable) { if (!zipValidationResponse.data.isServiceable) {
this.customAlertData.zip = this.zip; this.customAlertData.zip = this.zip;
this.$refs.funnelFooter.removeLoader(); this.$refs.funnelFooter.removeLoader();
@ -343,22 +348,21 @@ export default {
}, },
navigateForward(){ navigateForward(){
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle){ if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigateAfterSave(this.navigationScenarios.CLICKED_FORWARD, this.$route, {}, { displayVehicleChangeAlert: true }, {}); this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, { displayVehicleChangeAlert: true }, {});
return; return;
} else { } else {
this.$refs.loadingModal.showModal(); this.navigateForwardWithSingleCarMatch();
navigateAfterSaveToHeritageFunnel(this.$route);
return; return;
} }
}, },
validateZip(zip) { validateZip(zip) {
return baseMixin.methods.dispatchStoreAction(storeActions.VALIDATE_ZIP, { return this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip, zip,
}); });
}, },
lookupVehicle(vin) { lookupVehicle(vin) {
return baseMixin.methods.dispatchStoreAction( return this.dispatchStoreAction(
storeActions.LOOKUP_VEHICLE_BY_VIN, storeActions.LOOKUP_VEHICLE_BY_VIN,
{ vin } { vin }
); );

View file

@ -124,6 +124,32 @@ describe("analyticsMixin.js", () => {
//Assert //Assert
expect(obj!=null); expect(obj!=null);
}); });
test("Obj method name does not include bound", () => {
//Arrange
const obj = {baseMethodName:"testMethodName", data:"testData"};
const method = {name:"testMethodName", data:"testData" }
const action = "testAction";
//Act
analyticsMixin.methods.prependActionToMethod(obj, method, action);
//Assert
expect(method.name.startsWith("bound ")).toBe(false);
});
test("Prepended action does not include bound", () => {
//Arrange
const obj = {baseMethodName:"testMethodName", data:"testData"};
const method = {name:"testMethodName", data:"testData" }
const action = "testAction";
//Act
analyticsMixin.methods.prependActionToMethod(obj, method, action);
//Assert
expect(action.startsWith("bound ")).toBe(false);
});
test("analyticsPageEvents returns constants analyticsPageEvents", () => { test("analyticsPageEvents returns constants analyticsPageEvents", () => {
//Act //Act

View file

@ -0,0 +1,28 @@
import store from "@/store";
import { storeActions } from "@/constants/store-actions.js";
import { storeMutations } from "@/constants/store-mutations.js";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
export default {
methods: {
async navigateForwardWithSingleCarMatch() {
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
const partsOrQuestions = result.data.partsOrQuestions;
const hasPartsQuestions = partsOrQuestions.some(pq => pq.partQuestions?.length > 0);
const hasGlassLocationWithMultipleParts = partsOrQuestions.some(pq => pq.parts?.length > 1);
if (hasPartsQuestions) {
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, this.$route, {}, {}, result.data);
}
else if (hasGlassLocationWithMultipleParts) {
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, this.$route, {}, {}, result.data);
}
else {
store.commit(storeMutations.UPDATE_PARTS, result.data);
this.$refs.loadingModal.showModal();
navigateAfterSaveToHeritageFunnel(this.$route);
}
}
}
}

View file

@ -0,0 +1,921 @@
import vinPagesMixin from "@/mixins/vin-pages-mixin";
import { shallowMount } from "@vue/test-utils";
import { setupMocksForJsFiles, getMountOptions } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
import store from "@/store";
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateAfterSaveToHeritageFunnel: jest.fn()
}));
describe("vin-pages-mixin", () => {
afterEach(() => {
jest.clearAllMocks();
})
describe("navigateForwardWithSingleCarMatch", () => {
describe("should go to parts-questions", () => {
test("single glass location has part question => go to parts-questions", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": null,
"partQuestions": [
{
"questionSequence": 1,
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW01144"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW01143"
}
]
}
]
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
test("multiple glass locations have part questions => go to parts-questions", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": null,
"partQuestions": [
{
"questionSequence": 1,
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW01144"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW01143"
}
]
}
]
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD08158GTYN",
"description": "driver side, front",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Quarter",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DQ08162GTYN",
"description": "driver side, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "SideDoor",
"glassLocation": "Driver",
"parts": null,
"partQuestions": [
{
"questionSequence": 2,
"questionText": "Is this a super awesome question?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW01144000"
},
{
"answerText": "Super yes",
"nextQuestionSequence": null,
"answerResult": "DW01143001"
}
]
}
]
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "DB08165GTNN",
"description": "heated glass, stationary",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
test("multiple glass locations selected, one has part question => go to parts-questions", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": null,
"partQuestions": [
{
"questionSequence": 1,
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW01144"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW01143"
}
]
}
]
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD08158GTYN",
"description": "driver side, front",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Quarter",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DQ08162GTYN",
"description": "driver side, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "SideDoor",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD08160GTYN",
"description": "driver side, body side, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "DB08165GTNN",
"description": "heated glass, stationary",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
test("a selected glass location has part questions and multiple parts => go to parts-questions", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": null,
"partQuestions": [
{
"questionSequence": 1,
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW01144"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW01143"
}
]
}
]
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD08158GTYN",
"description": "driver side, front",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Quarter",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DQ08162GTYN",
"description": "driver side, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ08162YPYN",
"description": "driver side, 1 hole",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "SideDoor",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD08160GTYN",
"description": "driver side, body side, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DD08160YPYN",
"description": "driver side, body side, 1 hole",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "DB08165GTNN",
"description": "heated glass, stationary",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DB08165YPNN",
"description": "heated glass, stationary",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DB08166GTNN",
"description": "stationary",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DB08167GTNN",
"description": "heated glass, movable, 8 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DB08167YPNN",
"description": "heated glass, movable, 8 hole",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
});
describe("should go to vehicle-parts", () => {
test("single glass location has multiple parts => go to vehicle-parts", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "FB25724GTYN",
"description": "heated glass, solar, antenna",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "FB25759GTYN",
"description": "heated glass, solar, antenna, w/diversity antenna",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
test("multiple glass locations selected, one of them has multiple parts => go to vehicle parts", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "FW03647GTNN",
"description": "solar, 3rd visor band",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": [
{
"partNumber": "MWF03647",
"partType": "MOULDING",
"description": "Upper "
}
]
}
],
"partQuestions": null
},
{
"glassName": "Back",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FD25747GTYN",
"description": "solar, driver side, rear, ex models and above",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FD25719GTYN",
"description": "solar, driver side, front, ex models and above",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Vent",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FV25749GTNN",
"description": "solar, driver side, rear",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "FB25724GTYN",
"description": "heated glass, solar, antenna",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "FB25759GTYN",
"description": "heated glass, solar, antenna, w/diversity antenna",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
test("multiple glass locations selected, multiple have multiple parts => go to vehicle-parts", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "DW02101GTYN",
"description": "solar",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Back",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD12202GTYN",
"description": "solar, driver side, rear",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DD12202YPYN",
"description": "solar, driver side, rear",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DD12198GTYN",
"description": "solar, driver side, front",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DD12200GTYN",
"description": "solar, driver side, front, laminated, soundproofing",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Quarter",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "DQ12204GTYNOEM",
"description": "solar, driver side, encap",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12204YPYNOEM",
"description": "solar, driver side, encap",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12205GTYNOEM",
"description": "solar, antenna, driver side, encap",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12205YPYNOEM",
"description": "solar, antenna, driver side, encap",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12207GTYN",
"description": "solar, driver side, encap, chrome molding",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12207YPYNOEM",
"description": "solar, driver side, encap, chrome molding",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12208GTYNOEM",
"description": "solar, antenna, driver side, encap, chrome molding",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DQ12208YPYNOEM",
"description": "solar, antenna, driver side, encap, chrome molding",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "DB12209GTYN",
"description": "heated glass, solar, 1 hole",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
},
{
"partNumber": "DB12209YPYN",
"description": "heated glass, solar, 1 hole",
"color": "Gray Tint Privacy",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
});
});
describe("should go to heritage funnel", () => {
test("single glass location selected, has no part questions and has one part => go to heritage funnel", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "FW04186GTYN",
"description": "solar, soundproofing, lane keep assist",
"color": "Green Tint",
"requiresRecalibration": true,
"requiresCapabilityQuestions": false,
"childParts": [
{
"partNumber": "GGG 3563 KIT",
"partType": "MOULDING",
"description": "Kit, Top & Sides "
}
]
}
],
"partQuestions": null
}
]
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalledTimes(1);
});
test("multiple glass locations selected, each has one part and no part questions => go to heritage funnel", async () => {
// Arrange
const partsOrQuestions = [
{
"glassName": "Single",
"glassLocation": "Windshield",
"parts": [
{
"partNumber": "FW04186GTYN",
"description": "solar, soundproofing, lane keep assist",
"color": "Green Tint",
"requiresRecalibration": true,
"requiresCapabilityQuestions": false,
"childParts": [
{
"partNumber": "GGG 3563 KIT",
"partType": "MOULDING",
"description": "Kit, Top & Sides "
}
]
}
],
"partQuestions": null
},
{
"glassName": "Back",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FD25457GTYN",
"description": "solar, driver side, rear",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Front",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FD27090GTYN",
"description": "solar, driver side, front",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Vent",
"glassLocation": "Driver",
"parts": [
{
"partNumber": "FV25459GTNN",
"description": "solar, driver side, rear",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
},
{
"glassName": "Stationary",
"glassLocation": "Rear",
"parts": [
{
"partNumber": "FB25460GTYN",
"description": "heated glass, solar",
"color": "Green Tint",
"requiresRecalibration": false,
"requiresCapabilityQuestions": false,
"childParts": null
}
],
"partQuestions": null
}
];
const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions
});
// wrapper.vm.navigateAfterSaveToHeritageFunnel = jest.fn();
store.commit = jest.fn();
// Act
await wrapper.vm.navigateForwardWithSingleCarMatch();
// Assert
expect(store.commit).toHaveBeenCalledTimes(1);
expect(store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_PARTS, { partsOrQuestions })
expect(wrapper.vm.$refs.loadingModal.showModal).toHaveBeenCalledTimes(1);
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalledTimes(1);
});
});
});
});
function setupMocks({ partsOrQuestions = [] }) {
const baseMixin = setupMocksForJsFiles({
actionList: [
{
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
data: {
partsOrQuestions: partsOrQuestions
}
},
],
});
const mocks = getMountOptions({
router: {
navigateAfterSave: jest.fn()
},
});
const mockVinComponent = {
components: { loadingModal },
template: '<loadingModal ref="loadingModal" />',
// render() {
// return '<div ref="loadingModal"></div>'
// },
mixins: [vinPagesMixin, baseMixin.baseMixin]
};
// const mockVinComponent = Vue.component("mockcomponent", {
// template: '<loadingModal ref="loadingModal" />',
// mixins: [vinPagesMixin, baseMixin.baseMixin]
// })
const wrapper = shallowMount(mockVinComponent, mocks);
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
return { wrapper };
}

View file

@ -8,11 +8,11 @@ const navigationScenarios = {
CLICKED_FORWARD: "CLICKED_FORWARD", CLICKED_FORWARD: "CLICKED_FORWARD",
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN", CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
SELECTED_PARTS: "SELECTED_PARTS", SELECTED_PARTS: "SELECTED_PARTS",
CONTINUING_WITH_PARTS_QUESTION: "CONTINUING_WITH_PARTS_QUESTION", SELECTED_VIN_WITH_PART_QUESTIONS: "SELECTED_VIN_WITH_PART_QUESTIONS",
CONTINUING_WITH_MULTIPLE_PARTS: "CONTINUING_WITH_MULTIPLE_PARTS", SELECTED_VIN_WITH_MULTIPLE_PARTS: "SELECTED_VIN_WITH_MULTIPLE_PARTS",
CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART", CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART",
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES", CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
CONTINUING_WITH_DIFFERENT_GLASS: "CONTINUING_WITH_DIFFERENT_GLASS", SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS",
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN", CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN", SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE", SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",

View file

@ -72,7 +72,7 @@ const routingTable = [
maps: [ maps: [
{ {
scenario: navigationScenarios.CLICKED_BACK, scenario: navigationScenarios.CLICKED_BACK,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
}, },
{ {
scenario: navigationScenarios.SELECTED_PARTS, scenario: navigationScenarios.SELECTED_PARTS,
@ -105,12 +105,20 @@ const routingTable = [
destinationFmgPageValue: fmgPageValues.ESTIMATE, destinationFmgPageValue: fmgPageValues.ESTIMATE,
}, },
{ {
scenario: navigationScenarios.CLICKED_FORWARD, scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_WITH_VIN, scenario: navigationScenarios.CLICKED_BACK_WITH_VIN,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
},
{
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
},
{
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
} }
], ],
}, },
@ -125,6 +133,14 @@ const routingTable = [
scenario: navigationScenarios.CLICKED_FORWARD, scenario: navigationScenarios.CLICKED_FORWARD,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
}, },
{
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
},
{
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
}
], ],
}, },
{ {
@ -139,9 +155,17 @@ const routingTable = [
destinationFmgPageValue: fmgPageValues.ADDRESS_VEHICLES, destinationFmgPageValue: fmgPageValues.ADDRESS_VEHICLES,
}, },
{ {
scenario: navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS, scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
}, },
{
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
},
{
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
}
], ],
}, },
{ {
@ -155,6 +179,14 @@ const routingTable = [
scenario: navigationScenarios.CLICKED_FORWARD, scenario: navigationScenarios.CLICKED_FORWARD,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
}, },
{
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
},
{
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
}
], ],
}, },
{ {
@ -178,6 +210,15 @@ const routingTable = [
}, },
], ],
}, },
{
fmgPageValue: fmgPageValues.PART_QUESTIONS,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
}
]
},
]; ];
export { routingTable }; export { routingTable };

View file

@ -539,7 +539,16 @@ export const actions = {
// Parts API Actions // Parts API Actions
getPartsOrQuestions(context, { carId, glassArray, zipCode, vin = '' }) { getPartsOrQuestions(context) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const carId = vehicle.carId;
const glassArray = damage.glassToReplace;
const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin;
return globalMethods.callHttpClient({ return globalMethods.callHttpClient({
method: endpoints.GetPartsOrQuestions.method, method: endpoints.GetPartsOrQuestions.method,
endpoint: endpoints.GetPartsOrQuestions.url, endpoint: endpoints.GetPartsOrQuestions.url,