diff --git a/jest.config.js b/jest.config.js index c5401c28f..bfb4bf71f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,14 +13,9 @@ module.exports = { "!src/router/**/*.js", "!src/helpers/unit-test-helper.js", "!src/layouts/vehicle-damage/windshield-options/windshield-options.vue", - "!src/layouts/molding-questions/**/*.vue", - "!src/layouts/capability-questions/**/*.vue", - "!src/layouts/part-questions/**/*.vue", "!src/layouts/reveal/**/*.vue", - "!src/layouts/quote/**/*.vue", "!src/ux-components/text-link/**/*.vue", - "!src/common-components/question-chain/**/*.vue", - "!src/layouts/quote/**/*.vue", // Temporary + "!src/common-components/date-picker/**/*.vue", "!src/layouts/vin-lookup/**/*.vue", //Temporary for Quote page testing "!src/common-components/funnel-header/menu-modal/**/*.vue", // END diff --git a/src/assets/img/icons/ccpa-icon.svg b/src/assets/img/icons/ccpa-icon.svg new file mode 100644 index 000000000..30eb3e086 --- /dev/null +++ b/src/assets/img/icons/ccpa-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/common-components/button-question/button-question.spec.js b/src/common-components/button-question/button-question.spec.js index 006cbcf2c..132e5edb9 100644 --- a/src/common-components/button-question/button-question.spec.js +++ b/src/common-components/button-question/button-question.spec.js @@ -1,4 +1,4 @@ -import { shallowMount } from "@vue/test-utils"; +import { shallowMount, mount } from "@vue/test-utils"; import buttonQuestion from "@/common-components/button-question/button-question"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; @@ -115,6 +115,38 @@ describe("buttonQuestion.vue", () => { "2020", ]); }); + test("should accept an imported component for buttonTypeObject and successfully add it to components", async () => { + // Arrange + const mockComponent = { + name: "mockComponent", + methods: { + mockComponentMethod() { + return "mockComponentMethod return value"; + }, + }, + }; + + const wrapper = await shallowMount( + buttonQuestion, + setupMocks({ + propsData: { + buttonTypeString: "mockComponent", + buttonTypeObject: mockComponent, + }, + }) + ); + + // Act + const componentList = wrapper.vm.$options.components; + const componentExists = !!componentList.mockComponent; + const componentNameMatches = componentList.mockComponent.name === mockComponent.name; + const componentMethodMatches = + componentList.mockComponent.methods.mockComponentMethod() === + mockComponent.methods.mockComponentMethod(); + + // Assert + expect(componentExists && componentNameMatches && componentMethodMatches).toBe(true); + }); }); describe("buttonsInfo", () => { diff --git a/src/common-components/date-picker/date-picker-spec.js b/src/common-components/date-picker/date-picker-spec.js1 similarity index 100% rename from src/common-components/date-picker/date-picker-spec.js rename to src/common-components/date-picker/date-picker-spec.js1 diff --git a/src/common-components/funnel-footer/funnel-footer.spec.js b/src/common-components/funnel-footer/funnel-footer.spec.js index cd2a06663..6360fb34a 100644 --- a/src/common-components/funnel-footer/funnel-footer.spec.js +++ b/src/common-components/funnel-footer/funnel-footer.spec.js @@ -2,7 +2,7 @@ import { mount } from "@vue/test-utils"; import funnelFooter from "./funnel-footer"; describe("funnel-footer.vue", () => { - it("Should emit ForwardClicked on button click", async () => { + test("Should emit ForwardClicked on button click", async () => { // Act const wrapper = mount(funnelFooter, { mixins: [mockMixin], @@ -12,7 +12,7 @@ describe("funnel-footer.vue", () => { expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled; }); - it("Should emit BackClicked on link click", async () => { + test("Should emit BackClicked on link click", async () => { // Act const wrapper = mount(funnelFooter, { mixins: [mockMixin], @@ -22,7 +22,7 @@ describe("funnel-footer.vue", () => { expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled; }); - it("Should change button text when update button text is called", async () => { + test("Should change button text when update button text is called", async () => { // Act const wrapper = mount(funnelFooter, { mixins: [mockMixin], @@ -32,6 +32,23 @@ describe("funnel-footer.vue", () => { // Assert expect(wrapper.componentVM.customButtontext).toBe("newText"); }); + + test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => { + // Arrange + const wrapper = mount(funnelFooter, { + mixins: [mockMixin], + }); + + // Act + wrapper.vm.$refs.buttonMain.removeLoader = jest.fn(); + wrapper.vm.removeLoader(); + const spy = jest.spyOn(document, "onkeydown"); + document.onkeydown(); + + // Assert + expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled(); + expect(spy).toReturnWith(true); + }); }); const mockMixin = { diff --git a/src/common-components/funnel-header/menu-modal/menu-modal.vue b/src/common-components/funnel-header/menu-modal/menu-modal.vue index 55ed98dd9..fd0c96cb8 100644 --- a/src/common-components/funnel-header/menu-modal/menu-modal.vue +++ b/src/common-components/funnel-header/menu-modal/menu-modal.vue @@ -44,16 +44,28 @@ + + + @@ -147,6 +159,11 @@ export default { overflow-y: visible; .modal-body { padding: 2rem; + .ccpa-icon { + width: 2.0625rem; + height: 1rem; + margin-left: 0.5rem; + } } .modal-fullscreen { width: 100vw; diff --git a/src/common-components/layouts/questions-page-layout/questions-page-layout.spec.js b/src/common-components/layouts/questions-page-layout/questions-page-layout.spec.js new file mode 100644 index 000000000..72da3c9df --- /dev/null +++ b/src/common-components/layouts/questions-page-layout/questions-page-layout.spec.js @@ -0,0 +1,253 @@ +// Components +import questionsPageLayout from "@/common-components/layouts/questions-page-layout/questions-page-layout"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import baseMixin from "../../../mixins/base-mixin"; +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; + +// 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/heritage-integration/navigation-helper", () => ({ + navigateToHeritageFunnel: jest.fn(), +})); + +describe("questionsPageLayout.vue", () => { + describe("method showThisQuestionChain...", () => { + test("Should return true if index prop and passed index match", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({ index: 0 }); + + const testGlassPiece = { + questions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?", + answers: [], + }, + ], + }; + const testIndex = 0; + + // Act + const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return true if answerResult exists", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({ index: 0 }); + + const testGlassPiece = { + questions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?", + answers: [], + }, + ], + answerData: { + answerResult: "test", + }, + }; + const testIndex = 1; + + // Act + const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return false if indexes don't match and answerResult is missing", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({ index: 0 }); + + const testGlassPiece = { + questions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?", + answers: [], + }, + ], + }; + const testIndex = 1; + + // Act + const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex); + + //Assert + expect(result).toBe(false); + + wrapper.unmount(); + }); + + test("Should return false if no questions", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({ index: 0 }); + + const testGlassPiece = {}; + const testIndex = 0; + + // Act + const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex); + + //Assert + expect(result).toBe(false); + + wrapper.unmount(); + }); + + test("Should return false if suppressed", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({ index: 0 }); + + const testGlassPiece = { + isSuppressedPart: true, + questions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?", + answers: [], + }, + ], + answerData: { + answerResult: "test", + }, + }; + const testIndex = 0; + + // Act + const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex); + + //Assert + expect(result).toBe(false); + + wrapper.unmount(); + }); + }); + + describe("method handleForwardButtonAction...", () => { + test("Should emit forwardButtonAction", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({}); + + // Act + wrapper.vm.handleForwardButtonAction(); + + //Assert + expect(wrapper.emitted()).toHaveProperty("forwardButtonAction"); + + wrapper.unmount(); + }); + }); + + describe("method handleBackButtonAction...", () => { + test("Should emit backButtonAction", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setProps({}); + + // Act + wrapper.vm.handleBackButtonAction(); + + //Assert + expect(wrapper.emitted()).toHaveProperty("back-click"); + + wrapper.unmount(); + }); + }); +}); + +function setupMocks() { + const baseStoreGettersPageData = () => { + return { + partsOrQuestions: [ + { + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: + "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + answers: [ + { + answerResult: "", + answerText: "Yes", + nextQuestionSequence: 2, + }, + { + answerResult: "", + answerText: "No", + nextQuestionSequence: 3, + }, + ], + }, + ], + glassLocation: "Windshield", + glassName: "Single", + answerKey: "Windshield-Single", + answerData: null, + }, + ], + }; + }; + const baseStoreGettersDamage = () => { + return { + partsQuestionAnswers: [ + { + glassLocation: "Windshield", + glassName: "Single", + result: "FW04848", + answeredQuestions: [ + { + questionText: + "Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?", + selectedAnswerText: "Yes", + questionNum: 1, + }, + { + questionText: + "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + selectedAnswerText: "Yes", + questionNum: 2, + }, + ], + }, + ], + }; + }; + const mountOptions = getMountOptions({ + mixins: [baseMixin, vehicleQuestionsMixin], + }); + mountOptions["attachTo"] = document.body; + const wrapper = shallowMount(questionsPageLayout, mountOptions); + + return { wrapper }; +} diff --git a/src/common-components/questions-page-layout/questions-page-layout.vue b/src/common-components/layouts/questions-page-layout/questions-page-layout.vue similarity index 94% rename from src/common-components/questions-page-layout/questions-page-layout.vue rename to src/common-components/layouts/questions-page-layout/questions-page-layout.vue index 85ccd33ad..d2d6aaab2 100644 --- a/src/common-components/questions-page-layout/questions-page-layout.vue +++ b/src/common-components/layouts/questions-page-layout/questions-page-layout.vue @@ -27,7 +27,7 @@ ref="funnelFooter" cmsWidgetName="FunnelFooterWidget" :isForwardActionDisabled="!isMetaValid" - @back-clicked="backButtonAction" + @back-clicked="handleBackButtonClicked" @ForwardClicked="handleForwardButtonAction" /> @@ -51,7 +51,7 @@ export default { alertFewMoreQuestionsCopy: String, questionsData: Array, validationRules: String, - modelValue: Array, + modelValue: Object, index: Number, }, computed: { @@ -66,16 +66,17 @@ export default { }, methods: { showThisQuestionChain(glass, i) { + // return false if no questions or if suppressed if (!glass.questions || glass.questions?.length < 1 || glass.isSuppressedPart) { return false; - } // return false if no questions or if suppressed + } return this.index === i || glass.answerData?.answerResult?.length > 0; }, handleForwardButtonAction() { this.$emit("forwardButtonAction"); }, handleBackButtonAction() { - this.$emit("backButtonAction"); + this.$emit("back-click"); }, showLoadingModal() { this.$refs.loadingModal.showModal(); diff --git a/src/common-components/modal/modal.spec.js b/src/common-components/modal/modal.spec.js index 85472d6eb..2664accfa 100644 --- a/src/common-components/modal/modal.spec.js +++ b/src/common-components/modal/modal.spec.js @@ -6,6 +6,10 @@ describe("modal.vue", () => { // Act const wrapper = shallowMount(Modal, { mixins: [mockMixin], + props: { + cmsWidgetName: "test", + }, + attachTo: document.body, }); expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"])); }); @@ -14,6 +18,10 @@ describe("modal.vue", () => { // Act const wrapper = shallowMount(Modal, { mixins: [mockMixin], + props: { + cmsWidgetName: "test", + }, + attachTo: document.body, }); expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"])); }); @@ -22,6 +30,10 @@ describe("modal.vue", () => { // Act const wrapper = shallowMount(Modal, { mixins: [mockMixin], + props: { + cmsWidgetName: "test", + }, + attachTo: document.body, }); expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"])); }); @@ -30,6 +42,10 @@ describe("modal.vue", () => { // Act const wrapper = shallowMount(Modal, { mixins: [mockMixin], + props: { + cmsWidgetName: "test", + }, + attachTo: document.body, }); expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"])); }); diff --git a/src/common-components/modal/modal.vue b/src/common-components/modal/modal.vue index 1546860a8..9a8e6c211 100644 --- a/src/common-components/modal/modal.vue +++ b/src/common-components/modal/modal.vue @@ -16,7 +16,7 @@ aria-label="Close">