From a1c20e41a275245e3037ec615f72d58055ebfced Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Sat, 5 Nov 2022 16:13:50 -0400 Subject: [PATCH] CSR-803: bulk of refactoring --- .../question-chain/question-chain.vue | 8 +- .../questions-page/questions-page.vue | 106 +++ src/global-methods.js | 16 - .../capability-questions.vue | 141 ++- .../molding-questions/molding-questions.vue | 108 +-- src/layouts/part-questions/part-questions.vue | 106 +-- src/mixins/vehicle-questions-mixin.js | 311 +++---- src/mixins/vehicle-questions-mixin.spec.js | 821 +++++++++++++++++- 8 files changed, 1165 insertions(+), 452 deletions(-) create mode 100644 src/common-components/questions-page/questions-page.vue diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 6121cbd25..7c9767d47 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -31,8 +31,9 @@ export default { props: { questionData: Object, validationRules: String, - modelValue: Array, + modelValue: Object, glassIndex: Number, + answerKey: String, }, async created() { // do a test validation check upon create to prevent out of sync / incorrect valid states @@ -65,7 +66,7 @@ export default { }), answerSelected: q.answerSelected || "", }; - if (!q.suppressQuestion) { + if (!q.suppressThisQuestion) { this.questions.push(question); } }); @@ -81,7 +82,6 @@ export default { }, methods: { handleAnswer(question, returnedAnswer) { - question.answerSelected = returnedAnswer; /* returnedAnswer example format: { @@ -90,6 +90,8 @@ export default { "buttonId": "Driver-Front-1-1|answer|DD11132|Yes" } */ + + question.answerSelected = returnedAnswer; const isQuestionChainComplete = this.getQuestionChainAnswerIfComplete(returnedAnswer); if (isQuestionChainComplete) { diff --git a/src/common-components/questions-page/questions-page.vue b/src/common-components/questions-page/questions-page.vue new file mode 100644 index 000000000..3d04f804d --- /dev/null +++ b/src/common-components/questions-page/questions-page.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/global-methods.js b/src/global-methods.js index 30eeffb65..14e5cca0e 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -7,7 +7,6 @@ import { GaCategories, GaActions, GaLabels } from "@/constants/analytics"; import { headerKeys } from "@/constants/header-keys"; export default { -<<<<<<< Updated upstream callHttpClient({ method, endpoint, payload, logApiCall = true }) { return new Promise((resolve, reject) => { const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; @@ -15,21 +14,6 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; -======= - callHttpClient({ method, endpoint, payload, logApiCall = true }) { - return new Promise((resolve, reject) => { - let cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; - if (endpoint.includes("/order/")) { - cfDistroUrl = "https://localhost:5001"; - } - if (endpoint.includes("/parts/")) { - cfDistroUrl = "https://localhost:5003"; - } - const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); - const headers = { - [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings) - } ->>>>>>> Stashed changes axios({ method: method, diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index c46aa353a..0f7a0e57e 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -1,47 +1,28 @@ - - diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 336ee1096..9f0362b44 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -1,51 +1,28 @@ - - diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 7b389158d..02200585f 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -1,51 +1,28 @@ - diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 627874abd..a362ec2c6 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -1,6 +1,5 @@ import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { storeMutations } from "@/constants/store-mutations.js"; -import { damageLocationsSelected } from "@/constants/damage-locations-selected"; import { navigationScenarios } from "../router/router-constants/navigation-scenarios"; import { storeActions } from "@/constants/store-actions"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; @@ -68,8 +67,8 @@ export default { return this.comparePageIndices(currentPage, fmgPage) > 0; }, setupInitialData(glass, i, alreadyAnsweredQuestions, vm) { - glass.key = glass.glassLocation + "-" + glass.glassName; const self = vm ?? this; + // clear answerData if no questions are already answered if (!alreadyAnsweredQuestions) { glass.answerData = null; @@ -82,9 +81,7 @@ export default { !answeredGlass.glassName || !answeredGlass.answeredQuestions || (!answeredGlass.result && !answeredGlass.partNum) - ) { - return; - } + ) { return } // test if glass parts match if ( @@ -94,33 +91,33 @@ export default { let answerString = ""; // loop through answeredQuestions for matches - answeredGlass.answeredQuestions.forEach((aq) => { - if (!aq.questionNum || !aq.selectedAnswerText) { + answeredGlass.answeredQuestions.forEach((answeredQuestion) => { + if (!answeredQuestion.questionNum || !answeredQuestion.selectedAnswerText) { return; } // determine which answer was previously chosen - const chosenAns = glass.questions[aq.questionNum - 1].answers.find((a) => { + const chosenAns = glass.questions[answeredQuestion.questionNum - 1].answers.find((a) => { return ( - a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase() + a.answerText.toUpperCase() === answeredQuestion.selectedAnswerText.toUpperCase() ); }); // set the answerString to use for answerSelected if (chosenAns.nextQuestionSequence) { - answerString = `${aq.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`; + answerString = `${answeredQuestion.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`; } else { - answerString = `${aq.questionNum}|answer|${chosenAns.answerResult}|${chosenAns.answerText}`; + answerString = `${answeredQuestion.questionNum}|answer|${chosenAns.answerResult}|${chosenAns.answerText}`; } // mark this question as answered (question-chain will read this) - glass.questions[aq.questionNum - 1].answerSelected = answerString; + glass.questions[answeredQuestion.questionNum - 1].answerSelected = answerString; // mark this question as suppressed if needed (question-chain uses this) - if (aq.suppressQuestion) { - glass.questions[aq.questionNum - 1].suppressQuestion = true; + if (answeredQuestion.suppressThisQuestion) { + glass.questions[answeredQuestion.questionNum - 1].suppressThisQuestion = true; } }); - // advance the currentGlassIndex - self.currentGlassIndex = i; + // advance the currentGlassPieceIndex + self.currentGlassPieceIndex = i; const answerResult = answeredGlass.partNum ? answeredGlass.partNum @@ -135,21 +132,9 @@ export default { } }); - // Set up watch for each set of glass questions - // (updated when all questions for a glass have been answered in question-chain) - self.$watch( - "selectedAnswers." + glass.glassLocation + "-" + glass.glassName, - (newValue) => { - if (newValue) { - self.handleAnswerUpdates(newValue); - } - }, - { deep: true } - ); - return glass; }, - handleAnswerUpdates(answer, vm) { + handleAnswerUpdates(answer, glassKey, vm) { // only runs when all questions in a question-chain have been answered // when selectedAnswers updates, user has completed this part's question chain and has a final answer // (does not get run for each invididual question's answer, only when @@ -171,236 +156,183 @@ export default { const self = vm ?? this; - // collect a list of the answered questions' numbers, needed later below - const answeredQuestionIndexes = []; - const foundDuplicateQuestions = []; - - // if user has answered a question differently than anything that was preloaded, - // we need to clear out any preloaded answers + // clear out any preloaded answers self.selectedAnswers = {}; // loop through every answered question on the currently answered glass part - answer.answeredQuestions?.forEach((aq) => { + answer.answeredQuestions?.forEach((answeredQuestion) => { - // keep track of this question number - answeredQuestionIndexes.push(aq.questionNum); + /* answeredQuestion example format: + { + "questionText": "Is your Grand Cherokee the Laredo model?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + */ - const answeredQuestionText = aq.questionText.toUpperCase(); - const answeredQuestionAnswer = aq.selectedAnswerText.toUpperCase(); + const answeredQuestionText = answeredQuestion.questionText.toUpperCase(); + const answeredQuestionAnswer = answeredQuestion.selectedAnswerText.toUpperCase(); // HANDLE DUPLICATE QUESTIONS - // loop through all glass parts data - self.questionsData.forEach((glass, gpIndex) => { + // loop through all glass pieces data + self.questionsData.forEach((glassPiece, pieceIndex) => { + + /* glassPiece example format: + { + "glassName": "Single", + "glassLocation": "Windshield", + "parts": null, + "questions": [ + { + "questionSequence": 1, + "questionText": "Is your vehicle equipped with a black dotted pattern behind the rear view mirror, known as a third visor frit?", + "answers": [ + { + "answerResult": "DW01537", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "DW01537b", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ], + "answerKey": "Windshield-Single", + "answerData": null + } + */ - // only look for duplicates forward... to parts that follow after the currently being answered part - if (gpIndex > answer.glassIndex) { + // limit duplicate search to glass pieces that follow after the currently being answered glass piece + if (pieceIndex > answer.glassIndex) { - let suppressUntil; - // reset this glass part, in case user is changing their previous answers - glass.answerData = null; - glass.isSuppressedPart = null; + let indexToSuppressTo; + // reset this glass piece, in case user is changing their previous answers + glassPiece.answerData = null; + glassPiece.isSuppressedPart = null; - // loop through this glass part's questions, looking for a questionText match - glass.questions.forEach((pq, pqIndex) => { + // loop through this glass piece's questions, looking for a questionText match + glassPiece.questions.forEach((question, questionIndex) => { // clear out any previously set answers - pq.answerSelected = null; + question.answerSelected = null; - // clear or set suppressQuestion property for each question - if (suppressUntil) { - // if suppressUntil has been set, then suppress this question if before it - if (pqIndex + 1 < suppressUntil) { - pq.suppressQuestion = true; - } else { - pq.suppressQuestion = null; - } + // clear or set suppressThisQuestion property for each question + if (indexToSuppressTo && questionIndex + 1 < indexToSuppressTo) { + question.suppressThisQuestion = true; } else { - pq.suppressQuestion = null; + question.suppressThisQuestion = null; } - // if these match then we have a duplicate question - if (pq.questionText.toUpperCase() === answeredQuestionText) { - - const thisAnsweredQuestion = glass.questions[pqIndex]; + // handle duplicate questions + if (question.questionText.toUpperCase() === answeredQuestionText) { let matchedAnswer; - let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... - // which one of this questions' answers matches our answer? - pq.answers.forEach((ans) => { + // handle matching answer in duplicated question + question.answers.forEach((ans) => { if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { matchedAnswer = ans; ans.selected = true; } else { - rejectedAnswers.push(ans); ans.selected = null; } }); - // Update the key to re-render this part's question-chain component - self.questionsData[gpIndex].key = self.questionsData[gpIndex].glassLocation + self.questionsData[gpIndex].glassName + Date.now().toString(); - - // handle suppressing downstream in this question chain - + // handle duplicate's nextQuestion logic on other related questions if (matchedAnswer.nextQuestionSequence) { - // ensure that the question that the accepted answer has set to be next is NOT suppressed - glass.questions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; - // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number - if (pqIndex === 0) { - if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence} + // clear any suppression on the nextQuestion + glassPiece.questions[matchedAnswer.nextQuestionSequence - 1].suppressThisQuestion = null; + // if the duplicate is 1ST question in array, set indexToSuppressTo + if (questionIndex === 0) { + if (!indexToSuppressTo || matchedAnswer.nextQuestionSequence < indexToSuppressTo) { indexToSuppressTo = matchedAnswer.nextQuestionSequence} } } - // handle suppressing upstream in this question chain - glass.questions.forEach((q) => { - q.answers.forEach((thisAns) => { - // restore any of the answers that formerly led to the duplicated question - if (thisAns.originalNextQuestionSequence === pq.questionSequence) { + // update answers in this glass piece's questions with duplication logic modifications + glassPiece.questions.forEach((q) => { + q.answers.forEach((a) => { + // revert any previously set nextQuestion logic modifications + if (a.originalNextQuestionSequence === question.questionSequence) { // restore original nextQuestionSequence - thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; + a.nextQuestionSequence = a.originalNextQuestionSequence; self.originalNextQuestionSequence = null; // restore original answerResult - if (thisAns.originalAnswerResult) { - thisAns.answerResult = thisAns.originalAnswerResult; - thisAns.originalAnswerResult = null; + if (a.originalAnswerResult) { + a.answerResult = a.originalAnswerResult; + a.originalAnswerResult = null; } } - // search for any answers that lead to the duplicated question - if (thisAns.nextQuestionSequence === pq.questionSequence) { - // update either the nextQuestionSequence or the answerResult + // modify logic on any related questions + if (a.nextQuestionSequence === question.questionSequence) { + // update either nextQuestionSequence or answerResult + + // update questions that lead to duplicated question if (matchedAnswer.nextQuestionSequence) { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; + a.originalNextQuestionSequence = a.nextQuestionSequence; + a.nextQuestionSequence = matchedAnswer.nextQuestionSequence; } else { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = null; - thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; - thisAns.answerResult = matchedAnswer.answerResult; + a.originalNextQuestionSequence = a.nextQuestionSequence; + a.nextQuestionSequence = null; + a.originalAnswerResult = a.originalAnswerResult || a.answerResult; + a.answerResult = matchedAnswer.answerResult; } } }); }); // suppress current question - thisAnsweredQuestion.suppressQuestion = true; - - const thisGlassPart = "glass" + gpIndex; - if (foundDuplicateQuestions[thisGlassPart]) { - if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredQuestion.questionSequence)) { - foundDuplicateQuestions[thisGlassPart].push(thisAnsweredQuestion.questionSequence); - } - } else { - foundDuplicateQuestions[thisGlassPart] = [thisAnsweredQuestion.questionSequence]; - } + question.suppressThisQuestion = true; // are there any questions left that are not suppressed? - const remainingQuestions = glass.questions.filter((q) => { - return !q.suppressQuestion; + const remainingQuestions = glassPiece.questions.filter((q) => { + return !q.suppressThisQuestion; }); if (remainingQuestions.length < 1) { - // this is the final answer for this glass part + // this is the final answer for this glass piece - // mark this part as completely answered by adding answerData + // mark this glass piece as completely answered by adding answerData const answeredQuestionObj = { - questionText: pq.questionText, + questionText: question.questionText, selectedAnswerText: matchedAnswer.answerText, - questionNum: pq.questionSequence, - suppressQuestion: pq.suppressQuestion, + questionNum: question.questionSequence, + suppressThisQuestion: question.suppressThisQuestion, }; - // set the answerData as 'already answered' - glass.answerData = { + // set the answerData (used as indicator that it has been already answered) + glassPiece.answerData = { answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, answeredQuestions: [answeredQuestionObj], }; - // suppress this glass because it has an answer - glass.isSuppressedPart = true; + // suppress this glass piece because it has an answer + glassPiece.isSuppressedPart = true; } } - }); - // Update the key to re-render this part's question-chain component - self.questionsData[gpIndex].key = self.questionsData[gpIndex].glassLocation + self.questionsData[gpIndex].glassName + Date.now().toString(); - + // Update key to force re-render of glass piece with duplicate question in case user changes previous related answer in the chain + self.questionsData[pieceIndex].key = self.questionsData[pieceIndex].key + Date.now().toString(); } }); }); - // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART - - // look through all (this part's) part questions for any duplicates that were suppressed; - // add them to the list of answered questions if found - - // EX answeredQuestionIndexes: [1,5,11,13] - - // EX foundDuplicateQuestions = { - // "glassPart1": [1], - // "glassPart2": [7, 10] - // }; - - const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; - const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; - const glassPartAnswered = self.questionsData[answer.glassIndex]; - - thisPartsDupes?.forEach((dupe) => { - // dupe is a single integer - const dupeQuestion = glassPartAnswered.questions[dupe - 1]; - const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true); - - glassPartAnswered.questions.forEach((q) => { - let includeThisDupeInAnsweredQuestions = false; - - // did one of the answers of this question point to the duplicated question? - q.answers.forEach((a) => { - if ((dupe === a.originalNextQuestionSequence) && - (answeredQuestionIndexes.includes(q.questionSequence)) && - (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { - includeThisDupeInAnsweredQuestions = true; - } - }); - - // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? - if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { - includeThisDupeInAnsweredQuestions = true; - } - - if (includeThisDupeInAnsweredQuestions) { - completeAnsweredQuestions.push({ - questionNum: dupeQuestion.questionSequence, - questionText: dupeQuestion.questionText, - selectedAnswerText: dupeQuestionAnswer.answerText, - suppressQuestion: dupeQuestion.suppressQuestion, - }); - } - }); - }); - - // make sure there are no duplicated dupes in the list... - const foundInCompleteAnsweredQuestions = new Set(); - let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { - const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); - foundInCompleteAnsweredQuestions.add(el.questionText); - return !duplicate; - }); - filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum); - // set final answer data for the current answered glass part - glassPartAnswered.answerData = { + self.questionsData[answer.glassIndex].answerData = { answerResult: answer.answerResult, - answeredQuestions: filteredCompleteAnsweredQuestions, + answeredQuestions: answer.answeredQuestions, } // this part has been fully answered, so advance to next part's question chain - for (let i = answer.glassIndex + 1; i < self.questionsData.length; i++) { + for (let i = answer.glassIndex + 1; i < this.questionsData.length; i++) { // if this part has not yet been fully answered, then make it the current part - if (!self.questionsData[i].answerData?.answerResult) { - self.currentGlassIndex = i; + if (!this.questionsData[i].answerData?.answerResult) { + this.currentGlassPieceIndex = i; break; } } @@ -495,12 +427,19 @@ export default { { partsOrQuestions } ); } else { + // if single parts only const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); + // save to store lineItems.glassParts self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts); - self.$refs.loadingModal.showModal(); + if (self.$refs.questionsPage) { + self.$refs.questionsPage.showLoadingModal(); + } else if (self.$refs.loadingModal) { + self.$refs.loadingModal.showModal(); + } + navigateToHeritageFunnel(); } }, diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index 6f14cebdd..41ddc8ea2 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -337,24 +337,6 @@ describe("vehicle-questions-mixin", () => { }); describe("setupInitialData", () => { - describe("should always", () => { - test("return glass with new key attribute", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const glass = { - glassName: "Single", - glassLocation: "Windshield", - }; - const i = 0; - - // Act - const returnedGlass = await wrapper.vm.setupInitialData(glass, i); - - // Assert - expect(returnedGlass).toMatchObject({ key: "Windshield-Single" }); - }); - }); - describe("if no alreadyAnsweredQuestions", () => { test("should return glass with answerData of null", async () => { // Arrange @@ -382,8 +364,7 @@ describe("vehicle-questions-mixin", () => { questions: [ { questionSequence: 1, - questionText: - "Does the rubber seal around your windshield have a chrome strip running through it?", + questionText: "Does the rubber seal around your windshield have a chrome strip running through it?", answers: [ { answerResult: "WKT D1106 C", @@ -407,8 +388,7 @@ describe("vehicle-questions-mixin", () => { partNum: "WKT D1106 C", answeredQuestions: [ { - questionText: - "Does the rubber seal around your windshield have a chrome strip running through it?", + questionText: "Does the rubber seal around your windshield have a chrome strip running through it?", selectedAnswerText: "Yes", questionNum: 1, }, @@ -430,6 +410,803 @@ describe("vehicle-questions-mixin", () => { }); }); + describe("handleAnswerUpdates", () => { + describe("selectedAnswers", () => { + test("should be cleared to be empty", () => { + // Arrange + const answer = { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.selectedAnswers = { "test": "mockSelectedAnswers" }; + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [], + "answerData": "testAnswerData1" + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, '', wrapper.vm); + + // Assert + expect(wrapper.vm.selectedAnswers).toMatchObject({}); + }); + }); + + describe("questions in glass parts that are after the answered glass", () => { + test("should have answerData cleared", () => { + // Arrange + const answer = { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [], + "answerData": "testAnswerData1" + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [], + "answerData": "testAnswerData2" + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, '', wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].answerData).toEqual(null); + }); + test("should have isSuppressedPart cleared", () => { + // Arrange + const answer = { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [], + "answerData": "testAnswerData1" + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [], + "answerData": "testAnswerData2", + isSuppressedPart: true + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, '', wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].isSuppressedPart).toEqual(null); + }); + test("should set answerSelected for each glass part question to null ", () => { + // Arrange + const answer = { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [], + "answerData": "testAnswerData1" + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "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 + } + ], + "answerSelected": "456" + }, + { + "questionSequence": 2, + "questionText": "Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?", + "answers": [ + { + "answerResult": "FW04848", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "FW04846", + "answerText": "No", + "nextQuestionSequence": null + } + ], + "answerSelected": "789" + } + ], + "answerData": "testAnswerData2" + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answer, '', wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].questions[0].answerSelected).toEqual(null); + expect(wrapper.vm.questionsData[1].questions[1].answerSelected).toEqual(null); + }); + }); + + describe("if there is a duplicate question", () => { + + test("then the glass piece's key should be updated", () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "key": "testkey1", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "key": "testkey2", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ] + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + const glassPieceWithDuplicate = wrapper.vm.questionsData[1]; + + // Assert + expect(glassPieceWithDuplicate.key).not.toBe("testkey2"); + }); + + test("then that question should be supressed", () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ] + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + const duplicateQuestion = wrapper.vm.questionsData[1].questions[0]; + + // Assert + expect(duplicateQuestion.suppressThisQuestion).toBeTruthy(); + }); + + describe("and the duplicate has a nextQuestionSequence value", () => { + + test("then the question set as nextQuestionSequence should not be suppressed", () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "questionSequence": 1, + "questionText": "ZZZTest duplicate question 1?", + "answers": [ + { + "answerResult": "", + "answerText": "Yes", + "nextQuestionSequence": 2 + }, + { + "answerResult": "", + "answerText": "No", + "nextQuestionSequence": 3 + } + ] + }, + { + "questionSequence": 2, + "questionText": "Test question 2?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + { + "questionSequence": 3, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "345", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ], + "suppressThisQuestion": true + } + ] + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + const nextQuestionAfterDuplicate = wrapper.vm.questionsData[1].questions[2]; + + // Assert + expect(nextQuestionAfterDuplicate.suppressThisQuestion).not.toBeTruthy(); + }); + + test("then the nextQuestionSequence should be updated and the original value saved", () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test question 3?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test question 1?", + "answers": [ + { + "answerResult": "", + "answerText": "Yes", + "nextQuestionSequence": 2 + }, + { + "answerResult": "", + "answerText": "No", + "nextQuestionSequence": 3 + } + ] + }, + { + "questionSequence": 2, + "questionText": "Test question 2?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + { + "questionSequence": 3, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "", + "answerText": "Yes", + "nextQuestionSequence": 4 + }, + { + "answerResult": "", + "answerText": "No", + "nextQuestionSequence": 5 + } + ] + }, + { + "questionSequence": 4, + "questionText": "Test question 4?", + "answers": [ + { + "answerResult": "567", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "678", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + { + "questionSequence": 5, + "questionText": "Test question 5?", + "answers": [ + { + "answerResult": "789", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "890", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ] + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + const duplicatedQuestion = wrapper.vm.questionsData[1].questions[2]; + const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter(a => { + return a.selected; + }) + const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter(a => { + return a.originalNextQuestionSequence; + }); + + // Assert + expect(answerToTest[0].originalNextQuestionSequence).toEqual(duplicatedQuestion.questionSequence); + expect(answerToTest[0].nextQuestionSequence).toEqual(duplicatedQuestionAnswer[0].nextQuestionSequence); + }); + + describe("and the duplicate was the first question for that part", () => { + + test("then any questions up to the nextQuestionSequence value should be marked as suppressed", () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test duplicate question 1?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test duplicate question 1?", + "answers": [ + { + "answerResult": "", + "answerText": "Yes", + "nextQuestionSequence": 2 + }, + { + "answerResult": "", + "answerText": "No", + "nextQuestionSequence": 3 + } + ] + }, + { + "questionSequence": 2, + "questionText": "Test question 2?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + { + "questionSequence": 3, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "345", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + } + ] + } + ]; + + // Act + wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + + // Assert + expect(wrapper.vm.questionsData[1].questions[0].suppressThisQuestion).toBeTruthy(); + expect(wrapper.vm.questionsData[1].questions[1].suppressThisQuestion).toBeTruthy(); + expect(wrapper.vm.questionsData[1].questions[2].suppressThisQuestion).toBeFalsy(); + }); + + }); + + }); + + describe("and the duplicate has an answerResult", () => { + test("then any questions in the same glass piece that lead to the duplicate should be modified to just provide the duplicate's answerResult", async () => { + // Arrange + const answerNo = { + "answerResult": "456", + "answeredQuestions": [ + { + "questionText": "Test question 3?", + "selectedAnswerText": "No", + "questionNum": 1, + } + ], + "glassIndex": 0 + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + "glassLocation": "Windshield", + "glassName": "Single", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + }, + { + "glassLocation": "Driver", + "glassName": "Front", + "questions": [ + { + "questionSequence": 1, + "questionText": "Test question 1?", + "answers": [ + { + "answerResult": "", + "answerText": "Yes", + "nextQuestionSequence": 2 + }, + { + "answerResult": "", + "answerText": "No", + "nextQuestionSequence": 3 + } + ] + }, + { + "questionSequence": 2, + "questionText": "Test question 2?", + "answers": [ + { + "answerResult": "123", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "234", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + { + "questionSequence": 3, + "questionText": "Test question 3?", + "answers": [ + { + "answerResult": "345", + "answerText": "Yes", + "nextQuestionSequence": null + }, + { + "answerResult": "456", + "answerText": "No", + "nextQuestionSequence": null + } + ] + }, + ] + } + ]; + + // Act + await wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); + + const questionsToTest = wrapper.vm.questionsData[1].questions; + const answerLeadingToDuplicate = questionsToTest[0].answers[1]; + const duplicateQuestion = questionsToTest[2]; + const answerInDuplicateQuestion = duplicateQuestion.answers.filter(a => { + return a.selected; + }) + + // Assert + expect(answerLeadingToDuplicate.answerResult).toEqual(answerInDuplicateQuestion[0].answerResult); + expect(answerLeadingToDuplicate.originalAnswerResult).toBeFalsy(); + expect(answerLeadingToDuplicate.nextQuestionSequence).toEqual(null); + expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual(duplicateQuestion.questionSequence); + }); + }); + }); + }); + describe("navigateForward", () => { describe("should go to parts-questions", () => { test("single glass location has part question => go to parts-questions", async () => {