diff --git a/jest.config.js b/jest.config.js index c5309b45d..a73aac7ea 100644 --- a/jest.config.js +++ b/jest.config.js @@ -20,9 +20,8 @@ module.exports = { "!src/layouts/reveal/**/*.vue", "!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 850bd2fec..304fc2afd 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", - "test:unit": "vue-cli-service test:unit", + "test:unit": "vue-cli-service test:unit --coverage --ci", "test:unit:lite": "vue-cli-service test:unit --ci", "lint": "vue-cli-service lint" }, diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index f420a731b..b45394d64 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.CONTINUING_WITH_DIFFERENT_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(wrapper.vm.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"); @@ -778,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 e663db9be..ff276f54c 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -309,7 +309,6 @@ export default { // and one and only of them matches the car id entered const matchingCar = matchingCars[0]; this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle); - this.navigateForwardWithSingleCarMatch(); } else { // if there are no matches or there are multiple matches, navigate to "address-vehicles" page @@ -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-vehicles/address-vehicles.spec.js b/src/layouts/address-vehicles/address-vehicles.spec.js index 198b6e285..666ad41c1 100644 --- a/src/layouts/address-vehicles/address-vehicles.spec.js +++ b/src/layouts/address-vehicles/address-vehicles.spec.js @@ -245,9 +245,7 @@ describe("addressVehicles.vue", () => { }); }); -function setupMocks({ - cmsQuestionText = "CMS text goes here", -}) { +function setupMocks({}) { //Mock store store.dispatch = jest.fn(() => {}); store.getters = { @@ -296,7 +294,6 @@ function setupMocks({ router: { navigate: jest.fn(), }, - mixins: [vinPagesMixin] }); //Mock props @@ -323,10 +320,5 @@ function setupMocks({ const wrapper = shallowMount(addressVehicles, mountOptions); - //Mock CMS content - const cmsContent = { - QuestionText: cmsQuestionText, - }; - return { wrapper }; } 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 b9fc4bd8f..d711fa8bb 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js +++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js @@ -224,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({}); @@ -260,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); + }); }); }); @@ -534,7 +566,7 @@ function setupMocks({ }, }, }; - + mountOptionsMockData = { ...mountOptionsMockData, router: { @@ -548,7 +580,7 @@ function setupMocks({ } }, ] - } + } const apiPromise = Promise.resolve(apiResponses); diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index 8574b2505..d3f26380b 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -1,37 +1,38 @@ -import { shallowMount } from "@vue/test-utils"; +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" + commit: jest.fn(), + dispatch: jest.fn(), + getters: { + vehicle: { + year: 2019, + carId: 'initial carId' }, - customer: { - emailAddress: "builddigitaltest@safelite.com" + order: { + serviceLocation: { + zipCode: "45253" + }, + customer: { + emailAddress: "builddigitaltest@safelite.com" + } + }, + payment: { + insuranceCoverage: { + isVerified: true + } + }, + damage: { + glassToReplace: "windshield" } }, - payment: { - insuranceCoverage: { - isVerified: true - } - }, - damage: { - glassToReplace: "windshield" - } - }, })); -import { getDamageString, getIsWindshieldOnly,isGlassAvailableForCarId } from "@/helpers/damage-helper"; +import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper"; jest.mock("@/helpers/damage-helper", () => ({ isGlassAvailableForCarId: jest.fn(() => { @@ -45,21 +46,21 @@ jest.mock("@/helpers/damage-helper", () => ({ describe("vin-lookup.vue", () => { it("Should update the funnel-footer forward button when VIN is changed", (done) => { //Arrange - const { wrapper } = setupMocks({ }); + const { wrapper } = setupMocks({}); //Act - wrapper.setData({vin: "newValue"}); + 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(); + const { wrapper } = setupMocks({}); + wrapper.vm.navigateForward = jest.fn(); // Act await wrapper.vm.forwardButtonAction(); @@ -70,17 +71,17 @@ describe("vin-lookup.vue", () => { 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 { 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.navigateForward = jest.fn(); // Act await wrapper.vm.forwardButtonAction(); @@ -91,16 +92,16 @@ describe("vin-lookup.vue", () => { 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 { 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.navigateForward = jest.fn(); wrapper.vm.previouslyEnteredCarId = 'new carId'; @@ -113,7 +114,7 @@ describe("vin-lookup.vue", () => { it("Should not call navigateForward() if zip service returns a non-serviceable flag", async () => { // Arrange - const { wrapper } = setupMocks({ }); + const { wrapper } = setupMocks({}); const zipValidationApiResponse = { data: { isServiceable: false @@ -121,9 +122,9 @@ describe("vin-lookup.vue", () => { }; const zipPromise = Promise.resolve(zipValidationApiResponse); - + wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise); - wrapper.vm.navigateForward = jest.fn(); + wrapper.vm.navigateForward = jest.fn(); wrapper.vm.previouslyEnteredCarId = 'new carId'; @@ -136,16 +137,16 @@ describe("vin-lookup.vue", () => { it("Should not call navigateForward() when forward button is clicked but lookupVehicle errors out.", async () => { // Arrange - const { wrapper } = setupMocks({ }); + 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.navigateForward = jest.fn(); wrapper.vm.previouslyEnteredCarId = 'new carId'; @@ -155,19 +156,75 @@ describe("vin-lookup.vue", () => { //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.CONTINUING_WITH_DIFFERENT_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({}); + const mountOptions = getMountOptions({ + ...customMountOptions + }); - const finalMountOptions = Object.assign(mountOptions, customMountOptions); // Modify/augment default mount options - finalMountOptions.global.mocks["$store"] = store; - finalMountOptions.global.mixins = [mockMixin]; - finalMountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods + 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, finalMountOptions); + const wrapper = shallowMount(vinLookup, mountOptions); mockOutPromises(wrapper); mockOutStubFunctions(wrapper); return { wrapper }; @@ -183,8 +240,8 @@ function mockOutPromises(wrapper) { data: { carId: 'initial carId' } - }; - + }; + const zipPromise = Promise.resolve(zipValidationApiResponse); const vinPromise = Promise.resolve(vehicleLookupApiResponse); @@ -197,8 +254,8 @@ function mockOutStubFunctions(wrapper) { wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); } - const mockMixin = { +const mockMixin = { methods: { - getCmsContent: jest.fn(() => "placeholder CMS content"), + getCmsContent: jest.fn(() => "placeholder CMS content"), } - } \ No newline at end of file +} \ No newline at end of file