diff --git a/jest.config.js b/jest.config.js
index a6be0c11a..a73aac7ea 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -18,12 +18,10 @@ module.exports = {
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
"!src/layouts/part-questions/**/*.vue",
"!src/layouts/reveal/**/*.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.
+ "!src/layouts/estimate/**/*.vue",
// 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/ux-components/alert\alert.vue",
+ "!src/ux-components/alert/alert.vue",
"!src/helpers/validation-rules.js",
// END
], // ! means exclude from coverage.
diff --git a/package.json b/package.json
index ec3d65d79..304fc2afd 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit --coverage --ci",
+ "test:unit:lite": "vue-cli-service test:unit --ci",
"lint": "vue-cli-service lint"
},
"dependencies": {
diff --git a/src/common-components/funnel-header/menu-modal/menu-modal.vue b/src/common-components/funnel-header/menu-modal/menu-modal.vue
index c980036e9..e275cc65a 100644
--- a/src/common-components/funnel-header/menu-modal/menu-modal.vue
+++ b/src/common-components/funnel-header/menu-modal/menu-modal.vue
@@ -80,7 +80,7 @@ export default {
.bar3 {
width: 14px;
height: 2px;
- background-color: $blue-400;
+ background-color: $blue;
margin: 1px 0;
transition: 0.25s;
}
diff --git a/src/common-components/loading-modal/loading-modal.vue b/src/common-components/loading-modal/loading-modal.vue
index d06392755..2bcdc9c31 100644
--- a/src/common-components/loading-modal/loading-modal.vue
+++ b/src/common-components/loading-modal/loading-modal.vue
@@ -77,7 +77,7 @@ export default {
left: 0;
right: 0;
bottom: 0;
- z-index: 1055;
+ z-index: 1057;
width: 100%;
height: 100%;
overflow-x: hidden;
diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js
index 07632f5e5..592af9a5c 100644
--- a/src/helpers/unit-test-helper.js
+++ b/src/helpers/unit-test-helper.js
@@ -55,9 +55,11 @@ export function getMountOptions(mockData) {
mocks.$store = mockData.store;
mocks.$router = mockData.router;
mocks.$route = mockData.route;
+ mocks.$loadScript = mockData.loadScript;
const global = {
mocks: mocks,
+ mixins: mockData.mixins,
stubs: { Form }
};
diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js
index d1f261f9a..c66ead3c7 100644
--- a/src/layouts/address-lookup/address-lookup.spec.js
+++ b/src/layouts/address-lookup/address-lookup.spec.js
@@ -48,9 +48,9 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// 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 () => {
// Arrange
const mockRegistrationAddress = {
@@ -76,8 +76,8 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// 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 () => {
// Arrange
@@ -121,7 +121,7 @@ describe("address-lookup.vue", () => {
}
return Promise.resolve({ data });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -133,7 +133,7 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// 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 });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -183,13 +183,13 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// Assert
- expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
+ expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
});
- });
+ });
describe("navigation", () => {
-
+
test("if the back button is clicked, navigate back", async () => {
// Arrange
const { wrapper } = setupMocks(addressLookup, {
@@ -197,7 +197,7 @@ describe("address-lookup.vue", () => {
});
// Act
- await wrapper.vm.backButtonAction();
+ await wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
@@ -246,7 +246,7 @@ describe("address-lookup.vue", () => {
}
return Promise.resolve({ data });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -261,7 +261,7 @@ describe("address-lookup.vue", () => {
// Assert
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 () => {
// Arrange
@@ -306,7 +306,7 @@ describe("address-lookup.vue", () => {
return Promise.resolve({ data });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -322,8 +322,7 @@ describe("address-lookup.vue", () => {
// Assert
expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled();
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
-
- });
+ });
test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => {
// Arrange
@@ -368,20 +367,20 @@ describe("address-lookup.vue", () => {
return Promise.resolve({ data });
- })
-
+ })
+
const carsFound = [{
- vin: "TEST_VIN",
- vehicle: {
- carId: "CARID"
- }
- },
- {
- vin: "TEST_VIN2",
- vehicle: {
- carId: "CARID2"
- }
- }]
+ vin: "TEST_VIN",
+ vehicle: {
+ carId: "CARID"
+ }
+ },
+ {
+ vin: "TEST_VIN2",
+ vehicle: {
+ carId: "CARID2"
+ }
+ }]
await wrapper.setData({
customerQuestions: {
@@ -396,8 +395,7 @@ describe("address-lookup.vue", () => {
// Assert
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 () => {
// Arrange
@@ -442,7 +440,7 @@ describe("address-lookup.vue", () => {
return Promise.resolve({ data });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -458,7 +456,7 @@ describe("address-lookup.vue", () => {
// Assert
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 () => {
// Arrange
@@ -492,7 +490,7 @@ describe("address-lookup.vue", () => {
return Promise.resolve({ data });
- })
+ })
await wrapper.setData({
customerQuestions: {
@@ -520,13 +518,74 @@ describe("address-lookup.vue", () => {
await wrapper.vm.navigateForward(carEntered, carsFound);
// 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 () => {
// Arrange
const commitSpy = jest.spyOn(store, "commit");
@@ -544,7 +603,7 @@ describe("address-lookup.vue", () => {
});
});
-
+
describe("registration and service zips", () => {
describe("if registration zip is serviceable", () => {
test("if registration address is provided => update service address on successful continue", async () => {
@@ -556,7 +615,7 @@ describe("address-lookup.vue", () => {
zipCode: "43215"
}
- const { wrapper } = setupMocks(addressLookup,{
+ const { wrapper } = setupMocks(addressLookup, {
isZipServiceable: true
});
@@ -572,7 +631,7 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// 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, {
- isZipServiceable: false
- }
+ isZipServiceable: false
+ }
);
expect(wrapper.vm.showServiceZipField).toBeFalsy();
@@ -651,8 +710,8 @@ describe("address-lookup.vue", () => {
}
const { wrapper } = setupMocks(addressLookup, {
- isZipServiceable: false
- }
+ isZipServiceable: false
+ }
);
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);
const wrapper = shallowMount(addressLookup, getMountOptions({
...mountOptions,
@@ -757,7 +816,13 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
}
}]
}
- }
+ },
+ {
+ actionName: storeActions.GET_PARTS_OR_QUESTIONS,
+ data: {
+ partsOrQuestions: partsOrQuestions
+ }
+ },
],
router: {
navigate: jest.fn(),
@@ -772,6 +837,5 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
return { wrapper };
-
}
diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue
index 2e13299de..aa5d9fa90 100644
--- a/src/layouts/address-lookup/address-lookup.vue
+++ b/src/layouts/address-lookup/address-lookup.vue
@@ -85,12 +85,14 @@ import { storeMutations } from "@/constants/store-mutations";
import baseMixin from "@/mixins/base-mixin";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-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-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
export default {
name: "address-lookup",
+ mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@@ -291,26 +293,23 @@ export default {
this.$router.navigateAfterSave(
// then navigate back to "vehicle-damage", and display vehicle changed alert
// on that page
- this.navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS,
+ this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
this.$route, {}, {
displayVehicleChangeAlert: true
}, {}
);
} else {
// otherwise
- this.$refs.loadingModal.showModal();
- navigateAfterSaveToHeritageFunnel(this.$route);
+ this.navigateForwardWithSingleCarMatch();
}
} else if (carsFound.length > 1) {
// if multiple cars were found
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
if (matchingCars.length === 1) {
- this.$refs.loadingModal.showModal();
-
// and one and only of them matches the car id entered
const matchingCar = matchingCars[0];
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
- navigateAfterSaveToHeritageFunnel(this.$route);
+ this.navigateForwardWithSingleCarMatch();
} else {
// 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);
@@ -329,8 +328,8 @@ export default {
{
licenseLastName: lastName,
licenseStreetAddress: streetAddress,
- licenseZip: zip,
- licenseState: state,
+ licenseZip: zip,
+ licenseState: state
}, false
);
},
@@ -361,9 +360,7 @@ export default {
const serviceLocation = store.getters.order.serviceLocation;
if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) {
- baseMixin.methods.dispatchStoreAction(
- storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION
- );
+ this.dispatchStoreAction(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
}
}
},
diff --git a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js
index 11a0aa4ed..fb1154fe6 100644
--- a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js
+++ b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js
@@ -1,130 +1,630 @@
-import { shallowMount } from "@vue/test-utils";
+// Components
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
+import alert from "@/ux-components/alert/alert";
-const addressModel = {
- streetAddress: "",
- city: "",
- state: "",
- zipCode: "",
-}
+// Supporting Files
+import { mount, shallowMount } from "@vue/test-utils";
+import { getMountOptions } from "@/helpers/unit-test-helper.js";
+import { storeActions } from "@/constants/store-actions";
+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 () => {
- // Arrange
- const wrapper = shallowMount(addressQuestions);
+ describe("initial state", () => {
+ test("only street address field is shown", () => {
+ // 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
+ const streetAddressField = wrapper.findComponent({ ref: "autocomplete" });
+ const cityField = wrapper.findComponent({ ref: "city" });
+ const stateField = wrapper.findComponent({ ref: "state" });
+ const zipCodeField = 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);
-
+ expect(streetAddressField.exists()).toBe(true);
+ expect(streetAddressField.isVisible()).toBe(true);
+ expect(cityField.exists()).toBe(true);
+ expect(cityField.isVisible()).toBe(false);
+ expect(stateField.exists()).toBe(true);
+ expect(stateField.isVisible()).toBe(false);
+ expect(zipCodeField.exists()).toBe(true);
+ expect(zipCodeField.isVisible()).toBe(false);
+
+ const alerts = wrapper.findAllComponents(alert);
+ expect(alerts.length).toEqual(0);
+ })
+
+ test("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+
+ // Act
+ const streetAddress = wrapper.findComponent({ ref: 'autocomplete' });
+ const city = wrapper.findComponent({ ref: 'city' });
+ const state = wrapper.findComponent({ ref: 'state' });
+ const zipCode = wrapper.findComponent({ ref: 'zipCode' });
+
+ // Assert
+ expect(streetAddress.exists()).toBe(true);
+ expect(city.exists()).toBe(true);
+ expect(state.exists()).toBe(true);
+ expect(zipCode.exists()).toBe(true);
});
- it("Should call the watch handler for the address model when the addressModel is changed", async () => {
- // Arrange
- const wrapper = shallowMount(addressQuestions, {
- propsData: {
- modelValue: addressModel,
+ test("Should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
+ // Arrange
+ const newAddressModel = {
+ streetAddress: "foo",
+ city: "foo",
+ state: "foo",
+ zipCode: "55555",
+ };
+ const wrapper = shallowMount(addressQuestions, {
+ propsData: {
+ modelValue: newAddressModel,
+ },
+ });
+
+ await wrapper.setData({
+ displayNoMatchWarning: true
+ })
+ expect(wrapper.vm.displayNoMatchWarning).toBeTruthy();
+
+ // Act
+ wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, wrapper.vm.addressModel);
+
+ // Assert
+ expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
+ });
+
+ test("Should it set this.showAddressFields to true when the model is prepopulated", async () => {
+ // Arrange
+ // Act
+ const newAddressModel = {
+ streetAddress: "foo",
+ city: "foo",
+ state: "foo",
+ zipCode: "55555",
+ };
+ const wrapper = shallowMount(addressQuestions, {
+ propsData: {
+ modelValue: newAddressModel,
+ },
+ });
+
+ // Act
+ wrapper.vm.setupAddressLookup();
+
+ // Assert
+ expect(wrapper.vm.showAddressFields).toBe(true);
+
+ });
+ });
+
+ describe("happy paths", () => {
+ test("full street address is passed in => address fields are displayed", async () => {
+ // Arrange/Act
+ const { wrapper } = setupMocks({
+ props: {
+ modelValue: {
+ streetAddress: "12345 Test Road",
+ city: "Tests",
+ state: "OH",
+ zipCode: "12312"
+ }
+ }
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ const cityField = wrapper.findComponent({ ref: "city" });
+ const stateField = wrapper.findComponent({ ref: "state" });
+ const zipField = wrapper.findComponent({ ref: "zipCode" });
+ expect(cityField.exists()).toBeTruthy();
+ expect(cityField.isVisible()).toBeTruthy();
+ expect(stateField.exists()).toBeTruthy();
+ expect(cityField.isVisible()).toBeTruthy();
+ expect(zipField.exists()).toBeTruthy();
+ expect(cityField.isVisible()).toBeTruthy();
+ });
+
+ test("full street address is passed in => don't load Google Autocomplete script", async () => {
+ // Arrange/Act
+ const { wrapper } = setupMocks({
+ props: {
+ modelValue: {
+ streetAddress: "12345 Test Road",
+ city: "Tests",
+ state: "OH",
+ zipCode: "12312"
+ }
+ }
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.$loadScript).not.toHaveBeenCalled();
+ });
+
+ test("address field is focused => disable autocomplete", async () => {
+ // Arrange
+ let focusEventCallbackFunction;
+ autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
+ if (eventName == "focus") {
+ focusEventCallbackFunction = callbackFunction;
+ }
+ });
+ const { wrapper } = setupMocks({});
+ await wrapper.vm.$nextTick();
+
+ // Act
+ focusEventCallbackFunction();
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(autocompleteElement.getAttribute("autocomplete")).toEqual("do-not-autofill");
+ });
+
+ test("street address is entered, user chooses good result from autocomplete results => other fields are filled in", async () => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+ await wrapper.setData({
+ addressModel: {
+ streetAddress: "123 Test Street"
+ }
+ })
+
+ const selectedPlace = {
+ address_components: [
+ {
+ long_name: "1234",
+ short_name: "1234",
+ types: ["street_number"]
+ },
+ {
+ long_name: "Test Road",
+ short_name: "Test Road",
+ types: ["route"]
+ },
+ {
+ long_name: "East Columbus",
+ short_name: "Columbus",
+ types: ["neighborhood", "political"]
+ },
+ {
+ long_name: "Columbus",
+ short_name: "Columbus",
+ types: ["locality", "political"]
+ },
+ {
+ long_name: "Franklin County",
+ short_name: "Franklin County",
+ types: ["administrative_area_level_2", "political"]
+ },
+ {
+ long_name: "Ohio",
+ short_name: "OH",
+ types: ["administrative_area_level_1", "political"]
+ },
+ {
+ long_name: "United States",
+ short_name: "US",
+ types: ["country", "political"]
+ },
+ {
+ long_name: "43215",
+ short_name: "43215",
+ types: ["postal_code"]
+ },
+ ]
+ }
+
+ // Act
+ autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
+
+ // Assert
+ const addressModel = wrapper.vm.addressModel;
+ expect(addressModel.streetAddress).toEqual("1234 Test Road");
+ expect(addressModel.city).toEqual("Columbus");
+ expect(addressModel.state).toEqual("OH");
+ expect(addressModel.zipCode).toEqual("43215");
+ })
+
+ test("street address is entered, user chooses good result from autocomplete results => alerts are cleared", async () => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+ await wrapper.setData({
+ addressModel: {
+ streetAddress: "123 Test Street"
+ },
+ displayVerificationWarning: true,
+ displayNoMatchWarning: true
+ })
+
+ let alerts = wrapper.findAllComponents(alert);
+ alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy());
+
+ const selectedPlace = {
+ address_components: [
+ {
+ long_name: "1234",
+ short_name: "1234",
+ types: ["street_number"]
+ },
+ {
+ long_name: "Test Road",
+ short_name: "Test Road",
+ types: ["route"]
+ },
+ {
+ long_name: "East Columbus",
+ short_name: "Columbus",
+ types: ["neighborhood", "political"]
+ },
+ {
+ long_name: "Columbus",
+ short_name: "Columbus",
+ types: ["locality", "political"]
+ },
+ {
+ long_name: "Franklin County",
+ short_name: "Franklin County",
+ types: ["administrative_area_level_2", "political"]
+ },
+ {
+ long_name: "Ohio",
+ short_name: "OH",
+ types: ["administrative_area_level_1", "political"]
+ },
+ {
+ long_name: "United States",
+ short_name: "US",
+ types: ["country", "political"]
+ },
+ {
+ long_name: "43215",
+ short_name: "43215",
+ types: ["postal_code"]
+ },
+ ]
+ }
+
+ // Act
+ autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ alerts = wrapper.findAllComponents(alert);
+ alerts.forEach(alert => expect(alert.exists()).toBeFalsy());
+ });
+
+ test("street address is entered, but user clicks away => first result is selected and other fields are filled in", async () => {
+ // Arrange
+ let changeEventCallbackFunction;
+ autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
+ if (eventName == "change") {
+ changeEventCallbackFunction = callbackFunction;
+ }
+ });
+
+ const { wrapper } = setupMocks({
+ querySelectorFunction: function (query) {
+ if (query == ".pac-container .pac-item") {
+ let element = document.createElement("div");
+ element.textContent = "123 Test Street"
+ return element;
+ }
+ },
+ geocoderResult: {
+ address_components: [
+ {
+ long_name: "1234",
+ short_name: "1234",
+ types: ["street_number"]
},
+ {
+ long_name: "Test Road",
+ short_name: "Test Road",
+ types: ["route"]
+ },
+ {
+ long_name: "East Columbus",
+ short_name: "Columbus",
+ types: ["neighborhood", "political"]
+ },
+ {
+ long_name: "Columbus",
+ short_name: "Columbus",
+ types: ["locality", "political"]
+ },
+ {
+ long_name: "Franklin County",
+ short_name: "Franklin County",
+ types: ["administrative_area_level_2", "political"]
+ },
+ {
+ long_name: "Ohio",
+ short_name: "OH",
+ types: ["administrative_area_level_1", "political"]
+ },
+ {
+ long_name: "United States",
+ short_name: "US",
+ types: ["country", "political"]
+ },
+ {
+ long_name: "43215",
+ short_name: "43215",
+ types: ["postal_code"]
+ },
+ ]
+ }
+ });
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
+ expect(noMatchAlert.exists()).toBeFalsy();
+ expect(verificationAlert.exists()).toBeFalsy();
+
+ await wrapper.vm.$nextTick();
+
+ // Act
+ changeEventCallbackFunction();
+
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ const addressModel = wrapper.vm.addressModel;
+ expect(addressModel.streetAddress).toEqual("1234 Test Road");
+ expect(addressModel.city).toEqual("Columbus");
+ expect(addressModel.state).toEqual("OH");
+ expect(addressModel.zipCode).toEqual("43215");
+ });
+ });
+
+ describe("alerts", () => {
+ const places = [null, { address_components: null }, undefined, {}];
+ test.each(places)("selected place/place properties is null => display verification alert", async (place) => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+ await wrapper.setData({
+ addressModel: {
+ streetAddress: "123 Test Street"
+ },
+ displayVerificationWarning: true,
+ displayNoMatchWarning: true
+ })
+
+ let alerts = wrapper.findAllComponents(alert);
+ alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy());
+
+ const selectedPlace = place;
+
+ // Act
+ autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace }));
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ const verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
+ expect(verificationAlert.exists()).toBe(true);
+ expect(verificationAlert.isVisible()).toBe(true);
+ const noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBe(false);
+ });
+
+ test("user enters address that yields no autocomplete results => show noMatch alert", async () => {
+ // Arrange
+ let changeEventCallbackFunction;
+ autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
+ if (eventName == "change") {
+ changeEventCallbackFunction = callbackFunction;
+ }
+ });
+
+ const { wrapper } = setupMocks({});
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeFalsy();
+
+ await wrapper.vm.$nextTick();
+
+ // Act
+ changeEventCallbackFunction();
+
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayNoMatchWarning).toBeTruthy();
+ noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeTruthy();
+ expect(noMatchAlert.isVisible()).toBeTruthy();
+ });
+
+ test("user enters address that yields autocomplete results, but doesn't select => show verification alert", async () => {
+ // Arrange
+ let changeEventCallbackFunction;
+ autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => {
+ if (eventName == "change") {
+ changeEventCallbackFunction = callbackFunction;
+ }
+ });
+
+ const { wrapper } = setupMocks({
+ querySelectorFunction: function (query) {
+ if (query == ".pac-container .pac-item") {
+ let element = document.createElement("div");
+ element.textContent = "123 Test Street"
+ return element;
+ }
+ }
+ });
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
+ expect(noMatchAlert.exists()).toBeFalsy();
+ expect(verificationAlert.exists()).toBeFalsy();
+
+ await wrapper.vm.$nextTick();
+
+ // Act
+ changeEventCallbackFunction();
+
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" });
+ expect(wrapper.vm.displayVerificationWarning).toBeTruthy();
+ expect(verificationAlert.exists()).toBeTruthy();
+ expect(verificationAlert.isVisible()).toBeTruthy();
+ noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
+ expect(noMatchAlert.exists()).toBeFalsy();
+ });
+
+ describe("noMatch alert is cleared on address change", () => {
+ test("user sees noMatch warning and enters city => noMatch warning is removed", async () => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+
+ wrapper.setData({
+ displayNoMatchWarning: true
});
- wrapper.vm.displayNoMatchWarning = true;
+ await wrapper.vm.$nextTick();
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeTruthy();
+ expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
- const newAddressModel = {
- streetAddress: "foo",
- city: "foo",
- state: "foo",
- zipCode: "55555",
- };
-
- wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
+ wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
+ city: "Somewhere"
+ })
+ await wrapper.vm.$nextTick();
// 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 () => {
- // Arrange
- const wrapper = shallowMount(addressQuestions, {
- propsData: {
- modelValue: addressModel,
- },
+ wrapper.setData({
+ displayNoMatchWarning: true
});
- wrapper.vm.displayNoMatchWarning = true;
-
- // Act
- const newAddressModel = {
- streetAddress: "foo",
- city: "",
- state: "",
- zipCode: "",
- };
+ await wrapper.vm.$nextTick();
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeTruthy();
+ expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
- wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
+ wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
+ state: "KO"
+ })
+ await wrapper.vm.$nextTick();
// Assert
- expect(wrapper.vm.displayNoMatchWarning === false);
+ expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
+ noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeFalsy();
+ });
- });
-
- it("Should it not should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => {
- // Arrange
- const wrapper = shallowMount(addressQuestions, {
- propsData: {
- modelValue: addressModel,
- },
+ test("user sees noMatch warning and enters zip code => noMatch warning is removed", async () => {
+ // Arrange
+ const { wrapper } = setupMocks({});
+
+ wrapper.setData({
+ displayNoMatchWarning: true
});
- wrapper.vm.displayNoMatchWarning = true;
-
- // Act
- const newAddressModel = {
- streetAddress: "foo",
- city: "foo",
- state: "foo",
- zipCode: "55555",
- };
+ await wrapper.vm.$nextTick();
+
+ let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" });
+ expect(noMatchAlert.exists()).toBeTruthy();
+ expect(noMatchAlert.isVisible()).toBeTruthy();
// Act
- wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, newAddressModel);
+ wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, {
+ zipCode: "12345"
+ })
+ await wrapper.vm.$nextTick();
// 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 () => {
- // Arrange
- const wrapper = shallowMount(addressQuestions, {
- propsData: {
- modelValue: addressModel,
- },
- });
- wrapper.vm.displayNoMatchWarning = true;
-
- // Act
- const newAddressModel = {
- streetAddress: "foo",
- city: "foo",
- state: "foo",
- zipCode: "55555",
- };
+ const resultingMountOptions = getMountOptions({
+ ...mountOptions,
+ router: {
+ navigate: jest.fn(),
+ navigateAfterSave: jest.fn()
+ },
+ loadScript: jest.fn().mockResolvedValue()
+ });
- // Act
- wrapper.vm.setupAddressLookup();
+ window.google = {
+ maps: {
+ event: {
+ addListener: jest.fn().mockImplementation((element, eventName, callbackFunction) => {
+ function interceptedCallbackFunction(e) {
+ callbackFunction(e.detail);
+ }
+ // selectedPlace = "Woogly";
+ element.addEventListener(eventName, interceptedCallbackFunction);
+ }),
+ removeListener: jest.fn(),
+ clearInstanceListeners: jest.fn()
+ },
+ places: {
+ Autocomplete: jest.fn().mockImplementation((el) => el)
+ },
+ Geocoder: class Geocoder {
+ // constructor();
- // Assert
- expect(wrapper.vm.showAddressFields).toBe(true);
+ geocode(request, callback) {
+ callback([geocoderResult], true)
+ }
+ },
+ GeocoderStatus: {
+ OK: true
+ }
+ }
+ };
- });
+ if (props)
+ resultingMountOptions.propsData = props;
-})
\ No newline at end of file
+ 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 };
+}
\ No newline at end of file
diff --git a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue
index 61062ba47..d93c2559b 100644
--- a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue
+++ b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue
@@ -185,11 +185,10 @@ export default ({
},
methods: {
setupAddressLookup() {
-
- if (this.addressModel.streetAddress !== null &
- this.addressModel.city !== null &
- this.addressModel.state !== null &
- this.addressModel.zipCode !== null) {
+ if (this.addressModel.streetAddress &&
+ this.addressModel.city &&
+ this.addressModel.state &&
+ this.addressModel.zipCode) {
this.showAddressFields = true;
return;
@@ -228,10 +227,9 @@ export default ({
if (autocompleteResultsContainer) {
streetAddressField.appendChild(autocompleteResultsContainer);
}
-
})
- addressField1.onchange = function() {
+ addressField1.addEventListener("change", () => {
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 (hover === null) {
@@ -258,7 +256,7 @@ export default ({
self.displayNoMatchWarning = true;
}
}
- };
+ });
function fillInAddress(place) {
if (!place) {
@@ -310,7 +308,6 @@ export default ({
addressField1.onchange = null;
const pacContainer = document.querySelector(".pac-container");
pacContainer.remove();
-
}
})
.catch(() => {
@@ -325,16 +322,10 @@ export default ({
watch: {
addressModel: {
handler(newValue) {
- // The first time the address model changes is when the page first loads
- if (!newValue.city &&
- !newValue.state &&
- !newValue.zipCode) {
- return;
- }
-
- if (this.displayNoMatchWarning === true) {
+ // Clear no match warning on address change
+ if (newValue.city || newValue.state || newValue.zipCode) {
this.displayNoMatchWarning = false;
- }
+ }
},
deep: true
}
diff --git a/src/layouts/address-vehicles/address-vehicles.spec.js b/src/layouts/address-vehicles/address-vehicles.spec.js
index 90eeaecbe..0a89f214c 100644
--- a/src/layouts/address-vehicles/address-vehicles.spec.js
+++ b/src/layouts/address-vehicles/address-vehicles.spec.js
@@ -7,7 +7,6 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
-
// Mock our module for promises.
jest.mock("@/helpers/damage-helper", () => ({
isGlassAvailableForCarId: () => {
@@ -17,7 +16,6 @@ jest.mock("@/helpers/damage-helper", () => ({
describe("addressVehicles.vue", () => {
-
test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => {
// Arrange
const { wrapper } = setupMocks({});
@@ -225,40 +223,32 @@ describe("addressVehicles.vue", () => {
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
const { wrapper } = setupMocks({});
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
+ wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
// Act
wrapper.setData({
- selectedVehicleVin: ['5NMS3CADXLH233004'],
- isSelectedGlassAvailableForVehicle: true,
isCarIdDifferent: false,
});
await wrapper.vm.navigateForward();
//Assert
- expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toBeCalledTimes(1);
+ expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
wrapper.unmount();
});
-
});
-
-function setupMocks({
- // modelValueProp = "1900",
- cmsQuestionText = "CMS text goes here",
- // dataFromStoreApi = [],
-}) {
+function setupMocks({}) {
//Mock store
store.dispatch = jest.fn(() => {});
store.getters = {
pageData: jest.fn((pageName) => {
- // console.log('pageName: ', pageName) // address-vehicles
return [
{
vehicle: {
@@ -295,9 +285,6 @@ function setupMocks({
}
};
- // baseMixin.methods.dispatchStoreAction = jest.fn();
-
-
const mountOptions = getMountOptions({
store: {
dispatch: store.dispatch,
@@ -320,16 +307,6 @@ function setupMocks({
}
return null;
}),
- // dispatchStoreAction: jest.fn(() => {
- // console.log("23424243")
- // }),
- // isGlassAvailableForCarId: () => {
- // console.log("%%%%%%%%%%%%%%%")
- // return Promise.resolve(true)
- // }
-
- // lookupVin: jest.fn(() => Promise.resolve(lookupVinResponse)),
-
},
computed: {
dynamicStrings() {
@@ -337,18 +314,10 @@ function setupMocks({
}
}
}
- // mountOptions.propsData = {
- // modelValue: modelValueProp,
- // };
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(addressVehicles, mountOptions);
- //Mock CMS content
- const cmsContent = {
- QuestionText: cmsQuestionText,
- };
-
return { wrapper };
}
diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue
index faf71e1fb..db4000956 100644
--- a/src/layouts/address-vehicles/address-vehicles.vue
+++ b/src/layouts/address-vehicles/address-vehicles.vue
@@ -71,13 +71,15 @@ import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
import { doesCopyContainRouterLink,
splitCopyOnCMSPlaceHolder,
getRouterLinkRouteFromCopy,
- getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper"
+ getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper";
+import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES
defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED));
export default {
name: "address-vehicles",
+ mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@@ -188,8 +190,7 @@ export default {
);
return;
} else {
- this.$refs.loadingModal.showModal();
- navigateAfterSaveToHeritageFunnel(this.$route);
+ this.navigateForwardWithSingleCarMatch();
return;
}
},
diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js
new file mode 100644
index 000000000..5f82fa508
--- /dev/null
+++ b/src/layouts/estimate/estimate.spec.js
@@ -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 };
+
+}
\ No newline at end of file
diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
index 44ab645dd..d711fa8bb 100644
--- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
+++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
@@ -9,6 +9,7 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
+import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import store from "@/store";
@@ -223,7 +224,7 @@ describe("license-plate-lookup.vue", () => {
});
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
const { wrapper } = setupMocks({});
@@ -259,6 +260,38 @@ describe("license-plate-lookup.vue", () => {
//Assert
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();
})
- test("dispatch non blocking store action called on validate zip", async () => {
+ test("dispatchStoreAction called on validate zip", async () => {
// Arrange
const { wrapper } = setupMocks({});
@@ -497,7 +530,7 @@ describe("license-plate-lookup.vue", () => {
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
});
- test("dispatch non blocking store action called on lookup vin", async () => {
+ test("dispatchStoreAction called on lookup vin", async () => {
// Arrange
const { wrapper } = setupMocks({});
@@ -514,11 +547,8 @@ describe("license-plate-lookup.vue", () => {
function setupMocks({
pageHeaderWidgetHeaderText = {},
- mountOptionsMockData = {
- router: {
- navigate: jest.fn(),
- },
- },
+ mountOptionsMockData = {},
+ partsOrQuestions = []
}) {
store.commit(storeMutations.RESET_STATE);
//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);
settleAllPromises.mockImplementation(() => apiPromise);
diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue
index f3a5d3e83..b0360776c 100644
--- a/src/layouts/license-plate-lookup/license-plate-lookup.vue
+++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue
@@ -98,10 +98,10 @@ import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import { errorMessages } from "@/constants/error-messages";
-import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper";
import { required, regex, } from "@/helpers/validation-rules";
import { Form, defineRule, } from "vee-validate";
+import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES
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 {
name: "license-plate-lookup",
+ mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
@@ -297,8 +298,7 @@ export default {
);
return;
} else {
- this.$refs.loadingModal.showModal();
- navigateAfterSaveToHeritageFunnel(this.$route);
+ this.navigateForwardWithSingleCarMatch();
return;
}
},
@@ -312,7 +312,7 @@ export default {
},
updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) {
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_YEAR, vehicleInfo.year);
diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue
index e8c021954..36a7d6465 100644
--- a/src/layouts/part-questions/part-questions.vue
+++ b/src/layouts/part-questions/part-questions.vue
@@ -5,9 +5,7 @@