diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c8184f93f..3819fca35 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -26,7 +26,7 @@ resources: type: github name: Safelite/AzureDevOps endpoint: Safelite - ref: refs/tags/t5.4.0 + ref: refs/tags/t5.5.19 variables: - group: Digital-Infrastructure @@ -67,9 +67,10 @@ stages: - template: templates/digital/step-build-vue.yml@AzureDevOps parameters: buildOutputDir: dist + environment: Dev - template: templates/digital/step-deploy-vue.yml@AzureDevOps parameters: - artifactName: vueDist + artifactName: vueDistDev awsProfile: $(devDeploymentProfile) outputPath: /fmg/ deployBuckets: @@ -109,9 +110,10 @@ stages: - template: templates/digital/step-build-vue.yml@AzureDevOps parameters: buildOutputDir: dist + environment: Qa - template: templates/digital/step-deploy-vue.yml@AzureDevOps parameters: - artifactName: vueDist + artifactName: vueDistQa awsProfile: $(qaDeploymentProfile) outputPath: /fmg/ deployBuckets: @@ -150,9 +152,10 @@ stages: - template: templates/digital/step-build-vue.yml@AzureDevOps parameters: buildOutputDir: dist + environment: Prod - template: templates/digital/step-deploy-vue.yml@AzureDevOps parameters: - artifactName: vueDist + artifactName: vueDistProd awsProfile: $(prodDeploymentProfile) outputPath: /fmg/ deployBuckets: @@ -168,4 +171,11 @@ stages: indexDeployVariables: __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) - cfDistributionId: $(cfDistributionId) \ No newline at end of file + cfDistributionId: $(cfDistributionId) + - stage: AutoTagReleaseBuild + displayName: Auto Tag Release Build For Production + jobs: + - template: templates/digital/auto-tag.yml@AzureDevOps + parameters: + userName: SafeliteAzureDevops + userEmail: githubazuredevops@safelite.com \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index e8d3abcc9..0dd06d9be 100644 --- a/jest.config.js +++ b/jest.config.js @@ -23,10 +23,9 @@ module.exports = { "!src/layouts/address-lookup/address-lookup.vue", "!src/layouts/address-lookup/customer-questions/customer-questions.vue", "!src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue", - "!src/common-components/dropdown-question/dropdown-question.vue", - "!src/common-components/textbox-question/textbox-question.vue", "!src/ux-components/alert\alert.vue", "!src/helpers/validation-rules.js", + "!src/common-components/menu-modal/menu-modal.vue", // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], diff --git a/src/common-components/dropdown-question/dropdown-question.spec.js b/src/common-components/dropdown-question/dropdown-question.spec.js new file mode 100644 index 000000000..381f34890 --- /dev/null +++ b/src/common-components/dropdown-question/dropdown-question.spec.js @@ -0,0 +1,170 @@ +import { shallowMount } from "@vue/test-utils"; +import dropdownQuestion from "./dropdown-question"; + +// Mock CMS content +const questionText = "Question Text"; +const mockMixin = { + methods: { + getCmsContent: jest.fn().mockImplementation(()=> { + return questionText; + }) + } +} + +// TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''" +// It is not being used. +describe("dropdownQuestion.vue", () => { + + it("Should render a select input", async () => { + + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + wrapper.getCmsContent = jest.fn(); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.exists()).toBe(true); + + }); + + it("Should render the 'questionText' data value as the label text.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.text()).toContain(questionText); + + }); + + it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + disableAutoFill: true, + }, + mixins: [mockMixin] + }); + + // Mock CMS content ... + // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it + // Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools, + // you will see "Q⁠uestion T⁠ext" + const expectedQuestionText = "Q⁠uestion T⁠ext"; + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.text()).toContain(expectedQuestionText); + + }); + + it("Should return input id as the id of the select field", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + inputId: "input ID", + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.attributes().id).toEqual("input ID"); + + }); + + it("Should render the 'questionText' data value as the aria-label attribute.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.attributes("aria-label")).toContain(questionText); + + }); + + it("Should return aria-disabled state as disabled", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + isDisabled: true, + }, + mixins: [mockMixin] + }); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.attributes("aria-disabled")).toEqual("true"); + + }); + + it("Should emit new value when modelValue is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: "val", + }, + mixins: [mockMixin] + }); + + // Act + await wrapper.find("select").setValue("val2"); + + // Assert + expect(wrapper.emitted()).toHaveProperty('change') + + }); + + it("Should call this.handleChange with new value when selectedOption is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: 0, + }, + mixins: [mockMixin] + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + + // Act + wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1); + + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalled; + + }); + +}); diff --git a/src/common-components/dropdown-question/dropdown-question.spec.js1 b/src/common-components/dropdown-question/dropdown-question.spec.js1 deleted file mode 100644 index 81669f714..000000000 --- a/src/common-components/dropdown-question/dropdown-question.spec.js1 +++ /dev/null @@ -1,131 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import dropdownQuestion from "./dropdown-question"; -import { nextTick } from "vue"; -import { maska } from 'maska'; - -describe("dropdownQuestion.vue", () => { - - it("Should return aria-disabled state", async () => { - // Act - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - isDisabled: true, - }, - }); - - // Assert - const input = wrapper.find("select"); - - // Expect - expect(input.attributes()["aria-disabled"]).toEqual("true"); - }); - - it("Should render a select input", async () => { - // Act - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - name: "test", - label: "unit test label", - }, - }); - - // Assert - const input = wrapper.find("select"); - - expect(input.exists()).toBe(true); - }); - - it("Should return input id", async () => { - // Act - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - inputId: "input ID", - }, - }); - - // Assert - const input = wrapper.find("select"); - - // Expect - expect(input.attributes().id).toEqual("input ID"); - }); - - it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => { - // Arrange - //Mock CMS content - const questionText = "Question Text"; - const cmsContent = { - QuestionText: questionText, - }; - - // Act - const wrapper = shallowMount(dropdownQuestion, { - global: { - directives: { - maska: maska, - } - }, - }); - await wrapper.setData({ - questionText: questionText, - }); - wrapper.vm.initializeComponent(cmsContent); - - // Assert - expect(wrapper.find("label").text()).toContain(questionText); - wrapper.unmount(); - }); - - it("Should render the 'questionText' data value with '⁠' after the first character as the label text when disableAutoFill is true.", async () => { - // Arrange - //Mock CMS content - const originalQuestionText = "Question Text"; - // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it - // Don't believe me? Copy it and paste it into Google. Then inspect the search field element in Dev Tools, - // you will see "Q&uestion Text" - const expectedQuestionText = "Q⁠uestion Text"; - const cmsContent = { - QuestionText: originalQuestionText, - }; - - // Act - const wrapper = shallowMount(dropdownQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - disableAutoFill: true, - }, - }); - await wrapper.setData({ - questionText: originalQuestionText, - }); - wrapper.vm.initializeComponent(cmsContent); - - // Assert - expect(wrapper.vm.$el.children[0].innerHTML).toBe(expectedQuestionText); - wrapper.unmount(); - }); - - it("Should emit new value when modelValue is changed", async () => { - // Act - const wrapper = shallowMount(dropdownQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - modelValue: "val", - }, - }); - - await wrapper.find("select").setValue("val2"); - - // Assert - expect(wrapper.emitted()).toHaveProperty('change') - - }); -}); diff --git a/src/common-components/funnel-footer/funnel-footer.spec.js b/src/common-components/funnel-footer/funnel-footer.spec.js index 198fa5657..d246b602b 100644 --- a/src/common-components/funnel-footer/funnel-footer.spec.js +++ b/src/common-components/funnel-footer/funnel-footer.spec.js @@ -3,30 +3,6 @@ import funnelFooter from "./funnel-footer"; describe("funnel-footer.vue", () => { - it("Should return footer-link class", async () => { - // Act - const r = { - test:"testing", - clientHeight: 10, - offsetHeight: 24, - }; - - global.document.querySelector = jest.fn().mockImplementation(()=> { - return r; - }); - - const wrapper = mount(funnelFooter, { - mixins: [mockMixin] - }); - - // Assert - const link = wrapper.find("a"); - - // Expect - expect(link.attributes('class')).toContain("footer"); - - }); - it("Should emit ForwardClicked on button click", async () => { // Act const wrapper = mount(funnelFooter, { @@ -53,7 +29,7 @@ describe("funnel-footer.vue", () => { mixins: [mockMixin] }); wrapper.vm.updateButtonText('newText'); - + // Assert expect(wrapper.componentVM.customButtontext).toBe('newText'); }); @@ -65,4 +41,4 @@ const mockMixin = { getCmsContent: jest.fn(), getFooterInfoBoxHeight: jest.fn(()=>80) } -} \ No newline at end of file +} diff --git a/src/common-components/funnel-footer/funnel-footer.vue b/src/common-components/funnel-footer/funnel-footer.vue index 27ee88cb3..ab4796325 100644 --- a/src/common-components/funnel-footer/funnel-footer.vue +++ b/src/common-components/funnel-footer/funnel-footer.vue @@ -1,21 +1,6 @@ - - diff --git a/src/common-components/menu-button/menu-button.spec.js b/src/common-components/menu-modal/menu-modal.spec.js similarity index 100% rename from src/common-components/menu-button/menu-button.spec.js rename to src/common-components/menu-modal/menu-modal.spec.js diff --git a/src/common-components/menu-modal/menu-modal.vue b/src/common-components/menu-modal/menu-modal.vue new file mode 100644 index 000000000..de26738f0 --- /dev/null +++ b/src/common-components/menu-modal/menu-modal.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/common-components/textbox-question/textbox-question.spec.js1 b/src/common-components/textbox-question/textbox-question.spec.js similarity index 55% rename from src/common-components/textbox-question/textbox-question.spec.js1 rename to src/common-components/textbox-question/textbox-question.spec.js index 63214c126..09f929490 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js1 +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -1,139 +1,61 @@ import { shallowMount } from "@vue/test-utils"; import textboxQuestion from "./textbox-question"; -import { maska } from 'maska'; + +// Mock CMS content +const questionText = "Question Text"; +const mockMixin = { + methods: { + getCmsContent: jest.fn().mockImplementation(()=> { + return questionText; + }) + } +} +const maska = jest.fn(); describe("textboxQuestion.vue", () => { - it("Should return aria-disabled state", async () => { - // Act - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - isDisabled: true, - }, - }); - - // Assert - const input = wrapper.find("input"); - - // Expect - expect(input.attributes()["aria-disabled"]).toEqual("true"); - - }); - it("Should render a text input", async () => { - // Act + // Arrange const wrapper = shallowMount(textboxQuestion, { global: { directives: { maska: maska, } }, - propsData: { - name: "test", - label: "unit test label", - }, + mixins: [mockMixin] }); - // Assert + wrapper.getCmsContent = jest.fn(); + + // Act const input = wrapper.find("input"); + // Assert expect(input.exists()).toBe(true); }); - it("Should return input id", async () => { - // Act - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - inputId: "input ID", - }, - }); - - // Assert - const input = wrapper.find("input"); - - // Expect - expect(input.attributes().id).toEqual("input ID"); - - }); - - it("Should render the 'questionText' data value as the aria-label attribute.", async () => { - // Arrange - //Mock CMS content - const questionText = "Question Text"; - const cmsContent = { - QuestionText: questionText, - }; - - // Act - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - }); - await wrapper.setData({ - questionText: questionText, - }); - wrapper.vm.initializeComponent(cmsContent); - - // Assert - expect(wrapper.find("label").attributes('aria-label')).toBe(questionText); - wrapper.unmount(); - - }); - it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => { // Arrange - //Mock CMS content - const questionText = "Question Text"; - const cmsContent = { - QuestionText: questionText, - }; - - // Act const wrapper = shallowMount(textboxQuestion, { global: { directives: { maska: maska, } }, + mixins: [mockMixin] }); - await wrapper.setData({ - questionText: questionText, - }); - wrapper.vm.initializeComponent(cmsContent); - - // Assert - expect(wrapper.find("label").text()).toContain(questionText); - wrapper.unmount(); - - }); - - it("Should render the 'questionText' data value with '⁠' after the first character as the label text when disableAutoFill is true.", async () => { - // Arrange - //Mock CMS content - const originalQuestionText = "Question Text"; - // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it - // Don't believe me? Copy it and paste it into Google. Then inspect the search field element in Dev Tools, - // you will see "Q&uestion Text" - const expectedQuestionText = "Q⁠uestion Text"; - const cmsContent = { - QuestionText: originalQuestionText, - }; // Act + const label = wrapper.find("label"); + + // Assert + expect(label.text()).toContain(questionText); + + }); + + it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => { + // Arrange const wrapper = shallowMount(textboxQuestion, { global: { directives: { @@ -143,15 +65,84 @@ describe("textboxQuestion.vue", () => { propsData: { disableAutoFill: true, }, + mixins: [mockMixin] }); - await wrapper.setData({ - questionText: originalQuestionText, - }); - wrapper.vm.initializeComponent(cmsContent); + + // Mock CMS content ... + // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it + // Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools, + // you will see "Q⁠uestion T⁠ext" + const expectedQuestionText = "Q⁠uestion T⁠ext"; + + // Act + const label = wrapper.find("label"); // Assert - expect(wrapper.vm.$el.children[0].innerHTML).toBe(expectedQuestionText); - wrapper.unmount(); + expect(label.text()).toContain(expectedQuestionText); + + }); + + it("Should return input id as the id of the input field", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + } + }, + propsData: { + inputId: "input ID", + }, + mixins: [mockMixin] + }); + + // Act + const input = wrapper.find("input"); + + // Assert + expect(input.attributes().id).toEqual("input ID"); + + }); + + it("Should render the 'questionText' data value as the aria-label attribute.", async () => { + + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + } + }, + mixins: [mockMixin] + }); + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.attributes("aria-label")).toContain(questionText); + + }); + + it("Should return aria-disabled state as disabled", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + } + }, + propsData: { + isDisabled: true, + }, + mixins: [mockMixin] + }); + + // Assert + const input = wrapper.find("input"); + + // Expect + expect(input.attributes("aria-disabled")).toEqual("true"); }); @@ -166,6 +157,7 @@ describe("textboxQuestion.vue", () => { propsData: { modelValue: "val", }, + mixins: [mockMixin] }); await wrapper.find("input").setValue("val2"); @@ -175,4 +167,33 @@ describe("textboxQuestion.vue", () => { }); + it("Should call this.handleChange with new value when this.semiAggressiveValidation = true, the value is changed, and the new value is valid", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + } + }, + propsData: { + options: {}, + modelValue: "foo", + semiAggressiveValidation: true, + }, + mixins: [mockMixin] + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + wrapper.vm.validate = jest.fn().mockImplementation(() => { + return true; + }); + + // Act + wrapper.vm.$options.watch.value.call(wrapper.vm, "bar"); + + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalled; + + }); + }); diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 059693773..7ff9e3cec 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -79,6 +79,10 @@ const endpoints = { url: "/analytics/api/v1/analytics/log-custom-event", method: "POST", }, + InitializeSession:{ + url: "/analytics/api/v1/analytics/initialize", + method: "POST", + }, GetExperimentsByUser: { url: "/analytics/api/v1/analytics/get-experiments", method: "GET", diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index fe658fbe1..0ac79ac28 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -21,6 +21,7 @@ const storeActions = { LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure", LOG_PAGE_VIEW: "logPageView", LOG_CUSTOM_EVENT: "logCustomEvent", + INITIALIZE_SESSION: "initializeSession", GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser", UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION: "updateServiceLocationWithVehicleRegistration", diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js index f3b730f90..5d681f17f 100644 --- a/src/helpers/heritage-integration/cookie-helper.js +++ b/src/helpers/heritage-integration/cookie-helper.js @@ -104,6 +104,14 @@ export function getSessionIdValue(){ return '00000000-0000-0000-0000-000000000000'; } +export function setCookieProperties(properties) { + if (typeof properties == "object") { + Object.keys(properties).forEach(key => { + document.cookie = `${key}=${properties[key]}`; + }); + } +} + /* =========================== = PRIVATE FUNCTIONS = diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index d64ab865d..962550592 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -11,8 +11,8 @@ import baseMixin from "@/mixins/base-mixin"; export async function loadOrderIfPresent() { const funnelCookie = getFunnelCookie(); - // Do nothing if there is no cookie or no correlation id. - if (funnelCookie == null || funnelCookie.ReferralCorrelationId == null) { + // Do nothing if there is no cookie, correlation id, or referral number. + if (funnelCookie == null || funnelCookie.ReferralCorrelationId == null || !funnelCookie.ReferralNumber) { return null; } diff --git a/src/helpers/heritage-integration/order-helper.spec.js b/src/helpers/heritage-integration/order-helper.spec.js index b66286d50..7d769a8d8 100644 --- a/src/helpers/heritage-integration/order-helper.spec.js +++ b/src/helpers/heritage-integration/order-helper.spec.js @@ -18,7 +18,8 @@ describe("loadOrderIfPresent", () => { const testCookieValue = { ShouldResetState: testShouldResetState, - ReferralCorrelationId: "xxx" + ReferralCorrelationId: "xxx", + ReferralNumber: "12345" } document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify(testCookieValue)}; path=/; ${cookieHelper.getCookieDomainValue()}`; @@ -33,7 +34,11 @@ describe("loadOrderIfPresent", () => { test("ShouldResetState == true => reset store", () => { // Arrange - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce({ ShouldResetState: true, ReferralCorrelationId: "xxx-xxx-xxx" }); + cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce({ + ShouldResetState: true, + ReferralCorrelationId: "xxx-xxx-xxx", + ReferralNumber: "12345" + }); const mockData = { actionList: [{ diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 4f4214120..07632f5e5 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -24,14 +24,13 @@ export function getMountOptions(mockData) { mocks.logEvent = jest.fn(); mocks.pushExperimentsToDataLayer = jest.fn(); mocks.prependActionToMethod = jest.fn(); - mocks.dispatchStoreAction = jest.fn(); mocks.dispatchStoreAction.mockImplementation((actionName) => { let actionFilterResult = mockData.actionList.filter( (x) => x.actionName == actionName ); - if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { + if (actionFilterResult.length === 1) { return Promise.resolve({ data: actionFilterResult[0].data, }); diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js new file mode 100644 index 000000000..a80b07415 --- /dev/null +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -0,0 +1,504 @@ +// Components +import addressLookup from "@/layouts/address-lookup/address-lookup.vue"; +import funnelHeader from "@/common-components/funnel-header/funnel-header"; +import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; +import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; +import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; +import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; +import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; +import router from "@/router"; + +// Supporting Files +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import baseMixin from "@/mixins/base-mixin"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { mount, flushPromises, shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { maska } from 'maska'; +import { nextTick } from "vue"; +import { storeActions } from "@/constants/store-actions"; +import { storeMutations } from "@/constants/store-mutations"; +import store from "@/store"; +import { validate } from "vee-validate"; +import { isGlassAvailableForCarId } from "@/helpers/damage-helper.js" +import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { EXPECTATION_FAILED } from "http-status-codes"; + +// 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(), +// })); + +jest.mock("@/helpers/damage-helper", () => ({ + isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), + getDamageString: jest.fn() +})); + +jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ + navigateAfterSaveToHeritageFunnel: jest.fn() +})); + + +// const questionText = "Question Text"; +// const mockMixin = { +// methods: { +// getCmsContent: jest.fn().mockImplementation(() => { +// return questionText; +// }) +// } +// } + +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 () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup,{ + isZipServiceable: true + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); + }); + }); + + describe("if registration zip is not serviceable", () => { + test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(false); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(true); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true); + }); + + test("if registration address is provided user clicks continue => show service zip field on continue click", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + } + ); + + expect(wrapper.vm.showServiceZipField).toBeFalsy(); + expect(wrapper.findComponent({ ref: "serviceZip" }).exists()).toBe(false); + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.showServiceZipField).toBe(true); + expect(wrapper.findComponent({ ref: "serviceZip" }).isVisible()).toBe(true); + }); + + test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, { + isZipServiceable: false + } + ); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); + }); + + test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215" + } + + const { wrapper } = setupMocks(addressLookup, {}); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + baseMixin.methods.dispatchStoreAction = jest.fn(); + baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => { + let data = {}; + if (actionName == storeActions.VALIDATE_ZIP) { + if (value == "43215") { + data = { + isServiceable: false + }; + } + else { + data = { + isServiceable: true + } + } + } + else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) { + data = { + isStatePermissible: true, + vinVehicles: [{ + vin: "TEST_VIN", + vehicle: { + carId: "CARID" + } + }] + } + } + + return Promise.resolve({ data }); + }) + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress + } + }) + await wrapper.vm.forwardButtonAction(); + await wrapper.setData({ + serviceZipCode: "12345" + }) + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode); + expect(store.getters.vehicle.registration.zipCode).toEqual("43215"); + expect(store.getters.order.serviceLocation.zipCode).toEqual("12345"); + }); + }); + }); + + describe.skip("initialization", () => { + test("Page header is initialized with api data", async (done) => { + //Arrange + const pageHeaderWidgetHeaderText = "Select Damage"; + const { wrapper, apiPromise } = setupMocks({ + pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText, + }); + + //Act + addressLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "address-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith( + pageHeaderWidgetHeaderText + ); + done(); + }); + }); + + test("Customer Questions component is initialized with api data", async (done) => { + //Arrange + const StreetAddressQuestionWidget = { QuestionText: "test" }; + const CityQuestionWidget = { QuestionText: "test" }; + const StateQuestionWidget = { QuestionText: "test" }; + const ZipQuestionWidget = { QuestionText: "test" }; + const FirstNameQuestionWidget = { QuestionText: "test" }; + const LastNameQuestionWidget = { QuestionText: "test" }; + const EmailAddressQuestionWidget = { QuestionText: "test" }; + const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" }; + const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" }; + + const widgets = [ + StreetAddressQuestionWidget, + CityQuestionWidget, + StateQuestionWidget, + ZipQuestionWidget, + AlertVerificationWarningWidget, + AlertNoMatchWarningWidget, + FirstNameQuestionWidget, + LastNameQuestionWidget, + EmailAddressQuestionWidget, + ]; + + const { wrapper, apiPromise } = setupMocks({ + cmsContent: widgets, + }); + + //Act + addressLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "address-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith( + widgets + ); + done(); + }); + }); + }); +}); + +function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) { + store.commit(storeMutations.RESET_STATE); + const wrapper = shallowMount(addressLookup, getMountOptions({ + ...mountOptions, + actionList: [ + { + actionName: storeActions.VALIDATE_ZIP, + data: { + isServiceable: isZipServiceable + } + }, + { + actionName: storeActions.LOOKUP_VIN_BY_ADDRESS, + data: lookupVinbyAddressResponse ? lookupVinbyAddressResponse : { + isStatePermissible: true, + vinVehicles: [{ + vin: "TEST_VIN", + vehicle: { + carId: "CARID" + } + }] + } + } + ], + router: { + navigate: jest.fn(), + navigateAfterSave: jest.fn() + }, + })); + + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); + + // jest.mock("@/store", () => ({ + // commit: jest.fn(), + // dispatch: jest.fn(), + // getters: { + // vehicle: { + // carId: "CARID" + // } + // }, + // })); + + return { wrapper }; +} + +// function setupMocks({ +// pageHeaderWidgetHeaderText = {}, +// mountOptionsMockData = { +// router: { +// navigate: jest.fn(), +// }, +// store: { +// getters: { +// vehicle: {}, +// }, +// }, +// }, +// }) { +// //Mock api responses +// baseMixin.methods.dispatchStoreAction = jest.fn(); +// const apiResponses = { +// cmsContent: { +// FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, +// VehicleBannerWidget: { +// GenericVehicleImage: +// "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", +// }, +// FunnelHeaderWidget: { +// LogoImage: +// "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", +// }, +// StreetAddressQuestionWidget: { +// QuestionText: +// "test" +// }, +// CityQuestionWidget: { +// QuestionText: +// "test" +// }, +// StateQuestionWidget: { +// QuestionText: +// "test" +// }, +// ZipQuestionWidget: { +// QuestionText: +// "test" +// }, +// FirstNameQuestionWidget: { +// QuestionText: +// "test" +// }, +// LastNameQuestionWidget: { +// QuestionText: +// "test" +// }, +// EmailAddressQuestionWidget: { +// QuestionText: +// "test" +// }, +// AlertVerificationWarningWidget: { +// HeaderText: +// "test", +// BodyText: +// "test", +// }, +// AlertNoMatchWarningWidget: { +// HeaderText: +// "test", +// BodyText: +// "test", +// }, + +// }, +// }; + +// const apiPromise = Promise.resolve(apiResponses); + +// settleAllPromises.mockImplementation(() => apiPromise); +// fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + +// //Mock damage initialize methods +// funnelHeader.methods = { +// initializeComponent: jest.fn(), +// }; + +// vehicleBanner.methods = { +// initializeComponent: jest.fn(), +// }; + +// funnelSubHeader.methods = { +// initializeComponent: jest.fn(), +// }; + +// funnelFooter.methods = { +// initializeComponent: jest.fn(), +// }; + +// customerQuestions.methods = { +// initializeComponent: jest.fn(), +// }; + +// addressQuestions.methods = { +// initializeComponent: jest.fn(), +// setupAddressLookup: jest.fn(), +// }; + +// const mountOptions = getMountOptions(mountOptionsMockData); +// mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods + +// mountOptions.global.directives = { +// maska: maska +// }; + +// const wrapper = mount(addressLookup, mountOptions); + +// const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); +// funnelHeaderWrapper.vm.initializeComponent = +// funnelHeader.methods.initializeComponent; + +// const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); +// vehicleBannerWrapper.vm.initializeComponent = +// vehicleBanner.methods.initializeComponent; + +// const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" }); +// funnelSubHeaderWrapper.vm.initializeComponent = +// funnelSubHeader.methods.initializeComponent; + +// const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" }); +// funnelFooterWrapper.vm.initializeComponent = +// funnelFooter.methods.initializeComponent; + +// const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" }); +// customerQuestionsWrapper.vm.initializeComponent = +// customerQuestions.methods.initializeComponent; + +// const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" }); +// addressQuestionsWrapper.vm.initializeComponent = +// addressQuestions.methods.initializeComponent; +// addressQuestionsWrapper.vm.setupAddressLookup = +// addressQuestions.methods.setupAddressLookup; + +// return { wrapper, apiPromise }; +// } \ No newline at end of file diff --git a/src/layouts/address-lookup/address-lookup.spec.js1 b/src/layouts/address-lookup/address-lookup.spec.js1 deleted file mode 100644 index 4443100c3..000000000 --- a/src/layouts/address-lookup/address-lookup.spec.js1 +++ /dev/null @@ -1,244 +0,0 @@ -// Components -import addressLookup from "@/layouts/address-lookup/address-lookup.vue"; -import funnelHeader from "@/common-components/funnel-header/funnel-header"; -import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; -import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; -import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; -import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; -import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; - -// Supporting Files -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import baseMixin from "@/mixins/base-mixin"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import { mount, flushPromises } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { maska } from 'maska'; -import { nextTick } from "vue"; -import { storeActions } from "@/constants/store-actions"; -import { storeMutations } from "@/constants/store-mutations"; -import store from "@/store"; -import { validate } from "vee-validate"; - -// 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("address-lookup.vue", () => { - test("Page header is initialized with api data", async (done) => { - //Arrange - const pageHeaderWidgetHeaderText = "Select Damage"; - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText, - }); - - //Act - addressLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "address-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith( - pageHeaderWidgetHeaderText - ); - done(); - }); - }); - - test("Customer Questions component is initialized with api data", async (done) => { - //Arrange - const StreetAddressQuestionWidget = { QuestionText: "test" }; - const CityQuestionWidget = { QuestionText: "test" }; - const StateQuestionWidget = { QuestionText: "test" }; - const ZipQuestionWidget = { QuestionText: "test" }; - const FirstNameQuestionWidget = { QuestionText: "test" }; - const LastNameQuestionWidget = { QuestionText: "test" }; - const EmailAddressQuestionWidget = { QuestionText: "test" }; - const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" }; - const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" }; - - const widgets = [ - StreetAddressQuestionWidget, - CityQuestionWidget, - StateQuestionWidget, - ZipQuestionWidget, - AlertVerificationWarningWidget, - AlertNoMatchWarningWidget, - FirstNameQuestionWidget, - LastNameQuestionWidget, - EmailAddressQuestionWidget, - ]; - - const { wrapper, apiPromise } = setupMocks({ - cmsContent: widgets, - }); - - //Act - addressLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "address-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith( - widgets - ); - done(); - }); - }); - - }); - - - - function setupMocks({ - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = { - router: { - navigate: jest.fn(), - }, - store: { - getters: { - vehicle: {}, - }, - }, - }, - }) { - //Mock api responses - baseMixin.methods.dispatchStoreAction = jest.fn(); - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - StreetAddressQuestionWidget: { - QuestionText: - "test" - }, - CityQuestionWidget: { - QuestionText: - "test" - }, - StateQuestionWidget: { - QuestionText: - "test" - }, - ZipQuestionWidget: { - QuestionText: - "test" - }, - FirstNameQuestionWidget: { - QuestionText: - "test" - }, - LastNameQuestionWidget: { - QuestionText: - "test" - }, - EmailAddressQuestionWidget: { - QuestionText: - "test" - }, - AlertVerificationWarningWidget: { - HeaderText: - "test", - BodyText: - "test", - }, - AlertNoMatchWarningWidget: { - HeaderText: - "test", - BodyText: - "test", - }, - - }, - }; - - const apiPromise = Promise.resolve(apiResponses); - - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - - //Mock damage initialize methods - funnelHeader.methods = { - initializeComponent: jest.fn(), - }; - - vehicleBanner.methods = { - initializeComponent: jest.fn(), - }; - - funnelSubHeader.methods = { - initializeComponent: jest.fn(), - }; - - funnelFooter.methods = { - initializeComponent: jest.fn(), - }; - - customerQuestions.methods = { - initializeComponent: jest.fn(), - }; - - addressQuestions.methods = { - initializeComponent: jest.fn(), - setupAddressLookup: jest.fn(), - }; - - const mountOptions = getMountOptions(mountOptionsMockData); - mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods - - mountOptions.global.directives = { - maska: maska - }; - - const wrapper = mount(addressLookup, mountOptions); - - const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); - funnelHeaderWrapper.vm.initializeComponent = - funnelHeader.methods.initializeComponent; - - const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); - vehicleBannerWrapper.vm.initializeComponent = - vehicleBanner.methods.initializeComponent; - - const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" }); - funnelSubHeaderWrapper.vm.initializeComponent = - funnelSubHeader.methods.initializeComponent; - - const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" }); - funnelFooterWrapper.vm.initializeComponent = - funnelFooter.methods.initializeComponent; - - const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" }); - customerQuestionsWrapper.vm.initializeComponent = - customerQuestions.methods.initializeComponent; - - const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" }); - addressQuestionsWrapper.vm.initializeComponent = - addressQuestions.methods.initializeComponent; - addressQuestionsWrapper.vm.setupAddressLookup = - addressQuestions.methods.setupAddressLookup; - - return { wrapper, apiPromise }; - } \ No newline at end of file diff --git a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js1 b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js1 deleted file mode 100644 index 05fd2a0eb..000000000 --- a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js1 +++ /dev/null @@ -1,113 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -// import store from "@/store"; - -// jest.mock("@/store", () => { return {}; }, { virtual: true }); - -describe("addressVehiclesQuestion.vue", () => { - - it("Should include button-question component", () => { - // Arrange - const wrapper = shallowMount(addressVehiclesQuestion, { - propsData: { - // vehicles: [ - // { - // "Name": "testname", - // "Text": "testtext", - // } - // ] - } - }); - - // console.log('wrapper.html: ', wrapper.html()); - - // Assert - const buttonQuestion = wrapper.find('button-question-stub'); - expect(buttonQuestion).toBe; - }); - - it("on initialize should pass in questionText", () => { - // Arrange - const wrapper = shallowMount(addressVehiclesQuestion, { - propsData: {}, - }); - - //Act - addressVehiclesQuestion.methods.initializeComponent.call(wrapper.vm, {QuestionText: 'Testing question text'}); - - // console.log('wrapper.html: ', wrapper.html()); - // console.log('wrapper.vm.questionText: ', wrapper.vm.questionText); - - // Assert - expect(wrapper.vm.questionText).toEqual('Testing question text'); - }); - - // it("Alert should show if prop isCarIdDifferent is true", () => { - // // Arrange - // const wrapper = shallowMount(addressVehiclesQuestion, setupMountOptions({ - // propsData: { - // isCarIdDifferent: true, - // } - // })); - - // //Act - // const alert = wrapper.find('alert'); - // console.log('wrapper.html: ', wrapper.html()); - // console.log('wrapper.vm.questionText: ', wrapper.vm.questionText); - - // // Assert - // // expect(wrapper.vm.questionText).toEqual('Testing question text'); - // }); - -}); - - - -function setupMountOptions(mountOptionsMockData = {}) { - // //Mock store - // store.dispatch = jest.fn(() => {}); - // store.getters = {}; - - // const mockMixin = { - // methods: { - // getCmsContent: jest.fn().mockImplementation(() => { - // return ''; - // }), - // getDamageString: jest.fn().mockImplementation(() => { - // return ''; - // }) - // }, - // store: { - // dispatch: store.dispatch, - // getters: store.getters, - // }, - // } - - const mockGetCmsContent = jest.fn(); - mockGetCmsContent((cmsWidget, field) => { - return field - }); - const defaultMountOptions = { - // route: { query: { fmgPage: 'page-name' } }, - mixins: { - methods: { - getCmsContent: mockGetCmsContent, - }, - }, - global: { - mocks: { - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }, - }, - }; - const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData)); - const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); - - console.log('what are allMountOptions??? ', allMountOptions); - - return allMountOptions; -} \ No newline at end of file diff --git a/src/layouts/address-vehicles/address-vehicles.spec.js1 b/src/layouts/address-vehicles/address-vehicles.spec.js1 deleted file mode 100644 index f4dab360c..000000000 --- a/src/layouts/address-vehicles/address-vehicles.spec.js1 +++ /dev/null @@ -1,26 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import addressVehicles from "@/layouts/address-vehicles/address-vehicles"; - -describe("addressVehicles.vue", () => { - - it("Should include address-vehicles-question component", () => { - // Arrange - const wrapper = shallowMount(addressVehicles, { - propsData: { - vehicles: [ - { - "Name": "testname", - "Text": "testtext", - } - ] - } - }); - - // console.log('wrapper.html: ', wrapper.html()); - - // Assert - const addressVehiclesQuestion = wrapper.find('address-vehicles-question-stub'); - expect(addressVehiclesQuestion).toBe; - }); - -}); diff --git a/src/layouts/component-test/component-test.vue b/src/layouts/component-test/component-test.vue index 268351417..9cc376249 100644 --- a/src/layouts/component-test/component-test.vue +++ b/src/layouts/component-test/component-test.vue @@ -7,7 +7,7 @@
- +
@@ -1089,7 +1089,7 @@ import textboxQuestion from "@/common-components/textbox-question/textbox-question"; import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question"; import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information"; - import menuButton from "@/common-components/menu-button/menu-button"; + import menuModal from "@/common-components/menu-modal/menu-modal"; export default { name: "App", components: { @@ -1104,7 +1104,7 @@ textboxQuestion, dropdownQuestion, vinInformation, - menuButton, + menuModal, }, data() { return { 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 281947ae4..44ab645dd 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js +++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js @@ -6,9 +6,10 @@ import { settleAllPromises } from "@/helpers/layout-helper.js"; import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper"; import baseMixin from "@/mixins/base-mixin"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import { shallowMount, flushPromises } from "@vue/test-utils"; +import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { nextTick } from "vue"; +import { storeMutations } from "@/constants/store-mutations"; import store from "@/store"; jest.mock('@/assets/img/loader.gif', () => 'loader.gif') @@ -24,416 +25,502 @@ jest.mock("@/helpers/cms-content-helper", () => ({ fetchCmsContentForPage: jest.fn(), })); -// Mock Store -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), - getters: { - order: { - customer: { emailAddress: "test@test.com"}, - serviceLocation: {zip: "11111"}, - }, - vehicle: { - carId: "TESTID", - registration: { - licensePlate: "TESTPLATE", - zipCode: "12345", - }, - }, - eventBusItem: jest.fn(), - damage: { - glassToReplace: [] - }, - }, -})); - describe("license-plate-lookup.vue", () => { - test("CarId set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); + describe("get values from store", () => { + test("getLicensePlateFromStore returns store license plate", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockLicensePlate = "TESTPLATE"; + store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, mockLicensePlate); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); + // Act + const licensePlate = wrapper.vm.getLicensePlateFromStore(); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("BackButtonAction triggers a router.navigate change", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.backButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("getLicensePlateFromStore returns store license plate", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - // ACT - const licensePlate = wrapper.vm.getLicensePlateFromStore(); - - // Assert - expect(licensePlate).toEqual("TESTPLATE"); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("getRegistrationZipFromStore returns store registration zip", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - // ACT - const registrationZip = wrapper.vm.getRegistrationZipFromStore(); - - // Assert - expect(registrationZip).toEqual("12345"); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("getEmailFromStore returns store customer email", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - // ACT - const customerEmail = wrapper.vm.getEmailFromStore(); - - // Assert - expect(customerEmail).toEqual("test@test.com"); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("getServiceZipFromStore returns store service zip", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - // ACT - const serviceZip = wrapper.vm.getServiceZipFromStore(); - - // Assert - expect(serviceZip).toEqual("11111"); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("Navigate forward should be called and isCarId should be set to false when data entered matches store data on forwardButtonAction click", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return {data: {isServiceable: true}}; + // Assert + expect(licensePlate).toEqual(mockLicensePlate); }); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; - }); - const vinLookup = {data: {vehicle: {carId: "TESTID"}}} - wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { - return {catch: () => vinLookup}; + + test("getRegistrationZipFromStore returns store registration zip", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockRegistrationZip = "12345"; + store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, mockRegistrationZip); + + // ACT + const registrationZip = wrapper.vm.getRegistrationZipFromStore(); + + // Assert + expect(registrationZip).toEqual(mockRegistrationZip); }); - wrapper.vm.navigateForward = jest.fn(); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); + test("getEmailFromStore returns store customer email", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockEmail = "test@test.com"; + store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, mockEmail); - //Assert - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); - expect(wrapper.vm.isCarIdDifferent).toEqual(false); - }); -}); + // ACT + const customerEmail = wrapper.vm.getEmailFromStore(); -describe("license-plate-lookup.vue", () => { - test("Function should stop and datam isRegistrationZipServicable should be set to false when service zip entered returns false on forwardButtonAction click", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return {data: {isServiceable: false}}; + // Assert + expect(customerEmail).toEqual(mockEmail); }); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; - }); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - //Assert - expect(wrapper.vm.isRegistrationZipServicable).toEqual(false); - }); -}); + test("getServiceZipFromStore returns store service zip", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockServiceZip = "11111"; + store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, mockServiceZip); -describe("license-plate-lookup.vue", () => { - test("Function should stop and datam isCarIdDifferent should be set to true when carId entered doesn't match store carId or previously entered carId on forwardButtonAction click", async () => { + // ACT + const serviceZip = wrapper.vm.getServiceZipFromStore(); - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return {data: {isServiceable: true}}; + // Assert + expect(serviceZip).toEqual(mockServiceZip); }); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; - }); - const vinLookup = {data: {vehicle: {carId: "TESTID1"}}} - wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { - return {catch: () => vinLookup}; + }); + + describe("navigation", () => { + test("BackButtonAction triggers a router.navigate change", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.backButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); + describe("on forwardButtonAction click", () => { + test("Navigate forward should be called and isCarIdDifferent should be set to false when data entered matches store data on forwardButtonAction click", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockCarId = "TESTID"; + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); + store.commit(storeMutations.UPDATE_CAR_ID, mockCarId); - //Assert - expect(wrapper.vm.isCarIdDifferent).toEqual(true); - }); -}); + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: true } }; + }); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + const vinLookup = { data: { vehicle: { carId: mockCarId } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(vinLookup)); + }); + wrapper.vm.navigateForward = jest.fn(); -describe("license-plate-lookup.vue", () => { - test("Navigate forward should be called and isCarId should be set to true when carId entered matches previously entered carId and rest of data entered matches store data on forwardButtonAction click", async () => { + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); - // Arrange - const { wrapper } = setupMocks({}); + await wrapper.vm.forwardButtonAction(); - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return {data: {isServiceable: true}}; + //Assert + expect(wrapper.vm.isCarIdDifferent).toEqual(false); + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); + + test("Function should stop and datam isRegistrationZipServicable should be set to false when service zip entered returns false on forwardButtonAction click", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: false } }; + }); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.isRegistrationZipServicable).toEqual(false); + }); + + test("Function should stop and datam isCarIdDifferent should be set to true when carId entered doesn't match store carId or previously entered carId on forwardButtonAction click", async () => { + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); + + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: true } }; + }); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + const vinLookup = { data: { vehicle: { carId: "TESTID1" } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(vinLookup)); + }); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.isCarIdDifferent).toEqual(true); + }); + + test("Navigate forward should be called and isCarId should be set to true when carId entered matches previously entered carId and rest of data entered matches store data on forwardButtonAction click", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: true } }; + }); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + const vinLookup = { data: { vehicle: { carId: "TESTID1" } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(vinLookup)); + }); + wrapper.vm.previouslyEnteredCarId = "TESTID1"; + wrapper.vm.navigateForward = jest.fn(); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + expect(wrapper.vm.isCarIdDifferent).toEqual(true); + }); }); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; - }); - const vinLookup = {data: {vehicle: {carId: "TESTID1"}}} - wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { - return {catch: () => vinLookup}; + + describe("navigateForward", () => { + test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + //Act + wrapper.vm.isCarIdDifferent = true; + wrapper.vm.isSelectedGlassAvailableForVehicle = false; + wrapper.vm.$router.navigateAfterSave = jest.fn(); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + store.dispatch = jest.fn(); + + await wrapper.vm.navigateForward(); + + //Assert + expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); + }); + + test("navigateAfterSaveToHeritageFunnel should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + //Act + wrapper.vm.isCarIdDifferent = false; + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); + await wrapper.vm.navigateForward(); + + //Assert + expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled(); + }); }); - wrapper.vm.previouslyEnteredCarId = "TESTID1"; - wrapper.vm.navigateForward = jest.fn(); - - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); - expect(wrapper.vm.isCarIdDifferent).toEqual(true); }); -}); -describe("license-plate-lookup.vue", () => { - test("Button Text should revert to initial value when licensePlate textfield has new text", async () => { + describe("button text", () => { + test("Button Text should revert to initial value when licensePlate textfield has new text", async () => { - // Arrange - const { wrapper } = setupMocks({}); + // Arrange + const { wrapper } = setupMocks({}); - //Act - wrapper.vm.licensePlate = "NEWPLATE"; - wrapper.vm.getCmsContent = jest.fn(); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - await wrapper.vm.$nextTick(); + //Act + wrapper.vm.licensePlate = "NEWPLATE"; + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("Button Text should revert to initial value when registrationZip textfield has new text", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.vm.registrationZip = "55555"; - wrapper.vm.getCmsContent = jest.fn(); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("Button Text should revert to initial value when serviceZip textfield has new text", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.vm.serviceZip = "55555"; - wrapper.vm.getCmsContent = jest.fn(); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("Dispatch reset damage and dependencies should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when updateCustomerInfo is called", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.vm.isCarIdDifferent = true; - wrapper.vm.isSelectedGlassAvailableForVehicle = false; - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); }); - store.commit = jest.fn(); - store.dispatch = jest.fn(); - const vehicleInfo = {year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue"} - await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState'); + test("Button Text should revert to initial value when registrationZip textfield has new text", async () => { - //Assert - expect(store.dispatch).toHaveBeenCalled(); - }); -}); + // Arrange + const { wrapper } = setupMocks({}); -describe("license-plate-lookup.vue", () => { - test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => { + //Act + wrapper.vm.registrationZip = "55555"; + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.vm.isCarIdDifferent = true; - wrapper.vm.isSelectedGlassAvailableForVehicle = false; - wrapper.vm.$router.navigateAfterSave = jest.fn(); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); }); - store.dispatch = jest.fn(); - await wrapper.vm.navigateForward(); + test("Button Text should revert to initial value when serviceZip textfield has new text", async () => { - //Assert - expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); - }); -}); + // Arrange + const { wrapper } = setupMocks({}); -describe("license-plate-lookup.vue", () => { - test("navigateAfterSaveToHeritageFunnel should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { + //Act + wrapper.vm.serviceZip = "55555"; + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.vm.isCarIdDifferent = false; - wrapper.vm.$refs.loadingModal.showModal = jest.fn(); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); }); - navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); - await wrapper.vm.navigateForward(); + }) - //Assert - expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled(); - }); + describe("saving registrationZip and serviceZip on continue", () => { + test("registrationZip is serviceable and vehicle match is found => sets service zip/state to registration zip/state", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockCarId = "TESTID"; + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); + store.commit(storeMutations.UPDATE_CAR_ID, mockCarId) + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => { + if (zip) + return { data: { isServiceable: true, state: "OH" } }; + return + }); + const vinLookup = { data: { vehicle: { carId: mockCarId } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => new Promise(resolve => resolve(vinLookup))); + + await wrapper.setData({ registrationZip: "00000" }); + navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(store.getters.order.serviceLocation.zipCode).toEqual(store.getters.vehicle.registration.zipCode); + expect(store.getters.vehicle.registration.zipCode).toEqual("00000"); + expect(store.getters.order.serviceLocation.zipCode).toEqual("00000"); + }) + + test("vehicle match is found but registrationZip is not serviceable => shows service zip/state field", async () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: false, state: "XX" } }; + }); + + await wrapper.setData({ registrationZip: "00000" }); + navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZip']"); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); + }) + + test("registrationZip is not serviceable so serviceZip field is shown, continue clicked => user cannot continue", async () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: false, state: "XX" } }; + }); + + await wrapper.setData({ registrationZip: "00000" }); + navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn(); + await wrapper.vm.forwardButtonAction(); + wrapper.vm.$router.navigateAfterSave = jest.fn(); + // At this point, serviceZip field is shown + + // Act + // Continue without entering anything into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZip']"); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); 3 + expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).not.toHaveBeenCalled(); + expect(wrapper.vm.$router.navigateAfterSave).not.toHaveBeenCalled(); + }); + + test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => user can continue", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const registrationZip = "00000"; + const serviceZip = "99999"; + const mockCarId = "TestCarId"; + store.commit(storeMutations.UPDATE_CAR_ID, mockCarId); + wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => { + return { data: { isServiceable: zip == registrationZip ? false : true, state: "XX" } }; + }); + const vinLookup = { data: { vehicle: { carId: mockCarId } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(vinLookup)); + }); + wrapper.vm.navigateForward = jest.fn(); + await wrapper.setData({ registrationZip: registrationZip }); + await wrapper.vm.forwardButtonAction(); + // At this point, serviceZip field is shown + + await wrapper.setData({ serviceZip: serviceZip }); + + // Act + // Continue after entering input into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZip']"); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); + + test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => service and registration zips/states saved", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const registrationZip = "00000"; + const serviceZip = "99999"; + const mockCarId = "TestCarId"; + store.commit(storeMutations.UPDATE_CAR_ID, mockCarId); + wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => { + return { data: { isServiceable: zip == registrationZip ? false : true, state: "XX" } }; + }); + const vinLookup = { data: { vehicle: { carId: mockCarId } } } + wrapper.vm.lookupVin = jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(vinLookup)); + }); + wrapper.vm.navigateForward = jest.fn(); + await wrapper.setData({ registrationZip: registrationZip }); + await wrapper.vm.forwardButtonAction(); + // At this point, serviceZip field is shown + + await wrapper.setData({ serviceZip: serviceZip }); + + // Act + // Continue after entering value into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(store.getters.vehicle.registration.zipCode).toEqual(registrationZip); + expect(store.getters.order.serviceLocation.zipCode).toEqual(serviceZip); + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); + }) + + describe("miscellaneous", () => { + test("CarId set, arePagePrerequisitesValid should be true ", async () => { + //Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_CAR_ID, "TESTCARID"); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + await nextTick(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + + test("Dispatch reset damage and dependencies should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when updateCustomerInfo is called", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + //Act + wrapper.vm.isCarIdDifferent = true; + wrapper.vm.isSelectedGlassAvailableForVehicle = false; + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ''; + }); + store.commit = jest.fn(); + store.dispatch = jest.fn(); + + const vehicleInfo = { year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue" } + await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState'); + + //Assert + expect(store.dispatch).toHaveBeenCalled(); + }) + + test("dispatch non blocking store action called on validate zip", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + //Act + await wrapper.vm.validateZip("12345"); + + + //Assert + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled(); + }); + + test("dispatch non blocking store action called on lookup vin", async () => { + + // Arrange + const { wrapper } = setupMocks({}); + + //Act + await wrapper.vm.lookupVin("zzz123fqsfwg"); + + + //Assert + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled(); + }); + }) }); -describe("license-plate-lookup.vue", () => { - test("dispatch non blocking store action called on validate zip", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - await wrapper.vm.validateZip("12345"); - - - //Assert - expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled(); - }); -}); - -describe("license-plate-lookup.vue", () => { - test("dispatch non blocking store action called on lookup vin", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - await wrapper.vm.lookupVin("zzz123fqsfwg"); - - - //Assert - expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled(); - }); -}); - - - function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = { router: { navigate: jest.fn(), }, - licensePlate: "TESTPLATE", - registrationZip: "12345" }, }) { + store.commit(storeMutations.RESET_STATE); //Mock api responses baseMixin.methods.dispatchStoreAction = jest.fn(); const apiResponses = { @@ -455,13 +542,16 @@ function setupMocks({ settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions(mountOptionsMockData); mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods const wrapper = shallowMount(licensePlateLookup, mountOptions); wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); return { wrapper, apiPromise }; } diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 38217009d..f3a5d3e83 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -220,19 +220,18 @@ export default { return store.getters.order.customer.emailAddress; }, getServiceZipFromStore() { - return store.getters.order.serviceLocation.zip; + return store.getters.order.serviceLocation.zipCode; }, backButtonAction() { this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); }, async forwardButtonAction() { - //Call zip validation services const registrationZipValidationPromise = this.validateZip(this.registrationZip); const serviceZipValidationPromise = this.serviceZip ? this.validateZip(this.serviceZip) : null; const registrationZipValidationResults = await registrationZipValidationPromise; const serviceZipValidationResults = serviceZipValidationPromise !== null ? (await serviceZipValidationPromise) : registrationZipValidationResults; - + //Handle service zip validations if (!serviceZipValidationResults.data.isServiceable) { this.$refs.funnelFooter.removeLoader(); @@ -255,6 +254,7 @@ export default { this.isCarIdDifferent = false; return; }); + this.isCarIdDifferent = vinLookup.data.vehicle.carId !== store.getters.vehicle.carId; diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js index 0ce0fe085..46fa7763e 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.spec.js +++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js @@ -51,650 +51,663 @@ jest.mock("@/store", () => ({ }, eventBusItem: jest.fn(), damage: { - glassToReplace: [] + glassToReplace: [] }, }, })); describe("vehicle-damage.vue", () => { - test("CarId set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); + describe("navigation", () => { + test("BackButtonAction triggers a router.navigate change", async () => { - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); + //Arrange + const { wrapper } = setupMocks({}); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); -}); + wrapper.vm.backButtonAction(); -describe("vehicle-damage.vue", () => { - test("BackButtonAction triggers a router.navigate change", async () => { + //Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.backButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); - - }); -}); - -describe("vehicle-damage.vue", () => { - test("Replace several pieces of glass on ForwardButtonAction triggers a router.navigateAfterSave and saves selections to store", async () => { - //Arrange - const partsData = { - partsOrQuestions: [{ - glassName: "Single", - glassLocation: "Windshield", - parts: null, - partQuestions: [{ - questionSequence: 1, - questionText: "Is your vehicle equipped with a heated steering wheel?", - answers: [{ - answerText: "Yes", - nextQuestionSequence: null, - answerResult: "FW04957" - }, - { - answerText: "No", - nextQuestionSequence: 2, - answerResult: "" - }] - }, - { - questionSequence: 2, - questionText: "Is your vehicle equipped with a remote start?", - answers: [{ - answerText: "Yes", - nextQuestionSequence: null, - answerResult: "FW04181" - }, - { - answerText: "No", - nextQuestionSequence: null, - answerResult: "FW04179" - }] - }] - }] - }; - - const { wrapper } = setupMocks({ - pageHeaderWidgetHeaderText: "", - mountOptionsMockData: { - router: { navigateAfterSave: jest.fn(), }, - actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },], - store: { - getters: { - vehicle: {}, - payment: { insuranceCoverage: { isVerified: false } }, - }, - }, - }, }); - wrapper.vm.selectedDamageLocations = ["Windshield", "SideDoor", "RearWindow"]; - wrapper.vm.selectedWindshieldOptions = { - selectedWindshieldChipCount : null, - selectedWindshieldReplaceOptions : ["Single"], - selectedWindshieldDamageType: ["Replace"] - }; - - wrapper.vm.sideDoorOptionsData = { - selectedDoorSides: ["DriverSide", "PassengerSide"], - selectedDriverSideReplaceOptions: ["Back"], - selectedPassengerSideReplaceOptions: ["Quarter"] - }; - - wrapper.vm.selectedRearReplaceOptions = ["Stationary"]; - - const expectedGlassToReplace = [{location: "Windshield", name: "Single"}, {location: "Driver", name: "Back"}, - {location: "Passenger", name: "Quarter"}, {location: "Rear", name: "Stationary"}]; - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); - expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); - expect(store.commit).toBeCalledWith(storeMutations.UPDATE_IS_REPAIR, false); - expect(store.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_TO_REPLACE, expectedGlassToReplace); - }); -}); - -describe("vehicle-damage.vue", () => { - test("Windshield replace with multiple parts on ForwardButtonAction triggers a router.navigateAfterSave and saves selections to store", async () => { - //Arrange - const partsData = { partsOrQuestions: [ - { - glassLocation: "Windshield", - glassName: "Single", - partQuestions: null, - parts: [ - { - color: "Green Tint, Green Shade", - description: "rain sensor, solar", - partNumber: "FW02728GGYN", - requiresCapabilityQuestions: false, - requiresRecalibration: false - }, - { - color: "Green Tint, Green Shade", - description: "rain sensor, solar, hydrophobic coating", - partNumber: "FW02760GGYN", - requiresCapabilityQuestions: false, - requiresRecalibration: false - } - ]}, - { - glassName: "Stationary", - glassLocation: "Rear", - parts: [ - { - partNumber: "DB09626GTYN", - description: "heated glass, solar, antenna", - color: "Green Tint", - requiresRecalibration: false, - requiresCapabilityQuestions: false, - childParts: null + test("Replace several pieces of glass on ForwardButtonAction triggers a router.navigateAfterSave and saves selections to store", async () => { + //Arrange + const partsData = { + partsOrQuestions: [{ + glassName: "Single", + glassLocation: "Windshield", + parts: null, + partQuestions: [{ + questionSequence: 1, + questionText: "Is your vehicle equipped with a heated steering wheel?", + answers: [{ + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "FW04957" }, { - partNumber: "DB09821GTYN", - description: "heated glass, solar, antenna, onstar", - color: "Green Tint", - requiresRecalibration: false, - requiresCapabilityQuestions: false, - childParts: null - } - ], - "partQuestions": null - } - ]}; - - const { wrapper } = setupMocks({ - pageHeaderWidgetHeaderText: "", - mountOptionsMockData: { - router: { navigateAfterSave: jest.fn(), }, - actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },], - store: { - getters: { - vehicle: {}, - payment: { insuranceCoverage: { isVerified: false } }, + answerText: "No", + nextQuestionSequence: 2, + answerResult: "" + }] }, - }, - }, - }); - - wrapper.vm.selectedDamageLocations = ["Windshield"]; - wrapper.vm.selectedWindshieldOptions = { - selectedWindshieldChipCount : null, - selectedWindshieldReplaceOptions : ["Single"], - selectedWindshieldDamageType: ["Replace"] - }; - - const expectedGlassToReplace = [{location: "Windshield", name: "Single"},]; - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); - expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); - expect(store.commit).toBeCalledWith(storeMutations.UPDATE_IS_REPAIR, false); - expect(store.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_TO_REPLACE, expectedGlassToReplace); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isWindshieldDamageLocation is true when windshield is selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["Windshield"]; - - //Assert - expect(wrapper.vm.isWindshieldDamageLocation).toEqual(true); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isSideDoorDamageLocation is true Side door is selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["Sidedoor"]; - - //Assert - expect(wrapper.vm.isSideDoorDamageLocation).toEqual(true); - }); -}); - - -describe("vehicle-damage.vue", () => { - test("isRearWindowDamageLocation is true if Rear Window damage is selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["RearWindow"]; - - //Assert - expect(wrapper.vm.isRearWindowDamageLocation).toEqual(true); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isWindshieldRepair is true if windshield repair is selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["Windshield"]; - wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: ["Repair"]}; - - //Assert - expect(wrapper.vm.isWindshieldRepair).toEqual(true); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isWindshieldRepair is false if windshield damage is not selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["SideDoor"]; - wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: ["Repair"]}; - - //Assert - expect(wrapper.vm.isWindshieldRepair).toEqual(false); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isDriverSideReplace is true if side door driver is selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["Sidedoor"]; - wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["DriverSide"]}; - - //Assert - expect(wrapper.vm.isDriverSideReplace).toEqual(true); - }); -}); - -describe("vehicle-damage.vue", () => { - test("isPassengerSideReplace is true if side door passenger selected", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.selectedDamageLocations = ["Sidedoor"]; - wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["PassengerSide"]}; - - //Assert - expect(wrapper.vm.isPassengerSideReplace).toEqual(true); - }); -}); - -describe("vehicle-damage.vue", () => { - test("Call invalidation, ResetPartsAndState should be called", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.resetDependentState(); - - //Assert - expect(store.dispatch).toBeCalledWith(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES) - - }); -}); - -const damageLocations = [["Windshield", [damageLocationsSelected.WINDSHIELD]], - ["Driver", [damageLocationsSelected.SIDEDOOR]], - ["Passenger", [damageLocationsSelected.SIDEDOOR]], - ["Rear", [damageLocationsSelected.REARWINDOW]]]; -describe("vehicle-damage.vue", () => { - test.each(damageLocations)("getDamageLocationsFromStore for %s returns expected %s", async (damageLocation, expectedGlass) => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation}] }, isRepair: true}; - - var glassSelections = wrapper.vm.getDamageLocationsFromStore(); - - //Assert - expect(glassSelections).toEqual(expectedGlass); - - }); -}); - -const storeWindshieldOptions = [[1, false, "Windshield", "Single", { selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], - selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE]}], - [2, false, "Windshield", "Driver", { selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], - selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER]}], - [3, false, "Windshield", "Passenger", { selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], - selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER]}], - [4, true, "", "", { selectedWindshieldDamageType: [damageLocationsSelected.REPAIR], - selectedWindshieldChipCount: [2], selectedWindshieldReplaceOptions: []}] - ]; -describe("vehicle-damage.vue", () => { - test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - store.getters = { - vehicle: - { carId: "C0000000" }, - eventBusItem: jest.fn(), - damage: - { - glassToReplace: [{location: damageLocation, name: damageName}], - isRepair: isRepair, - numberOfChips: 2 - }, + { + questionSequence: 2, + questionText: "Is your vehicle equipped with a remote start?", + answers: [{ + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "FW04181" + }, + { + answerText: "No", + nextQuestionSequence: null, + answerResult: "FW04179" + }] + }] + }] }; - var windshieldSelections = wrapper.vm.getWindshieldOptionsFromStore(); - - //Assert - expect(windshieldSelections).toEqual(expectedWindshieldOptions); + const { wrapper } = setupMocks({ + pageHeaderWidgetHeaderText: "", + mountOptionsMockData: { + router: { navigateAfterSave: jest.fn(), }, + actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },], + store: { + getters: { + vehicle: {}, + payment: { insuranceCoverage: { isVerified: false } }, + }, + }, + }, + }); + + wrapper.vm.selectedDamageLocations = ["Windshield", "SideDoor", "RearWindow"]; + wrapper.vm.selectedWindshieldOptions = { + selectedWindshieldChipCount: null, + selectedWindshieldReplaceOptions: ["Single"], + selectedWindshieldDamageType: ["Replace"] + }; + + wrapper.vm.sideDoorOptionsData = { + selectedDoorSides: ["DriverSide", "PassengerSide"], + selectedDriverSideReplaceOptions: ["Back"], + selectedPassengerSideReplaceOptions: ["Quarter"] + }; + + wrapper.vm.selectedRearReplaceOptions = ["Stationary"]; + + const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }, { location: "Driver", name: "Back" }, + { location: "Passenger", name: "Quarter" }, { location: "Rear", name: "Stationary" }]; + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); + expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); + expect(store.commit).toBeCalledWith(storeMutations.UPDATE_IS_REPAIR, false); + expect(store.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_TO_REPLACE, expectedGlassToReplace); + }); + + test("Windshield replace with multiple parts on ForwardButtonAction triggers a router.navigateAfterSave and saves selections to store", async () => { + //Arrange + const partsData = { + partsOrQuestions: [ + { + glassLocation: "Windshield", + glassName: "Single", + partQuestions: null, + parts: [ + { + color: "Green Tint, Green Shade", + description: "rain sensor, solar", + partNumber: "FW02728GGYN", + requiresCapabilityQuestions: false, + requiresRecalibration: false + }, + { + color: "Green Tint, Green Shade", + description: "rain sensor, solar, hydrophobic coating", + partNumber: "FW02760GGYN", + requiresCapabilityQuestions: false, + requiresRecalibration: false + } + ] + }, + { + glassName: "Stationary", + glassLocation: "Rear", + parts: [ + { + partNumber: "DB09626GTYN", + description: "heated glass, solar, antenna", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null + }, + { + partNumber: "DB09821GTYN", + description: "heated glass, solar, antenna, onstar", + color: "Green Tint", + requiresRecalibration: false, + requiresCapabilityQuestions: false, + childParts: null + } + ], + "partQuestions": null + } + ] + }; + + const { wrapper } = setupMocks({ + pageHeaderWidgetHeaderText: "", + mountOptionsMockData: { + router: { navigateAfterSave: jest.fn(), }, + actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },], + store: { + getters: { + vehicle: {}, + payment: { insuranceCoverage: { isVerified: false } }, + }, + }, + }, + }); + + wrapper.vm.selectedDamageLocations = ["Windshield"]; + wrapper.vm.selectedWindshieldOptions = { + selectedWindshieldChipCount: null, + selectedWindshieldReplaceOptions: ["Single"], + selectedWindshieldDamageType: ["Replace"] + }; + + const expectedGlassToReplace = [{ location: "Windshield", name: "Single" },]; + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled(); + expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace); + expect(store.commit).toBeCalledWith(storeMutations.UPDATE_IS_REPAIR, false); + expect(store.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_TO_REPLACE, expectedGlassToReplace); + }); + }); -}); -const driverDoorSides = [["Driver", "Front", [damageLocationsSelected.FRONT]], - ["Driver", "Back", [damageLocationsSelected.BACK]], - ["Driver", "Vent", [damageLocationsSelected.VENT]], - ["Driver", "Quarter", [damageLocationsSelected.QUARTER]] - ]; -describe("vehicle-damage.vue", () => { - test.each(driverDoorSides)("getDriverSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true}; - - var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore(); - - //Assert - expect(glassSelections).toEqual(expectedGlass); - - }); -}); - -const passengerDoorSides = [["Passenger", "Front", [damageLocationsSelected.FRONT]], - ["Passenger", "Back", [damageLocationsSelected.BACK]], - ["Passenger", "Vent", [damageLocationsSelected.VENT]], - ["Passenger", "Quarter", [damageLocationsSelected.QUARTER]] - ]; -describe("vehicle-damage.vue", () => { - test.each(passengerDoorSides)("getPassengerSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true}; - - var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore(); - - //Assert - expect(glassSelections).toEqual(expectedGlass); - - }); -}); - -const rearReplaceOptions = [["Rear", "Stationary", [damageLocationsSelected.STATIONARY]], - ["Rear", "Slider", [damageLocationsSelected.SLIDER]] - ]; -describe("vehicle-damage.vue", () => { - test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true}; - - var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore(); - - //Assert - expect(glassSelections).toEqual(expectedGlass); - - }); -}); - -describe("vehicle-damage.vue", () => { - test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be visible", () => { - // Arrange & Act - const { wrapper } = setupMocks({ - mountOptionsMockData: { - route: { - params: { - [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true + describe("alert", () => { + test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be visible", () => { + // Arrange & Act + const { wrapper } = setupMocks({ + mountOptionsMockData: { + route: { + params: { + [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true + } } } - } + }); + // Assert + expect(wrapper.findComponent({ ref: 'vehicleChangeAlert' }).isVisible()).toBe(true); }); - // Assert - expect(wrapper.findComponent({ref: 'vehicleChangeAlert'}).isVisible()).toBe(true); - }) -}); -describe("vehicle-damage.vue", () => { - test("when displayVehicleChangeAlert router params is false, the alert: 'vehicleChangeAlert' should not be visible", () => { - // Arrange & Act - const { wrapper } = setupMocks({ - mountOptionsMockData: { - route: { - params: { - [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false + test("when displayVehicleChangeAlert router params is false, the alert: 'vehicleChangeAlert' should not be visible", () => { + // Arrange & Act + const { wrapper } = setupMocks({ + mountOptionsMockData: { + route: { + params: { + [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false + } } } - } + }); + // Assert + expect(wrapper.findComponent({ ref: 'vehicleChangeAlert' }).isVisible()).toBe(false); }); - // Assert - expect(wrapper.findComponent({ref: 'vehicleChangeAlert'}).isVisible()).toBe(false); - }) -}); -describe("vehicle-damage.vue", () => { - test("when displayVehicleChangeAlert router params is undefined, the alert: 'vehicleChangeAlert' should not be visible", () => { - // Arrange & Act - const { wrapper } = setupMocks({ - mountOptionsMockData: { - route: { - params: { - [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: undefined + test("when displayVehicleChangeAlert router params is undefined, the alert: 'vehicleChangeAlert' should not be visible", () => { + // Arrange & Act + const { wrapper } = setupMocks({ + mountOptionsMockData: { + route: { + params: { + [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: undefined + } } } - } + }); + // Assert + expect(wrapper.findComponent({ ref: 'vehicleChangeAlert' }).isVisible()).toBe(false); + }) + }); + + describe("glass selections and corresponding variables", () => { + test("isWindshieldDamageLocation is true when windshield is selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["Windshield"]; + + //Assert + expect(wrapper.vm.isWindshieldDamageLocation).toEqual(true); + }); + + test("isSideDoorDamageLocation is true Side door is selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["Sidedoor"]; + + //Assert + expect(wrapper.vm.isSideDoorDamageLocation).toEqual(true); + }); + + test("isRearWindowDamageLocation is true if Rear Window damage is selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["RearWindow"]; + + //Assert + expect(wrapper.vm.isRearWindowDamageLocation).toEqual(true); + }); + + test("isWindshieldRepair is true if windshield repair is selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["Windshield"]; + wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: ["Repair"] }; + + //Assert + expect(wrapper.vm.isWindshieldRepair).toEqual(true); + }); + + test("isWindshieldRepair is false if windshield damage is not selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["SideDoor"]; + wrapper.vm.selectedWindshieldOptions = { selectedWindshieldDamageType: ["Repair"] }; + + //Assert + expect(wrapper.vm.isWindshieldRepair).toEqual(false); + }); + + test("isDriverSideReplace is true if side door driver is selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["Sidedoor"]; + wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["DriverSide"] }; + + //Assert + expect(wrapper.vm.isDriverSideReplace).toEqual(true); + }); + + test("isPassengerSideReplace is true if side door passenger selected", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.selectedDamageLocations = ["Sidedoor"]; + wrapper.vm.sideDoorOptionsData = { selectedDoorSides: ["PassengerSide"] }; + + //Assert + expect(wrapper.vm.isPassengerSideReplace).toEqual(true); + }); + }); + + describe("state validations", () => { + test("CarId set, arePagePrerequisitesValid should be true ", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + await nextTick(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + + test("Call invalidation, ResetPartsAndState should be called", async () => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + wrapper.vm.resetDependentState(); + + //Assert + expect(store.dispatch).toBeCalledWith(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES) + + }); + }); + + describe("input validations", () => { + // THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE + // BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST + test("when validation rules are set they should validate correctly", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + const testNull = validate("", "replace-options-required"); + const testString = validate("sldfj", "replace-options-required"); + + //Assert + testNull.then(function (data) { + expect(data.valid).toEqual(false); + }); + testString.then(function (data) { + expect(data.valid).toEqual(true); + }); + }); + }); + + describe("get glass options from store", () => { + const damageLocations = [["Windshield", [damageLocationsSelected.WINDSHIELD]], + ["Driver", [damageLocationsSelected.SIDEDOOR]], + ["Passenger", [damageLocationsSelected.SIDEDOOR]], + ["Rear", [damageLocationsSelected.REARWINDOW]]]; + test.each(damageLocations)("getDamageLocationsFromStore for %s returns expected %s", async (damageLocation, expectedGlass) => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation }] }, isRepair: true }; + + var glassSelections = wrapper.vm.getDamageLocationsFromStore(); + + //Assert + expect(glassSelections).toEqual(expectedGlass); + }); + + const storeWindshieldOptions = [[1, false, "Windshield", "Single", { + selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], + selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE] + }], + [2, false, "Windshield", "Driver", { + selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], + selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER] + }], + [3, false, "Windshield", "Passenger", { + selectedWindshieldDamageType: [damageLocationsSelected.REPLACE], + selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER] + }], + [4, true, "", "", { + selectedWindshieldDamageType: [damageLocationsSelected.REPAIR], + selectedWindshieldChipCount: [2], selectedWindshieldReplaceOptions: [] + }] + ]; + test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + store.getters = { + vehicle: + { carId: "C0000000" }, + eventBusItem: jest.fn(), + damage: + { + glassToReplace: [{ location: damageLocation, name: damageName }], + isRepair: isRepair, + numberOfChips: 2 + }, + }; + + var windshieldSelections = wrapper.vm.getWindshieldOptionsFromStore(); + + //Assert + expect(windshieldSelections).toEqual(expectedWindshieldOptions); + }); + + const driverDoorSides = [["Driver", "Front", [damageLocationsSelected.FRONT]], + ["Driver", "Back", [damageLocationsSelected.BACK]], + ["Driver", "Vent", [damageLocationsSelected.VENT]], + ["Driver", "Quarter", [damageLocationsSelected.QUARTER]] + ]; + test.each(driverDoorSides)("getDriverSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + + var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore(); + + //Assert + expect(glassSelections).toEqual(expectedGlass); + + }); + + const passengerDoorSides = [["Passenger", "Front", [damageLocationsSelected.FRONT]], + ["Passenger", "Back", [damageLocationsSelected.BACK]], + ["Passenger", "Vent", [damageLocationsSelected.VENT]], + ["Passenger", "Quarter", [damageLocationsSelected.QUARTER]] + ]; + test.each(passengerDoorSides)("getPassengerSideReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + + var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore(); + + //Assert + expect(glassSelections).toEqual(expectedGlass); + }); + + const rearReplaceOptions = [["Rear", "Stationary", [damageLocationsSelected.STATIONARY]], + ["Rear", "Slider", [damageLocationsSelected.SLIDER]] + ]; + test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => { + + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + + var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore(); + + //Assert + expect(glassSelections).toEqual(expectedGlass); }); - // Assert - expect(wrapper.findComponent({ref: 'vehicleChangeAlert'}).isVisible()).toBe(false); }) -}); -describe("vehicle-damage.vue wasDelayedClaimRegistration", () => { - test.todo("if wasDelayedClaimRegistration, should hide back button") -}); + describe("hide back button", () => { + test("if claim registration is delayed => should hide back button", () => { + // Arrange + const { wrapper } = setupMocks({ + funnelCookie: { + HasDelayedClaimRegistration: true + } + }); -// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE -// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST -// -describe("vehicle-damage.vue", () => { - test("when validation rules are set they should validate correctly", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleDamage.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-damage" } }, - undefined, - (c) => c(wrapper.vm) - ); - const testNull = validate( "", "replace-options-required"); - const testString = validate( "sldfj", "replace-options-required"); - - //Assert - testNull.then(function(data) { - expect(data.valid).toEqual(false); - }); - testString.then(function(data) { - expect(data.valid).toEqual(true); + // Assert + expect(wrapper.vm.shouldHideBackButton).toBe(true); }); + test("if claim is verified => should hide back button", () => { + // Arrange + const { wrapper } = setupMocks({ + mountOptionsMockData: { + router: { navigateAfterSave: jest.fn(), }, + actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: {}, },], + store: { + getters: { + vehicle: {}, + payment: { insuranceCoverage: { isVerified: true } }, + }, + }, + }, + }) + + // Assert + expect(wrapper.vm.shouldHideBackButton).toBe(true); + }) + + test("if claim isn't verified yet => allow user to go back", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Assert + expect(wrapper.vm.shouldHideBackButton).toBeFalsy(); + }) }); }); - -function setupMocks({pageHeaderWidgetHeaderText, mountOptionsMockData}) { +function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCookie = {} }) { var pageHeaderWidgetHeaderTextDefault = {}; var mountOptionsMockDataDefault = { router: { @@ -751,7 +764,7 @@ function setupMocks({pageHeaderWidgetHeaderText, mountOptionsMockData}) { settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValue({}); + cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValue(funnelCookie); //Mock damage initialize methods damageLocationQuestion.methods = { @@ -787,11 +800,11 @@ function setupMocks({pageHeaderWidgetHeaderText, mountOptionsMockData}) { const backGlassOptionsWrapper = wrapper.findComponent({ name: "replaceOptionsQuestion" }); backGlassOptionsWrapper.vm.initializeComponent = - replaceOptionsQuestion.methods.initializeComponent; + replaceOptionsQuestion.methods.initializeComponent; const damageLocationQuestionWrapper = wrapper.findComponent({ name: "damageLocationQuestion" }); damageLocationQuestionWrapper.vm.initializeComponent = - damageLocationQuestion.methods.initializeComponent; + damageLocationQuestion.methods.initializeComponent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index d4e44feb7..266e2ba1a 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -405,7 +405,7 @@ export default { shouldDisplayVehicleChangeAlert() { return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]; }, - shouldHideBackButton(){ + shouldHideBackButton() { return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration; } }, diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index ca5a24a3e..fda94e79d 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -1,18 +1,17 @@ import { storeActions } from "@/constants/store-actions"; -import { getDeviceIdValue, getSessionIdValue, getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper"; +import { setCookieProperties, getDeviceIdValue, getSessionIdValue, getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper"; import { queryStrings } from "@/constants/query-strings"; import { experimentSettings } from "@/constants/experiments"; import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics"; +import { cookieNames } from "@/constants/cookie-names"; import baseMixin from "@/mixins/base-mixin"; export default { methods: { logPageView(pageEvent) { - // if the user does not have a session id from the content site, do not log. - const sid = getSessionIdValue(); - if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) { - return; + if (getSessionKeyValue() === 0 || getSessionIdValue() === '00000000-0000-0000-0000-000000000000') { + this.initSession(); } const currentPageName = getPageNameByQueryString(); @@ -20,38 +19,59 @@ export default { userId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), pageName: currentPageName, - sessionId: sid, + sessionId: getSessionIdValue(), action: '', event: pageEvent, - shouldUseSessionId: true, + shouldUseSessionId: false, }; baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false); }, logCustomEvent(category, action, label, value) { - // if the user does not have a session id from the content site, do not log. - const sid = getSessionIdValue(); - if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) { - return; + if (getSessionKeyValue() === 0 || getSessionIdValue() === '00000000-0000-0000-0000-000000000000') { + this.initSession(); } const currentPageName = getPageNameByQueryString(); + var payload = { userId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), pageName: currentPageName, - sessionId: sid, + sessionId: getSessionIdValue(), category: category, action: action, label: label, value: value, - shouldUseSessionId: true, + shouldUseSessionId: false, }; baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false); }, + async initSession() { + const sid = getSessionIdValue(); + const skey = getSessionKeyValue(); + var payload = { + userId: getDeviceIdValue(), + sessionId: sid, + userAgent: navigator.userAgent, + referrer: document.referrer, + }; + + const response = await baseMixin.methods.dispatchStoreAction(storeActions.INITIALIZE_SESSION, payload, false); + + if (response.data) { + if (response.data.sessionKey && skey === 0) { + setCookieProperties({ [cookieNames.SESSION_KEY]: response.data.sessionKey}); + } + if (response.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') { + setCookieProperties({ [cookieNames.SESSION_ID]: response.data.sessionId}); + } + } + }, + pushEventToGA(category, action, label, pushToLogApp = false) { const currentPageName = getPageNameByQueryString(); const eventToBePushed = { diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index db773da56..7d9cec1bb 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -1,6 +1,7 @@ import analyticsMixin from "@/mixins/analytics-mixin"; import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js"; import { storeActions } from "@/constants/store-actions"; +import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics"; describe("analyticsMixin.js", () => { test("logPageView: calls dispatch with type and payload", () => { @@ -26,9 +27,6 @@ describe("analyticsMixin.js", () => { }); test("logCustomEvent: calls dispatch with type and payload", () => { - const type = ""; - const payload = {}; - const mockData = { actionList: [{ actionName: storeActions.LOG_CUSTOM_EVENT @@ -36,7 +34,7 @@ describe("analyticsMixin.js", () => { } const mocks = setupMocksForJsFiles(mockData); - analyticsMixin.methods.logCustomEvent(type, payload); + analyticsMixin.methods.logCustomEvent("someCat", "someAction", "someLabel", "someVal"); expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled(); }); @@ -126,4 +124,37 @@ describe("analyticsMixin.js", () => { //Assert expect(obj!=null); }); + + test("analyticsPageEvents returns constants analyticsPageEvents", () => { + //Act + const analyticsPE = analyticsMixin.computed.analyticsPageEvents(); + + //Assert + expect(analyticsPE).toEqual(analyticsPageEvents); + }); + + test("GaActions returns constants GaActions", () => { + //Act + const gaActions = analyticsMixin.computed.GaActions(); + + //Assert + expect(gaActions).toEqual(GaActions); + }); + + test("GaCategories returns constants GaCategories", () => { + //Act + const gaCategories = analyticsMixin.computed.GaCategories(); + + //Assert + expect(gaCategories).toEqual(GaCategories); + }); + + test("GaLabels returns constants GaLabels", () => { + //Act + const gaLabels = analyticsMixin.computed.GaLabels(); + + //Assert + expect(gaLabels).toEqual(GaLabels); + }); + }); \ No newline at end of file diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index d0474d67b..0a30524ec 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -43,9 +43,9 @@ export default { } }, getFooterInfoBoxHeight() { - const footerInfoBox = document.querySelector(".footer #infoBox"); + const footerInfoBox = document.querySelector(".footer#infoBox"); return footerInfoBox ? footerInfoBox.offsetHeight : 0; - } + }, }, computed: { storeActions() { diff --git a/src/store/index.js b/src/store/index.js index 814ca2d5b..dda0fab35 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -509,6 +509,26 @@ export const actions = { }); }, + initializeSession(context, { userId, sessionId, userAgent, referrer }) { + var payload = { + applicationName: 'SafeliteDotCom', + userId: userId, + deviceId: userId, + sessionId: sessionId, + userAgent: userAgent, + operatorId: "WEB", + userName: "SafeliteConceptFunnel", + referrer: referrer + }; + + return globalMethods.callHttpClient({ + method: endpoints.InitializeSession.method, + endpoint: endpoints.InitializeSession.url, + payload: payload, + logApiCall: false + }); + }, + GetExperimentsByUser(context, { userId }){ return globalMethods.callHttpClient({ method: endpoints.GetExperimentsByUser.method, diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 24aa7cbd3..bdb49ece7 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -642,7 +642,7 @@ describe("Actions", () => { }); // Assert - const response = await actions.logPageView(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", pageEvent: pageEvent, shouldUseSessionId: true }); + const response = await actions.logPageView(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", pageEvent: pageEvent, shouldUseSessionId: false }); expect(response).toEqual({}); }); @@ -663,7 +663,22 @@ describe("Actions", () => { }); // Assert - const response = await actions.logCustomEvent(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", customEvent: customEvent, shouldUseSessionId: true }); + const response = await actions.logCustomEvent(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", customEvent: customEvent, shouldUseSessionId: false }); + expect(response).toEqual({}); + }); + + it("initializeSession action, should return nothing", async () => { + + // Arrange + const context = state; + + // Act + globalMethods.callHttpClient.mockImplementation(() => { + return Promise.resolve({ }); + }); + + // Assert + const response = await actions.initializeSession(context, { userId: "userId", sessionId: "", userAgent: "", referrer: "", shouldUseSessionId: false }); expect(response).toEqual({}); }); diff --git a/src/styles/common-styles.scss b/src/styles/common-styles.scss index 850f346b1..13eb42d53 100644 --- a/src/styles/common-styles.scss +++ b/src/styles/common-styles.scss @@ -47,4 +47,14 @@ body { .page-container-grouped-styles { @extend .container-fluid, .shadow, .rounded-3, .p-2, .position-relative, .make-tall, .px-5; } -} \ No newline at end of file + + //Footer modal backdrop adjustments for positioning + .modal-backdrop { + left: 50%; + transform: translateX(-50%); + max-width: 576px; + height: calc(100% - 152px); + top: 72px; + } + +} diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 88d95030e..52cf89169 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -180,3 +180,7 @@ $box-shadow-inset: inset 0 1px 2px rgba($black, .075); $alert-bg-scale: -90%; $alert-border-scale: -100%; $alert-color-scale: 40%; + +//Modal animation +$modal-fade-transform: translate(0, 0); +$modal-backdrop-opacity: 0;