Merging from develop
This commit is contained in:
commit
b1328b7cdc
24 changed files with 2294 additions and 255 deletions
|
|
@ -18,12 +18,10 @@ module.exports = {
|
||||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||||
"!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.
|
||||||
|
|
|
||||||
|
|
@ -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": {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,9 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => {
|
test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mockRegistrationAddress = {
|
const mockRegistrationAddress = {
|
||||||
|
|
@ -76,8 +76,8 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => {
|
test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -121,7 +121,7 @@ describe("address-lookup.vue", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -133,7 +133,7 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()).toBe(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -169,7 +169,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -183,13 +183,13 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("navigation", () => {
|
describe("navigation", () => {
|
||||||
|
|
||||||
test("if the back button is clicked, navigate back", async () => {
|
test("if the back button is clicked, navigate back", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks(addressLookup, {
|
||||||
|
|
@ -197,7 +197,7 @@ describe("address-lookup.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.backButtonAction();
|
await wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
||||||
|
|
@ -246,7 +246,7 @@ describe("address-lookup.vue", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -261,7 +261,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the car entered matches one of multiple vehicles found, update vehicle info and navigate to the heritage funnel", async () => {
|
test("if the car entered matches one of multiple vehicles found, update vehicle info and navigate to the heritage funnel", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -306,7 +306,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -322,8 +322,7 @@ 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 () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -368,20 +367,20 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
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,8 +395,7 @@ 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 () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -442,7 +440,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -458,7 +456,7 @@ describe("address-lookup.vue", () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0);
|
expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => {
|
test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -492,7 +490,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
return Promise.resolve({ data });
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -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");
|
||||||
|
|
@ -544,7 +603,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("registration and service zips", () => {
|
describe("registration and service zips", () => {
|
||||||
describe("if registration zip is serviceable", () => {
|
describe("if registration zip is serviceable", () => {
|
||||||
test("if registration address is provided => update service address on successful continue", async () => {
|
test("if registration address is provided => update service address on successful continue", async () => {
|
||||||
|
|
@ -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 };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -329,8 +328,8 @@ 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
||||||
describe("addressQuestions.vue", () => {
|
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);
|
||||||
|
})
|
||||||
|
|
||||||
it("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => {
|
describe("initial state", () => {
|
||||||
// Arrange
|
test("only street address field is shown", () => {
|
||||||
const wrapper = shallowMount(addressQuestions);
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
// Act
|
// Assert
|
||||||
const streetAddress = wrapper.findComponent({ ref: 'autocomplete' });
|
const streetAddressField = wrapper.findComponent({ ref: "autocomplete" });
|
||||||
const city = wrapper.findComponent({ ref: 'city' });
|
const cityField = wrapper.findComponent({ ref: "city" });
|
||||||
const state = wrapper.findComponent({ ref: 'state' });
|
const stateField = wrapper.findComponent({ ref: "state" });
|
||||||
const zipCode = wrapper.findComponent({ ref: 'zipCode' });
|
const zipCodeField = wrapper.findComponent({ ref: "zipCode" });
|
||||||
|
|
||||||
// Assert
|
expect(streetAddressField.exists()).toBe(true);
|
||||||
expect(streetAddress.exists()).toBe(true);
|
expect(streetAddressField.isVisible()).toBe(true);
|
||||||
expect(city.exists()).toBe(true);
|
expect(cityField.exists()).toBe(true);
|
||||||
expect(state.exists()).toBe(true);
|
expect(cityField.isVisible()).toBe(false);
|
||||||
expect(zipCode.exists()).toBe(true);
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should call the watch handler for the address model when the addressModel is changed", async () => {
|
test("Should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = shallowMount(addressQuestions, {
|
const newAddressModel = {
|
||||||
propsData: {
|
streetAddress: "foo",
|
||||||
modelValue: addressModel,
|
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
|
||||||
});
|
});
|
||||||
wrapper.vm.displayNoMatchWarning = true;
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
|
||||||
|
expect(noMatchAlert.exists()).toBeTruthy();
|
||||||
|
expect(noMatchAlert.isVisible()).toBeTruthy();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const newAddressModel = {
|
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
|
||||||
streetAddress: "foo",
|
city: "Somewhere"
|
||||||
city: "foo",
|
})
|
||||||
state: "foo",
|
await wrapper.vm.$nextTick();
|
||||||
zipCode: "55555",
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.addressModel.handler).toHaveBeenCalled;
|
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({});
|
||||||
|
|
||||||
it("Should set this.displayNoMatchWarning to false, if the model changes when it is set to true", async () => {
|
wrapper.setData({
|
||||||
// Arrange
|
displayNoMatchWarning: true
|
||||||
const wrapper = shallowMount(addressQuestions, {
|
|
||||||
propsData: {
|
|
||||||
modelValue: addressModel,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
wrapper.vm.displayNoMatchWarning = true;
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Act
|
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
|
||||||
const newAddressModel = {
|
expect(noMatchAlert.exists()).toBeTruthy();
|
||||||
streetAddress: "foo",
|
expect(noMatchAlert.isVisible()).toBeTruthy();
|
||||||
city: "",
|
|
||||||
state: "",
|
|
||||||
zipCode: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
|
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
|
||||||
|
state: "KO"
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.displayNoMatchWarning === false);
|
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
|
||||||
it("Should it not should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
|
const { wrapper } = setupMocks({});
|
||||||
// Arrange
|
|
||||||
const wrapper = shallowMount(addressQuestions, {
|
wrapper.setData({
|
||||||
propsData: {
|
displayNoMatchWarning: true
|
||||||
modelValue: addressModel,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
wrapper.vm.displayNoMatchWarning = true;
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Act
|
let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
|
||||||
const newAddressModel = {
|
expect(noMatchAlert.exists()).toBeTruthy();
|
||||||
streetAddress: "foo",
|
expect(noMatchAlert.isVisible()).toBeTruthy();
|
||||||
city: "foo",
|
|
||||||
state: "foo",
|
|
||||||
zipCode: "55555",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
|
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
|
||||||
|
zipCode: "12345"
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.displayNoMatchWarning === true);
|
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);
|
||||||
|
|
||||||
it("Should it set this.showAddressFields to true when the model is prepopulated", async () => {
|
const resultingMountOptions = getMountOptions({
|
||||||
// Arrange
|
...mountOptions,
|
||||||
const wrapper = shallowMount(addressQuestions, {
|
router: {
|
||||||
propsData: {
|
navigate: jest.fn(),
|
||||||
modelValue: addressModel,
|
navigateAfterSave: jest.fn()
|
||||||
},
|
},
|
||||||
});
|
loadScript: jest.fn().mockResolvedValue()
|
||||||
wrapper.vm.displayNoMatchWarning = true;
|
});
|
||||||
|
|
||||||
// Act
|
|
||||||
const newAddressModel = {
|
|
||||||
streetAddress: "foo",
|
|
||||||
city: "foo",
|
|
||||||
state: "foo",
|
|
||||||
zipCode: "55555",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
window.google = {
|
||||||
wrapper.vm.setupAddressLookup();
|
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();
|
||||||
|
|
||||||
// Assert
|
geocode(request, callback) {
|
||||||
expect(wrapper.vm.showAddressFields).toBe(true);
|
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 };
|
||||||
|
}
|
||||||
|
|
@ -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,16 +322,10 @@ 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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
187
src/layouts/estimate/estimate.spec.js
Normal file
187
src/layouts/estimate/estimate.spec.js
Normal 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 };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<div class="page-container-grouped-styles">
|
<div class="page-container-grouped-styles">
|
||||||
<loadingModal ref="loadingModal"/>
|
<loadingModal ref="loadingModal"/>
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||||
<vehicleBanner
|
<vehicleBanner
|
||||||
cmsWidgetName="VehicleBannerWidget"
|
cmsWidgetName="VehicleBannerWidget"
|
||||||
:displayGenericVehicleImage="false"
|
:displayGenericVehicleImage="false"
|
||||||
/>
|
/>
|
||||||
|
|
@ -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 }
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
28
src/mixins/vin-pages-mixin.js
Normal file
28
src/mixins/vin-pages-mixin.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
921
src/mixins/vin-pages-mixin.spec.js
Normal file
921
src/mixins/vin-pages-mixin.spec.js
Normal 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 };
|
||||||
|
}
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -154,7 +178,15 @@ 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 };
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue