diff --git a/jest.config.js b/jest.config.js index a511fdc02..fe6eeb04d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -20,10 +20,8 @@ module.exports = { "!src/layouts/reveal/**/*.vue", "!src/layouts/estimate/**/*.vue", // TODO REMOVE THESE AFTER WRITING UNIT TESTS - "!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue", "!src/ux-components/alert/alert.vue", "!src/helpers/validation-rules.js", - "!src/common-components/question-chain/question-chain", // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], 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..84795fac0 --- /dev/null +++ b/src/common-components/question-chain/question-chain.spec.js @@ -0,0 +1,241 @@ +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 d605d7fde..ef56c4041 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -9,7 +9,7 @@ :groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`" textPosition="text-start" v-model="selectedValue" - isRequired=true + :isRequired=true :validationRules="validationRules" :clearOnUnmount=false /> @@ -30,12 +30,14 @@ export default { }; }, props: { - questionData: Array, + questionData: Object, validationRules: String, - modelValue: String, + modelValue: Array, }, computed: { + questions() { + console.log("answeredQuestions: ", this.answeredQuestions) const questions = this.questionData.partQuestions.map((q, i) => { return { questionText: q.questionText, @@ -52,7 +54,7 @@ export default { } }); // add an empty item to be array[0] since we start with 1 - questions.unshift({}); + questions.unshift({ "DeliberatelyBlankObject": "This object has been added as a placeholder only for question #0"}); return questions; }, selectedValue: { diff --git a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js index eaa24c9d4..d030c7c76 100644 --- a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js +++ b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js @@ -1,7 +1,6 @@ import { shallowMount } from "@vue/test-utils"; import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question"; - describe("addressVehiclesQuestion.vue", () => { it("Should return content for differentVehicleAlertHeader", () => { diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue index 7d936c5bf..d0def364d 100644 --- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue +++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue @@ -29,7 +29,11 @@ :buttonID="`${glassLocation}-${glassName}-${name}`" :groupName="`${glassLocation}-${glassName}`" @isCheckedChanged="ResetTintAndPartSelections()" + :validationRules="validationRules" /> +