diff --git a/src/common-components/loading-modal/loading-modal.vue b/src/common-components/loading-modal/loading-modal.vue index 8e4d1d994..9622435cf 100644 --- a/src/common-components/loading-modal/loading-modal.vue +++ b/src/common-components/loading-modal/loading-modal.vue @@ -13,19 +13,19 @@

- Assessing your damage + Finding shops near you . . .

- Finding your glass + Looking for dates . . .

- Generating your quote + Searching for times . . . diff --git a/src/common-components/modal/modal.vue b/src/common-components/modal/modal.vue index e41204cf8..1546860a8 100644 --- a/src/common-components/modal/modal.vue +++ b/src/common-components/modal/modal.vue @@ -22,10 +22,13 @@

@@ -33,6 +36,8 @@ @@ -104,7 +112,6 @@ export default { box-shadow: 0px -1px 0px rgba(179, 180, 181, 0.3); button { margin: 0; - height: 3rem; } } } diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 6121cbd25..432fd2eca 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -7,7 +7,7 @@ :class="q.questionSequence === currentQuestionNum && 'current-question'" :questionText="q.questionText" :answers="q.answers" - :groupName="`question-${glassIndex}-${q.questionSequence}`" + :groupName="`question-${index}-${q.questionSequence}`" :modelValue="q.answerSelected" @update:modelValue="handleAnswer(q, $event)" isRequired @@ -31,8 +31,9 @@ export default { props: { questionData: Object, validationRules: String, - modelValue: Array, - glassIndex: Number, + modelValue: Object, + index: 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) { @@ -153,7 +155,7 @@ export default { return { answerResult: questionAnswer, answeredQuestions: answeredQuestions, - glassIndex: this.glassIndex, + index: this.index, }; } }, diff --git a/src/common-components/questions-page-layout/questions-page-layout.vue b/src/common-components/questions-page-layout/questions-page-layout.vue new file mode 100644 index 000000000..f544fef53 --- /dev/null +++ b/src/common-components/questions-page-layout/questions-page-layout.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index e92ed342d..bfc65da16 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -53,7 +53,7 @@ describe("textboxQuestion.vue", () => { expect(paragraph.attributes("class")).toContain("rounded-pill"); }); - it.only("Should return text-center class", async () => { + it.only("Should return form-control class", async () => { // Act const wrapper = shallowMount(textboxQuestion, { global: { @@ -70,7 +70,7 @@ describe("textboxQuestion.vue", () => { // Assert const paragraph = wrapper.find("input"); - expect(paragraph.attributes("class")).toContain("text-center"); + expect(paragraph.attributes("class")).toContain("form-control"); }); it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => { diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 197e67a63..05d17dcd4 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -4,7 +4,6 @@ :for="inputId" :aria-label="questionText" class="form-label" - :class="[questionAlignment ? 'mx-auto' : '']" v-html="labelText">
-
- - - -
- -
- -
- -
-
+ - - diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 89b617b3c..d7d0b0371 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -1,56 +1,27 @@ - - diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index e0dda08fc..f370dde93 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -1,56 +1,27 @@ - - diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index d2934fe3c..3a52453b2 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -9,7 +9,11 @@
+ 0; }, - setupInitialData(glass, i, alreadyAnsweredQuestions, vm) { - glass.key = glass.glassLocation + "-" + glass.glassName; + setupInitialData(glass, index, alreadyAnsweredQuestions, vm) { const self = vm ?? this; + // clear answerData if no questions are already answered if (!alreadyAnsweredQuestions) { glass.answerData = null; @@ -100,33 +99,39 @@ 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; + self.currentGlassIndex = index; const answerResult = answeredGlass.partNum ? answeredGlass.partNum @@ -141,20 +146,221 @@ 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, 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 + // all relevant questions for the current part have been answered) + + /* answer example format: + { + "answerResult": "DD11132", + "answeredQuestions": [ + { + "questionText": "Is your Grand Cherokee the Laredo model?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + ], + "index": 0 + } + */ + + const self = vm ?? this; + + // clear out any preloaded answers + self.selectedAnswers = {}; + + // loop through every answered question on the currently answered glass part + answer.answeredQuestions?.forEach((answeredQuestion) => { + /* answeredQuestion example format: + { + "questionText": "Is your Grand Cherokee the Laredo model?", + "selectedAnswerText": "Yes", + "questionNum": 1, + } + */ + + const answeredQuestionText = answeredQuestion.questionText.toUpperCase(); + const answeredQuestionAnswer = answeredQuestion.selectedAnswerText.toUpperCase(); + + // HANDLE DUPLICATE QUESTIONS + + // loop through all glass data + self.questionsData.forEach((glass, glassIndex) => { + /* glass 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 + } + */ + + // limit duplicate search to glass pieces that follow after the currently being answered glass piece + if (glassIndex > answer.index) { + let indexToSuppressTo; + // reset this glass piece, in case user is changing their previous answers + glass.answerData = null; + glass.isSuppressedPart = null; + + // loop through this glass piece's questions, looking for a questionText match + glass.questions.forEach((question, questionIndex) => { + // clear out any previously set answers + question.answerSelected = null; + + // clear or set suppressThisQuestion property for each question + if (indexToSuppressTo && questionIndex + 1 < indexToSuppressTo) { + question.suppressThisQuestion = true; + } else { + question.suppressThisQuestion = null; + } + + // handle duplicate questions + if (question.questionText.toUpperCase() === answeredQuestionText) { + let matchedAnswer; + + // handle matching answer in duplicated question + question.answers.forEach((ans) => { + if (ans.answerText.toUpperCase() === answeredQuestionAnswer) { + matchedAnswer = ans; + ans.selected = true; + } else { + ans.selected = null; + } + }); + + // handle duplicate's nextQuestion logic on other related questions + if (matchedAnswer.nextQuestionSequence) { + // clear any suppression on the nextQuestion + glass.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; + } + } + } + + // update answers in this glass piece's questions with duplication logic modifications + glass.questions.forEach((q) => { + q.answers.forEach((a) => { + // revert any previously set nextQuestion logic modifications + if ( + a.originalNextQuestionSequence === + question.questionSequence + ) { + // restore original nextQuestionSequence + a.nextQuestionSequence = a.originalNextQuestionSequence; + self.originalNextQuestionSequence = null; + // restore original answerResult + if (a.originalAnswerResult) { + a.answerResult = a.originalAnswerResult; + a.originalAnswerResult = null; + } + } + // 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) { + a.originalNextQuestionSequence = + a.nextQuestionSequence; + a.nextQuestionSequence = + matchedAnswer.nextQuestionSequence; + } else { + a.originalNextQuestionSequence = + a.nextQuestionSequence; + a.nextQuestionSequence = null; + a.originalAnswerResult = + a.originalAnswerResult || a.answerResult; + a.answerResult = matchedAnswer.answerResult; + } + } + }); + }); + + // suppress current question + question.suppressThisQuestion = true; + + // are there any questions left that are not suppressed? + const remainingQuestions = glass.questions.filter((q) => { + return !q.suppressThisQuestion; + }); + + if (remainingQuestions.length < 1) { + // this is the final answer for this glass piece + + // mark this glass piece as completely answered by adding answerData + const answeredQuestionObj = { + questionText: question.questionText, + selectedAnswerText: matchedAnswer.answerText, + questionNum: question.questionSequence, + suppressThisQuestion: question.suppressThisQuestion, + }; + // set the answerData (used as indicator that it has been already answered) + glass.answerData = { + answerResult: matchedAnswer.nextQuestionSequence + ? matchedAnswer.nextQuestionSequence + : matchedAnswer.answerResult, + answeredQuestions: [answeredQuestionObj], + }; + + // suppress this glass piece because it has an answer + glass.isSuppressedPart = true; + } + } + }); + + // Update key to force re-render of glass piece with duplicate question in case user changes previous related answer in the chain + self.questionsData[glassIndex].key = + self.questionsData[glassIndex].key + Date.now().toString(); + } + }); + }); + + // set final answer data for the current answered glass part + self.questionsData[answer.index].answerData = { + answerResult: answer.answerResult, + answeredQuestions: answer.answeredQuestions, + }; + + // this part has been fully answered, so advance to next part's question chain + for (let i = answer.index + 1; i < this.questionsData.length; i++) { + // if this part has not yet been fully answered, then make it the current part + if (!this.questionsData[i].answerData?.answerResult) { + this.currentGlassIndex = i; + break; + } + } + }, // TODO KO Delete `shouldGoToHeritageQuote` // Can't use `this` because navigateForward is also called from vin-pages-mixin async navigateForward(partsOrQuestions, vm, shouldGoToHeritageQuote) { @@ -247,6 +453,7 @@ export default { } else { // if single parts only const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); + // save to store lineItems.glassParts self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts); diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index cabee328d..a156a0c66 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -335,24 +335,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 @@ -428,6 +410,816 @@ 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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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 glassWithDuplicate = wrapper.vm.questionsData[1]; + + // Assert + expect(glassWithDuplicate.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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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, + }, + ], + index: 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 () => {