Merge branch 'feature/CSR-439' of https://github.com/Safelite/DigitalConsumer.FixMyGlass into feature/CSR-439
This commit is contained in:
commit
7e8513cdd6
45 changed files with 2381 additions and 2313 deletions
|
|
@ -11,19 +11,9 @@ module.exports = {
|
||||||
"!src/constants/*.js",
|
"!src/constants/*.js",
|
||||||
"!src/router/**/*.js",
|
"!src/router/**/*.js",
|
||||||
"!src/helpers/unit-test-helper.js",
|
"!src/helpers/unit-test-helper.js",
|
||||||
"!src/layouts/component-test/component-test.vue",
|
|
||||||
"!src/layouts/form-test/form-test.vue",
|
|
||||||
"!src/layouts/vin-lookup/vin-lookup.vue",
|
|
||||||
"!src/layouts/vehicle-damage/windshield-damage-type-question/windshield-damage-type-question.vue",
|
|
||||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||||
"!src/layouts/part-questions/**/*.vue",
|
"!src/layouts/part-questions/**/*.vue",
|
||||||
"!src/layouts/reveal/**/*.vue",
|
"!src/layouts/reveal/**/*.vue"
|
||||||
"!src/layouts/estimate/**/*.vue",
|
|
||||||
// TODO REMOVE THESE AFTER WRITING UNIT TESTS
|
|
||||||
"!src/layouts/address-vehicles/address-vehicles.vue",
|
|
||||||
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
|
|
||||||
"!src/ux-components/alert\alert.vue",
|
|
||||||
"!src/helpers/validation-rules.js",
|
|
||||||
// END
|
// END
|
||||||
], // ! means exclude from coverage.
|
], // ! means exclude from coverage.
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,8 @@ describe("buttonQuestion.vue", () => {
|
||||||
const wrapper = shallowMount(buttonQuestion, setupMocks({}));
|
const wrapper = shallowMount(buttonQuestion, setupMocks({}));
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
answers: ["2022", "2021", "2020"],
|
answers: ["2022", "2021", "2020"],
|
||||||
isMultiSelect: false
|
isMultiSelect: false,
|
||||||
|
modelValue: []
|
||||||
});
|
});
|
||||||
const val = { checkValue: true, value: "2021", }
|
const val = { checkValue: true, value: "2021", }
|
||||||
wrapper.vm.handleCheckedChanged(val);
|
wrapper.vm.handleCheckedChanged(val);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
data-test="button"
|
data-test="button"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:class="[suppressError ? 'alertError' : '']"
|
:class="[suppressError ? 'alertError' : '']"
|
||||||
|
:clearOnUnmount="clearOnUnmount"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
@ -84,6 +85,10 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
suppressError: Boolean,
|
suppressError: Boolean,
|
||||||
useTextForValue: Boolean,
|
useTextForValue: Boolean,
|
||||||
|
clearOnUnmount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getFieldSetClasses() {
|
getFieldSetClasses() {
|
||||||
|
|
@ -133,17 +138,14 @@ export default {
|
||||||
return answer.Name ? answer.Name : answer;
|
return answer.Name ? answer.Name : answer;
|
||||||
},
|
},
|
||||||
handleCheckedChanged(val) {
|
handleCheckedChanged(val) {
|
||||||
|
if(this.selectingInitiatesLoad) {
|
||||||
if(this.isMultiSelect && this.selectedValues) {
|
this.selectedValues = [val.value];
|
||||||
// Add or remove item to array of data to emit
|
} else {
|
||||||
const newSelectedValues = this.selectedValues;
|
|
||||||
|
|
||||||
if(Array.isArray(this.selectedValues)) {
|
if(Array.isArray(this.selectedValues)) {
|
||||||
|
const newSelectedValues = this.selectedValues;
|
||||||
val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1);
|
val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1);
|
||||||
this.selectedValues = newSelectedValues;
|
this.selectedValues = newSelectedValues;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.selectedValues = [val.value];
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -179,4 +181,22 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vehicle-parts {
|
||||||
|
.question-text {
|
||||||
|
span {
|
||||||
|
font-size: .875rem;
|
||||||
|
text-align: left;
|
||||||
|
margin: 0 0 .5rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.question-text {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
fieldset {
|
||||||
|
.ui-radio {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -29,20 +29,22 @@ export default {
|
||||||
name: "FunnelSubHeader",
|
name: "FunnelSubHeader",
|
||||||
props: {
|
props: {
|
||||||
hasBackButton: Boolean,
|
hasBackButton: Boolean,
|
||||||
backButtonAccessibleText: String,
|
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonBack,
|
buttonBack,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
text(){
|
text() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
||||||
},
|
},
|
||||||
subText(){
|
subText() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'HeaderSubText');
|
return this.getCmsContent(this.cmsWidgetName, 'HeaderSubText');
|
||||||
},
|
},
|
||||||
headerColor(){
|
backButtonAccessibleText() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, 'BackButtonAccessibleText');
|
||||||
|
},
|
||||||
|
headerColor() {
|
||||||
return this.subText ? 'dark-header' : 'light-header';
|
return this.subText ? 'dark-header' : 'light-header';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
241
src/common-components/question-chain/question-chain.spec.js
Normal file
241
src/common-components/question-chain/question-chain.spec.js
Normal file
|
|
@ -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 };
|
||||||
|
}
|
||||||
120
src/common-components/question-chain/question-chain.vue
Normal file
120
src/common-components/question-chain/question-chain.vue
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
<template>
|
||||||
|
<div v-for="(q, i) in questions" :key="i">
|
||||||
|
<transition appear name="fade" mode="out-in">
|
||||||
|
<buttonQuestion
|
||||||
|
v-if="q.questionSequence === currentQuestion"
|
||||||
|
class="radioQuestion"
|
||||||
|
:questionText="q.questionText"
|
||||||
|
:answers="q.answers"
|
||||||
|
:groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`"
|
||||||
|
textPosition="text-start"
|
||||||
|
v-model="selectedValue"
|
||||||
|
:isRequired=true
|
||||||
|
:validationRules="validationRules"
|
||||||
|
:clearOnUnmount=false
|
||||||
|
/>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "questionChain",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentQuestion: 1,
|
||||||
|
answeredQuestions: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
questionData: Object,
|
||||||
|
validationRules: String,
|
||||||
|
modelValue: Array,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
questions() {
|
||||||
|
console.log("answeredQuestions: ", this.answeredQuestions)
|
||||||
|
const questions = this.questionData.partQuestions.map((q, i) => {
|
||||||
|
return {
|
||||||
|
questionText: q.questionText,
|
||||||
|
questionSequence: q.questionSequence,
|
||||||
|
answers: q.answers.map((a) => {
|
||||||
|
return {
|
||||||
|
Text: a.answerText,
|
||||||
|
// Name will either be nextQuestionSequence or answerResult
|
||||||
|
Name: a.nextQuestionSequence ? a.nextQuestionSequence : "answer-" + a.answerResult,
|
||||||
|
nextQuestionSequence: a.nextQuestionSequence,
|
||||||
|
answerResult: a.answerResult,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// add an empty item to be array[0] since we start with 1
|
||||||
|
questions.unshift({ "DeliberatelyBlankObject": "This object has been added as a placeholder only for question #0"});
|
||||||
|
return questions;
|
||||||
|
},
|
||||||
|
selectedValue: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set: function(returnedAnswer) {
|
||||||
|
const isNewModelValueComplete = this.getNewModelValue(returnedAnswer);
|
||||||
|
|
||||||
|
if (isNewModelValueComplete) {
|
||||||
|
this.$emit("update:modelValue", isNewModelValueComplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getNewModelValue(returnedAnswer) {
|
||||||
|
if (!returnedAnswer || !Array.isArray(returnedAnswer)) { return false }
|
||||||
|
const lastAnswer = returnedAnswer[returnedAnswer.length - 1];
|
||||||
|
const currentQuestion = this.questions[this.currentQuestion];
|
||||||
|
|
||||||
|
if (lastAnswer.indexOf("answer-") === 0) {
|
||||||
|
// if it is an answerResult
|
||||||
|
const finalAnswer = lastAnswer.slice(7);
|
||||||
|
|
||||||
|
const currentQuestionSelectedAnswer = currentQuestion.answers.find(
|
||||||
|
({ answerResult }) => answerResult === finalAnswer
|
||||||
|
);
|
||||||
|
|
||||||
|
// add current item to list of answered questions
|
||||||
|
this.answeredQuestions.push(
|
||||||
|
{
|
||||||
|
questionText: currentQuestion.questionText,
|
||||||
|
selectedAnswerText: currentQuestionSelectedAnswer.Text,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
answerResult: finalAnswer,
|
||||||
|
answeredQuestions: this.answeredQuestions,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const currentQuestionSelectedAnswer = currentQuestion.answers.find(
|
||||||
|
({ nextQuestionSequence }) => nextQuestionSequence === parseInt(lastAnswer)
|
||||||
|
);
|
||||||
|
|
||||||
|
// add current item to list of answered questions
|
||||||
|
this.answeredQuestions.push(
|
||||||
|
{
|
||||||
|
questionText: currentQuestion.questionText,
|
||||||
|
selectedAnswerText: currentQuestionSelectedAnswer.Text,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currentQuestion = parseInt(lastAnswer); // update count to display next question
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
buttonQuestion,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
|
||||||
import textInput from "./text-input";
|
|
||||||
|
|
||||||
describe("text-input.vue", () => {
|
|
||||||
it("Should render a text input", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(textInput, {
|
|
||||||
propsData: {
|
|
||||||
name: "test",
|
|
||||||
label: "unit test label",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
const input = wrapper.find("input");
|
|
||||||
|
|
||||||
expect(input.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return aria-required state", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(textInput, {
|
|
||||||
propsData: {
|
|
||||||
name: "test",
|
|
||||||
label: "unit test label",
|
|
||||||
isRequired: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
const input = wrapper.find("input");
|
|
||||||
|
|
||||||
expect(input.attributes()["aria-required"]).toEqual("true");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<!-- Simple implementation of an input field -->
|
|
||||||
<template>
|
|
||||||
<div class="d-flex w-50 mb-2" :class="{ 'has-error': !!errorMessage }">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
:name="name"
|
|
||||||
:value="inputValue"
|
|
||||||
:id="name"
|
|
||||||
:aria-required="isRequired"
|
|
||||||
@input="handleChange"
|
|
||||||
@blur="handleBlur"
|
|
||||||
:data-focus-target="name"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
:for="name"
|
|
||||||
:aria-labelledby="name"
|
|
||||||
class="d-flex justify-content-center py-3 px-4"
|
|
||||||
>
|
|
||||||
<span class="m-0">{{ label }}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div v-show="errorMessage" class="row px-3 form-test-error">
|
|
||||||
{{ errorMessage }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { useField } from "vee-validate";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "textInput",
|
|
||||||
props: {
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: "text",
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
isRequired: Boolean,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const {
|
|
||||||
value: inputValue,
|
|
||||||
errorMessage,
|
|
||||||
handleBlur,
|
|
||||||
handleChange,
|
|
||||||
meta,
|
|
||||||
} = useField(props.name, undefined, {
|
|
||||||
initialValue: props.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleChange,
|
|
||||||
handleBlur,
|
|
||||||
errorMessage,
|
|
||||||
inputValue,
|
|
||||||
meta,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -167,7 +167,7 @@ describe("textboxQuestion.vue", () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should call this.handleChange with new value when this.semiAggressiveValidation = true, the value is changed, and the new value is valid", async () => {
|
it("Should call this.handleChange with new value when the value is changed and the new value is valid", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = shallowMount(textboxQuestion, {
|
const wrapper = shallowMount(textboxQuestion, {
|
||||||
global: {
|
global: {
|
||||||
|
|
@ -178,7 +178,6 @@ describe("textboxQuestion.vue", () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
options: {},
|
options: {},
|
||||||
modelValue: "foo",
|
modelValue: "foo",
|
||||||
semiAggressiveValidation: true,
|
|
||||||
},
|
},
|
||||||
mixins: [mockMixin]
|
mixins: [mockMixin]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@blur="handleChange"
|
@blur="handleChange"
|
||||||
:maxlength="maxLength ? maxLength : '999'"
|
:maxlength="maxLength ? maxLength : '999'"
|
||||||
|
@focus="$emit('focus', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
<div v-show="errorMessage" class="row my-2 form-test-error">
|
<div v-show="errorMessage" class="row my-2 form-test-error">
|
||||||
<span class="d-inline-flex mt-0" role="alert">{{ errorMessage }}</span>
|
<span class="d-inline-flex mt-0" role="alert">{{ errorMessage }}</span>
|
||||||
|
|
@ -54,7 +55,6 @@ export default {
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
semiAggressiveValidation: Boolean,
|
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
maxLength: String,
|
maxLength: String,
|
||||||
},
|
},
|
||||||
|
|
@ -129,12 +129,10 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
async value(newValue) {
|
async value(newValue) {
|
||||||
if (this.semiAggressiveValidation) {
|
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
||||||
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
if (result.valid) {
|
||||||
if (result.valid) {
|
this.handleChange(newValue); // trigger full validation on this field only
|
||||||
this.handleChange(newValue); // trigger full validation on this field only
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const storeMutations = {
|
||||||
UPDATE_IS_REPAIR: "updateIsRepair",
|
UPDATE_IS_REPAIR: "updateIsRepair",
|
||||||
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
||||||
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
|
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
|
||||||
UPDATE_PARTS: "updateParts",
|
UPDATE_GLASS_PARTS: "updateGlassParts",
|
||||||
UPDATE_REGISTRATION_LICENSE_PLATE : "updateRegistrationLicensePlate",
|
UPDATE_REGISTRATION_LICENSE_PLATE : "updateRegistrationLicensePlate",
|
||||||
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
|
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
|
||||||
UPDATE_REGISTRATION_CITY: "updateRegistrationCity",
|
UPDATE_REGISTRATION_CITY: "updateRegistrationCity",
|
||||||
|
|
@ -40,7 +40,7 @@ const storeMutations = {
|
||||||
RESET_VEHICLE_STATE: "resetVehicleState",
|
RESET_VEHICLE_STATE: "resetVehicleState",
|
||||||
RESET_DAMAGE_STATE: "resetDamageState",
|
RESET_DAMAGE_STATE: "resetDamageState",
|
||||||
RESET_REGISTRATION_STATE: "resetRegistrationState",
|
RESET_REGISTRATION_STATE: "resetRegistrationState",
|
||||||
RESET_PARTS_STATE: "resetPartsState",
|
RESET_GLASS_PARTS_STATE: "resetGlassPartsState",
|
||||||
RESET_STATE: "resetState",
|
RESET_STATE: "resetState",
|
||||||
|
|
||||||
// OTHER MUTATIONS
|
// OTHER MUTATIONS
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const tintMap = {
|
||||||
{ name: "brown tint, blue shade", src: "Glass-BlueShade-BrownTint.svg" },
|
{ name: "brown tint, blue shade", src: "Glass-BlueShade-BrownTint.svg" },
|
||||||
{ name: "gray tint, blue shade", src: "Glass-BlueShade-GrayTint.svg" },
|
{ name: "gray tint, blue shade", src: "Glass-BlueShade-GrayTint.svg" },
|
||||||
{ name: "green tint, blue shade", src: "Glass-BlueShade-GreenTint.svg" },
|
{ name: "green tint, blue shade", src: "Glass-BlueShade-GreenTint.svg" },
|
||||||
{ name: "blue shade", src: "Glass-BlueShade-NoTint.svg" },
|
{ name: "clear, blue shade", src: "Glass-BlueShade-NoTint.svg" },
|
||||||
|
|
||||||
// Brown Shade
|
// Brown Shade
|
||||||
{ name: "brown tint, brown shade", src: "Glass-BrownShade-BrownTint.svg" },
|
{ name: "brown tint, brown shade", src: "Glass-BrownShade-BrownTint.svg" },
|
||||||
|
|
@ -26,13 +26,13 @@ const tintMap = {
|
||||||
{ name: "green tint, green shade", src: "Glass-GreenShade-GreenTint.svg" },
|
{ name: "green tint, green shade", src: "Glass-GreenShade-GreenTint.svg" },
|
||||||
|
|
||||||
// Tints Only
|
// Tints Only
|
||||||
{ name: "blue tint", src: "Glass-NoShade-BlueTint.svg" },
|
{ name: "blue tint privacy", src: "Glass-NoShade-BlueTint.svg" },
|
||||||
{ name: "brown tint", src: "Glass-NoShade-BrownTint.svg" },
|
{ name: "bronze tint", src: "Glass-NoShade-BrownTint.svg" },
|
||||||
{ name: "dark brown tint", src: "Glass-NoShade-DarkBrownTint.svg" },
|
{ name: "dark brown tint", src: "Glass-NoShade-DarkBrownTint.svg" },
|
||||||
{ name: "dark gray tint", src: "Glass-NoShade-DarkGrayTint.svg" },
|
{ name: "privacy, black frame", src: "Glass-NoShade-Privacy.svg" },
|
||||||
{ name: "gray tint", src: "Glass-NoShade-GrayTint.svg" },
|
{ name: "gray tint", src: "Glass-NoShade-GrayTint.svg" },
|
||||||
{ name: "green tint", src: "Glass-NoShade-GreenTint.svg" },
|
{ name: "green tint", src: "Glass-NoShade-GreenTint.svg" },
|
||||||
{ name: "gray tint privacy", src: "Glass-NoShade-Privacy.svg" },
|
{ name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" },
|
||||||
|
|
||||||
// No shade or tint
|
// No shade or tint
|
||||||
{ name: "clear", src: "Glass-NoShade-NoTint.svg" }
|
{ name: "clear", src: "Glass-NoShade-NoTint.svg" }
|
||||||
|
|
@ -41,13 +41,13 @@ const tintMap = {
|
||||||
windshield: [
|
windshield: [
|
||||||
// Blue Shade
|
// Blue Shade
|
||||||
{ name: "blue tint, blue shade", src: "Windshield-BlueShade-BlueTint.svg" },
|
{ name: "blue tint, blue shade", src: "Windshield-BlueShade-BlueTint.svg" },
|
||||||
{ name: "brown tint, blue shade", src: "Windshield-BlueShade-BrownTint.svg" },
|
{ name: "bronze tint, blue shade", src: "Windshield-BlueShade-BrownTint.svg" },
|
||||||
{ name: "gray tint, blue shade", src: "Windshield-BlueShade-GrayTint.svg" },
|
{ name: "gray tint, blue shade", src: "Windshield-BlueShade-GrayTint.svg" },
|
||||||
{ name: "green tint, blue shade", src: "Windshield-BlueShade-GreenTint.svg" },
|
{ name: "green tint, blue shade", src: "Windshield-BlueShade-GreenTint.svg" },
|
||||||
{ name: "blue shade", src: "Windshield-BlueShade-NoTint.svg" },
|
{ name: "clear, blue shade", src: "Windshield-BlueShade-NoTint.svg" },
|
||||||
|
|
||||||
// Brown Shade
|
// Brown Shade
|
||||||
{ name: "brown tint, brown shade", src: "Windshield-BrownShade-BrownTint.svg" },
|
{ name: "bronze tint, bronze shade", src: "Windshield-BrownShade-BrownTint.svg" },
|
||||||
|
|
||||||
// Gray Shade
|
// Gray Shade
|
||||||
{ name: "blue tint, gray shade", src: "Windshield-GrayShade-BlueTint.svg" },
|
{ name: "blue tint, gray shade", src: "Windshield-GrayShade-BlueTint.svg" },
|
||||||
|
|
@ -62,12 +62,12 @@ const tintMap = {
|
||||||
|
|
||||||
// Tints Only
|
// Tints Only
|
||||||
{ name: "blue tint", src: "Windshield-NoShade-BlueTint.svg" },
|
{ name: "blue tint", src: "Windshield-NoShade-BlueTint.svg" },
|
||||||
{ name: "brown tint", src: "Windshield-NoShade-BrownTint.svg" },
|
{ name: "bronze tint", src: "Windshield-NoShade-BrownTint.svg" },
|
||||||
{ name: "dark brown tint", src: "Windshield-NoShade-DarkBrownTint.svg" },
|
{ name: "dark brown tint", src: "Windshield-NoShade-DarkBrownTint.svg" },
|
||||||
{ name: "dark gray tint", src: "Windshield-NoShade-DarkGrayTint.svg" },
|
{ name: "privacy, black frame", src: "Windshield-NoShade-Privacy.svg" },
|
||||||
{ name: "gray tint", src: "Windshield-NoShade-GrayTint.svg" },
|
{ name: "gray tint", src: "Windshield-NoShade-GrayTint.svg" },
|
||||||
{ name: "green tint", src: "Windshield-NoShade-GreenTint.svg" },
|
{ name: "green tint", src: "Windshield-NoShade-GreenTint.svg" },
|
||||||
{ name: "gray tint privacy", src: "Windshield-NoShade-Privacy.svg" },
|
{ name: "gray tint privacy", src: "Windshield-NoShade-GrayTint.svg" },
|
||||||
|
|
||||||
// No shade or tint
|
// No shade or tint
|
||||||
{ name: "clear", src: "Windshield-NoShade-NoTint.svg" },
|
{ name: "clear", src: "Windshield-NoShade-NoTint.svg" },
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
|
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
|
||||||
|
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
@ -32,7 +31,7 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: false
|
isZipServiceable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -48,9 +47,9 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => {
|
test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mockRegistrationAddress = {
|
const mockRegistrationAddress = {
|
||||||
|
|
@ -60,7 +59,7 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -76,8 +75,8 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => {
|
test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -88,41 +87,27 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: false,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: false,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vin: "TEST_VIN2",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -133,7 +118,7 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()).toBe(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -146,31 +131,16 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [] // Return no vehicles
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [] // Return no vehicles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -183,21 +153,21 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
|
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("navigation", () => {
|
describe("navigation", () => {
|
||||||
|
|
||||||
test("if the back button is clicked, navigate back", async () => {
|
test("if the back button is clicked, navigate back", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.backButtonAction();
|
await wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
||||||
|
|
@ -213,41 +183,27 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vin: "TEST_VIN2",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -261,7 +217,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if the car entered matches one of multiple vehicles found, update vehicle info and navigate to the heritage funnel", async () => {
|
test("if the car entered matches one of multiple vehicles found, update vehicle info and navigate to the heritage funnel", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -272,42 +228,27 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vin: "TEST_VIN2",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -322,8 +263,7 @@ describe("address-lookup.vue", () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled();
|
expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled();
|
||||||
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => {
|
test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -334,54 +274,39 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vin: "TEST_VIN2",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
const carsFound = [{
|
const carsFound = [{
|
||||||
vin: "TEST_VIN",
|
vin: "TEST_VIN",
|
||||||
vehicle: {
|
vehicle: {
|
||||||
carId: "CARID"
|
carId: "CARID"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
vin: "TEST_VIN2",
|
vin: "TEST_VIN2",
|
||||||
vehicle: {
|
vehicle: {
|
||||||
carId: "CARID2"
|
carId: "CARID2"
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
|
|
@ -396,8 +321,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, carsFound);
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, carsFound);
|
||||||
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => {
|
test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -408,42 +332,27 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: false,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
|
||||||
data = {
|
|
||||||
isServiceable: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
vin: "TEST_VIN2",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -458,7 +367,7 @@ describe("address-lookup.vue", () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0);
|
expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => {
|
test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -469,31 +378,21 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true,
|
||||||
|
lookupVinbyAddressResponse: {
|
||||||
|
isStatePermissible: true,
|
||||||
|
vinVehicles: [{
|
||||||
|
vin: "TEST_VIN",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
|
||||||
let data = {};
|
|
||||||
if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
|
||||||
data = {
|
|
||||||
isStatePermissible: true,
|
|
||||||
vinVehicles: [{
|
|
||||||
vin: "TEST_VIN",
|
|
||||||
vehicle: {
|
|
||||||
carId: "CARID2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve({ data });
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
customerQuestions: {
|
customerQuestions: {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
|
|
@ -520,18 +419,79 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.navigateForward(carEntered, carsFound);
|
await wrapper.vm.navigateForward(carEntered, carsFound);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS, undefined, {}, {"displayVehicleChangeAlert": true}, {});
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, undefined, {}, { "displayVehicleChangeAlert": true }, {});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const carEntered = {
|
||||||
|
carId: "CARID2"
|
||||||
|
};
|
||||||
|
|
||||||
|
const carsFound = [
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN_2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({}, {});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.navigateForward(carEntered, carsFound);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple cars were found and one matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const carEntered = {
|
||||||
|
carId: "CARID2"
|
||||||
|
};
|
||||||
|
|
||||||
|
const carsFound = [
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN_1",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN_2",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vin: "TEST_VIN_3",
|
||||||
|
vehicle: {
|
||||||
|
carId: "CARID3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({}, {});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.navigateForward(carEntered, carsFound);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("reseting dependent state", () => {
|
describe("resetting dependent state", () => {
|
||||||
test("when reseting dependent state, license plate is set to null and parts state and dependencies are reset", async () => {
|
test("when reseting dependent state, license plate is set to null and parts state and dependencies are reset", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const commitSpy = jest.spyOn(store, "commit");
|
const commitSpy = jest.spyOn(store, "commit");
|
||||||
const dispatchSpy = jest.spyOn(store, "dispatch");
|
const dispatchSpy = jest.spyOn(store, "dispatch");
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -544,7 +504,7 @@ describe("address-lookup.vue", () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("registration and service zips", () => {
|
describe("registration and service zips", () => {
|
||||||
describe("if registration zip is serviceable", () => {
|
describe("if registration zip is serviceable", () => {
|
||||||
test("if registration address is provided => update service address on successful continue", async () => {
|
test("if registration address is provided => update service address on successful continue", async () => {
|
||||||
|
|
@ -556,7 +516,7 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup,{
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: true
|
isZipServiceable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -572,7 +532,7 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -586,7 +546,7 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: false
|
isZipServiceable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -618,9 +578,9 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: false
|
isZipServiceable: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(wrapper.vm.showServiceZipField).toBeFalsy();
|
expect(wrapper.vm.showServiceZipField).toBeFalsy();
|
||||||
|
|
@ -650,9 +610,9 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {
|
const { wrapper } = setupMocks({
|
||||||
isZipServiceable: false
|
isZipServiceable: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
@ -667,7 +627,7 @@ describe("address-lookup.vue", () => {
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => {
|
test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => {
|
||||||
|
|
@ -679,12 +639,13 @@ describe("address-lookup.vue", () => {
|
||||||
zipCode: "43215"
|
zipCode: "43215"
|
||||||
}
|
}
|
||||||
|
|
||||||
const { wrapper } = setupMocks(addressLookup, {});
|
const { wrapper } = setupMocks({});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
wrapper.vm.dispatchStoreAction = jest.fn();
|
||||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
wrapper.vm.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||||
let data = {};
|
let data = {};
|
||||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||||
if (value == "43215") {
|
if (value == "43215") {
|
||||||
|
|
@ -718,15 +679,16 @@ describe("address-lookup.vue", () => {
|
||||||
addressQuestions: mockRegistrationAddress
|
addressQuestions: mockRegistrationAddress
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
await wrapper.setData({
|
await wrapper.setData({
|
||||||
serviceZipCode: "12345"
|
serviceZipCode: "12345"
|
||||||
})
|
})
|
||||||
|
|
||||||
// Act
|
// // Act
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
// Assert
|
// // Assert
|
||||||
expect(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode);
|
expect(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode);
|
||||||
expect(store.getters.vehicle.registration.zipCode).toEqual("43215");
|
expect(store.getters.vehicle.registration.zipCode).toEqual("43215");
|
||||||
expect(store.getters.order.serviceLocation.zipCode).toEqual("12345");
|
expect(store.getters.order.serviceLocation.zipCode).toEqual("12345");
|
||||||
|
|
@ -735,10 +697,9 @@ describe("address-lookup.vue", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) {
|
function setupMocks({ isZipServiceable = true, lookupVinbyAddressResponse, partsOrQuestions = [] }) {
|
||||||
store.commit(storeMutations.RESET_STATE);
|
store.commit(storeMutations.RESET_STATE);
|
||||||
const wrapper = shallowMount(addressLookup, getMountOptions({
|
const wrapper = shallowMount(addressLookup, getMountOptions({
|
||||||
...mountOptions,
|
|
||||||
actionList: [
|
actionList: [
|
||||||
{
|
{
|
||||||
actionName: storeActions.VALIDATE_ZIP,
|
actionName: storeActions.VALIDATE_ZIP,
|
||||||
|
|
@ -757,7 +718,13 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
|
||||||
|
data: {
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
}
|
||||||
|
},
|
||||||
],
|
],
|
||||||
router: {
|
router: {
|
||||||
navigate: jest.fn(),
|
navigate: jest.fn(),
|
||||||
|
|
@ -766,12 +733,11 @@ function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressR
|
||||||
}));
|
}));
|
||||||
|
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
||||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,15 +82,15 @@ import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
import { getDamageString, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||||
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
|
|
||||||
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
defineRule("service-zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||||
defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
|
defineRule("service-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "address-lookup",
|
name: "address-lookup",
|
||||||
|
mixins: [vinPagesMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -291,26 +291,23 @@ export default {
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
// then navigate back to "vehicle-damage", and display vehicle changed alert
|
// then navigate back to "vehicle-damage", and display vehicle changed alert
|
||||||
// on that page
|
// on that page
|
||||||
this.navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS,
|
this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||||
this.$route, {}, {
|
this.$route, {}, {
|
||||||
displayVehicleChangeAlert: true
|
displayVehicleChangeAlert: true
|
||||||
}, {}
|
}, {}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// otherwise
|
// otherwise
|
||||||
this.$refs.loadingModal.showModal();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
||||||
}
|
}
|
||||||
} else if (carsFound.length > 1) {
|
} else if (carsFound.length > 1) {
|
||||||
// if multiple cars were found
|
// if multiple cars were found
|
||||||
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
||||||
if (matchingCars.length === 1) {
|
if (matchingCars.length === 1) {
|
||||||
this.$refs.loadingModal.showModal();
|
|
||||||
|
|
||||||
// and one and only of them matches the car id entered
|
// and one and only of them matches the car id entered
|
||||||
const matchingCar = matchingCars[0];
|
const matchingCar = matchingCars[0];
|
||||||
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
this.navigateForwardWithSingleCarMatch();
|
||||||
} else {
|
} else {
|
||||||
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page
|
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page
|
||||||
this.$router.navigate(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
this.$router.navigate(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
||||||
|
|
@ -319,18 +316,18 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
validateZip(zip) {
|
validateZip(zip) {
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.VALIDATE_ZIP,
|
storeActions.VALIDATE_ZIP,
|
||||||
{ zip });
|
{ zip });
|
||||||
},
|
},
|
||||||
lookupVin(lastName, streetAddress, zip, state) {
|
lookupVin(lastName, streetAddress, zip, state) {
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.LOOKUP_VIN_BY_ADDRESS,
|
storeActions.LOOKUP_VIN_BY_ADDRESS,
|
||||||
{
|
{
|
||||||
licenseLastName: lastName,
|
licenseLastName: lastName,
|
||||||
licenseStreetAddress: streetAddress,
|
licenseStreetAddress: streetAddress,
|
||||||
licenseZip: zip,
|
licenseZip: zip,
|
||||||
licenseState: state,
|
licenseState: state
|
||||||
}, false
|
}, false
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -361,9 +358,7 @@ export default {
|
||||||
const serviceLocation = store.getters.order.serviceLocation;
|
const serviceLocation = store.getters.order.serviceLocation;
|
||||||
|
|
||||||
if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) {
|
if (!serviceLocation.address && serviceLocation.zipCode && serviceLocation.zipCode == store.getters.vehicle.registration.zipCode) {
|
||||||
baseMixin.methods.dispatchStoreAction(
|
this.dispatchStoreAction(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
||||||
storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
inputId="cbf28188fdf2436688fd735915f7ee56"
|
inputId="cbf28188fdf2436688fd735915f7ee56"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="city-required"
|
validationRules="city-required"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -52,7 +51,6 @@
|
||||||
mask="#####"
|
mask="#####"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="zip-code-required|zip-code-format"
|
validationRules="zip-code-required|zip-code-format"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
inputId="00450a91b8964a768ce3992e6feb890f"
|
inputId="00450a91b8964a768ce3992e6feb890f"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="email-address-required|email-address-format"
|
validationRules="email-address-required|email-address-format"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question";
|
import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question";
|
||||||
|
|
||||||
|
|
||||||
describe("addressVehiclesQuestion.vue", () => {
|
describe("addressVehiclesQuestion.vue", () => {
|
||||||
|
|
||||||
it("Should return content for differentVehicleAlertHeader", () => {
|
it("Should return content for differentVehicleAlertHeader", () => {
|
||||||
|
|
@ -40,7 +39,7 @@ describe("addressVehiclesQuestion.vue", () => {
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const localThis = { $emit: jest.fn() }
|
const localThis = { $emit: jest.fn() }
|
||||||
addressVehiclesQuestion.computed.selectedVehicleVin.set.call(localThis, 'newValue');
|
addressVehiclesQuestion.computed.selectedVehicleVinAsArray.set.call(localThis, ['newValue']);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue");
|
expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue");
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
groupName="ChooseAddressVehicle"
|
groupName="ChooseAddressVehicle"
|
||||||
:questionText="questionText"
|
:questionText="questionText"
|
||||||
:answers="vehicles"
|
:answers="vehicles"
|
||||||
v-model="selectedVehicleVin"
|
v-model="selectedVehicleVinAsArray"
|
||||||
isRequired=true
|
isRequired=true
|
||||||
:validation-rules="validationRules"
|
:validation-rules="validationRules"
|
||||||
/>
|
/>
|
||||||
|
|
@ -62,16 +62,18 @@ export default {
|
||||||
questionText() {
|
questionText() {
|
||||||
return this.getCmsContent("VehicleConfirmationQuestion", "QuestionText");
|
return this.getCmsContent("VehicleConfirmationQuestion", "QuestionText");
|
||||||
},
|
},
|
||||||
selectedVehicleVin: {
|
selectedVehicleVinAsArray: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.modelValue;
|
const modelValueAsArray = this.modelValue ? [this.modelValue] : [];
|
||||||
|
return modelValueAsArray;
|
||||||
},
|
},
|
||||||
set: function(newValue) {
|
set: function(newValue) {
|
||||||
this.$emit("update:modelValue", newValue);
|
const newValueAsScalar = newValue && newValue.length > 0 ? newValue[newValue.length-1] : null;
|
||||||
|
this.$emit("update:modelValue", newValueAsScalar);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedVehicle() {
|
selectedVehicle() { // this computed is only needed for the computed differentVehicleAlertBody text above
|
||||||
return this.vehicles.find( ({ vin }) => vin === this.selectedVehicleVin[0] );
|
return this.vehicles.find( ({ vin }) => vin === this.selectedVehicleVinAsArray[this.selectedVehicleVinAsArray.length-1] );
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@ import addressVehicles from "@/layouts/address-vehicles/address-vehicles";
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
|
||||||
// Mock our module for promises.
|
// Mock our module for promises.
|
||||||
jest.mock("@/helpers/damage-helper", () => ({
|
jest.mock("@/helpers/damage-helper", () => ({
|
||||||
isGlassAvailableForCarId: () => {
|
isGlassAvailableForCarId: () => {
|
||||||
|
|
@ -17,11 +18,12 @@ jest.mock("@/helpers/damage-helper", () => ({
|
||||||
|
|
||||||
|
|
||||||
describe("addressVehicles.vue", () => {
|
describe("addressVehicles.vue", () => {
|
||||||
|
|
||||||
test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => {
|
test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$router.navigate = jest.fn();
|
store.commit(storeMutations.UPDATE_CAR_ID, "NOT NULL");
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, "12345");
|
||||||
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, "test@test.com");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
@ -35,10 +37,9 @@ describe("addressVehicles.vue", () => {
|
||||||
test("Should return false for valid page requisites if carId is missing", async () => {
|
test("Should return false for valid page requisites if carId is missing", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$router.navigate = jest.fn();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.$store.getters.order.vehicle.carId = null;
|
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
||||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
|
|
@ -55,8 +56,8 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.$router.navigate = jest.fn();
|
wrapper.vm.$router.navigate = jest.fn();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
});
|
});
|
||||||
wrapper.vm.backButtonAction();
|
wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
|
|
@ -85,8 +86,8 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.navigateForward = jest.fn().mockImplementation(()=> {});
|
wrapper.vm.navigateForward = jest.fn().mockImplementation(()=> {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
});
|
});
|
||||||
|
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
@ -115,8 +116,8 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {});
|
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
});
|
});
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
wrapper.vm.$nextTick();
|
wrapper.vm.$nextTick();
|
||||||
|
|
@ -142,15 +143,15 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
isSelectedGlassAvailableForVehicle: false,
|
isSelectedGlassAvailableForVehicle: false,
|
||||||
isCarIdDifferent: true,
|
isCarIdDifferent: true,
|
||||||
});
|
});
|
||||||
await wrapper.vm.updateCustomerInfo(wrapper.vm.selectedVehicle.vin, wrapper.vm.selectedVehicle.vehicle);
|
await wrapper.vm.updateCustomerInfo(wrapper.vm.selectedVehicle.vin, wrapper.vm.selectedVehicle.vehicle);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(store.dispatch).toBeCalledWith("resetDamageAndDependencies");
|
expect(wrapper.vm.dispatchStoreAction).toBeCalledWith("resetDamageAndDependencies");
|
||||||
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
@ -164,7 +165,7 @@ describe("addressVehicles.vue", () => {
|
||||||
await wrapper.vm.lookupVin('1234567890');
|
await wrapper.vm.lookupVin('1234567890');
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(store.dispatch).toBeCalledWith("lookupVehicleByVin", {"vin": "1234567890"});
|
expect(wrapper.vm.dispatchStoreAction).toBeCalledWith("lookupVehicleByVin", {"vin": "1234567890"});
|
||||||
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
@ -172,11 +173,10 @@ describe("addressVehicles.vue", () => {
|
||||||
test("If selectedVehicleVin changes, then should update isCarIdDifferent", async () => {
|
test("If selectedVehicleVin changes, then should update isCarIdDifferent", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
isCarIdDifferent: false,
|
isCarIdDifferent: false,
|
||||||
});
|
});
|
||||||
await wrapper.vm.resetDependentState();
|
await wrapper.vm.resetDependentState();
|
||||||
|
|
@ -193,8 +193,8 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
isCarIdDifferent: false,
|
isCarIdDifferent: false,
|
||||||
});
|
});
|
||||||
await wrapper.vm.resetDependentState();
|
await wrapper.vm.resetDependentState();
|
||||||
|
|
@ -212,8 +212,8 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
selectedVehicleVin: '5NMS3CADXLH233004',
|
||||||
isSelectedGlassAvailableForVehicle: false,
|
isSelectedGlassAvailableForVehicle: false,
|
||||||
isCarIdDifferent: true,
|
isCarIdDifferent: true,
|
||||||
});
|
});
|
||||||
|
|
@ -225,7 +225,7 @@ describe("addressVehicles.vue", () => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Should navigate to navigateAfterSaveToHeritageFunnel if carId is not different on navigateForward", async () => {
|
test("carId is not different on navigateForward (car was found) => Should handle navigating forward with car match", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
|
|
@ -233,79 +233,49 @@ describe("addressVehicles.vue", () => {
|
||||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.setData({
|
await wrapper.setData({
|
||||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
|
||||||
isSelectedGlassAvailableForVehicle: true,
|
|
||||||
isCarIdDifferent: false,
|
isCarIdDifferent: false,
|
||||||
});
|
});
|
||||||
await wrapper.vm.navigateForward();
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toBeCalledTimes(1);
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
|
||||||
|
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setupMocks({}) {
|
||||||
function setupMocks({
|
|
||||||
// modelValueProp = "1900",
|
|
||||||
cmsQuestionText = "CMS text goes here",
|
|
||||||
// dataFromStoreApi = [],
|
|
||||||
}) {
|
|
||||||
//Mock store
|
//Mock store
|
||||||
store.dispatch = jest.fn(() => {});
|
store.commit(storeMutations.RESET_STATE);
|
||||||
store.getters = {
|
store.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
pageData: jest.fn((pageName) => {
|
page: "address-vehicles",
|
||||||
// console.log('pageName: ', pageName) // address-vehicles
|
data: [{
|
||||||
return [
|
|
||||||
{
|
|
||||||
vehicle: {
|
|
||||||
"carId": "CR00069309",
|
|
||||||
"category": "SUV",
|
|
||||||
"year": 2020,
|
|
||||||
"make": "Hyundai",
|
|
||||||
"model": "Santa Fe",
|
|
||||||
"style": "4 door utility",
|
|
||||||
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg",
|
|
||||||
"imageVifNumber": "13769",
|
|
||||||
"imageVifColor": "white"
|
|
||||||
},
|
|
||||||
vin: "5NMS3CADXLH233004"
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}),
|
|
||||||
order: {
|
|
||||||
vehicle: {
|
vehicle: {
|
||||||
carId: "123",
|
"carId": "CR00069309",
|
||||||
|
"category": "SUV",
|
||||||
|
"year": 2020,
|
||||||
|
"make": "Hyundai",
|
||||||
|
"model": "Santa Fe",
|
||||||
|
"style": "4 door utility",
|
||||||
|
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg",
|
||||||
|
"imageVifNumber": "13769",
|
||||||
|
"imageVifColor": "white"
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
vin: "5NMS3CADXLH233004"
|
||||||
zipCode: "12345"
|
}],
|
||||||
},
|
})
|
||||||
customer: {
|
|
||||||
emailAddress: "qw@er.ty"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
damage: {
|
|
||||||
glassToReplace: "Windshield"
|
|
||||||
},
|
|
||||||
vehicle: {
|
|
||||||
carId: "456",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
|
|
||||||
|
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
store: {
|
|
||||||
dispatch: store.dispatch,
|
|
||||||
getters: store.getters,
|
|
||||||
},
|
|
||||||
router: {
|
router: {
|
||||||
navigate: jest.fn(),
|
navigate: jest.fn(),
|
||||||
},
|
},
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.LOOKUP_VEHICLE_BY_VIN,
|
||||||
|
data: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
//Mock props
|
//Mock props
|
||||||
|
|
@ -320,16 +290,6 @@ function setupMocks({
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
// dispatchStoreAction: jest.fn(() => {
|
|
||||||
// console.log("23424243")
|
|
||||||
// }),
|
|
||||||
// isGlassAvailableForCarId: () => {
|
|
||||||
// console.log("%%%%%%%%%%%%%%%")
|
|
||||||
// return Promise.resolve(true)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// lookupVin: jest.fn(() => Promise.resolve(lookupVinResponse)),
|
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
dynamicStrings() {
|
dynamicStrings() {
|
||||||
|
|
@ -337,18 +297,13 @@ function setupMocks({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// mountOptions.propsData = {
|
|
||||||
// modelValue: modelValueProp,
|
|
||||||
// };
|
|
||||||
|
|
||||||
mountOptions.mixins = [mockMixin];
|
mountOptions.mixins = [mockMixin];
|
||||||
|
|
||||||
const wrapper = shallowMount(addressVehicles, mountOptions);
|
const wrapper = shallowMount(addressVehicles, mountOptions);
|
||||||
|
|
||||||
//Mock CMS content
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
const cmsContent = {
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
QuestionText: cmsQuestionText,
|
|
||||||
};
|
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,25 +59,25 @@ import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import { required } from "@/helpers/validation-rules";
|
import { required } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||||
import { doesCopyContainRouterLink,
|
import { doesCopyContainRouterLink,
|
||||||
splitCopyOnCMSPlaceHolder,
|
splitCopyOnCMSPlaceHolder,
|
||||||
getRouterLinkRouteFromCopy,
|
getRouterLinkRouteFromCopy,
|
||||||
getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper"
|
getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper";
|
||||||
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED));
|
defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "address-vehicles",
|
name: "address-vehicles",
|
||||||
|
mixins: [vinPagesMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -102,7 +102,7 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedVehicleVin: null,
|
selectedVehicleVin: "",
|
||||||
isCarIdDifferent: false,
|
isCarIdDifferent: false,
|
||||||
isSelectedGlassAvailableForVehicle: true,
|
isSelectedGlassAvailableForVehicle: true,
|
||||||
};
|
};
|
||||||
|
|
@ -145,7 +145,7 @@ export default {
|
||||||
return store.getters.pageData(fmgPageValues.ADDRESS_VEHICLES);
|
return store.getters.pageData(fmgPageValues.ADDRESS_VEHICLES);
|
||||||
},
|
},
|
||||||
selectedVehicle() {
|
selectedVehicle() {
|
||||||
return this.VehiclesForQuestions.find( ({ vin }) => vin === this.selectedVehicleVin[0] );
|
return this.VehiclesForQuestions.find( ({ vin }) => vin === this.selectedVehicleVin );
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -188,13 +188,12 @@ export default {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.$refs.loadingModal.showModal();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lookupVin(vin) {
|
lookupVin(vin) {
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.LOOKUP_VEHICLE_BY_VIN,
|
storeActions.LOOKUP_VEHICLE_BY_VIN,
|
||||||
{ vin }
|
{ vin }
|
||||||
);
|
);
|
||||||
|
|
@ -205,7 +204,7 @@ export default {
|
||||||
//this.$store.dispatch(storeActions.SAVE_VIN, vin,vehicle),
|
//this.$store.dispatch(storeActions.SAVE_VIN, vin,vehicle),
|
||||||
updateCustomerInfo(vin, vehicle) {
|
updateCustomerInfo(vin, vehicle) {
|
||||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
this.dispatchStoreAction(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
|
||||||
store.commit(storeMutations.UPDATE_YEAR, vehicle.year);
|
store.commit(storeMutations.UPDATE_YEAR, vehicle.year);
|
||||||
|
|
@ -221,10 +220,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
selectedVehicleVin() {
|
selectedVehicleVin: {
|
||||||
// does this vehicle match the previously selected carId?
|
handler() {
|
||||||
this.isCarIdDifferent = this.selectedVehicle.vehicle.carId !== store.getters.vehicle.carId;
|
// does this vehicle match the previously selected carId?
|
||||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`);
|
this.isCarIdDifferent = this.selectedVehicle.vehicle.carId !== store.getters.vehicle.carId;
|
||||||
|
this.$refs.funnelFooter.updateButtonText(`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`);
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,244 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="container-fluid shadow rounded-3 p-2 position-relative make-tall">
|
|
||||||
<funnelHeader ref="funnelHeader" />
|
|
||||||
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
|
|
||||||
<funnelSubHeader ref="funnelSubHeader" />
|
|
||||||
<Form
|
|
||||||
@submit="onSubmit"
|
|
||||||
@invalid-submit="onInvalidSubmit"
|
|
||||||
ref="theForm"
|
|
||||||
v-slot="{ values, meta, errors }"
|
|
||||||
>
|
|
||||||
<damageLocationQuestion
|
|
||||||
ref="damageLocation"
|
|
||||||
v-model="selectedDamageLocations"
|
|
||||||
groupName="DamageLocationQuestion"
|
|
||||||
/>
|
|
||||||
<windshieldOptions
|
|
||||||
ref="windshieldOptions"
|
|
||||||
v-model="selectedWindshieldOptions"
|
|
||||||
:hasRepairReplaceConflict="hasRepairReplaceConflict"
|
|
||||||
:selectedDamageLocations="selectedDamageLocations"
|
|
||||||
/>
|
|
||||||
<alert
|
|
||||||
class="my-3"
|
|
||||||
v-show="hasRepairReplaceConflict"
|
|
||||||
alertClass="alert-danger"
|
|
||||||
alertHeadline="You'll need to schedule separate appointments"
|
|
||||||
alertCopy="Vehicle service requiring both glass repair and replacement must be scheduled separately, as they're performed by different technicians. Continue scheduling your first service now, and then come back to schedule the second service."
|
|
||||||
:isDismissible="false"
|
|
||||||
/>
|
|
||||||
<sideDoorOptions
|
|
||||||
ref="sideDoorOptions"
|
|
||||||
groupName="SideDoorSideQuestion"
|
|
||||||
v-model="sideDoorOptionsData"
|
|
||||||
v-show="!hasRepairReplaceConflict"
|
|
||||||
:selectedDamageLocations="selectedDamageLocations"
|
|
||||||
/>
|
|
||||||
<replaceOptionsQuestion
|
|
||||||
ref="backGlassOptions"
|
|
||||||
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
|
|
||||||
v-model="selectedRearReplaceOptions"
|
|
||||||
groupName="BackGlassReplaceOptionsQuestion"
|
|
||||||
validationRules="replace-options-required"
|
|
||||||
/>
|
|
||||||
<funnel-footer
|
|
||||||
ref="funnelFooter"
|
|
||||||
:isForwardActionDisabled="!meta.valid"
|
|
||||||
@back-clicked="backButtonAction"
|
|
||||||
@ForwardClicked="forwardButtonAction"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- KEEP TEMPORARILY FOR TROUBLESHOOTING VALIDATION -->
|
|
||||||
<div class="g-2 mt-6 mx-4 w-25 position-fixed fixed-top">
|
|
||||||
<p>Current Form, values:</p>
|
|
||||||
<pre>{{ values }}</pre>
|
|
||||||
<p>Errors:</p>
|
|
||||||
<pre>{{ errors }}</pre>
|
|
||||||
<p>Is Form Valid? (Meta.valid):</p>
|
|
||||||
<pre>{{ meta.valid }}</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Components
|
|
||||||
import funnelHeader from "@/common-components/funnel-header/funnel-header";
|
|
||||||
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
|
|
||||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
|
||||||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
|
||||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
|
||||||
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
|
||||||
import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options";
|
|
||||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
|
||||||
import alert from "@/ux-components/alert/alert";
|
|
||||||
|
|
||||||
// Supporting files
|
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
|
||||||
import store from "@/store";
|
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
|
||||||
import { Form, defineRule } from "vee-validate";
|
|
||||||
import { required } from "@/helpers/validation-rules";
|
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
|
||||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
|
||||||
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "form-test",
|
|
||||||
async beforeRouteEnter(to, from, next) {
|
|
||||||
// Call APIs
|
|
||||||
const cmsContentPromise = fetchCmsContentForPage('vehicle-damage');
|
|
||||||
const damageOptionsPromise =
|
|
||||||
baseMixin.methods.dispatchStoreAction(
|
|
||||||
storeActions.GET_DAMAGE_OPTIONS,
|
|
||||||
{ carId: store.getters.vehicle.carId }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Settle promises and get results
|
|
||||||
const promiseResultMap = [
|
|
||||||
{
|
|
||||||
resultKey: "cmsContent",
|
|
||||||
promise: cmsContentPromise,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
resultKey: "damageOptions",
|
|
||||||
promise: damageOptionsPromise,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
|
||||||
next((vm) => {
|
|
||||||
vm.$refs.funnelHeader.initializeComponent(
|
|
||||||
resultMap.cmsContent.FunnelHeaderWidget
|
|
||||||
);
|
|
||||||
vm.$refs.vehicleBanner.initializeComponent(
|
|
||||||
resultMap.cmsContent.VehicleBannerWidget
|
|
||||||
);
|
|
||||||
vm.$refs.funnelSubHeader.initializeComponent(
|
|
||||||
resultMap.cmsContent.FunnelSubHeaderWidget
|
|
||||||
);
|
|
||||||
vm.$refs.damageLocation.initializeComponent(
|
|
||||||
resultMap.cmsContent.DamageLocationQuestion, resultMap.damageOptions
|
|
||||||
);
|
|
||||||
vm.$refs.sideDoorOptions.initializeComponent(
|
|
||||||
resultMap.cmsContent.SideDoorSideQuestion, resultMap.cmsContent.DriverSideReplaceOptionsQuestion, resultMap.cmsContent.PassengerSideReplaceOptionsQuestion, resultMap.damageOptions.driverSideOptions.availableReplacementOptions, resultMap.damageOptions.passengerSideOptions.availableReplacementOptions
|
|
||||||
);
|
|
||||||
vm.$refs.windshieldOptions.initializeComponent(
|
|
||||||
resultMap.cmsContent.WindshieldDamageTypeQuestion, resultMap.cmsContent.WindshieldChipCountQuestion,
|
|
||||||
resultMap.cmsContent.WindshieldReplaceOptionsQuestion, resultMap.damageOptions.windshieldOptions.availableReplacementOptions
|
|
||||||
);
|
|
||||||
vm.$refs.backGlassOptions.initializeComponent(
|
|
||||||
resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions
|
|
||||||
);
|
|
||||||
vm.$refs.funnelFooter.initializeComponent(
|
|
||||||
resultMap.cmsContent.FunnelFooterWidget
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
selectedDamageLocations: [],
|
|
||||||
sideDoorOptionsData: {
|
|
||||||
selectedDoorSides: [],
|
|
||||||
selectedDriverSideReplaceOptions: [],
|
|
||||||
selectedPassengerSideReplaceOptions: []
|
|
||||||
},
|
|
||||||
selectedWindshieldOptions: [],
|
|
||||||
selectedRearReplaceOptions: [],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
arePagePrerequisitesValid() {
|
|
||||||
return store.getters.vehicle.carId !== null;
|
|
||||||
},
|
|
||||||
resetDependentState() {
|
|
||||||
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
|
||||||
},
|
|
||||||
onSubmit(values) {
|
|
||||||
window.alert('Success! Submitted values: ' + JSON.stringify(values, null ,2))
|
|
||||||
console.log('submitted: ', JSON.stringify(values, null ,2));
|
|
||||||
},
|
|
||||||
onInvalidSubmit({ values, errors, results }) {
|
|
||||||
// identify the first error field and put focus on it
|
|
||||||
console.log("values: ", values);
|
|
||||||
console.log("errors: ", errors);
|
|
||||||
console.log("results: ", results);
|
|
||||||
// get error names array
|
|
||||||
const errorNames = errors ? Object.keys(errors) : [];
|
|
||||||
const firstErrorEl = errorNames[0];
|
|
||||||
if (firstErrorEl) {
|
|
||||||
console.log('firstErrorEl: ', firstErrorEl);
|
|
||||||
const qsString = "[data-focus-target='" + firstErrorEl + "']";
|
|
||||||
document.querySelector(qsString).focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isWindshieldDamageLocation() {
|
|
||||||
return this.selectedDamageLocations.some(selectedDamages =>
|
|
||||||
{
|
|
||||||
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isSideDoorDamageLocation() {
|
|
||||||
return this.selectedDamageLocations.some(selectedDamages =>
|
|
||||||
{
|
|
||||||
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isRearWindowDamageLocation() {
|
|
||||||
return this.selectedDamageLocations.some(selectedDamages =>
|
|
||||||
{
|
|
||||||
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isWindshieldRepair() {
|
|
||||||
if (!this.isWindshieldDamageLocation) return false;
|
|
||||||
|
|
||||||
return this.selectedWindshieldOptions.selectedWindshieldDamageType && this.selectedWindshieldOptions.selectedWindshieldDamageType.some(selectedDamageType =>
|
|
||||||
{
|
|
||||||
return selectedDamageType.toUpperCase() === "REPAIR";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isDriverSideReplace() {
|
|
||||||
if (!this.isSideDoorDamageLocation) return false;
|
|
||||||
|
|
||||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedDriverSide =>
|
|
||||||
{
|
|
||||||
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isPassengerSideReplace() {
|
|
||||||
if (!this.isSideDoorDamageLocation) return false;
|
|
||||||
|
|
||||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedPassengerSide =>
|
|
||||||
{
|
|
||||||
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
hasRepairReplaceConflict() {
|
|
||||||
return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
funnelHeader,
|
|
||||||
funnelFooter,
|
|
||||||
vehicleBanner,
|
|
||||||
funnelSubHeader,
|
|
||||||
sideDoorOptions,
|
|
||||||
damageLocationQuestion,
|
|
||||||
windshieldOptions,
|
|
||||||
replaceOptionsQuestion,
|
|
||||||
Form,
|
|
||||||
alert,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -4,11 +4,11 @@ import licensePlateLookup from "@/layouts/license-plate-lookup/license-plate-loo
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
|
|
@ -223,19 +223,22 @@ describe("license-plate-lookup.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("navigateForward", () => {
|
describe("navigateForward", () => {
|
||||||
test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => {
|
test("navigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.isCarIdDifferent = true;
|
await wrapper.setData({
|
||||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
isCarIdDifferent: true,
|
||||||
|
isSelectedGlassAvailableForVehicle: false
|
||||||
|
})
|
||||||
|
|
||||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
store.dispatch = jest.fn();
|
wrapper.vm.dispatchStoreAction = jest.fn();
|
||||||
|
|
||||||
await wrapper.vm.navigateForward();
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
|
@ -249,7 +252,9 @@ describe("license-plate-lookup.vue", () => {
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.isCarIdDifferent = false;
|
await wrapper.setData({
|
||||||
|
isCarIdDifferent: false
|
||||||
|
})
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
|
|
@ -259,6 +264,38 @@ describe("license-plate-lookup.vue", () => {
|
||||||
//Assert
|
//Assert
|
||||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("carId matches returned vehicle => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
await wrapper.setData({
|
||||||
|
isCarIdDifferent: false
|
||||||
|
})
|
||||||
|
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
await wrapper.setData({
|
||||||
|
isSelectedGlassAvailableForVehicle: true
|
||||||
|
})
|
||||||
|
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -269,7 +306,9 @@ describe("license-plate-lookup.vue", () => {
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.licensePlate = "NEWPLATE";
|
wrapper.setData({
|
||||||
|
licensePlate: "NEWPLATE"
|
||||||
|
})
|
||||||
wrapper.vm.getCmsContent = jest.fn();
|
wrapper.vm.getCmsContent = jest.fn();
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -283,7 +322,9 @@ describe("license-plate-lookup.vue", () => {
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.registrationZip = "55555";
|
await wrapper.setData({
|
||||||
|
registrationZip: "55555"
|
||||||
|
})
|
||||||
wrapper.vm.getCmsContent = jest.fn();
|
wrapper.vm.getCmsContent = jest.fn();
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -297,7 +338,9 @@ describe("license-plate-lookup.vue", () => {
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.serviceZip = "55555";
|
await wrapper.setData({
|
||||||
|
serviceZip: "55555"
|
||||||
|
})
|
||||||
wrapper.vm.getCmsContent = jest.fn();
|
wrapper.vm.getCmsContent = jest.fn();
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
|
@ -469,22 +512,23 @@ describe("license-plate-lookup.vue", () => {
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.vm.isCarIdDifferent = true;
|
await wrapper.setData({
|
||||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
isCarIdDifferent: true,
|
||||||
|
isSelectedGlassAvailableForVehicle: false
|
||||||
|
})
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
store.commit = jest.fn();
|
store.commit = jest.fn();
|
||||||
store.dispatch = jest.fn();
|
|
||||||
|
|
||||||
const vehicleInfo = { year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue" }
|
const vehicleInfo = { year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue" }
|
||||||
await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState');
|
await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState');
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(store.dispatch).toHaveBeenCalled();
|
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled();
|
||||||
})
|
})
|
||||||
|
|
||||||
test("dispatch non blocking store action called on validate zip", async () => {
|
test("dispatchStoreAction called on validate zip", async () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
@ -494,10 +538,10 @@ describe("license-plate-lookup.vue", () => {
|
||||||
|
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dispatch non blocking store action called on lookup vin", async () => {
|
test("dispatchStoreAction called on lookup vin", async () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
@ -507,22 +551,18 @@ describe("license-plate-lookup.vue", () => {
|
||||||
|
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupMocks({
|
function setupMocks({
|
||||||
pageHeaderWidgetHeaderText = {},
|
pageHeaderWidgetHeaderText = {},
|
||||||
mountOptionsMockData = {
|
mountOptionsMockData = {},
|
||||||
router: {
|
partsOrQuestions = []
|
||||||
navigate: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}) {
|
}) {
|
||||||
store.commit(storeMutations.RESET_STATE);
|
store.commit(storeMutations.RESET_STATE);
|
||||||
//Mock api responses
|
//Mock api responses
|
||||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
|
||||||
const apiResponses = {
|
const apiResponses = {
|
||||||
cmsContent: {
|
cmsContent: {
|
||||||
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
|
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
|
||||||
|
|
@ -537,6 +577,21 @@ function setupMocks({
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mountOptionsMockData = {
|
||||||
|
...mountOptionsMockData,
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn(),
|
||||||
|
},
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
|
||||||
|
data: {
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
const apiPromise = Promise.resolve(apiResponses);
|
const apiPromise = Promise.resolve(apiResponses);
|
||||||
|
|
||||||
settleAllPromises.mockImplementation(() => apiPromise);
|
settleAllPromises.mockImplementation(() => apiPromise);
|
||||||
|
|
@ -547,7 +602,7 @@ function setupMocks({
|
||||||
|
|
||||||
const wrapper = shallowMount(licensePlateLookup, mountOptions);
|
const wrapper = shallowMount(licensePlateLookup, mountOptions);
|
||||||
|
|
||||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
v-model="email"
|
v-model="email"
|
||||||
inputId="email"
|
inputId="email"
|
||||||
validationRules="email-address-required|email-address-format"
|
validationRules="email-address-required|email-address-format"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -54,7 +53,6 @@
|
||||||
v-model="serviceZip"
|
v-model="serviceZip"
|
||||||
inputId="serviceZip"
|
inputId="serviceZip"
|
||||||
validationRules="zip-required|zip-format"
|
validationRules="zip-required|zip-format"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -94,14 +92,13 @@ import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper";
|
import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper";
|
||||||
import { required, regex, } from "@/helpers/validation-rules";
|
import { required, regex, } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule, } from "vee-validate";
|
import { Form, defineRule, } from "vee-validate";
|
||||||
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
|
defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
|
||||||
|
|
@ -112,6 +109,7 @@ defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "license-plate-lookup",
|
name: "license-plate-lookup",
|
||||||
|
mixins: [vinPagesMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -297,22 +295,21 @@ export default {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.$refs.loadingModal.showModal();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
validateZip(zip) {
|
validateZip(zip) {
|
||||||
return baseMixin.methods.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
|
return this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
|
||||||
zip,
|
zip,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lookupVin(plate, state) {
|
lookupVin(plate, state) {
|
||||||
return baseMixin.methods.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_PLATE,{ licensePlate: plate, licenseState: state }, false);
|
return this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_PLATE,{ licensePlate: plate, licenseState: state }, false);
|
||||||
},
|
},
|
||||||
updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) {
|
updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) {
|
||||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
this.dispatchStoreAction(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, vin);
|
||||||
store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year);
|
store.commit(storeMutations.UPDATE_YEAR, vehicleInfo.year);
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<h1>Part Questions Page Placeholder</h1>
|
<h1>Part Questions Page Placeholder</h1>
|
||||||
<funnel-footer
|
<funnel-footer cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction" />
|
||||||
cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -65,14 +63,11 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
if (Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length !== 0) {
|
return Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length !== 0;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
resetDependentState() {
|
resetDependentState() {
|
||||||
// Set
|
// Set
|
||||||
store.commit(storeMutations.UPDATE_PARTS, null);
|
store.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
|
|
||||||
// Invokes
|
// Invokes
|
||||||
store.dispatch(storeActions.RESET_PARTS_AND_DEPS);
|
store.dispatch(storeActions.RESET_PARTS_AND_DEPS);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export default {
|
||||||
},
|
},
|
||||||
resetDependentState() {
|
resetDependentState() {
|
||||||
// Set
|
// Set
|
||||||
store.commit(storeMutations.UPDATE_PARTS, null);
|
store.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
|
|
||||||
// Invokes
|
// Invokes
|
||||||
store.dispatch(storeActions.RESET_PARTS_AND_DEPS);
|
store.dispatch(storeActions.RESET_PARTS_AND_DEPS);
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ describe("vehicle-damage.vue", () => {
|
||||||
|
|
||||||
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }, { location: "Driver", name: "Back" },
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
||||||
{ location: "Passenger", name: "Quarter" }, { location: "Rear", name: "Stationary" }];
|
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
vehicleDamage.beforeRouteEnter.call(
|
vehicleDamage.beforeRouteEnter.call(
|
||||||
|
|
@ -237,7 +237,7 @@ describe("vehicle-damage.vue", () => {
|
||||||
selectedWindshieldDamageType: ["Replace"]
|
selectedWindshieldDamageType: ["Replace"]
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" },];
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" },];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
vehicleDamage.beforeRouteEnter.call(
|
vehicleDamage.beforeRouteEnter.call(
|
||||||
|
|
|
||||||
|
|
@ -314,25 +314,25 @@ export default {
|
||||||
const selectedGlassToReplace = [];
|
const selectedGlassToReplace = [];
|
||||||
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){
|
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){
|
||||||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => {
|
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.WINDSHIELD, name: wsItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.WINDSHIELD, glassName: wsItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDriverSideReplace){
|
if (this.isDriverSideReplace){
|
||||||
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => {
|
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.DRIVER, name: driverItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.DRIVER, glassName: driverItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isPassengerSideReplace){
|
if (this.isPassengerSideReplace){
|
||||||
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => {
|
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.PASSENGER, name: passengerItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.PASSENGER, glassName: passengerItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isRearWindowDamageLocation) {
|
if (this.isRearWindowDamageLocation) {
|
||||||
this.selectedRearReplaceOptions.forEach(rearItem => {
|
this.selectedRearReplaceOptions.forEach(rearItem => {
|
||||||
selectedGlassToReplace.push({ location: damageLocationsSelected.REAR, name: rearItem});
|
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.REAR, glassName: rearItem});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
<funnelSubHeader
|
<funnelSubHeader
|
||||||
cmsWidgetName="FunnelSubHeaderWidget"
|
cmsWidgetName="FunnelSubHeaderWidget"
|
||||||
:hasBackButton="true"
|
:hasBackButton="true"
|
||||||
backButtonAccessibleText="Change Vehicle Year"
|
|
||||||
@click-event="backButtonAction"
|
@click-event="backButtonAction"
|
||||||
/>
|
/>
|
||||||
<div class="fade-on-route-transition">
|
<div class="fade-on-route-transition">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
<funnelSubHeader
|
<funnelSubHeader
|
||||||
cmsWidgetName="FunnelSubHeaderWidget"
|
cmsWidgetName="FunnelSubHeaderWidget"
|
||||||
:hasBackButton="true"
|
:hasBackButton="true"
|
||||||
backButtonAccessibleText="Change Vehicle Make"
|
|
||||||
@click-event="backButtonAction"
|
@click-event="backButtonAction"
|
||||||
/>
|
/>
|
||||||
<div class="fade-on-route-transition">
|
<div class="fade-on-route-transition">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p class="mb-0">{{ colorQuestionText }}</p>
|
<p class="mb-0 color-question-text">{{ colorQuestionText }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -29,7 +29,11 @@
|
||||||
:buttonID="`${glassLocation}-${glassName}-${name}`"
|
:buttonID="`${glassLocation}-${glassName}-${name}`"
|
||||||
:groupName="`${glassLocation}-${glassName}`"
|
:groupName="`${glassLocation}-${glassName}`"
|
||||||
@isCheckedChanged="ResetTintAndPartSelections()"
|
@isCheckedChanged="ResetTintAndPartSelections()"
|
||||||
|
:validationRules="validationRules"
|
||||||
/>
|
/>
|
||||||
|
<div class="row form-test-error mt-1">
|
||||||
|
<error-message :name="`${glassLocation}-${glassName}`" v-if="!suppressError"></error-message>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
|
|
@ -53,6 +57,7 @@
|
||||||
:loaderEnabled="false"
|
:loaderEnabled="false"
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}-${name}`"
|
:groupName="`${glassLocation}-${glassName}-${name}`"
|
||||||
|
:validationRules="validationRules"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -68,6 +73,7 @@ import buttonQuestion from "@/common-components/button-question/button-question"
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import { getTintImage } from "@/constants/tint-mapper";
|
import { getTintImage } from "@/constants/tint-mapper";
|
||||||
import { getCustomTransformValue } from "@/constants/dynamictext-mapper";
|
import { getCustomTransformValue } from "@/constants/dynamictext-mapper";
|
||||||
|
import { ErrorMessage } from 'vee-validate';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "glass-part-question",
|
name: "glass-part-question",
|
||||||
|
|
@ -84,6 +90,7 @@ export default {
|
||||||
glassLocation: String,
|
glassLocation: String,
|
||||||
colorAnswers: Array,
|
colorAnswers: Array,
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
|
validationRules: String,
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.LoadPreselectedValues();
|
this.LoadPreselectedValues();
|
||||||
|
|
@ -91,6 +98,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
listCard,
|
listCard,
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
|
ErrorMessage,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
colorQuestionText() {
|
colorQuestionText() {
|
||||||
|
|
@ -168,23 +176,25 @@ export default {
|
||||||
// Check if only a single part is present for the tint and set the v-model if it is.
|
// Check if only a single part is present for the tint and set the v-model if it is.
|
||||||
AutoSelectIfSinglePart() {
|
AutoSelectIfSinglePart() {
|
||||||
// Check if the selected tint only has a single feature
|
// Check if the selected tint only has a single feature
|
||||||
Object.keys(this.PartDataFromApi.partsOrQuestions).forEach((key) => {
|
Object.keys(this.PartDataFromApi.partsOrQuestions ?? {}).forEach(
|
||||||
const currentGlassSelection =
|
(key) => {
|
||||||
this.PartDataFromApi.partsOrQuestions[key];
|
const currentGlassSelection =
|
||||||
|
this.PartDataFromApi.partsOrQuestions[key];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currentGlassSelection.glassName === this.glassName &&
|
currentGlassSelection.glassName === this.glassName &&
|
||||||
currentGlassSelection.glassLocation === this.glassLocation
|
currentGlassSelection.glassLocation === this.glassLocation
|
||||||
) {
|
) {
|
||||||
if (currentGlassSelection.parts.length === 1) {
|
if (currentGlassSelection.parts.length === 1) {
|
||||||
this.selectedPart = {
|
this.selectedPart = {
|
||||||
[currentGlassSelection.glassLocation]: [
|
[currentGlassSelection.glassLocation]: [
|
||||||
currentGlassSelection.parts[0].partNumber,
|
currentGlassSelection.parts[0].partNumber,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Loads the preselected values from the store.
|
// Loads the preselected values from the store.
|
||||||
|
|
@ -227,4 +237,9 @@ export default {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-question-text {
|
||||||
|
color: $black;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="page-container-grouped-styles">
|
<Form
|
||||||
|
@submit="onSubmit"
|
||||||
|
@invalid-submit="onInvalidSubmit"
|
||||||
|
ref="theForm"
|
||||||
|
v-slot="{ meta }"
|
||||||
|
>
|
||||||
|
<div class="page-container-grouped-styles vehicle-parts">
|
||||||
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" />
|
||||||
<vehicleBanner ref="vehicleBanner" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
|
<vehicleBanner ref="vehicleBanner" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
|
||||||
<funnelSubHeader ref="funnelSubHeader" cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader ref="funnelSubHeader" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
|
|
@ -8,10 +14,10 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<alert
|
<alert
|
||||||
class="rounded border-0 shadow-sm"
|
class="rounded border-0 shadow-sm"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
cmsWidgetName="AlertWidget"
|
cmsWidgetName="AlertWidget"
|
||||||
:isDismissible="false"
|
:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -24,16 +30,24 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<glassPartQuestion
|
<glassPartQuestion
|
||||||
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
||||||
v-model="glassParts[item.glassLocation + '-' + item.glassName]"
|
v-model="glassParts[item.glassLocation + '-' + item.glassName]"
|
||||||
:glassLocation="item.glassLocation"
|
:glassLocation="item.glassLocation"
|
||||||
:glassName="item.glassName"
|
:glassName="item.glassName"
|
||||||
:colorAnswers="item.colorAnswers"
|
:colorAnswers="item.colorAnswers"
|
||||||
|
validationRules="replace-options-required"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<funnelFooter cmsWidgetName="FunnelFooterWidget" ref="funnelFooter" @back-clicked="backButtonAction" @ForwardClicked="forwardButtonAction" />
|
<funnelFooter
|
||||||
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
ref="funnelFooter"
|
||||||
|
:isForwardActionDisabled="!meta.valid"
|
||||||
|
@back-clicked="backButtonAction"
|
||||||
|
@ForwardClicked="forwardButtonAction"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -50,132 +64,141 @@ import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
import { Form, defineRule } from "vee-validate";
|
||||||
|
import { required } from "@/helpers/validation-rules";
|
||||||
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
||||||
|
// DEFINE VALIDATION RULES
|
||||||
|
defineRule("replace-options-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "vehicle-parts",
|
name: "vehicle-parts",
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [{
|
const promiseResultMap = [{
|
||||||
resultKey: "cmsContent",
|
resultKey: "cmsContent",
|
||||||
promise: cmsContentPromise,
|
promise: cmsContentPromise,
|
||||||
}, ];
|
}, ];
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
|
||||||
// Glass Part Question dynamic component
|
// Glass Part Question dynamic component
|
||||||
Object.keys(vm.$refs)
|
Object.keys(vm.$refs)
|
||||||
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
||||||
.forEach((c) =>
|
.forEach((c) =>
|
||||||
vm.$refs[c][0].initializeComponent({
|
vm.$refs[c][0].initializeComponent({
|
||||||
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
|
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
|
||||||
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
|
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
glassParts: {},
|
||||||
|
alertWidgetData: Object,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Form,
|
||||||
|
glassPartQuestion,
|
||||||
|
funnelHeader,
|
||||||
|
vehicleBanner,
|
||||||
|
funnelSubHeader,
|
||||||
|
funnelFooter,
|
||||||
|
alert,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
PartsForQuestions() {
|
||||||
|
const partsData = this.PartsFromApi;
|
||||||
|
|
||||||
|
// Map API result data, to vehicle-parts data structure
|
||||||
|
const mappedData = partsData.partsOrQuestions.map((g) => {
|
||||||
|
return {
|
||||||
|
glassName: g.glassName,
|
||||||
|
glassLocation: g.glassLocation,
|
||||||
|
colorAnswers: g.parts.reduce((arr, p) => {
|
||||||
|
arr.push({
|
||||||
|
ColorAnswerText: p.color,
|
||||||
|
FeatureAnswers: [
|
||||||
|
{
|
||||||
|
FeatureAnswerText:
|
||||||
|
p.description === "" ? p.color : p.description,
|
||||||
|
PartNumber: p.partNumber,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return arr;
|
||||||
|
}, []),
|
||||||
|
};
|
||||||
});
|
});
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
glassParts: {},
|
|
||||||
alertWidgetData: Object,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
glassPartQuestion,
|
|
||||||
funnelHeader,
|
|
||||||
vehicleBanner,
|
|
||||||
funnelSubHeader,
|
|
||||||
funnelFooter,
|
|
||||||
alert,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
PartsForQuestions() {
|
|
||||||
const partsData = this.PartsFromApi;
|
|
||||||
|
|
||||||
// Map API result data, to vehicle-parts data structure
|
return mappedData;
|
||||||
const mappedData = partsData.partsOrQuestions.map((g) => {
|
|
||||||
return {
|
|
||||||
glassName: g.glassName,
|
|
||||||
glassLocation: g.glassLocation,
|
|
||||||
colorAnswers: g.parts.reduce((arr, p) => {
|
|
||||||
arr.push({
|
|
||||||
ColorAnswerText: p.color,
|
|
||||||
FeatureAnswers: [
|
|
||||||
{
|
|
||||||
FeatureAnswerText:
|
|
||||||
p.description === "" ? p.color : p.description,
|
|
||||||
PartNumber: p.partNumber,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
return arr;
|
|
||||||
}, []),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return mappedData;
|
|
||||||
},
|
|
||||||
|
|
||||||
PartsFromApi() {
|
|
||||||
return store.getters.pageData(fmgPageValues.VEHICLE_PARTS);
|
|
||||||
},
|
|
||||||
|
|
||||||
RefPrefix() {
|
|
||||||
return "partQuestion";
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
arePagePrerequisitesValid() {
|
PartsFromApi() {
|
||||||
// Check if isRepair is populated and if the pageData we need is here (Parts data)
|
return store.getters.pageData(fmgPageValues.VEHICLE_PARTS);
|
||||||
if (
|
},
|
||||||
(store.getters.damage.isRepair != null) &&
|
|
||||||
Object.keys(store.getters.pageData(fmgPageValues.VEHICLE_PARTS))
|
RefPrefix() {
|
||||||
.length !== 0
|
return "partQuestion";
|
||||||
) {
|
},
|
||||||
return true;
|
},
|
||||||
|
methods: {
|
||||||
|
arePagePrerequisitesValid() {
|
||||||
|
// Check if isRepair is populated and if the pageData we need is here (Parts data)
|
||||||
|
if (
|
||||||
|
(store.getters.damage.isRepair != null) &&
|
||||||
|
Object.keys(store.getters.pageData(fmgPageValues.VEHICLE_PARTS))
|
||||||
|
.length !== 0
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
backButtonAction() {
|
||||||
|
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
|
},
|
||||||
|
forwardButtonAction() {
|
||||||
|
const selectedGlassPartNumbers = [];
|
||||||
|
const matchedParts = [];
|
||||||
|
|
||||||
|
// Compile all selected parts from the page.
|
||||||
|
for (let [key, value] of Object.entries(this.glassParts)) {
|
||||||
|
for (let [glassKey, glassValue] of Object.entries(value)) {
|
||||||
|
selectedGlassPartNumbers.push(glassValue[0]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
// Match them to the parts from the API.
|
||||||
},
|
for (let [key, value] of Object.entries(
|
||||||
backButtonAction() {
|
this.PartsFromApi.partsOrQuestions
|
||||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
)) {
|
||||||
},
|
for (let [partKey, partValue] of Object.entries(value.parts)) {
|
||||||
forwardButtonAction() {
|
const currentPart =
|
||||||
const selectedGlassPartNumbers = [];
|
this.PartsFromApi.partsOrQuestions[key].parts[partKey];
|
||||||
const matchedParts = [];
|
const isMatched = selectedGlassPartNumbers.some(
|
||||||
|
(p) => p === currentPart.partNumber
|
||||||
|
);
|
||||||
|
|
||||||
// Compile all selected parts from the page.
|
if (isMatched) {
|
||||||
for (let [key, value] of Object.entries(this.glassParts)) {
|
matchedParts.push(currentPart);
|
||||||
for (let [glassKey, glassValue] of Object.entries(value)) {
|
|
||||||
selectedGlassPartNumbers.push(glassValue[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Match them to the parts from the API.
|
// If no parts could be matched, throw an error.
|
||||||
for (let [key, value] of Object.entries(
|
if (matchedParts.length === 0) {
|
||||||
this.PartsFromApi.partsOrQuestions
|
throw new Error("Could not match any parts to the selected parts");
|
||||||
)) {
|
}
|
||||||
for (let [partKey, partValue] of Object.entries(value.parts)) {
|
|
||||||
const currentPart =
|
|
||||||
this.PartsFromApi.partsOrQuestions[key].parts[partKey];
|
|
||||||
const isMatched = selectedGlassPartNumbers.some(
|
|
||||||
(p) => p === currentPart.partNumber
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isMatched) {
|
|
||||||
matchedParts.push(currentPart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no parts could be matched, throw an error.
|
|
||||||
if (matchedParts.length === 0) {
|
|
||||||
throw new Error("Could not match any parts to the selected parts");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Save parts to the store.
|
||||||
|
store.commit(storeMutations.UPDATE_GLASS_PARTS, matchedParts);
|
||||||
// Save parts to the store.
|
// Save parts to the store.
|
||||||
store.commit(storeMutations.UPDATE_PARTS, matchedParts);
|
store.commit(storeMutations.UPDATE_PARTS, matchedParts);
|
||||||
|
|
||||||
|
|
@ -206,10 +229,11 @@ export default {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.LoadInitialPartsData();
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.LoadInitialPartsData();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
<funnelSubHeader
|
<funnelSubHeader
|
||||||
cmsWidgetName="FunnelSubHeaderWidget"
|
cmsWidgetName="FunnelSubHeaderWidget"
|
||||||
:hasBackButton="true"
|
:hasBackButton="true"
|
||||||
backButtonAccessibleText="Change Vehicle Model"
|
|
||||||
@click-event="backButtonAction"
|
@click-event="backButtonAction"
|
||||||
/>
|
/>
|
||||||
<div class="fade-on-route-transition">
|
<div class="fade-on-route-transition">
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,38 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import vinLookup from "./vin-lookup.vue";
|
import vinLookup from "./vin-lookup.vue";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js";
|
||||||
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
jest.mock("@/store", () => ({
|
jest.mock("@/store", () => ({
|
||||||
commit: jest.fn(),
|
commit: jest.fn(),
|
||||||
dispatch: jest.fn(),
|
dispatch: jest.fn(),
|
||||||
getters: {
|
getters: {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
year: 2019,
|
year: 2019,
|
||||||
carId: 'initial carId'
|
carId: 'initial carId'
|
||||||
},
|
|
||||||
order: {
|
|
||||||
serviceLocation: {
|
|
||||||
zipCode: "45253"
|
|
||||||
},
|
},
|
||||||
customer: {
|
order: {
|
||||||
emailAddress: "builddigitaltest@safelite.com"
|
serviceLocation: {
|
||||||
|
zipCode: "45253"
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
emailAddress: "builddigitaltest@safelite.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
glassToReplace: "windshield"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
payment: {
|
|
||||||
insuranceCoverage: {
|
|
||||||
isVerified: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
damage: {
|
|
||||||
glassToReplace: "windshield"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { getDamageString, getIsWindshieldOnly,isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||||
|
|
||||||
jest.mock("@/helpers/damage-helper", () => ({
|
jest.mock("@/helpers/damage-helper", () => ({
|
||||||
isGlassAvailableForCarId: jest.fn(() => {
|
isGlassAvailableForCarId: jest.fn(() => {
|
||||||
|
|
@ -45,41 +46,21 @@ jest.mock("@/helpers/damage-helper", () => ({
|
||||||
describe("vin-lookup.vue", () => {
|
describe("vin-lookup.vue", () => {
|
||||||
it("Should update the funnel-footer forward button when VIN is changed", (done) => {
|
it("Should update the funnel-footer forward button when VIN is changed", (done) => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({ });
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
|
||||||
//Act
|
//Act
|
||||||
wrapper.setData({vin: "newValue"});
|
wrapper.setData({ vin: "newValue" });
|
||||||
//Assert
|
//Assert
|
||||||
wrapper.vm.$nextTick(() => {
|
wrapper.vm.$nextTick(() => {
|
||||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled();
|
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => {
|
it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({ });
|
const { wrapper } = setupMocks({});
|
||||||
const zipValidationApiResponse = {
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
data: {
|
|
||||||
isServiceable: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const vehicleLookupApiResponse = {
|
|
||||||
data: {
|
|
||||||
carId: 'initial carId'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const zipPromise = Promise.resolve(zipValidationApiResponse);
|
|
||||||
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
|
||||||
|
|
||||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
|
|
||||||
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
|
||||||
|
|
||||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
|
||||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
|
||||||
wrapper.vm.navigateForward = jest.fn();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.forwardButtonAction();
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
@ -87,26 +68,231 @@ describe("vin-lookup.vue", () => {
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should do a VIN lookup if the user has clicked on the VIN field and entered a new VIN or changed a previously matched VIN.", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
wrapper.vm.vinTouched = true;
|
||||||
|
wrapper.vm.vin = "foo";
|
||||||
|
wrapper.vm.initialVin = "!foo";
|
||||||
|
|
||||||
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
|
const vehicleLookupApiResponse = {
|
||||||
|
data: {
|
||||||
|
carId: 'new carId' // does not match the store value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
||||||
|
|
||||||
|
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.lookupVehicle).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not call navigateForward() if the store carId does not match the vin response carId and forward button is clicked", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
// New lookup
|
||||||
|
wrapper.vm.vinTouched = true;
|
||||||
|
wrapper.vm.vin = "";
|
||||||
|
wrapper.vm.initialVin = "foo";
|
||||||
|
|
||||||
|
const vehicleLookupApiResponse = {
|
||||||
|
data: {
|
||||||
|
carId: 'new carId' // does not match the store value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
||||||
|
|
||||||
|
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
||||||
|
|
||||||
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should call navigateForward() if the store carId does not match the vin response carId but does match previously enterted carId and forward button is clicked", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
const vehicleLookupApiResponse = {
|
||||||
|
data: {
|
||||||
|
carId: 'new carId' // does not match the store value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
||||||
|
|
||||||
|
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
||||||
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
|
|
||||||
|
wrapper.vm.previouslyEnteredCarId = 'new carId';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not call navigateForward() if zip service returns a non-serviceable flag", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
const zipValidationApiResponse = {
|
||||||
|
data: {
|
||||||
|
isServiceable: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const zipPromise = Promise.resolve(zipValidationApiResponse);
|
||||||
|
|
||||||
|
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
|
||||||
|
wrapper.vm.setupUiForNonServiceableZip = jest.fn();
|
||||||
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
|
|
||||||
|
wrapper.vm.previouslyEnteredCarId = 'new carId';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not call navigateForward() when forward button is clicked but lookupVehicle errors out.", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
wrapper.vm.vinTouched = true;
|
||||||
|
wrapper.vm.vin = "foo";
|
||||||
|
wrapper.vm.initialVin = "!foo";
|
||||||
|
|
||||||
|
const vehicleLookupApiResponse = {
|
||||||
|
status: {
|
||||||
|
carId: 'new carId' // does not match the store value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vinPromise = Promise.reject(vehicleLookupApiResponse);
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
status: 404
|
||||||
|
};
|
||||||
|
wrapper.vm.lookupVehicle = jest.fn().mockImplementation((response) => vinPromise);
|
||||||
|
wrapper.vm.navigateForward = jest.fn();
|
||||||
|
|
||||||
|
wrapper.vm.previouslyEnteredCarId = 'new carId';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForward).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("navigateForward", () => {
|
||||||
|
test("carId is different from returned vehicle and selected glass isn't available => continue with different glass", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
router: {
|
||||||
|
navigateAfterSave: jest.fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
wrapper.setData({
|
||||||
|
isCarIdDifferent: true,
|
||||||
|
isSelectedGlassAvailableForVehicle: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toBeCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, wrapper.vm.$route, expect.anything(), expect.anything(), expect.anything());
|
||||||
|
})
|
||||||
|
|
||||||
|
test("carId matches => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
wrapper.setData({
|
||||||
|
isCarIdDifferent: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||||
|
wrapper.setData({
|
||||||
|
isSelectedGlassAvailableForVehicle: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForward();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function setupMocks({ customMountOptions }) {
|
function setupMocks({ customMountOptions }) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
...customMountOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const mountOptions = getMountOptions({});
|
|
||||||
|
|
||||||
const finalMountOptions = Object.assign(mountOptions, customMountOptions);
|
|
||||||
// Modify/augment default mount options
|
// Modify/augment default mount options
|
||||||
finalMountOptions.global.mocks["$store"] = store;
|
mountOptions.global.mocks["$store"] = store;
|
||||||
finalMountOptions.global.mixins = [mockMixin];
|
mountOptions.global.mixins = [mockMixin];
|
||||||
finalMountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
||||||
|
|
||||||
const wrapper = shallowMount(vinLookup, finalMountOptions);
|
|
||||||
return { wrapper };
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockMixin = {
|
const wrapper = shallowMount(vinLookup, mountOptions);
|
||||||
|
mockOutPromises(wrapper);
|
||||||
|
mockOutStubFunctions(wrapper);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockOutPromises(wrapper) {
|
||||||
|
const zipValidationApiResponse = {
|
||||||
|
data: {
|
||||||
|
isServiceable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vehicleLookupApiResponse = {
|
||||||
|
data: {
|
||||||
|
carId: 'initial carId'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const zipPromise = Promise.resolve(zipValidationApiResponse);
|
||||||
|
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
||||||
|
|
||||||
|
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
|
||||||
|
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockOutStubFunctions(wrapper) {
|
||||||
|
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||||
|
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
getCmsContent: jest.fn(() => "placeholder CMS content"),
|
getCmsContent: jest.fn(() => "placeholder CMS content"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<div class="page-container-grouped-styles">
|
<div class="page-container-grouped-styles">
|
||||||
<loadingModal ref="loadingModal"/>
|
<loadingModal ref="loadingModal"/>
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||||
<vehicleBanner
|
<vehicleBanner
|
||||||
cmsWidgetName="VehicleBannerWidget"
|
cmsWidgetName="VehicleBannerWidget"
|
||||||
:displayGenericVehicleImage="false"
|
:displayGenericVehicleImage="false"
|
||||||
/>
|
/>
|
||||||
|
|
@ -25,6 +25,9 @@
|
||||||
validationRules="vin-required|vin-format"
|
validationRules="vin-required|vin-format"
|
||||||
:isDisabled="isVinFieldReadOnly"
|
:isDisabled="isVinFieldReadOnly"
|
||||||
maxLength="17"
|
maxLength="17"
|
||||||
|
:mask="vinMask"
|
||||||
|
@focus="setVinTouched"
|
||||||
|
@maska="rawVinValue = $event.target.dataset.maskRawValue"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -55,7 +58,6 @@
|
||||||
isRequired
|
isRequired
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="email-address-required|email-address-format"
|
validationRules="email-address-required|email-address-format"
|
||||||
semiAggressiveValidation
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -132,7 +134,6 @@ import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
@ -141,6 +142,8 @@ import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
|
import { StatusCodes } from 'http-status-codes';
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||||
|
|
@ -152,6 +155,7 @@ defineRule("vin-format", regex(/^[a-hA-Hj-nJ-NpPr-zR-Z0-9]{17}$/, errorMessages.
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "vin-lookup",
|
name: "vin-lookup",
|
||||||
|
mixins: [vinPagesMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -183,10 +187,16 @@ export default {
|
||||||
previouslyEnteredCarId: '',
|
previouslyEnteredCarId: '',
|
||||||
invalidZip: '',
|
invalidZip: '',
|
||||||
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
||||||
|
initialVin: this.getVinFromStore(),
|
||||||
|
vinTouched: false,
|
||||||
|
rawVinValue: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.attachCustomEvents();
|
this.attachCustomEvents();
|
||||||
|
if (this.vinPopulatedOnPageLoad) {
|
||||||
|
this.setupVinMask();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
vin() {
|
vin() {
|
||||||
|
|
@ -194,13 +204,17 @@ export default {
|
||||||
this.$refs.funnelFooter.updateButtonText(
|
this.$refs.funnelFooter.updateButtonText(
|
||||||
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
|
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
zip() {
|
||||||
|
this.noServiceZip = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
perfectMatchNewVinAlert() {
|
perfectMatchNewVinAlert() {
|
||||||
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && this.vin === this.getVinFromStore();
|
const vinToCheck = this.vinTouched ? this.rawVinValue : this.initialVin;
|
||||||
this.updateIsCarIdDifferent(isVinPerfectMatch);
|
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && vinToCheck === this.getVinFromStore();
|
||||||
return isVinPerfectMatch;
|
this.updateIsCarIdDifferent(isVinPerfectMatch);
|
||||||
|
return isVinPerfectMatch;
|
||||||
},
|
},
|
||||||
MatchedDifferentVehicleAlertHeader(){
|
MatchedDifferentVehicleAlertHeader(){
|
||||||
const text = this.getCmsContent("MatchedDifferentVehicle",
|
const text = this.getCmsContent("MatchedDifferentVehicle",
|
||||||
|
|
@ -238,10 +252,22 @@ export default {
|
||||||
getIsWindshieldOnly())
|
getIsWindshieldOnly())
|
||||||
},
|
},
|
||||||
isVinFieldReadOnly(){
|
isVinFieldReadOnly(){
|
||||||
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setVinTouched() {
|
||||||
|
if (!this.vinTouched) {
|
||||||
|
this.vinMask = "XXXXXXXXXXXXXXXXX";
|
||||||
|
this.vin = this.initialVin;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vinTouched = true;
|
||||||
|
},
|
||||||
|
setupVinMask() {
|
||||||
|
const lastSixChars = this.initialVin.substring(11, this.initialVin.length);
|
||||||
|
this.vinMask = `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
|
||||||
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return store.getters.vehicle.carId !== null;
|
return store.getters.vehicle.carId !== null;
|
||||||
},
|
},
|
||||||
|
|
@ -285,22 +311,51 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
|
let zipValidationResponse;
|
||||||
|
let vehicleLookupResponse;
|
||||||
|
|
||||||
const zipValidation = this.validateZip(this.zip);
|
const zipValidation = this.validateZip(this.zip);
|
||||||
const vehicleLookup = this.lookupVehicle(this.vin);
|
|
||||||
const zipValidationResponse = await zipValidation;
|
if (this.vinTouched && this.vin != this.initialVin) {
|
||||||
const vehicleLookupResponse = await vehicleLookup.catch(() => {
|
// If the user has clicked on the VIN field, either they are doing a new VIN lookup or changing the VIN previously matched.
|
||||||
this.vinNotFound = true;
|
// Therefore we need to do a Vehicle Lookup
|
||||||
this.$refs.funnelFooter.removeLoader();
|
const vinToLookup = this.vinTouched ? this.vin : this.initialVin;
|
||||||
this.noServiceZip = false;
|
const vehicleLookup = this.lookupVehicle(vinToLookup);
|
||||||
return;
|
|
||||||
});
|
zipValidationResponse = await zipValidation;
|
||||||
if (!zipValidationResponse.data.isServiceable) {
|
vehicleLookupResponse = await vehicleLookup.catch(() => {
|
||||||
this.customAlertData.zip = this.zip;
|
this.vinNotFound = true;
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
this.noServiceZip = true;
|
return false;
|
||||||
this.invalidZip = this.zip;
|
});
|
||||||
|
|
||||||
|
// Check if Service Zip entered is servicable, if not display an alert
|
||||||
|
if (!zipValidationResponse.data.isServiceable) {
|
||||||
|
this.setupUiForNonServiceableZip(this.zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vehicleLookupResponse || !zipValidationResponse.data.isServiceable) {
|
||||||
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const zipValidationResponse = await zipValidation;
|
||||||
|
|
||||||
|
// Check if Service Zip entered is serviceable, if not display an alert
|
||||||
|
if (!zipValidationResponse.data.isServiceable) {
|
||||||
|
this.setupUiForNonServiceableZip(this.zip);
|
||||||
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.navigateForward();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vehicleLookupResponse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
||||||
|
|
||||||
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
||||||
|
|
@ -314,26 +369,27 @@ export default {
|
||||||
this.isCarIdDifferent = true;
|
this.isCarIdDifferent = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
||||||
this.navigateForward();
|
this.navigateForward();
|
||||||
|
|
||||||
},
|
},
|
||||||
navigateForward(){
|
navigateForward(){
|
||||||
if(this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle){
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route, {}, { displayVehicleChangeAlert: true }, {});
|
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, { displayVehicleChangeAlert: true }, {});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.$refs.loadingModal.showModal();
|
this.navigateForwardWithSingleCarMatch();
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
validateZip(zip) {
|
validateZip(zip) {
|
||||||
return baseMixin.methods.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
|
return this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
|
||||||
zip,
|
zip,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lookupVehicle(vin) {
|
lookupVehicle(vin) {
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
return this.dispatchStoreAction(
|
||||||
storeActions.LOOKUP_VEHICLE_BY_VIN,
|
storeActions.LOOKUP_VEHICLE_BY_VIN,
|
||||||
{ vin }
|
{ vin }
|
||||||
);
|
);
|
||||||
|
|
@ -356,6 +412,11 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, zipInfo.state);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, zipInfo.state);
|
||||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
||||||
},
|
},
|
||||||
|
setupUiForNonServiceableZip(zip) {
|
||||||
|
this.customAlertData.zip = zip;
|
||||||
|
this.invalidZip = zip;
|
||||||
|
this.noServiceZip = true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Form,
|
Form,
|
||||||
|
|
|
||||||
28
src/mixins/vin-pages-mixin.js
Normal file
28
src/mixins/vin-pages-mixin.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import store from "@/store";
|
||||||
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations.js";
|
||||||
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
async navigateForwardWithSingleCarMatch() {
|
||||||
|
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
|
||||||
|
|
||||||
|
const partsOrQuestions = result.data.partsOrQuestions;
|
||||||
|
const hasPartsQuestions = partsOrQuestions.some(pq => pq.partQuestions?.length > 0);
|
||||||
|
const hasGlassLocationWithMultipleParts = partsOrQuestions.some(pq => pq.parts?.length > 1);
|
||||||
|
|
||||||
|
if (hasPartsQuestions) {
|
||||||
|
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, this.$route, {}, {}, result.data);
|
||||||
|
}
|
||||||
|
else if (hasGlassLocationWithMultipleParts) {
|
||||||
|
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, this.$route, {}, {}, result.data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
store.commit(storeMutations.UPDATE_GLASS_PARTS, result.data);
|
||||||
|
this.$refs.loadingModal.showModal();
|
||||||
|
navigateAfterSaveToHeritageFunnel(this.$route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
921
src/mixins/vin-pages-mixin.spec.js
Normal file
921
src/mixins/vin-pages-mixin.spec.js
Normal file
|
|
@ -0,0 +1,921 @@
|
||||||
|
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { setupMocksForJsFiles, getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
|
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
||||||
|
import store from "@/store";
|
||||||
|
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
|
navigateAfterSaveToHeritageFunnel: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("vin-pages-mixin", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("navigateForwardWithSingleCarMatch", () => {
|
||||||
|
describe("should go to parts-questions", () => {
|
||||||
|
test("single glass location has part question => go to parts-questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": null,
|
||||||
|
"partQuestions": [
|
||||||
|
{
|
||||||
|
"questionSequence": 1,
|
||||||
|
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"answerText": "Yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answerText": "No",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01143"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple glass locations have part questions => go to parts-questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": null,
|
||||||
|
"partQuestions": [
|
||||||
|
{
|
||||||
|
"questionSequence": 1,
|
||||||
|
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"answerText": "Yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answerText": "No",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01143"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD08158GTYN",
|
||||||
|
"description": "driver side, front",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Quarter",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DQ08162GTYN",
|
||||||
|
"description": "driver side, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "SideDoor",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": null,
|
||||||
|
"partQuestions": [
|
||||||
|
{
|
||||||
|
"questionSequence": 2,
|
||||||
|
"questionText": "Is this a super awesome question?",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"answerText": "Yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01144000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answerText": "Super yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01143001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DB08165GTNN",
|
||||||
|
"description": "heated glass, stationary",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple glass locations selected, one has part question => go to parts-questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": null,
|
||||||
|
"partQuestions": [
|
||||||
|
{
|
||||||
|
"questionSequence": 1,
|
||||||
|
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"answerText": "Yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answerText": "No",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01143"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD08158GTYN",
|
||||||
|
"description": "driver side, front",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Quarter",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DQ08162GTYN",
|
||||||
|
"description": "driver side, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "SideDoor",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD08160GTYN",
|
||||||
|
"description": "driver side, body side, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DB08165GTNN",
|
||||||
|
"description": "heated glass, stationary",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a selected glass location has part questions and multiple parts => go to parts-questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": null,
|
||||||
|
"partQuestions": [
|
||||||
|
{
|
||||||
|
"questionSequence": 1,
|
||||||
|
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"answerText": "Yes",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answerText": "No",
|
||||||
|
"nextQuestionSequence": null,
|
||||||
|
"answerResult": "DW01143"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD08158GTYN",
|
||||||
|
"description": "driver side, front",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Quarter",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DQ08162GTYN",
|
||||||
|
"description": "driver side, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ08162YPYN",
|
||||||
|
"description": "driver side, 1 hole",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "SideDoor",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD08160GTYN",
|
||||||
|
"description": "driver side, body side, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DD08160YPYN",
|
||||||
|
"description": "driver side, body side, 1 hole",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DB08165GTNN",
|
||||||
|
"description": "heated glass, stationary",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DB08165YPNN",
|
||||||
|
"description": "heated glass, stationary",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DB08166GTNN",
|
||||||
|
"description": "stationary",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DB08167GTNN",
|
||||||
|
"description": "heated glass, movable, 8 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DB08167YPNN",
|
||||||
|
"description": "heated glass, movable, 8 hole",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("should go to vehicle-parts", () => {
|
||||||
|
test("single glass location has multiple parts => go to vehicle-parts", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FB25724GTYN",
|
||||||
|
"description": "heated glass, solar, antenna",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "FB25759GTYN",
|
||||||
|
"description": "heated glass, solar, antenna, w/diversity antenna",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple glass locations selected, one of them has multiple parts => go to vehicle parts", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FW03647GTNN",
|
||||||
|
"description": "solar, 3rd visor band",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": [
|
||||||
|
{
|
||||||
|
"partNumber": "MWF03647",
|
||||||
|
"partType": "MOULDING",
|
||||||
|
"description": "Upper "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Back",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FD25747GTYN",
|
||||||
|
"description": "solar, driver side, rear, ex models and above",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FD25719GTYN",
|
||||||
|
"description": "solar, driver side, front, ex models and above",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Vent",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FV25749GTNN",
|
||||||
|
"description": "solar, driver side, rear",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FB25724GTYN",
|
||||||
|
"description": "heated glass, solar, antenna",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "FB25759GTYN",
|
||||||
|
"description": "heated glass, solar, antenna, w/diversity antenna",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple glass locations selected, multiple have multiple parts => go to vehicle-parts", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DW02101GTYN",
|
||||||
|
"description": "solar",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Back",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD12202GTYN",
|
||||||
|
"description": "solar, driver side, rear",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DD12202YPYN",
|
||||||
|
"description": "solar, driver side, rear",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DD12198GTYN",
|
||||||
|
"description": "solar, driver side, front",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DD12200GTYN",
|
||||||
|
"description": "solar, driver side, front, laminated, soundproofing",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Quarter",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12204GTYNOEM",
|
||||||
|
"description": "solar, driver side, encap",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12204YPYNOEM",
|
||||||
|
"description": "solar, driver side, encap",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12205GTYNOEM",
|
||||||
|
"description": "solar, antenna, driver side, encap",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12205YPYNOEM",
|
||||||
|
"description": "solar, antenna, driver side, encap",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12207GTYN",
|
||||||
|
"description": "solar, driver side, encap, chrome molding",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12207YPYNOEM",
|
||||||
|
"description": "solar, driver side, encap, chrome molding",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12208GTYNOEM",
|
||||||
|
"description": "solar, antenna, driver side, encap, chrome molding",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DQ12208YPYNOEM",
|
||||||
|
"description": "solar, antenna, driver side, encap, chrome molding",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "DB12209GTYN",
|
||||||
|
"description": "heated glass, solar, 1 hole",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partNumber": "DB12209YPYN",
|
||||||
|
"description": "heated glass, solar, 1 hole",
|
||||||
|
"color": "Gray Tint Privacy",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("should go to heritage funnel", () => {
|
||||||
|
test("single glass location selected, has no part questions and has one part => go to heritage funnel", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FW04186GTYN",
|
||||||
|
"description": "solar, soundproofing, lane keep assist",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": true,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": [
|
||||||
|
{
|
||||||
|
"partNumber": "GGG 3563 KIT",
|
||||||
|
"partType": "MOULDING",
|
||||||
|
"description": "Kit, Top & Sides "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple glass locations selected, each has one part and no part questions => go to heritage funnel", async () => {
|
||||||
|
// Arrange
|
||||||
|
const partsOrQuestions = [
|
||||||
|
{
|
||||||
|
"glassName": "Single",
|
||||||
|
"glassLocation": "Windshield",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FW04186GTYN",
|
||||||
|
"description": "solar, soundproofing, lane keep assist",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": true,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": [
|
||||||
|
{
|
||||||
|
"partNumber": "GGG 3563 KIT",
|
||||||
|
"partType": "MOULDING",
|
||||||
|
"description": "Kit, Top & Sides "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Back",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FD25457GTYN",
|
||||||
|
"description": "solar, driver side, rear",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Front",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FD27090GTYN",
|
||||||
|
"description": "solar, driver side, front",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Vent",
|
||||||
|
"glassLocation": "Driver",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FV25459GTNN",
|
||||||
|
"description": "solar, driver side, rear",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glassName": "Stationary",
|
||||||
|
"glassLocation": "Rear",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"partNumber": "FB25460GTYN",
|
||||||
|
"description": "heated glass, solar",
|
||||||
|
"color": "Green Tint",
|
||||||
|
"requiresRecalibration": false,
|
||||||
|
"requiresCapabilityQuestions": false,
|
||||||
|
"childParts": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"partQuestions": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
});
|
||||||
|
|
||||||
|
// wrapper.vm.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||||
|
store.commit = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(store.commit).toHaveBeenCalledTimes(1);
|
||||||
|
expect(store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_GLASS_PARTS, { partsOrQuestions })
|
||||||
|
expect(wrapper.vm.$refs.loadingModal.showModal).toHaveBeenCalledTimes(1);
|
||||||
|
expect(navigateAfterSaveToHeritageFunnel).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks({ partsOrQuestions = [] }) {
|
||||||
|
const baseMixin = setupMocksForJsFiles({
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_PARTS_OR_QUESTIONS,
|
||||||
|
data: {
|
||||||
|
partsOrQuestions: partsOrQuestions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const mocks = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigateAfterSave: jest.fn()
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockVinComponent = {
|
||||||
|
components: { loadingModal },
|
||||||
|
template: '<loadingModal ref="loadingModal" />',
|
||||||
|
// render() {
|
||||||
|
// return '<div ref="loadingModal"></div>'
|
||||||
|
// },
|
||||||
|
mixins: [vinPagesMixin, baseMixin.baseMixin]
|
||||||
|
};
|
||||||
|
|
||||||
|
// const mockVinComponent = Vue.component("mockcomponent", {
|
||||||
|
// template: '<loadingModal ref="loadingModal" />',
|
||||||
|
// mixins: [vinPagesMixin, baseMixin.baseMixin]
|
||||||
|
// })
|
||||||
|
|
||||||
|
const wrapper = shallowMount(mockVinComponent, mocks);
|
||||||
|
|
||||||
|
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -18,22 +18,7 @@ import eventBus from "@/helpers/event-bus/event-bus";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import analyticsMixin from "@/mixins/analytics-mixin";
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
|
|
||||||
// Components
|
|
||||||
import ComponentTest from "@/layouts/component-test/component-test.vue";
|
|
||||||
import FormTest from "@/layouts/form-test/form-test.vue";
|
|
||||||
|
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
|
||||||
path: "/component-test", // This is a temporary route for testing.
|
|
||||||
name: "ComponentTest",
|
|
||||||
component: ComponentTest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/form-test", // This is a temporary route for testing.
|
|
||||||
name: "FormTest",
|
|
||||||
component: FormTest,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "root",
|
name: "root",
|
||||||
|
|
@ -46,6 +31,7 @@ const routes = [
|
||||||
|
|
||||||
// If the saved session has timed out, clear the session, execute 404 logic.
|
// If the saved session has timed out, clear the session, execute 404 logic.
|
||||||
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
||||||
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
||||||
await GoToFunnelStartOn404(next);
|
await GoToFunnelStartOn404(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ const navigationScenarios = {
|
||||||
CLICKED_FORWARD: "CLICKED_FORWARD",
|
CLICKED_FORWARD: "CLICKED_FORWARD",
|
||||||
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
|
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
|
||||||
SELECTED_PARTS: "SELECTED_PARTS",
|
SELECTED_PARTS: "SELECTED_PARTS",
|
||||||
CONTINUING_WITH_PARTS_QUESTION: "CONTINUING_WITH_PARTS_QUESTION",
|
SELECTED_VIN_WITH_PART_QUESTIONS: "SELECTED_VIN_WITH_PART_QUESTIONS",
|
||||||
CONTINUING_WITH_MULTIPLE_PARTS: "CONTINUING_WITH_MULTIPLE_PARTS",
|
SELECTED_VIN_WITH_MULTIPLE_PARTS: "SELECTED_VIN_WITH_MULTIPLE_PARTS",
|
||||||
CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART",
|
CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART",
|
||||||
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
|
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
|
||||||
CONTINUING_WITH_DIFFERENT_GLASS: "CONTINUING_WITH_DIFFERENT_GLASS",
|
SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS",
|
||||||
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
|
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
|
||||||
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
||||||
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ const routingTable = [
|
||||||
maps: [
|
maps: [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_PARTS,
|
scenario: navigationScenarios.SELECTED_PARTS,
|
||||||
|
|
@ -105,12 +105,20 @@ const routingTable = [
|
||||||
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK_WITH_VIN,
|
scenario: navigationScenarios.CLICKED_BACK_WITH_VIN,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -125,6 +133,14 @@ const routingTable = [
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -139,9 +155,17 @@ const routingTable = [
|
||||||
destinationFmgPageValue: fmgPageValues.ADDRESS_VEHICLES,
|
destinationFmgPageValue: fmgPageValues.ADDRESS_VEHICLES,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS,
|
scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -154,7 +178,15 @@ const routingTable = [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -178,6 +210,15 @@ const routingTable = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||||
|
maps: [
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export { routingTable };
|
export { routingTable };
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ export const mutations = {
|
||||||
updateGlassToReplace(state, glassToReplace) {
|
updateGlassToReplace(state, glassToReplace) {
|
||||||
state.order.damage.glassToReplace = glassToReplace;
|
state.order.damage.glassToReplace = glassToReplace;
|
||||||
},
|
},
|
||||||
updateParts(state, partsData) {
|
updateGlassParts(state, partsData) {
|
||||||
state.order.lineItems.glassParts = partsData;
|
state.order.lineItems.glassParts = partsData;
|
||||||
},
|
},
|
||||||
updatePageData(state, pageData) {
|
updatePageData(state, pageData) {
|
||||||
|
|
@ -216,9 +216,8 @@ export const mutations = {
|
||||||
state.order.vehicle.registration.firstName = null;
|
state.order.vehicle.registration.firstName = null;
|
||||||
state.order.vehicle.registration.lastName = null;
|
state.order.vehicle.registration.lastName = null;
|
||||||
},
|
},
|
||||||
resetPartsState(state) {
|
resetGlassPartsState(state) {
|
||||||
state.order.lineItems.glassParts = null;
|
state.order.lineItems.glassParts = null;
|
||||||
state.order.lineItems.otherParts = null;
|
|
||||||
},
|
},
|
||||||
resetState(state) {
|
resetState(state) {
|
||||||
Object.assign(state, getDefaultState());
|
Object.assign(state, getDefaultState());
|
||||||
|
|
@ -404,14 +403,14 @@ export const actions = {
|
||||||
},
|
},
|
||||||
resetDamageAndDependencies(context) {
|
resetDamageAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_DAMAGE_STATE);
|
context.commit(storeMutations.RESET_DAMAGE_STATE);
|
||||||
context.commit(storeMutations.RESET_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
},
|
},
|
||||||
resetRegistrationAndDependencies(context) {
|
resetRegistrationAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||||
context.commit(storeMutations.RESET_PARTS_STATE)
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE)
|
||||||
},
|
},
|
||||||
resetPartsAndDependencies(context) {
|
resetPartsAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
},
|
},
|
||||||
resetState(context) {
|
resetState(context) {
|
||||||
context.commit(storeMutations.RESET_STATE);
|
context.commit(storeMutations.RESET_STATE);
|
||||||
|
|
@ -543,7 +542,16 @@ export const actions = {
|
||||||
|
|
||||||
|
|
||||||
// Parts API Actions
|
// Parts API Actions
|
||||||
getPartsOrQuestions(context, { carId, glassArray, zipCode, vin = '' }) {
|
getPartsOrQuestions(context) {
|
||||||
|
const vehicle = context.getters.vehicle;
|
||||||
|
const damage = context.getters.damage;
|
||||||
|
const order = context.state.order;
|
||||||
|
|
||||||
|
const carId = vehicle.carId;
|
||||||
|
const glassArray = damage.glassToReplace;
|
||||||
|
const zipCode = order.serviceLocation.zipCode;
|
||||||
|
const vin = vehicle.vin;
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetPartsOrQuestions.method,
|
method: endpoints.GetPartsOrQuestions.method,
|
||||||
endpoint: endpoints.GetPartsOrQuestions.url,
|
endpoint: endpoints.GetPartsOrQuestions.url,
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ describe("Mutations", () => {
|
||||||
const storeState = state;
|
const storeState = state;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
mutations.updateParts(storeState, { 'Windshield-Single': 'PARTNUM101'});
|
mutations.updateGlassParts(storeState, { 'Windshield-Single': 'PARTNUM101'});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(storeState.order.lineItems.glassParts).toEqual({ 'Windshield-Single': 'PARTNUM101'});
|
expect(storeState.order.lineItems.glassParts).toEqual({ 'Windshield-Single': 'PARTNUM101'});
|
||||||
|
|
@ -446,7 +446,7 @@ describe("Actions", () => {
|
||||||
await actions.resetDamageAndDependencies(context)
|
await actions.resetDamageAndDependencies(context)
|
||||||
|
|
||||||
expect(commit).toBeCalledWith(storeMutations.RESET_DAMAGE_STATE);
|
expect(commit).toBeCalledWith(storeMutations.RESET_DAMAGE_STATE);
|
||||||
expect(commit).toBeCalledWith(storeMutations.RESET_PARTS_STATE);
|
expect(commit).toBeCalledWith(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -462,7 +462,7 @@ describe("Actions", () => {
|
||||||
await actions.resetRegistrationAndDependencies(context)
|
await actions.resetRegistrationAndDependencies(context)
|
||||||
|
|
||||||
expect(commit).toBeCalledWith(storeMutations.RESET_REGISTRATION_STATE);
|
expect(commit).toBeCalledWith(storeMutations.RESET_REGISTRATION_STATE);
|
||||||
expect(commit).toBeCalledWith(storeMutations.RESET_PARTS_STATE);
|
expect(commit).toBeCalledWith(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -477,7 +477,7 @@ describe("Actions", () => {
|
||||||
// Act
|
// Act
|
||||||
await actions.resetPartsAndDependencies(context)
|
await actions.resetPartsAndDependencies(context)
|
||||||
|
|
||||||
expect(commit).toBeCalledWith(storeMutations.RESET_PARTS_STATE);
|
expect(commit).toBeCalledWith(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -747,7 +747,7 @@ describe("Getters", () => {
|
||||||
const storeState = state;
|
const storeState = state;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
mutations.updateParts(storeState, {"Rear-Stationary": 'PART101'});
|
mutations.updateGlassParts(storeState, {"Rear-Stationary": 'PART101'});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(getters.lineItems(storeState).glassParts).toEqual({"Rear-Stationary": 'PART101'});
|
expect(getters.lineItems(storeState).glassParts).toEqual({"Rear-Stationary": 'PART101'});
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
selectedValues: [Array, String],
|
selectedValues: [Array, String],
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
clearOnUnmount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -92,9 +96,11 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unmounted() { // needed to clear this button's selectedValues if it is removed
|
unmounted() { // needed to clear this button's selectedValues if it is removed to keep validation in sync
|
||||||
this.checkValue = false;
|
if (this.clearOnUnmount) {
|
||||||
this.handleCheckChange();
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
selectedValues: [Array, String],
|
selectedValues: [Array, String],
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
clearOnUnmount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -92,9 +96,11 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unmounted() { // needed to clear this button's selectedValues if it is removed
|
unmounted() { // needed to clear this button's selectedValues if it is removed to keep validation in sync
|
||||||
this.checkValue = false;
|
if (this.clearOnUnmount) {
|
||||||
this.handleCheckChange();
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ export default {
|
||||||
selectedValues: [Array, String],
|
selectedValues: [Array, String],
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
clearOnUnmount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -99,9 +103,11 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unmounted() { // needed to clear this button's selectedValues if it is removed
|
unmounted() { // needed to clear this button's selectedValues if it is removed to keep validation in sync
|
||||||
this.checkValue = false;
|
if (this.clearOnUnmount) {
|
||||||
this.handleCheckChange();
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getLabelClasses() {
|
getLabelClasses() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue