From c286f748b67949573a1a99c97e74830222541df2 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Thu, 17 Nov 2022 14:28:40 -0500 Subject: [PATCH] CSR-803: several unit tests --- jest.config.js | 5 +- ...te-picker-spec.js => date-picker-spec.js1} | 0 .../funnel-footer/funnel-footer.spec.js | 23 +- .../question-chain/question-chain.spec.js | 322 ++++++++++++++ .../question-chain/question-chain.spec.js1 | 241 ----------- .../question-chain/question-chain.vue | 8 +- .../questions-page-layout.spec.js | 253 +++++++++++ .../questions-page-layout.vue | 5 +- .../capability-questions.spec.js | 404 ++++++++++++++++++ .../capability-questions.vue | 5 +- .../molding-questions.spec.js | 351 +++++++++++++++ .../molding-questions/molding-questions.vue | 6 +- .../part-questions/part-questions.spec.js | 385 +++++++++++++++++ src/layouts/part-questions/part-questions.vue | 13 +- 14 files changed, 1759 insertions(+), 262 deletions(-) rename src/common-components/date-picker/{date-picker-spec.js => date-picker-spec.js1} (100%) create mode 100644 src/common-components/question-chain/question-chain.spec.js delete mode 100644 src/common-components/question-chain/question-chain.spec.js1 create mode 100644 src/common-components/questions-page-layout/questions-page-layout.spec.js create mode 100644 src/layouts/capability-questions/capability-questions.spec.js create mode 100644 src/layouts/molding-questions/molding-questions.spec.js create mode 100644 src/layouts/part-questions/part-questions.spec.js diff --git a/jest.config.js b/jest.config.js index 146264edd..bfb4bf71f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,12 +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/ux-components/text-link/**/*.vue", - "!src/common-components/question-chain/**/*.vue", + "!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/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/question-chain/question-chain.spec.js b/src/common-components/question-chain/question-chain.spec.js new file mode 100644 index 000000000..8288f351c --- /dev/null +++ b/src/common-components/question-chain/question-chain.spec.js @@ -0,0 +1,322 @@ +import { shallowMount } from "@vue/test-utils"; +import questionChain from "@/common-components/question-chain/question-chain.vue"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { nextTick } from "vue"; + +jest.mock( + "@/store", + () => { + return {}; + }, + { virtual: true } +); + +describe("Question Chain component", () => { + describe("on create...", () => { + test("Should populate questions data array", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const expectedFirstQuestionAnswer = { + answerResult: "DB09410", + buttonLabel: "Yes", + nextQuestionSequence: null, + questionSequence: 1, + questionType: "answer", + value: "1|answer|DB09410|Yes", + }; + + //Act + await nextTick(); + + //Assert + expect(wrapper.vm.questions[0].answers[0]).toMatchObject(expectedFirstQuestionAnswer); + }); + + test("Should not include suppressed questions on questions data array", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + await wrapper.setData({ + questionData: [ + { + questionSequence: 1, + questionText: "Question here?", + answers: [ + { + answerResult: "DB09410", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "DB10840", + answerText: "No", + nextQuestionSequence: null, + }, + ], + suppressThisQuestion: true, + }, + ], + }); + + //Act + await nextTick(); + + //Assert + expect(wrapper.vm.questions[0]).toBeFalsy(); + }); + }); + + describe("method handleAnswer...", () => { + test("should run getQuestionChainAnswerIfComplete", () => { + //Arrange + const { wrapper } = setupMocks({}); + const testQuestion = {}; + const testReturnedAnswer = "aReturnedAnswer"; + wrapper.vm.getQuestionChainAnswerIfComplete = jest.fn(); + + //Act + wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer); + + //Assert + expect(wrapper.vm.getQuestionChainAnswerIfComplete).toBeCalled(); + }); + + test("should emit update:modelValue if returnedAnswer contains 'answer'", () => { + //Arrange + const { wrapper } = setupMocks({}); + const testQuestion = {}; + const testReturnedAnswer = "1|answer|DB10840|No"; + + //Act + wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer); + + //Assert + expect(wrapper.emitted()).toHaveProperty("update:modelValue"); + expect(wrapper.emitted()["update:modelValue"][0][0]).toMatchObject({ + answerResult: "DB10840", + }); + }); + + test("should NOT emit update:modelValue if no returnedAnswer", () => { + //Arrange + const { wrapper } = setupMocks({}); + const testQuestion = {}; + + //Act + wrapper.vm.handleAnswer(testQuestion); + + //Assert + expect(wrapper.emitted()).not.toHaveProperty("update:modelValue"); + }); + + test("should NOT emit update:modelValue if returnedAnswer contains 'nextQuestion'", () => { + //Arrange + const { wrapper } = setupMocks({}); + const testQuestion = {}; + const testReturnedAnswer = "1|nextQuestion|DB10840|No"; + + //Act + wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer); + + //Assert + expect(wrapper.emitted()).not.toHaveProperty("update:modelValue"); + }); + }); + + describe("method getQuestionChainAnswerIfComplete...", () => { + test("should return false if no returned answer", () => { + //Arrange + const { wrapper } = setupMocks({}); + + //Act + const result = wrapper.vm.getQuestionChainAnswerIfComplete(); + + //Assert + expect(result).toBeFalsy(); + }); + + test("should set the answerSelected to match the answered one", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const testReturnedAnswer = "1|answer|DB10840|No"; + await wrapper.setData({ + questionData: [ + { + questionSequence: 1, + questionText: "Question here?", + answers: [ + { + answerResult: "DB09410", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "DB10840", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + }); + + //Act + wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer); + + //Assert + expect(wrapper.vm.questions[0].answerSelected).toBe("1|answer|DB10840|No"); + }); + + test("should remove answers of questions after the answered one", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const testReturnedAnswer = "1|answer|DB10840|No"; + await wrapper.setData({ + questionData: [ + { + questionSequence: 1, + questionText: "Question here?", + answers: [ + { + answerResult: "DB09410", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "DB10840", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + { + questionSequence: 2, + questionText: "Question 2", + answers: [ + { + answerResult: "2-yes", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "2-no", + answerText: "No", + nextQuestionSequence: null, + }, + ], + answerSelected: "previously selected answer", + }, + ], + }); + + //Act + wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer); + + //Assert + expect(wrapper.vm.questions[1].answerSelected).toBeUndefined; + }); + + test("should return false if returnedAnswer is a nextQuestion (not a final answer)", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const testReturnedAnswer = "1|nextQuestion|DB10840|No"; + + //Act + const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer); + + //Assert + expect(result).toBeFalsy(); + }); + + test("should trigger scroll to .current-question if returnedAnswer is a nextQuestion (not a final answer)", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const testReturnedAnswer = "1|nextQuestion|DB10840|No"; + + //Act + wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer); + + await nextTick(); + + //Assert + expect(Element.prototype.scrollIntoView).toHaveBeenCalled(); + }); + + test("should return answer object if returnedAnswer is a final matching answer", async () => { + //Arrange + const { wrapper } = setupMocks({}); + const testReturnedAnswer = "1|answer|DB10840|No"; + await wrapper.setData({ + questions: [ + { + questionSequence: 1, + questionText: "Question here?", + answers: [ + { + answerResult: "DB09410", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "DB10840", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + index: 0, + }); + + //Act + const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer); + + //Assert + expect(result).toMatchObject({ + answerResult: "DB10840", + answeredQuestions: [ + { questionNum: 1, questionText: "Question here?", selectedAnswerText: "No" }, + { + questionNum: 1, + questionText: "Does only your center sliding piece need to be replaced?", + selectedAnswerText: "No", + }, + ], + index: 0, + }); + }); + }); +}); + +function setupMocks({ + questionDataProp = [ + { + questionSequence: 1, + questionText: "Does only your center sliding piece need to be replaced?", + answers: [ + { + answerResult: "DB09410", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "DB10840", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], +}) { + Element.prototype.scrollIntoView = jest.fn(); + + const mountOptions = getMountOptions({}); + mountOptions.propsData = { + questionData: questionDataProp, + }; + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(questionChain, mountOptions); + + return { wrapper }; +} diff --git a/src/common-components/question-chain/question-chain.spec.js1 b/src/common-components/question-chain/question-chain.spec.js1 deleted file mode 100644 index 84795fac0..000000000 --- a/src/common-components/question-chain/question-chain.spec.js1 +++ /dev/null @@ -1,241 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import questionChain from "@/common-components/question-chain/question-chain.vue"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock("@/store",()=>{return{};},{virtual:true}); - -describe("Question Chain component", () => { - - it("Should not emit a modelValue change when setting selectedValue if isNewModelValueComplete is false", () => { - - //Arrange - const { wrapper } = setupMocks({ modelValueProp: [] }); - wrapper.vm.currentQuestion = 6; - const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()]; - const localThis = { - $emit: jest.fn(), - getNewModelValue: jest.fn(() => { return false }) - } - - //Act - questionChain.computed.selectedValue.set.call(localThis, answerReturned); - - //Assert - expect(localThis.$emit).not.toBeCalled(); - }); - - it("Should emit a modelValue change when setting selectedValue if isNewModelValueComplete is true", () => { - - //Arrange - const { wrapper } = setupMocks({ modelValueProp: [] }); - wrapper.vm.currentQuestion = 6; - const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()]; - const localThis = { - $emit: jest.fn(), - getNewModelValue: jest.fn(() => { return true }) - } - - //Act - questionChain.computed.selectedValue.set.call(localThis, answerReturned); - - //Assert - expect(localThis.$emit).toBeCalledWith("update:modelValue", true); - }); - - it("should return false if no returned answer is given", () => { - - //Arrange - const { wrapper } = setupMocks({ modelValueProp: [] }); - wrapper.vm.currentQuestion = 1; - const answerReturned = null; - - //Act - const result = wrapper.vm.getNewModelValue(answerReturned); - - //Assert - expect(result).toEqual(false); - }); - - it("should return false if the user's answer on the current question leads to another question", () => { - - //Arrange - const { wrapper } = setupMocks({ modelValueProp: [] }); - wrapper.vm.currentQuestion = 1; - const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()]; - - //Act - const result = wrapper.vm.getNewModelValue(answerReturned); - - //Assert - expect(result).toEqual(false); - }); - - it("should return an object with the final answer if the user's answer on the current question is a part number", () => { - - //Arrange - const { wrapper } = setupMocks({ modelValueProp: [] }); - wrapper.vm.currentQuestion = 6; - const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()]; - - //Act - const result = wrapper.vm.getNewModelValue(answerReturned); - - //Assert - expect(result).toEqual( - { - answerResult: 'DW02102', - answeredQuestions: [ - { - questionText: 'Is your vehicle equipped with heated seats?', - selectedAnswerText: 'Yes' - } - ] - } - ); - - }); - -}); - -function setupMocks({ - modelValueProp = "", - questionDataProp = { - "glassName": "Single", - "glassLocation": "Windshield", - "parts": null, - "partQuestions": [ - { - "questionSequence": 1, - "questionText": "Is your Cherokee the Overland edition which can be identified by having a wood and leather wrapped steering wheel?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": 2, - "answerResult": "" - }, - { - "answerText": "No", - "nextQuestionSequence": 3, - "answerResult": "" - } - ] - }, - { - "questionSequence": 2, - "questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": null, - "answerResult": "DW02270" - }, - { - "answerText": "No", - "nextQuestionSequence": null, - "answerResult": "DW02264" - } - ] - }, - { - "questionSequence": 3, - "questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": null, - "answerResult": "DW02268" - }, - { - "answerText": "No", - "nextQuestionSequence": 4, - "answerResult": "" - } - ] - }, - { - "questionSequence": 4, - "questionText": "Is your vehicle equipped with automatic climate control which will change the fan speed automatically in order to maintain a set temperature?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": 5, - "answerResult": "" - }, - { - "answerText": "No", - "nextQuestionSequence": 6, - "answerResult": "" - } - ] - }, - { - "questionSequence": 5, - "questionText": "Is your vehicle equipped with heated seats?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": null, - "answerResult": "DW02104" - }, - { - "answerText": "No", - "nextQuestionSequence": null, - "answerResult": "DW02103" - } - ] - }, - { - "questionSequence": 6, - "questionText": "Is your vehicle equipped with heated seats?", - "answers": [ - { - "answerText": "Yes", - "nextQuestionSequence": null, - "answerResult": "DW02102" - }, - { - "answerText": "No", - "nextQuestionSequence": null, - "answerResult": "DW02101" - } - ] - } - ], - }, - methodsToMock = [], -}) { - - //Mock store - store.dispatch = jest.fn(() => dataFromStoreApi); - store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); - - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn() - } - } - mountOptions.propsData = { - modelValue: modelValueProp, - questionData: questionDataProp, - }; - mountOptions.mixins = [mockMixin]; - - //Mock methods - methodsToMock.forEach((methodName) => { - questionChain.methods[methodName] = jest.fn(); - }); - - const wrapper = shallowMount(questionChain, mountOptions); - - //Mock CMS content - const cmsContent = { - }; - return { wrapper, cmsContent }; -} \ No newline at end of file diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 432fd2eca..11874670b 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -29,7 +29,7 @@ export default { }; }, props: { - questionData: Object, + questionData: Array, validationRules: String, modelValue: Object, index: Number, @@ -84,11 +84,7 @@ export default { handleAnswer(question, returnedAnswer) { /* returnedAnswer example format: - { - "checkValue": "1|answer|DD11132|Yes", - "value": "1|answer|DD11132|Yes", - "buttonId": "Driver-Front-1-1|answer|DD11132|Yes" - } + "1|answer|DD11132|Yes" */ question.answerSelected = returnedAnswer; diff --git a/src/common-components/questions-page-layout/questions-page-layout.spec.js b/src/common-components/questions-page-layout/questions-page-layout.spec.js new file mode 100644 index 000000000..b7e5446bb --- /dev/null +++ b/src/common-components/questions-page-layout/questions-page-layout.spec.js @@ -0,0 +1,253 @@ +// Components +import questionsPageLayout from "@/common-components/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/questions-page-layout/questions-page-layout.vue index b8411c755..d2d6aaab2 100644 --- a/src/common-components/questions-page-layout/questions-page-layout.vue +++ b/src/common-components/questions-page-layout/questions-page-layout.vue @@ -51,7 +51,7 @@ export default { alertFewMoreQuestionsCopy: String, questionsData: Array, validationRules: String, - modelValue: Array, + modelValue: Object, index: Number, }, computed: { @@ -66,9 +66,10 @@ 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() { diff --git a/src/layouts/capability-questions/capability-questions.spec.js b/src/layouts/capability-questions/capability-questions.spec.js new file mode 100644 index 000000000..c59857182 --- /dev/null +++ b/src/layouts/capability-questions/capability-questions.spec.js @@ -0,0 +1,404 @@ +// Components +import capabilityQuestions from "@/layouts/capability-questions/capability-questions"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import store from "@/store"; +import baseMixin from "../../mixins/base-mixin"; +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; +import { nextTick } from "vue"; + +// 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( + "@/store", + () => { + return {}; + }, + { virtual: true } +); + +jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ + navigateToHeritageFunnel: jest.fn(), +})); + +const baseStoreGettersPageData = () => { + return { + partsOrQuestions: [ + { + parts: [ + { + childPartQuestions: [], + }, + ], + capabilityQuestions: [ + { + 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: [ + { + answerResult1: "DYNAMIC", + answerResult2: "1", + answerText: "Yes", + nextQuestionSequence: null, + answerResult: "DYNAMIC", + }, + { + answerResult1: "Unknown", + answerResult2: "0", + answerText: "No", + nextQuestionSequence: null, + answerResult: "Unknown", + }, + ], + }, + ], + partQuestions: [], + questions: [], + 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, + }, + ], + }, + ], + }; +}; +store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, +}; +store.commit = jest.fn(); + +afterEach(() => { + // reset store after each test + store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, + }; +}); + +describe("capabilityQuestions.vue", () => { + describe("method arePagePrerequisitesValid...", () => { + test("Should return true for valid page requisites if pageData exists", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.getters.pageData = jest.fn(() => { + return undefined; + }); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + + test("Should be at least one item in partsOrQuestions", () => { + // Arrange + store.getters = { + pageData: jest.fn(() => { + return { + partsOrQuestions: [], + }; + }), + damage: baseStoreGettersDamage, + }; + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + }); + + describe("watch on selectedAnswers should be set up...", () => { + test("Should trigger handleAnswerUpdates if watched data changes", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + + // Act + wrapper.setData({ + selectedAnswers: { + "Windshield-Single": { + answerResult: "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, + }, + ], + index: 0, + }, + }, + }); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); + + describe("forwardButtonAction", () => { + test("Should clear out answerData", () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + questions: [], + parts: [ + { + childPartQuestions: [{}], + }, + ], + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.questionsData[0].answerData).toEqual({}); + + wrapper.unmount(); + }); + + test("Should save to Vuex store", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + questions: [], + parts: [ + { + childPartQuestions: [], + }, + ], + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenNthCalledWith( + 1, + "saveCapabilityQuestionAnswers", + [ + { + answeredQuestions: [], + glassLocation: "Windshield", + glassName: "Single", + isSuppressedPart: undefined, + result: "FW04848", + result1: "FW04848", + result2: undefined, + }, + ], + false + ); + + wrapper.unmount(); + }); + + test("Should call GET_PART_FROM_CAPABILITY_QUESTION_ANSWER API", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + questions: [], + parts: [ + { + childPartQuestions: [], + }, + ], + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenNthCalledWith( + 2, + "getPartFromCapabilityQuestionAnswer", + "Windshield", + false + ); + + wrapper.unmount(); + }); + + test("Should trigger navigateForward", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + questions: [], + parts: [ + { + childPartQuestions: [], + }, + ], + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); +}); + +function setupMocks({ + mountOptionsMockData = { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + store: { + getters: store.getters, + commit: store.commit, + }, + route: { + query: { + fmgPage: "capability-questions", + }, + }, + }, +}) { + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, vehicleQuestionsMixin], + }); + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(capabilityQuestions, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 33c9b0c08..298752045 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -106,7 +106,10 @@ export default { fmgPageValues.CAPABILITY_QUESTIONS ); return ( - capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0 + capabilityQuestionsPageData && + capabilityQuestionsPageData.partsOrQuestions.some( + (el) => el.capabilityQuestions.length > 0 + ) ); }, async forwardButtonAction() { diff --git a/src/layouts/molding-questions/molding-questions.spec.js b/src/layouts/molding-questions/molding-questions.spec.js new file mode 100644 index 000000000..a408a406f --- /dev/null +++ b/src/layouts/molding-questions/molding-questions.spec.js @@ -0,0 +1,351 @@ +// Components +import moldingQuestions from "@/layouts/molding-questions/molding-questions"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import store from "@/store"; +import baseMixin from "../../mixins/base-mixin"; +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; +import { nextTick } from "vue"; + +// 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( + "@/store", + () => { + return {}; + }, + { virtual: true } +); + +jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ + navigateToHeritageFunnel: jest.fn(), +})); + +const baseStoreGettersPageData = () => { + return { + partsOrQuestions: [ + { + parts: [ + { + childPartQuestions: [ + { + questionSequence: 1, + questionText: + "Does the rubber seal around your windshield have a chrome strip running through it?", + answers: [ + { + answerResult: "WKT D1106 C", + answerText: "Yes", + nextQuestionSequence: null, + }, + { + answerResult: "WKT D1106 B", + answerText: "No", + nextQuestionSequence: null, + }, + ], + }, + ], + basePartNumber: "DW01105", + color: "Green Tint, Blue Shade", + requiresRecalibration: false, + recalibrationType: "", + canSafeliteRecalibrate: false, + requiresCapabilityQuestions: false, + childParts: null, + partNumber: "DW01105GBNN", + description: "solar", + partType: "WINDSHIELD", + }, + ], + partQuestions: [], + 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, + }, + ], + }, + ], + }; +}; +store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, +}; +store.commit = jest.fn(); + +afterEach(() => { + // reset store after each test + store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, + }; +}); + +describe("moldingQuestions.vue", () => { + describe("method arePagePrerequisitesValid...", () => { + test("Should return true for valid page requisites if pageData exists", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.getters.pageData = jest.fn(() => { + return undefined; + }); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + + test("Should be at least one item in partsOrQuestions", () => { + // Arrange + store.getters = { + pageData: jest.fn(() => { + return { + partsOrQuestions: [], + }; + }), + damage: baseStoreGettersDamage, + }; + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + }); + + describe("watch on selectedAnswers should be set up...", () => { + test("Should trigger handleAnswerUpdates if watched data changes", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + + // Act + wrapper.setData({ + selectedAnswers: { + "Windshield-Single": { + answerResult: "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, + }, + ], + index: 0, + }, + }, + }); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); + + describe("forwardButtonAction", () => { + test("Should clear out answerData", () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.questionsData[0].answerData).toEqual({}); + + wrapper.unmount(); + }); + + test("Should save to Vuex store", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenNthCalledWith( + 1, + "saveMoldingQuestionAnswers", + [ + { + answeredQuestions: [], + glassLocation: "Windshield", + glassName: "Single", + isSuppressedPart: undefined, + partNum: "FW04848", + }, + ], + false + ); + + wrapper.unmount(); + }); + + test("Should trigger navigateForward", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); +}); + +function setupMocks({ + mountOptionsMockData = { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + store: { + getters: store.getters, + commit: store.commit, + }, + route: { + query: { + fmgPage: "molding-questions", + }, + }, + }, +}) { + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, vehicleQuestionsMixin], + }); + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(moldingQuestions, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index eb472bc4c..fc44c1a98 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -104,8 +104,12 @@ export default { const moldingQuestionsFromPageData = store.getters.pageData( fmgPageValues.MOLDING_QUESTIONS ); + return ( - moldingQuestionsFromPageData && Object.keys(moldingQuestionsFromPageData).length > 0 + moldingQuestionsFromPageData && + moldingQuestionsFromPageData.partsOrQuestions.some((glass) => + glass.parts?.some((part) => part?.childPartQuestions.length > 0) + ) ); }, async forwardButtonAction() { diff --git a/src/layouts/part-questions/part-questions.spec.js b/src/layouts/part-questions/part-questions.spec.js new file mode 100644 index 000000000..e74874ed7 --- /dev/null +++ b/src/layouts/part-questions/part-questions.spec.js @@ -0,0 +1,385 @@ +// Components +import partQuestions from "@/layouts/part-questions/part-questions"; + +// Supporting Files +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import store from "@/store"; +import { storeActions } from "@/constants/store-actions"; +import { storeMutations } from "@/constants/store-mutations"; +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import baseMixin from "../../mixins/base-mixin"; +import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; +import { nextTick } from "vue"; + +// 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( + "@/store", + () => { + return {}; + }, + { virtual: true } +); + +jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ + navigateToHeritageFunnel: jest.fn(), +})); + +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, + }, + ], + }, + ], + }; +}; +store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, +}; +store.commit = jest.fn(); + +afterEach(() => { + // reset store after each test + store.getters = { + pageData: baseStoreGettersPageData, + damage: baseStoreGettersDamage, + }; +}); + +describe("partQuestions.vue...", () => { + describe("method arePagePrerequisitesValid...", () => { + test("Should return true for valid page requisites if pageData exists", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBe(true); + + wrapper.unmount(); + }); + + test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => { + // Arrange + const { wrapper } = setupMocks({}); + store.getters.pageData = jest.fn(() => { + return undefined; + }); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + + test("Should be at least one item in partsOrQuestions", () => { + // Arrange + store.getters = { + pageData: jest.fn(() => { + return { + partsOrQuestions: [], + }; + }), + damage: baseStoreGettersDamage, + }; + const { wrapper } = setupMocks({}); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(result).toBeFalsy(); + + wrapper.unmount(); + }); + }); + + describe("watch on selectedAnswers should be set up...", () => { + test("Should trigger handleAnswerUpdates if watched data changes", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates"); + + // Act + wrapper.setData({ + selectedAnswers: { + "Windshield-Single": { + answerResult: "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, + }, + ], + index: 0, + }, + }, + }); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); + + describe("forwardButtonAction", () => { + test("Should clear out answerData", () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + + // Act + wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.questionsData[0].answerData).toEqual({}); + + wrapper.unmount(); + }); + + test("Should save to Vuex store", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenNthCalledWith( + 1, + "savePartQuestionAnswers", + [ + { + answeredQuestions: [], + glassLocation: "Windshield", + glassName: "Single", + isSuppressedPart: undefined, + result: "FW04848", + }, + ], + false + ); + + wrapper.unmount(); + }); + + test("Should call GET_PARTS API", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction"); + + // Act + wrapper.vm.forwardButtonAction(); + + await nextTick(); + + //Assert + expect(spy).toHaveBeenNthCalledWith(2, "getParts"); + + wrapper.unmount(); + }); + + test("Should trigger navigateForward", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + answerData: { + answerResult: "FW04848", + answeredQuestions: [], + }, + }, + ]; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: { + glassPieceParts: [], + }, + }; + }); + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + + wrapper.unmount(); + }); + }); +}); + +function setupMocks({ + mountOptionsMockData = { + router: { + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + actionList: [ + { + actionName: storeActions.SAVE_PART_QUESTION_ANSWERS, + data: {}, + }, + { + actionName: storeActions.GET_PARTS, + data: {}, + }, + ], + store: { + getters: store.getters, + commit: store.commit, + }, + route: { + query: { + fmgPage: "part-questions", + }, + }, + }, +}) { + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, vehicleQuestionsMixin], + }); + mountOptions["attachTo"] = document.body; + + const wrapper = shallowMount(partQuestions, mountOptions); + + return { wrapper }; +} diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 7c82fe6df..1704d46e8 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -103,22 +103,27 @@ export default { methods: { arePagePrerequisitesValid() { const partQuestionsFromPageData = store.getters.pageData(fmgPageValues.PART_QUESTIONS); - return partQuestionsFromPageData && Object.keys(partQuestionsFromPageData).length > 0; + return ( + partQuestionsFromPageData && + Object.keys(partQuestionsFromPageData.partsOrQuestions).length > 0 + ); }, async forwardButtonAction() { const questionAnswersArray = this.questionsData.map((glass) => { return { glassLocation: glass.glassLocation, glassName: glass.glassName, - result: glass.answerData.answerResult, - answeredQuestions: glass.answerData.answeredQuestions, + result: (glass.answerData && glass.answerData.answerResult) || "", + answeredQuestions: glass.answerData?.answeredQuestions, isSuppressedPart: glass.isSuppressedPart, }; }); // clear out answerData for future page loads; must occur prior to store save this.questionsData.forEach((glass) => { - glass.answerData = {}; + if (glass.answerData) { + glass.answerData = {}; + } }); // save to vuex store as order.damage.partQuestionAnswers (array)