CSR-747 Fix merge conflict
This commit is contained in:
commit
bd53177d53
54 changed files with 4019 additions and 695 deletions
|
|
@ -13,14 +13,9 @@ module.exports = {
|
|||
"!src/router/**/*.js",
|
||||
"!src/helpers/unit-test-helper.js",
|
||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||
"!src/layouts/molding-questions/**/*.vue",
|
||||
"!src/layouts/capability-questions/**/*.vue",
|
||||
"!src/layouts/part-questions/**/*.vue",
|
||||
"!src/layouts/reveal/**/*.vue",
|
||||
"!src/layouts/quote/**/*.vue",
|
||||
"!src/ux-components/text-link/**/*.vue",
|
||||
"!src/common-components/question-chain/**/*.vue",
|
||||
"!src/layouts/quote/**/*.vue", // Temporary
|
||||
"!src/common-components/date-picker/**/*.vue",
|
||||
"!src/layouts/vin-lookup/**/*.vue", //Temporary for Quote page testing
|
||||
"!src/common-components/funnel-header/menu-modal/**/*.vue",
|
||||
// END
|
||||
|
|
|
|||
6
src/assets/img/icons/ccpa-icon.svg
Normal file
6
src/assets/img/icons/ccpa-icon.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 30 14" viewBox="0 0 30 14">
|
||||
<path d="M7.4 12.8h6.8l3.1-11.6H7.4C4.2 1.2 1.6 3.8 1.6 7s2.6 5.8 5.8 5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#fff"/>
|
||||
<path d="M22.6 0H7.4c-3.9 0-7 3.1-7 7s3.1 7 7 7h15.2c3.9 0 7-3.1 7-7s-3.2-7-7-7zm-21 7c0-3.2 2.6-5.8 5.8-5.8h9.9l-3.1 11.6H7.4c-3.2 0-5.8-2.6-5.8-5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#06f"/>
|
||||
<path d="M24.6 4c.2.2.2.6 0 .8L22.5 7l2.2 2.2c.2.2.2.6 0 .8-.2.2-.6.2-.8 0l-2.2-2.2-2.2 2.2c-.2.2-.6.2-.8 0-.2-.2-.2-.6 0-.8L20.8 7l-2.2-2.2c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0l2.2 2.2L23.8 4c.2-.2.6-.2.8 0z" style="fill:#fff"/>
|
||||
<path d="M12.7 4.1c.2.2.3.6.1.8L8.6 9.8c-.1.1-.2.2-.3.2-.2.1-.5.1-.7-.1L5.4 7.7c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0L8 8.6l3.8-4.5c.2-.2.6-.2.9 0z" style="fill:#06f"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 865 B |
|
|
@ -1,4 +1,4 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { shallowMount, mount } from "@vue/test-utils";
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
|
||||
|
|
@ -115,6 +115,38 @@ describe("buttonQuestion.vue", () => {
|
|||
"2020",
|
||||
]);
|
||||
});
|
||||
test("should accept an imported component for buttonTypeObject and successfully add it to components", async () => {
|
||||
// Arrange
|
||||
const mockComponent = {
|
||||
name: "mockComponent",
|
||||
methods: {
|
||||
mockComponentMethod() {
|
||||
return "mockComponentMethod return value";
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = await shallowMount(
|
||||
buttonQuestion,
|
||||
setupMocks({
|
||||
propsData: {
|
||||
buttonTypeString: "mockComponent",
|
||||
buttonTypeObject: mockComponent,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Act
|
||||
const componentList = wrapper.vm.$options.components;
|
||||
const componentExists = !!componentList.mockComponent;
|
||||
const componentNameMatches = componentList.mockComponent.name === mockComponent.name;
|
||||
const componentMethodMatches =
|
||||
componentList.mockComponent.methods.mockComponentMethod() ===
|
||||
mockComponent.methods.mockComponentMethod();
|
||||
|
||||
// Assert
|
||||
expect(componentExists && componentNameMatches && componentMethodMatches).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buttonsInfo", () => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { mount } from "@vue/test-utils";
|
|||
import funnelFooter from "./funnel-footer";
|
||||
|
||||
describe("funnel-footer.vue", () => {
|
||||
it("Should emit ForwardClicked on button click", async () => {
|
||||
test("Should emit ForwardClicked on button click", async () => {
|
||||
// Act
|
||||
const wrapper = mount(funnelFooter, {
|
||||
mixins: [mockMixin],
|
||||
|
|
@ -12,7 +12,7 @@ describe("funnel-footer.vue", () => {
|
|||
expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled;
|
||||
});
|
||||
|
||||
it("Should emit BackClicked on link click", async () => {
|
||||
test("Should emit BackClicked on link click", async () => {
|
||||
// Act
|
||||
const wrapper = mount(funnelFooter, {
|
||||
mixins: [mockMixin],
|
||||
|
|
@ -22,7 +22,7 @@ describe("funnel-footer.vue", () => {
|
|||
expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled;
|
||||
});
|
||||
|
||||
it("Should change button text when update button text is called", async () => {
|
||||
test("Should change button text when update button text is called", async () => {
|
||||
// Act
|
||||
const wrapper = mount(funnelFooter, {
|
||||
mixins: [mockMixin],
|
||||
|
|
@ -32,6 +32,23 @@ describe("funnel-footer.vue", () => {
|
|||
// Assert
|
||||
expect(wrapper.componentVM.customButtontext).toBe("newText");
|
||||
});
|
||||
|
||||
test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => {
|
||||
// Arrange
|
||||
const wrapper = mount(funnelFooter, {
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.$refs.buttonMain.removeLoader = jest.fn();
|
||||
wrapper.vm.removeLoader();
|
||||
const spy = jest.spyOn(document, "onkeydown");
|
||||
document.onkeydown();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled();
|
||||
expect(spy).toReturnWith(true);
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
|
|
|
|||
|
|
@ -44,16 +44,28 @@
|
|||
<textLink
|
||||
linkType="navigation"
|
||||
text="Terms of use"
|
||||
href="https://www.safelite.com/terms-of-use"
|
||||
href="//www.safelite.com/terms-of-use"
|
||||
target="_blank" />
|
||||
<textLink
|
||||
linkType="navigation"
|
||||
text="Privacy policy"
|
||||
href="https://www.safelite.com/safelite-group-privacy-policy"
|
||||
text="Your privacy choices"
|
||||
href="//www.safelite.com/privacy-center"
|
||||
target="_blank">
|
||||
<template v-slot:after-text>
|
||||
<img
|
||||
class="ccpa-icon"
|
||||
src="~@/assets/img/icons/ccpa-icon.svg"
|
||||
alt="Your privacy choices" />
|
||||
</template>
|
||||
</textLink>
|
||||
<textLink
|
||||
linkType="navigation"
|
||||
text="Warranty"
|
||||
href="//www.safelite.com/national-lifetime-warranty"
|
||||
target="_blank" />
|
||||
<textLink
|
||||
linkType="navigation"
|
||||
text="Do not sell my information"
|
||||
text="Notice at collection"
|
||||
href="https://privacyportal-cdn.onetrust.com/dsarwebform/d3b95a93-e22e-4d4d-a806-482052406557/9e371601-eae3-4338-9430-b90b9036022b.html"
|
||||
target="_blank" />
|
||||
</div>
|
||||
|
|
@ -147,6 +159,11 @@ export default {
|
|||
overflow-y: visible;
|
||||
.modal-body {
|
||||
padding: 2rem;
|
||||
.ccpa-icon {
|
||||
width: 2.0625rem;
|
||||
height: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
.modal-fullscreen {
|
||||
width: 100vw;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
// Components
|
||||
import questionsPageLayout from "@/common-components/layouts/questions-page-layout/questions-page-layout";
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import baseMixin from "../../../mixins/base-mixin";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||
navigateToHeritageFunnel: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("questionsPageLayout.vue", () => {
|
||||
describe("method showThisQuestionChain...", () => {
|
||||
test("Should return true if index prop and passed index match", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({ index: 0 });
|
||||
|
||||
const testGlassPiece = {
|
||||
questions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
|
||||
answers: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
const testIndex = 0;
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return true if answerResult exists", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({ index: 0 });
|
||||
|
||||
const testGlassPiece = {
|
||||
questions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
|
||||
answers: [],
|
||||
},
|
||||
],
|
||||
answerData: {
|
||||
answerResult: "test",
|
||||
},
|
||||
};
|
||||
const testIndex = 1;
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false if indexes don't match and answerResult is missing", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({ index: 0 });
|
||||
|
||||
const testGlassPiece = {
|
||||
questions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
|
||||
answers: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
const testIndex = 1;
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(false);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false if no questions", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({ index: 0 });
|
||||
|
||||
const testGlassPiece = {};
|
||||
const testIndex = 0;
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(false);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false if suppressed", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({ index: 0 });
|
||||
|
||||
const testGlassPiece = {
|
||||
isSuppressedPart: true,
|
||||
questions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
|
||||
answers: [],
|
||||
},
|
||||
],
|
||||
answerData: {
|
||||
answerResult: "test",
|
||||
},
|
||||
};
|
||||
const testIndex = 0;
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(false);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("method handleForwardButtonAction...", () => {
|
||||
test("Should emit forwardButtonAction", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({});
|
||||
|
||||
// Act
|
||||
wrapper.vm.handleForwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()).toHaveProperty("forwardButtonAction");
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("method handleBackButtonAction...", () => {
|
||||
test("Should emit backButtonAction", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.setProps({});
|
||||
|
||||
// Act
|
||||
wrapper.vm.handleBackButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()).toHaveProperty("back-click");
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks() {
|
||||
const baseStoreGettersPageData = () => {
|
||||
return {
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: null,
|
||||
partQuestions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: 2,
|
||||
},
|
||||
{
|
||||
answerResult: "",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerKey: "Windshield-Single",
|
||||
answerData: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
const baseStoreGettersDamage = () => {
|
||||
return {
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
result: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
const mountOptions = getMountOptions({
|
||||
mixins: [baseMixin, vehicleQuestionsMixin],
|
||||
});
|
||||
mountOptions["attachTo"] = document.body;
|
||||
const wrapper = shallowMount(questionsPageLayout, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
ref="funnelFooter"
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
:isForwardActionDisabled="!isMetaValid"
|
||||
@back-clicked="backButtonAction"
|
||||
@back-clicked="handleBackButtonClicked"
|
||||
@ForwardClicked="handleForwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,7 +51,7 @@ export default {
|
|||
alertFewMoreQuestionsCopy: String,
|
||||
questionsData: Array,
|
||||
validationRules: String,
|
||||
modelValue: Array,
|
||||
modelValue: Object,
|
||||
index: Number,
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -66,16 +66,17 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
showThisQuestionChain(glass, i) {
|
||||
// return false if no questions or if suppressed
|
||||
if (!glass.questions || glass.questions?.length < 1 || glass.isSuppressedPart) {
|
||||
return false;
|
||||
} // return false if no questions or if suppressed
|
||||
}
|
||||
return this.index === i || glass.answerData?.answerResult?.length > 0;
|
||||
},
|
||||
handleForwardButtonAction() {
|
||||
this.$emit("forwardButtonAction");
|
||||
},
|
||||
handleBackButtonAction() {
|
||||
this.$emit("backButtonAction");
|
||||
this.$emit("back-click");
|
||||
},
|
||||
showLoadingModal() {
|
||||
this.$refs.loadingModal.showModal();
|
||||
|
|
@ -6,6 +6,10 @@ describe("modal.vue", () => {
|
|||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"]));
|
||||
});
|
||||
|
|
@ -14,6 +18,10 @@ describe("modal.vue", () => {
|
|||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"]));
|
||||
});
|
||||
|
|
@ -22,6 +30,10 @@ describe("modal.vue", () => {
|
|||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"]));
|
||||
});
|
||||
|
|
@ -30,6 +42,10 @@ describe("modal.vue", () => {
|
|||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"]));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body ps-4 pe-4 pt-5 pb-4">
|
||||
<img :src="this.ModalImage" class="w-100 mb-4" alt="" />
|
||||
<img :src="this.ModalImage" class="mw-100 d-flex mx-auto mb-4" alt="" />
|
||||
<h5 class="mb-4" v-html="this.ModalHeadline"></h5>
|
||||
<p class="fw-bold mb-2 subheader-text" v-html="this.ModalSubheadertext"></p>
|
||||
<p class="mb-0" v-html="this.ModalBodyText"></p>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<buttonMain
|
||||
class="w-100"
|
||||
ref="buttonMain"
|
||||
isPrimary
|
||||
suppressLoader
|
||||
:buttonText="ModalCloseButtonText"
|
||||
@click-event="buttonClick"
|
||||
data-bs-dismiss="modal" />
|
||||
|
|
@ -60,6 +60,12 @@ export default {
|
|||
return this.getCmsContent(this.cmsWidgetName, "FooterText");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const modal = document.querySelector("#" + this.cmsWidgetName);
|
||||
modal.addEventListener("hidden.bs.modal", (event) => {
|
||||
this.$refs.buttonMain.resetButtonStyle();
|
||||
});
|
||||
},
|
||||
components: {
|
||||
buttonMain,
|
||||
},
|
||||
|
|
|
|||
322
src/common-components/question-chain/question-chain.spec.js
Normal file
322
src/common-components/question-chain/question-chain.spec.js
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import questionChain from "@/common-components/question-chain/question-chain.vue";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
jest.mock(
|
||||
"@/store",
|
||||
() => {
|
||||
return {};
|
||||
},
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
describe("Question Chain component", () => {
|
||||
describe("on create...", () => {
|
||||
test("Should populate questions data array", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const expectedFirstQuestionAnswer = {
|
||||
answerResult: "DB09410",
|
||||
buttonLabel: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
questionSequence: 1,
|
||||
questionType: "answer",
|
||||
value: "1|answer|DB09410|Yes",
|
||||
};
|
||||
|
||||
//Act
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questions[0].answers[0]).toMatchObject(expectedFirstQuestionAnswer);
|
||||
});
|
||||
|
||||
test("Should not include suppressed questions on questions data array", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
await wrapper.setData({
|
||||
questionData: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText: "Question here?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "DB09410",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "DB10840",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
suppressThisQuestion: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
//Act
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questions[0]).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("method handleAnswer...", () => {
|
||||
test("should run getQuestionChainAnswerIfComplete", () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testQuestion = {};
|
||||
const testReturnedAnswer = "aReturnedAnswer";
|
||||
wrapper.vm.getQuestionChainAnswerIfComplete = jest.fn();
|
||||
|
||||
//Act
|
||||
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.getQuestionChainAnswerIfComplete).toBeCalled();
|
||||
});
|
||||
|
||||
test("should emit update:modelValue if returnedAnswer contains 'answer'", () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testQuestion = {};
|
||||
const testReturnedAnswer = "1|answer|DB10840|No";
|
||||
|
||||
//Act
|
||||
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()).toHaveProperty("update:modelValue");
|
||||
expect(wrapper.emitted()["update:modelValue"][0][0]).toMatchObject({
|
||||
answerResult: "DB10840",
|
||||
});
|
||||
});
|
||||
|
||||
test("should NOT emit update:modelValue if no returnedAnswer", () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testQuestion = {};
|
||||
|
||||
//Act
|
||||
wrapper.vm.handleAnswer(testQuestion);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
|
||||
});
|
||||
|
||||
test("should NOT emit update:modelValue if returnedAnswer contains 'nextQuestion'", () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testQuestion = {};
|
||||
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
|
||||
|
||||
//Act
|
||||
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
|
||||
});
|
||||
});
|
||||
|
||||
describe("method getQuestionChainAnswerIfComplete...", () => {
|
||||
test("should return false if no returned answer", () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getQuestionChainAnswerIfComplete();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should set the answerSelected to match the answered one", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testReturnedAnswer = "1|answer|DB10840|No";
|
||||
await wrapper.setData({
|
||||
questionData: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText: "Question here?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "DB09410",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "DB10840",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
//Act
|
||||
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questions[0].answerSelected).toBe("1|answer|DB10840|No");
|
||||
});
|
||||
|
||||
test("should remove answers of questions after the answered one", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testReturnedAnswer = "1|answer|DB10840|No";
|
||||
await wrapper.setData({
|
||||
questionData: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText: "Question here?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "DB09410",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "DB10840",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
questionSequence: 2,
|
||||
questionText: "Question 2",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "2-yes",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "2-no",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
answerSelected: "previously selected answer",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
//Act
|
||||
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questions[1].answerSelected).toBeUndefined;
|
||||
});
|
||||
|
||||
test("should return false if returnedAnswer is a nextQuestion (not a final answer)", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should trigger scroll to .current-question if returnedAnswer is a nextQuestion (not a final answer)", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
|
||||
|
||||
//Act
|
||||
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(Element.prototype.scrollIntoView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should return answer object if returnedAnswer is a final matching answer", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const testReturnedAnswer = "1|answer|DB10840|No";
|
||||
await wrapper.setData({
|
||||
questions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText: "Question here?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "DB09410",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "DB10840",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
});
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
|
||||
|
||||
//Assert
|
||||
expect(result).toMatchObject({
|
||||
answerResult: "DB10840",
|
||||
answeredQuestions: [
|
||||
{ questionNum: 1, questionText: "Question here?", selectedAnswerText: "No" },
|
||||
{
|
||||
questionNum: 1,
|
||||
questionText: "Does only your center sliding piece need to be replaced?",
|
||||
selectedAnswerText: "No",
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
questionDataProp = [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText: "Does only your center sliding piece need to be replaced?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "DB09410",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "DB10840",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}) {
|
||||
Element.prototype.scrollIntoView = jest.fn();
|
||||
|
||||
const mountOptions = getMountOptions({});
|
||||
mountOptions.propsData = {
|
||||
questionData: questionDataProp,
|
||||
};
|
||||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(questionChain, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import questionChain from "@/common-components/question-chain/question-chain.vue";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
jest.mock("@/store",()=>{return{};},{virtual:true});
|
||||
|
||||
describe("Question Chain component", () => {
|
||||
|
||||
it("Should not emit a modelValue change when setting selectedValue if isNewModelValueComplete is false", () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: [] });
|
||||
wrapper.vm.currentQuestion = 6;
|
||||
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
|
||||
const localThis = {
|
||||
$emit: jest.fn(),
|
||||
getNewModelValue: jest.fn(() => { return false })
|
||||
}
|
||||
|
||||
//Act
|
||||
questionChain.computed.selectedValue.set.call(localThis, answerReturned);
|
||||
|
||||
//Assert
|
||||
expect(localThis.$emit).not.toBeCalled();
|
||||
});
|
||||
|
||||
it("Should emit a modelValue change when setting selectedValue if isNewModelValueComplete is true", () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: [] });
|
||||
wrapper.vm.currentQuestion = 6;
|
||||
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
|
||||
const localThis = {
|
||||
$emit: jest.fn(),
|
||||
getNewModelValue: jest.fn(() => { return true })
|
||||
}
|
||||
|
||||
//Act
|
||||
questionChain.computed.selectedValue.set.call(localThis, answerReturned);
|
||||
|
||||
//Assert
|
||||
expect(localThis.$emit).toBeCalledWith("update:modelValue", true);
|
||||
});
|
||||
|
||||
it("should return false if no returned answer is given", () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: [] });
|
||||
wrapper.vm.currentQuestion = 1;
|
||||
const answerReturned = null;
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getNewModelValue(answerReturned);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return false if the user's answer on the current question leads to another question", () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: [] });
|
||||
wrapper.vm.currentQuestion = 1;
|
||||
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getNewModelValue(answerReturned);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return an object with the final answer if the user's answer on the current question is a part number", () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ modelValueProp: [] });
|
||||
wrapper.vm.currentQuestion = 6;
|
||||
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
|
||||
|
||||
//Act
|
||||
const result = wrapper.vm.getNewModelValue(answerReturned);
|
||||
|
||||
//Assert
|
||||
expect(result).toEqual(
|
||||
{
|
||||
answerResult: 'DW02102',
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText: 'Is your vehicle equipped with heated seats?',
|
||||
selectedAnswerText: 'Yes'
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
modelValueProp = "",
|
||||
questionDataProp = {
|
||||
"glassName": "Single",
|
||||
"glassLocation": "Windshield",
|
||||
"parts": null,
|
||||
"partQuestions": [
|
||||
{
|
||||
"questionSequence": 1,
|
||||
"questionText": "Is your Cherokee the Overland edition which can be identified by having a wood and leather wrapped steering wheel?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": 2,
|
||||
"answerResult": ""
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": 3,
|
||||
"answerResult": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"questionSequence": 2,
|
||||
"questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02270"
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02264"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"questionSequence": 3,
|
||||
"questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02268"
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": 4,
|
||||
"answerResult": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"questionSequence": 4,
|
||||
"questionText": "Is your vehicle equipped with automatic climate control which will change the fan speed automatically in order to maintain a set temperature?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": 5,
|
||||
"answerResult": ""
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": 6,
|
||||
"answerResult": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"questionSequence": 5,
|
||||
"questionText": "Is your vehicle equipped with heated seats?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02104"
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02103"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"questionSequence": 6,
|
||||
"questionText": "Is your vehicle equipped with heated seats?",
|
||||
"answers": [
|
||||
{
|
||||
"answerText": "Yes",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02102"
|
||||
},
|
||||
{
|
||||
"answerText": "No",
|
||||
"nextQuestionSequence": null,
|
||||
"answerResult": "DW02101"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
methodsToMock = [],
|
||||
}) {
|
||||
|
||||
//Mock store
|
||||
store.dispatch = jest.fn(() => dataFromStoreApi);
|
||||
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
|
||||
const mountOptions = getMountOptions({
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn()
|
||||
}
|
||||
}
|
||||
mountOptions.propsData = {
|
||||
modelValue: modelValueProp,
|
||||
questionData: questionDataProp,
|
||||
};
|
||||
mountOptions.mixins = [mockMixin];
|
||||
|
||||
//Mock methods
|
||||
methodsToMock.forEach((methodName) => {
|
||||
questionChain.methods[methodName] = jest.fn();
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(questionChain, mountOptions);
|
||||
|
||||
//Mock CMS content
|
||||
const cmsContent = {
|
||||
};
|
||||
return { wrapper, cmsContent };
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ export default {
|
|||
};
|
||||
},
|
||||
props: {
|
||||
questionData: Object,
|
||||
questionData: Array,
|
||||
validationRules: String,
|
||||
modelValue: Object,
|
||||
index: Number,
|
||||
|
|
@ -84,11 +84,7 @@ export default {
|
|||
handleAnswer(question, returnedAnswer) {
|
||||
/*
|
||||
returnedAnswer example format:
|
||||
{
|
||||
"checkValue": "1|answer|DD11132|Yes",
|
||||
"value": "1|answer|DD11132|Yes",
|
||||
"buttonId": "Driver-Front-1-1|answer|DD11132|Yes"
|
||||
}
|
||||
"1|answer|DD11132|Yes"
|
||||
*/
|
||||
|
||||
question.answerSelected = returnedAnswer;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
:for="inputId"
|
||||
:aria-label="questionText"
|
||||
class="form-label"
|
||||
:class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']"
|
||||
v-html="labelText"></label>
|
||||
<div class="input-wrapper" :class="[includeSearchIcon ? 'has-search-icon' : '']">
|
||||
<input
|
||||
|
|
@ -22,7 +23,6 @@
|
|||
:class="[
|
||||
hasIcon ? 'has-icon' : '',
|
||||
iconRight ? 'icon-right' : '',
|
||||
questionAlignment === 'center' ? 'text-center' : '',
|
||||
cornerStyle === 'rounded' ? 'rounded-pill' : '',
|
||||
]"
|
||||
:validationRules="validationRules"
|
||||
|
|
@ -203,6 +203,7 @@ export default {
|
|||
border: 1px solid $gray-500;
|
||||
border-radius: 0.5rem;
|
||||
min-height: 3rem;
|
||||
max-height: 48px;
|
||||
padding: 12px 16px;
|
||||
&::placeholder {
|
||||
color: $gray-500;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,18 @@ const endpoints = {
|
|||
url: "/parts/api/v1/parts/parts",
|
||||
method: "POST",
|
||||
},
|
||||
GetWipers: {
|
||||
url: "/parts/api/v1/parts/wipers",
|
||||
method: "GET",
|
||||
},
|
||||
GetRainDefense: {
|
||||
url: "/parts/api/v1/parts/rain-defense",
|
||||
method: "GET",
|
||||
},
|
||||
GetSupportingItems: {
|
||||
url: "/parts/api/v1/parts/supporting-items",
|
||||
method: "POST",
|
||||
},
|
||||
GetCapabilityQuestions: {
|
||||
url: "/parts/api/v1/parts/capability-questions",
|
||||
method: "GET",
|
||||
|
|
@ -76,12 +88,16 @@ const endpoints = {
|
|||
},
|
||||
LoadSession: {
|
||||
url: "/order/api/v1/order/load-session",
|
||||
method: "POST",
|
||||
method: "GET",
|
||||
},
|
||||
ValidateZip: {
|
||||
url: "/location/api/v1/location/zip",
|
||||
method: "GET",
|
||||
},
|
||||
PriceOrderItems: {
|
||||
url: "/price/api/v1/price/order-items",
|
||||
method: "POST",
|
||||
},
|
||||
LogExperimentExposureIfAssigned: {
|
||||
url: "/experiments/api/v1/experiments/log-exposure",
|
||||
method: "POST",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const storeActions = {
|
|||
SET_VEHICLE: "setVehicle",
|
||||
GET_DAMAGE_OPTIONS: "getDamageOptions",
|
||||
GET_EVOX_IMAGE: "getEvoxImage",
|
||||
IS_VIN_OPTIONAL_VEHICLE: "isVinOptionalVehicle",
|
||||
|
||||
// Lookup Actions
|
||||
LOOKUP_VEHICLE_BY_YMMS: "lookupVehicleByYmms",
|
||||
|
|
@ -20,6 +21,9 @@ const storeActions = {
|
|||
LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress",
|
||||
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
||||
GET_PARTS: "getParts",
|
||||
GET_WIPERS: "getWipers",
|
||||
GET_RAIN_DEFENSE: "getRainDefense",
|
||||
GET_SUPPORTING_ITEMS: "getSupportingItems",
|
||||
GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions",
|
||||
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
|
||||
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
|
||||
|
|
@ -27,6 +31,7 @@ const storeActions = {
|
|||
LOAD_SESSION: "loadSession",
|
||||
UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse",
|
||||
VALIDATE_ZIP: "validateZip",
|
||||
PRICE_ORDER_ITEMS: "priceOrderItems",
|
||||
LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
|
||||
LOG_PAGE_VIEW: "logPageView",
|
||||
LOG_CUSTOM_EVENT: "logCustomEvent",
|
||||
|
|
@ -37,7 +42,6 @@ const storeActions = {
|
|||
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
||||
|
||||
// DEPENDENCY MUTATIONS
|
||||
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies",
|
||||
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
||||
RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies",
|
||||
RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies",
|
||||
|
|
@ -62,6 +66,7 @@ const storeActions = {
|
|||
SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers",
|
||||
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers",
|
||||
SAVE_IS_INSURANCE: "saveIsInsurance",
|
||||
SAVE_QUOTE_PAGE_SELECTIONS: "saveQuotePageSelections",
|
||||
};
|
||||
|
||||
export { storeActions };
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ const storeMutations = {
|
|||
UPDATE_MOLDING_QUESTION_ANSWERS: "updateMoldingQuestionAnswers",
|
||||
UPDATE_CAPABILITY_QUESTION_ANSWERS: "updateCapabilityQuestionAnswers",
|
||||
UPDATE_GLASS_PARTS: "updateGlassParts",
|
||||
UPDATE_OTHER_PARTS: "updateOtherParts",
|
||||
UPDATE_VAPS: "updateVaps",
|
||||
UPDATE_SUPPORTING_ITEMS: "updateSupportingItems",
|
||||
|
||||
UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate",
|
||||
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
|
||||
|
|
@ -36,14 +37,13 @@ const storeMutations = {
|
|||
|
||||
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",
|
||||
|
||||
UPDATE_IS_INSURANCE: "updateIsInsurance",
|
||||
|
||||
// ORDER MUTATIONS
|
||||
UPDATE_REFERRAL_NUMBER: "updateReferralNumber",
|
||||
UPDATE_REFERRAL_DATE: "updateReferralDate",
|
||||
UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId",
|
||||
UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber",
|
||||
UPDATE_EON: "updateEON",
|
||||
UPDATE_IS_INSURANCE: "updateIsInsurance",
|
||||
UPDATE_SAVED_SESSION_ID: "updateSavedSessionId",
|
||||
UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId",
|
||||
|
||||
|
|
@ -56,6 +56,8 @@ const storeMutations = {
|
|||
RESET_DAMAGE_STATE: "resetDamageState",
|
||||
RESET_REGISTRATION_STATE: "resetRegistrationState",
|
||||
RESET_GLASS_PARTS_STATE: "resetGlassPartsState",
|
||||
RESET_SUPPORTING_ITEMS_STATE: "resetSupportingItemsState",
|
||||
RESET_VAPS_STATE: "resetVapsState",
|
||||
RESET_STATE: "resetState",
|
||||
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export function updateOrCreateFunnelCookie() {
|
|||
ReferralParentAccountNumber: store.getters.order.accountNumber,
|
||||
HasDelayedClaimRegistration: wasClaimRegistrationDelayed,
|
||||
SuppressConceptFunnel: shouldSuppressConceptFunnel,
|
||||
SavedSessionId: store.getters.applicationUser.savedSessionId,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
|||
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
|
||||
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { storeActions } from "@/constants/store-actions.js";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
|
||||
|
|
@ -78,6 +80,8 @@ async function getLatestPageForRedirection() {
|
|||
fmgPageValues.CAPABILITY_QUESTIONS
|
||||
);
|
||||
|
||||
const isVinOptionalVehicle = await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE);
|
||||
|
||||
if (!vehicleMakeComponent.methods.arePagePrerequisitesValid()) {
|
||||
return fmgPageValues.VEHICLE_YEAR;
|
||||
} else if (!vehicleModelComponent.methods.arePagePrerequisitesValid()) {
|
||||
|
|
@ -99,7 +103,8 @@ async function getLatestPageForRedirection() {
|
|||
return fmgPageValues.PART_QUESTIONS;
|
||||
} else if (
|
||||
vinLookupComponent.methods.arePagePrerequisitesValid() &&
|
||||
!store.getters.damage.isRepair
|
||||
!store.getters.damage.isRepair &&
|
||||
!isVinOptionalVehicle
|
||||
) {
|
||||
return fmgPageValues.VIN_LOOKUP;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
import * as orderHelper from "@/helpers/heritage-integration/order-helper";
|
||||
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import { setupMocksForJsFiles, getMockOrderInfo } from "@/helpers/unit-test-helper.js";
|
||||
import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
|
|
@ -25,6 +26,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: false,
|
||||
|
|
@ -43,6 +47,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -62,6 +69,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -82,6 +92,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -103,6 +116,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -125,6 +141,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -152,6 +171,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -179,6 +201,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -206,6 +231,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -233,6 +261,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -260,6 +291,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
query: {},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Mock out the lazy load calls for all components.
|
||||
mockLazyLoadComponentReturnValues({
|
||||
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||
|
|
@ -289,6 +323,9 @@ describe("getPageToRouteExistingOrderTo", () => {
|
|||
},
|
||||
};
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
// Act
|
||||
const result = await getPageToRouteExistingOrderTo(toRoute, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,8 @@ import { storeMutations } from "@/constants/store-mutations";
|
|||
export async function loadSessionIfPresent() {
|
||||
const funnelCookie = getFunnelCookie();
|
||||
|
||||
// Do nothing if there is no cookie, correlation id, or referral number.
|
||||
if (
|
||||
funnelCookie == null ||
|
||||
funnelCookie.ReferralCorrelationId == null ||
|
||||
!funnelCookie.ReferralNumber
|
||||
) {
|
||||
// Do nothing if there is no cookie or session to use for loading.
|
||||
if (funnelCookie == null || funnelCookie.SavedSessionId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -33,15 +29,8 @@ export async function loadSessionIfPresent() {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Load referral if there is a cookie, and it doesn't indicate it needs a state reset.
|
||||
return (
|
||||
await loadSession(
|
||||
funnelCookie.ReferralNumber,
|
||||
funnelCookie.ReferralDate,
|
||||
funnelCookie.ReferralCorrelationId,
|
||||
funnelCookie.ReferralParentAccountNumber,
|
||||
)
|
||||
).data;
|
||||
// Loads session including referral if there is a cookie, and it doesn't indicate it needs a state reset.
|
||||
return (await loadSession(funnelCookie.SavedSessionId)).data;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -72,16 +61,13 @@ export async function saveSession() {
|
|||
Calls API to load session given the referral number, referralDate, and referralCorrelationId
|
||||
and returns the response.
|
||||
*/
|
||||
async function loadSession(referralNumber, referralDate, referralCorrelationId, accountNumber) {
|
||||
async function loadSession(savedSessionId) {
|
||||
// await the saveSessionPromise in the store to make sure we're loading up to date information
|
||||
await store.getters.applicationUser.saveSessionPromise;
|
||||
const response = await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.LOAD_SESSION,
|
||||
{
|
||||
referralNumber: referralNumber.toString(),
|
||||
referralDate: referralDate,
|
||||
referralCorrelationId: referralCorrelationId,
|
||||
accountNumber: accountNumber?.toString(),
|
||||
savedSessionId: savedSessionId?.toString(),
|
||||
},
|
||||
false
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ describe("loadSessionIfPresent", () => {
|
|||
ShouldResetState: testShouldResetState,
|
||||
ReferralCorrelationId: "xxx",
|
||||
ReferralNumber: "12345",
|
||||
SavedSessionId: "aa115a05-e268-4eb4-a095-1d54b44f4a99",
|
||||
};
|
||||
|
||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify(
|
||||
|
|
@ -46,6 +47,7 @@ describe("loadSessionIfPresent", () => {
|
|||
ShouldResetState: true,
|
||||
ReferralCorrelationId: "xxx-xxx-xxx",
|
||||
ReferralNumber: "12345",
|
||||
SavedSessionId: "aa115a05-e268-4eb4-a095-1d54b44f4a99",
|
||||
});
|
||||
|
||||
const mockData = {
|
||||
|
|
@ -103,6 +105,7 @@ describe("loadSessionIfPresent", () => {
|
|||
ReferralNumber: 123456,
|
||||
ReferralCorrelationId: "yyy-yyy-yyyy",
|
||||
ReferralDate: new Date(),
|
||||
SavedSessionId: "aa115a05-e268-4eb4-a095-1d54b44f4a99",
|
||||
});
|
||||
|
||||
const mockData = {
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ describe("address-lookup.vue", () => {
|
|||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
|
||||
undefined,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -381,7 +381,7 @@ describe("address-lookup.vue", () => {
|
|||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
undefined,
|
||||
{},
|
||||
{ displayVehicleChangeAlert: true }
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ export default {
|
|||
matchingCars.length === 1
|
||||
) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
|
||||
|
|
@ -373,7 +373,7 @@ export default {
|
|||
await this.navigateForwardWithSingleCarMatch();
|
||||
} else {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES,
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
|
||||
this.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
|
|||
404
src/layouts/capability-questions/capability-questions.spec.js
Normal file
404
src/layouts/capability-questions/capability-questions.spec.js
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
// Components
|
||||
import capabilityQuestions from "@/layouts/capability-questions/capability-questions";
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
import baseMixin from "../../mixins/base-mixin";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
"@/store",
|
||||
() => {
|
||||
return {};
|
||||
},
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||
navigateToHeritageFunnel: jest.fn(),
|
||||
}));
|
||||
|
||||
const baseStoreGettersPageData = () => {
|
||||
return {
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [],
|
||||
},
|
||||
],
|
||||
capabilityQuestions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
|
||||
answers: [
|
||||
{
|
||||
answerResult1: "DYNAMIC",
|
||||
answerResult2: "1",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
answerResult: "DYNAMIC",
|
||||
},
|
||||
{
|
||||
answerResult1: "Unknown",
|
||||
answerResult2: "0",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
answerResult: "Unknown",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
partQuestions: [],
|
||||
questions: [],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerKey: "Windshield-Single",
|
||||
answerData: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
const baseStoreGettersDamage = () => {
|
||||
return {
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
result: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
store.commit = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
// reset store after each test
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
});
|
||||
|
||||
describe("capabilityQuestions.vue", () => {
|
||||
describe("method arePagePrerequisitesValid...", () => {
|
||||
test("Should return true for valid page requisites if pageData exists", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
store.getters.pageData = jest.fn(() => {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should be at least one item in partsOrQuestions", () => {
|
||||
// Arrange
|
||||
store.getters = {
|
||||
pageData: jest.fn(() => {
|
||||
return {
|
||||
partsOrQuestions: [],
|
||||
};
|
||||
}),
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("watch on selectedAnswers should be set up...", () => {
|
||||
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedAnswers: {
|
||||
"Windshield-Single": {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("forwardButtonAction", () => {
|
||||
test("Should clear out answerData", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [{}],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should save to Vuex store", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"saveCapabilityQuestionAnswers",
|
||||
[
|
||||
{
|
||||
answeredQuestions: [],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
isSuppressedPart: undefined,
|
||||
result: "FW04848",
|
||||
result1: "FW04848",
|
||||
result2: undefined,
|
||||
},
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should call GET_PART_FROM_CAPABILITY_QUESTION_ANSWER API", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"getPartFromCapabilityQuestionAnswer",
|
||||
"Windshield",
|
||||
false
|
||||
);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should trigger navigateForward", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn(),
|
||||
},
|
||||
store: {
|
||||
getters: store.getters,
|
||||
commit: store.commit,
|
||||
},
|
||||
route: {
|
||||
query: {
|
||||
fmgPage: "capability-questions",
|
||||
},
|
||||
},
|
||||
},
|
||||
}) {
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin],
|
||||
});
|
||||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(capabilityQuestions, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -6,17 +6,17 @@
|
|||
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
|
||||
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
|
||||
:questionsData="questionsData"
|
||||
:validationRules="questions - required"
|
||||
validationRules="questions-required"
|
||||
v-model="selectedAnswers"
|
||||
@forwardButtonAction="forwardButtonAction"
|
||||
@backButtonAction="backButtonAction"
|
||||
@back-click="navigateBack"
|
||||
:index="currentGlassIndex" />
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import questionsPageLayout from "@/common-components/questions-page-layout/questions-page-layout";
|
||||
import questionsPageLayout from "@/common-components/layouts/questions-page-layout/questions-page-layout";
|
||||
|
||||
// Supporting Files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -67,38 +67,13 @@ export default {
|
|||
AlertFewMoreQuestionsCopy() {
|
||||
return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText");
|
||||
},
|
||||
pageData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
||||
partsOrQuestionsData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)
|
||||
.partsOrQuestions;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// are there alreadyAnsweredQuestions?
|
||||
const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers;
|
||||
|
||||
this.questionsData = this.pageData.partsOrQuestions
|
||||
.filter((x) => x.capabilityQuestions)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.capabilityQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(glass, index, alreadyAnsweredQuestions);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
this.getInitialQuestionData();
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
@ -106,9 +81,46 @@ export default {
|
|||
fmgPageValues.CAPABILITY_QUESTIONS
|
||||
);
|
||||
return (
|
||||
capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0
|
||||
// has capabilityQuestions array and has glassName not null
|
||||
capabilityQuestionsPageData?.partsOrQuestions?.some((part) => part?.glassName) &&
|
||||
capabilityQuestionsPageData?.partsOrQuestions?.some(
|
||||
(part) => part?.capabilityQuestions?.length > 0
|
||||
)
|
||||
);
|
||||
},
|
||||
getInitialQuestionData() {
|
||||
// get any questions that were already answered
|
||||
const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers;
|
||||
|
||||
this.questionsData = this.partsOrQuestionsData
|
||||
.filter((x) => x.capabilityQuestions)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.capabilityQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(
|
||||
glass,
|
||||
index,
|
||||
alreadyAnsweredQuestions
|
||||
);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
// get answerResult2 of returned answer
|
||||
|
|
@ -139,6 +151,7 @@ export default {
|
|||
});
|
||||
|
||||
// save to vuex store as order.damage.capabilityQuestionAnswers (array)
|
||||
// used in GET_PART_FROM_CAPABILITY_QUESTION_ANSWER call following this one
|
||||
await this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_CAPABILITY_QUESTION_ANSWERS,
|
||||
questionAnswersArray,
|
||||
|
|
@ -146,7 +159,7 @@ export default {
|
|||
);
|
||||
|
||||
// get parts from the capabilityQuestionAnswers
|
||||
const partsOrQuestions = this.pageData.partsOrQuestions;
|
||||
const partsOrQuestions = this.partsOrQuestionsData;
|
||||
for (let answer of questionAnswersArray) {
|
||||
const partFromCapabilityQuestionAnswer = (
|
||||
await this.dispatchStoreAction(
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ describe("estimate.vue", () => {
|
|||
selectedVinLookupMethod: vinLookupMethodSelections.MANUALVIN,
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
|
||||
store.commit(storeMutations.UPDATE_MAKE, "acura");
|
||||
|
||||
//Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
|
|
@ -216,8 +219,27 @@ describe("estimate.vue", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("skipVinLookup", () => {
|
||||
const skipOptions = [
|
||||
[true, true, true],
|
||||
[true, false, true],
|
||||
[false, true, true],
|
||||
[false, false, false],
|
||||
];
|
||||
test.each(skipOptions)(
|
||||
"isRepair %s and isVinOptional %s should return %s",
|
||||
async (isRepair, isVinOptionalVehicle, expectedVinSkip) => {
|
||||
const { wrapper } = setupMocks({ isVinOptionalVehicle: isVinOptionalVehicle });
|
||||
store.commit(storeMutations.UPDATE_IS_REPAIR, isRepair);
|
||||
|
||||
expect(wrapper.vm.skipVinLookup).toEqual(expectedVinSkip);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
groupName = "estimate",
|
||||
isVinOptionalVehicle = false,
|
||||
cmsQuestionText = "Let's get your VIN. Or we can look it up for you!",
|
||||
cmsAnswers = [
|
||||
{ Name: "Provide my VIN manually Most specific to your vehicle" },
|
||||
|
|
@ -249,6 +271,7 @@ function setupMocks({
|
|||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(estimate, mountOptions);
|
||||
wrapper.vm.isVinOptionalVehicle = isVinOptionalVehicle;
|
||||
|
||||
return { wrapper, apiPromise };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" />
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<div class="fade-on-route-transition sub-container make-tall">
|
||||
<div v-if="!isRepair">
|
||||
<div v-if="!skipVinLookup">
|
||||
<alert
|
||||
class="vinLookupMethodHeading"
|
||||
cmsWidgetName="AlertVinLookupQuestion"
|
||||
|
|
@ -127,12 +127,14 @@ export default {
|
|||
emailAddress: this.getEmailFromStore(),
|
||||
displayInvalidZipAlert: false,
|
||||
displayNonServiceableZipAlert: false,
|
||||
isVinOptionalVehicle: false,
|
||||
};
|
||||
},
|
||||
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
//Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||
|
||||
//Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
|
|
@ -140,12 +142,16 @@ export default {
|
|||
promise: cmsContentPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
const isVinOptionalVehicle = await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE);
|
||||
|
||||
next((vm) => {
|
||||
vm.isVinOptionalVehicle = isVinOptionalVehicle;
|
||||
if (resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.includes("|")) {
|
||||
const forwardTextOption =
|
||||
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.split("|");
|
||||
if (store.getters.damage.isRepair) {
|
||||
if (store.getters.damage.isRepair || vm.isVinOptionalVehicle) {
|
||||
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText =
|
||||
forwardTextOption[1];
|
||||
} else {
|
||||
|
|
@ -172,9 +178,9 @@ export default {
|
|||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
if (this.isRepair) {
|
||||
if (this.skipVinLookup) {
|
||||
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
|
||||
//todo: validation
|
||||
|
||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
|
||||
await this.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_LOCATION,
|
||||
|
|
@ -200,10 +206,10 @@ export default {
|
|||
const payment = this.$store.getters.payment;
|
||||
// TODO KO If coverageStatus is null, they haven't gone to heritage yet... I think
|
||||
if (payment.isInsurance && payment.insuranceCoverage.coverageStatus) {
|
||||
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal })
|
||||
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
||||
} else {
|
||||
return this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.HAS_NO_QUESTIONS,
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS,
|
||||
this.$route
|
||||
);
|
||||
}
|
||||
|
|
@ -249,6 +255,9 @@ export default {
|
|||
isRepair() {
|
||||
return store.getters.damage.isRepair;
|
||||
},
|
||||
skipVinLookup() {
|
||||
return this.isRepair || this.isVinOptionalVehicle;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
serviceZipCode() {
|
||||
|
|
|
|||
351
src/layouts/molding-questions/molding-questions.spec.js
Normal file
351
src/layouts/molding-questions/molding-questions.spec.js
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
// Components
|
||||
import moldingQuestions from "@/layouts/molding-questions/molding-questions";
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
import baseMixin from "../../mixins/base-mixin";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
"@/store",
|
||||
() => {
|
||||
return {};
|
||||
},
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||
navigateToHeritageFunnel: jest.fn(),
|
||||
}));
|
||||
|
||||
const baseStoreGettersPageData = () => {
|
||||
return {
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Does the rubber seal around your windshield have a chrome strip running through it?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "WKT D1106 C",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
{
|
||||
answerResult: "WKT D1106 B",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
basePartNumber: "DW01105",
|
||||
color: "Green Tint, Blue Shade",
|
||||
requiresRecalibration: false,
|
||||
recalibrationType: "",
|
||||
canSafeliteRecalibrate: false,
|
||||
requiresCapabilityQuestions: false,
|
||||
childParts: null,
|
||||
partNumber: "DW01105GBNN",
|
||||
description: "solar",
|
||||
partType: "WINDSHIELD",
|
||||
},
|
||||
],
|
||||
partQuestions: [],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerKey: "Windshield-Single",
|
||||
answerData: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
const baseStoreGettersDamage = () => {
|
||||
return {
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
result: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
store.commit = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
// reset store after each test
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
});
|
||||
|
||||
describe("moldingQuestions.vue", () => {
|
||||
describe("method arePagePrerequisitesValid...", () => {
|
||||
test("Should return true for valid page requisites if pageData exists", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
store.getters.pageData = jest.fn(() => {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should be at least one item in partsOrQuestions", () => {
|
||||
// Arrange
|
||||
store.getters = {
|
||||
pageData: jest.fn(() => {
|
||||
return {
|
||||
partsOrQuestions: [],
|
||||
};
|
||||
}),
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("watch on selectedAnswers should be set up...", () => {
|
||||
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedAnswers: {
|
||||
"Windshield-Single": {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("forwardButtonAction", () => {
|
||||
test("Should clear out answerData", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should save to Vuex store", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"saveMoldingQuestionAnswers",
|
||||
[
|
||||
{
|
||||
answeredQuestions: [],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
isSuppressedPart: undefined,
|
||||
partNum: "FW04848",
|
||||
},
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should trigger navigateForward", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn(),
|
||||
},
|
||||
store: {
|
||||
getters: store.getters,
|
||||
commit: store.commit,
|
||||
},
|
||||
route: {
|
||||
query: {
|
||||
fmgPage: "molding-questions",
|
||||
},
|
||||
},
|
||||
},
|
||||
}) {
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin],
|
||||
});
|
||||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(moldingQuestions, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -6,17 +6,17 @@
|
|||
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
|
||||
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
|
||||
:questionsData="questionsData"
|
||||
:validationRules="questions - required"
|
||||
validationRules="questions-required"
|
||||
v-model="selectedAnswers"
|
||||
@forwardButtonAction="forwardButtonAction"
|
||||
@backButtonAction="backButtonAction"
|
||||
@back-click="navigateBack"
|
||||
:index="currentGlassIndex" />
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import questionsPageLayout from "@/common-components/questions-page-layout/questions-page-layout";
|
||||
import questionsPageLayout from "@/common-components/layouts/questions-page-layout/questions-page-layout";
|
||||
|
||||
// Supporting Files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -67,37 +67,12 @@ export default {
|
|||
AlertFewMoreQuestionsCopy() {
|
||||
return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText");
|
||||
},
|
||||
pageData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.MOLDING_QUESTIONS);
|
||||
partsOrQuestionsData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.MOLDING_QUESTIONS).partsOrQuestions;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// are there alreadyAnsweredQuestions?
|
||||
const alreadyAnsweredQuestions = store.getters.damage.moldingQuestionAnswers;
|
||||
|
||||
this.questionsData = this.pageData.partsOrQuestions
|
||||
.filter((x) => x.parts[0].childPartQuestions.length)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.parts[0].childPartQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(glass, index, alreadyAnsweredQuestions);
|
||||
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
this.getInitialQuestionData();
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
@ -105,9 +80,46 @@ export default {
|
|||
fmgPageValues.MOLDING_QUESTIONS
|
||||
);
|
||||
return (
|
||||
moldingQuestionsFromPageData && Object.keys(moldingQuestionsFromPageData).length > 0
|
||||
// has childPartQuestions array and has glassName not null
|
||||
moldingQuestionsFromPageData?.partsOrQuestions?.some((part) => part?.glassName) &&
|
||||
moldingQuestionsFromPageData.partsOrQuestions.some((glass) =>
|
||||
glass.parts?.some((part) => part?.childPartQuestions?.length > 0)
|
||||
)
|
||||
);
|
||||
},
|
||||
getInitialQuestionData() {
|
||||
// get any questions that were already answered
|
||||
const alreadyAnsweredQuestions = store.getters.damage.moldingQuestionAnswers;
|
||||
|
||||
this.questionsData = this.partsOrQuestionsData
|
||||
.filter((x) => x.parts[0].childPartQuestions.length)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.parts[0].childPartQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(
|
||||
glass,
|
||||
index,
|
||||
alreadyAnsweredQuestions
|
||||
);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
return {
|
||||
|
|
@ -132,7 +144,7 @@ export default {
|
|||
);
|
||||
|
||||
// get parts from the questionAnswers
|
||||
let partsOrQuestions = this.pageData.partsOrQuestions;
|
||||
let partsOrQuestions = this.partsOrQuestionsData;
|
||||
for (let answer of questionAnswersArray) {
|
||||
partsOrQuestions.find((partOrQuestion) => {
|
||||
return (
|
||||
|
|
|
|||
427
src/layouts/part-questions/part-questions.spec.js
Normal file
427
src/layouts/part-questions/part-questions.spec.js
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
// Components
|
||||
import partQuestions from "@/layouts/part-questions/part-questions";
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import baseMixin from "../../mixins/base-mixin";
|
||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||
import { nextTick } from "vue";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
"@/store",
|
||||
() => {
|
||||
return {};
|
||||
},
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||
navigateToHeritageFunnel: jest.fn(),
|
||||
}));
|
||||
|
||||
const baseStoreGettersPageData = () => {
|
||||
return {
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: null,
|
||||
partQuestions: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
answers: [
|
||||
{
|
||||
answerResult: "",
|
||||
answerText: "Yes",
|
||||
nextQuestionSequence: 2,
|
||||
},
|
||||
{
|
||||
answerResult: "",
|
||||
answerText: "No",
|
||||
nextQuestionSequence: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerKey: "Windshield-Single",
|
||||
answerData: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
const baseStoreGettersDamage = () => {
|
||||
return {
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
result: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
store.commit = jest.fn();
|
||||
|
||||
describe("partQuestions.vue...", () => {
|
||||
describe("method arePagePrerequisitesValid...", () => {
|
||||
test("Should return true for valid page requisites if pageData exists", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
store.getters.pageData = jest.fn(() => {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should be at least one item in partsOrQuestions", () => {
|
||||
// Arrange
|
||||
store.getters = {
|
||||
pageData: jest.fn(() => {
|
||||
return {
|
||||
partsOrQuestions: [],
|
||||
};
|
||||
}),
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("watch on selectedAnswers should be set up...", () => {
|
||||
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
|
||||
// Arrange
|
||||
store.getters = {
|
||||
pageData: baseStoreGettersPageData,
|
||||
damage: baseStoreGettersDamage,
|
||||
};
|
||||
const { wrapper } = setupMocks({});
|
||||
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedAnswers: {
|
||||
"Windshield-Single": {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText: "One?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText: "Two?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
wrapper.setData({
|
||||
selectedAnswers: {
|
||||
"Windshield-Single": {
|
||||
answerResult: "NEW-ANSWER",
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText: "One?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 1,
|
||||
},
|
||||
{
|
||||
questionText: "Two?",
|
||||
selectedAnswerText: "Yes",
|
||||
questionNum: 2,
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("forwardButtonAction", () => {
|
||||
test("Should clear out answerData", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
await wrapper.setData({
|
||||
questionsData: [
|
||||
{
|
||||
glassLocation: "fbfWindshield",
|
||||
glassName: "fbfSingle",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should save to Vuex store", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"savePartQuestionAnswers",
|
||||
[
|
||||
{
|
||||
answeredQuestions: [],
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
isSuppressedPart: undefined,
|
||||
result: "FW04848",
|
||||
},
|
||||
],
|
||||
false
|
||||
);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should call GET_PARTS API", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(spy).toHaveBeenNthCalledWith(2, "getParts");
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should trigger navigateForward", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||
return {
|
||||
data: {
|
||||
glassPieceParts: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn(),
|
||||
},
|
||||
actionList: [
|
||||
{
|
||||
actionName: storeActions.SAVE_PART_QUESTION_ANSWERS,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
actionName: storeActions.GET_PARTS,
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
store: {
|
||||
getters: store.getters,
|
||||
commit: store.commit,
|
||||
},
|
||||
route: {
|
||||
query: {
|
||||
fmgPage: "part-questions",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedSwitcher: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
answerData: {
|
||||
answerResult: "FW04848",
|
||||
answeredQuestions: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
questionsData: {
|
||||
get() {
|
||||
return this.computedSwitcher;
|
||||
},
|
||||
set(val) {
|
||||
this.computedSwitcher = val;
|
||||
},
|
||||
},
|
||||
},
|
||||
}) {
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin],
|
||||
});
|
||||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(partQuestions, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -6,17 +6,17 @@
|
|||
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
|
||||
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
|
||||
:questionsData="questionsData"
|
||||
:validationRules="questions - required"
|
||||
validationRules="questions-required"
|
||||
v-model="selectedAnswers"
|
||||
@forwardButtonAction="forwardButtonAction"
|
||||
@backButtonAction="backButtonAction"
|
||||
@back-click="navigateBack"
|
||||
:index="currentGlassIndex" />
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import questionsPageLayout from "@/common-components/questions-page-layout/questions-page-layout";
|
||||
import questionsPageLayout from "@/common-components/layouts/questions-page-layout/questions-page-layout";
|
||||
|
||||
// Supporting Files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -67,61 +67,77 @@ export default {
|
|||
AlertFewMoreQuestionsCopy() {
|
||||
return this.getCmsContent("AlertPartsQuestions", "BodyText");
|
||||
},
|
||||
pageData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS);
|
||||
partsOrQuestionsData() {
|
||||
return this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS).partsOrQuestions;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// are there alreadyAnsweredQuestions?
|
||||
const alreadyAnsweredQuestions = store.getters.damage.partQuestionAnswers;
|
||||
|
||||
this.questionsData = this.pageData.partsOrQuestions
|
||||
.filter((x) => x.partQuestions)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.partQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(glass, index, alreadyAnsweredQuestions);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
this.getInitialQuestionData();
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
const partQuestionsFromPageData = store.getters.pageData(fmgPageValues.PART_QUESTIONS);
|
||||
return partQuestionsFromPageData && Object.keys(partQuestionsFromPageData).length > 0;
|
||||
return (
|
||||
// has .partQuestions array and has glassName not null
|
||||
partQuestionsFromPageData?.partsOrQuestions?.some((part) => part?.glassName) &&
|
||||
partQuestionsFromPageData?.partsOrQuestions?.some(
|
||||
(part) => part?.partQuestions?.length > 0
|
||||
)
|
||||
);
|
||||
},
|
||||
getInitialQuestionData() {
|
||||
// get any questions that were already answered
|
||||
const alreadyAnsweredQuestions = store.getters.damage.partQuestionAnswers;
|
||||
|
||||
this.questionsData = this.partsOrQuestionsData
|
||||
.filter((x) => x.partQuestions)
|
||||
.map((glass, index) => {
|
||||
// NOTE: questions for property "questions" can differ between layouts
|
||||
glass.questions = glass.partQuestions;
|
||||
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
|
||||
// reset selectedAnswers for this glass
|
||||
this.selectedAnswers[glass.answerKey] = [];
|
||||
|
||||
const updatedGlass = this.setupInitialData(
|
||||
glass,
|
||||
index,
|
||||
alreadyAnsweredQuestions
|
||||
);
|
||||
|
||||
// Set up watch for each set of glass questions
|
||||
this.$watch(
|
||||
"selectedAnswers." + glass.answerKey,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue).length > 0) {
|
||||
this.handleAnswerUpdates(newValue, glass.answerKey);
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return updatedGlass;
|
||||
});
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const questionAnswersArray = this.questionsData.map((glass) => {
|
||||
return {
|
||||
glassLocation: glass.glassLocation,
|
||||
glassName: glass.glassName,
|
||||
result: glass.answerData.answerResult,
|
||||
answeredQuestions: glass.answerData.answeredQuestions,
|
||||
result: (glass.answerData && glass.answerData.answerResult) || "",
|
||||
answeredQuestions: glass.answerData?.answeredQuestions,
|
||||
isSuppressedPart: glass.isSuppressedPart,
|
||||
};
|
||||
});
|
||||
|
||||
// clear out answerData for future page loads; must occur prior to store save
|
||||
this.questionsData.forEach((glass) => {
|
||||
glass.answerData = {};
|
||||
if (glass.answerData) {
|
||||
glass.answerData = {};
|
||||
}
|
||||
});
|
||||
|
||||
// save to vuex store as order.damage.partQuestionAnswers (array)
|
||||
// used in GET_PARTS call following this one
|
||||
await this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_PART_QUESTION_ANSWERS,
|
||||
questionAnswersArray,
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ import modal from "@/common-components/modal/modal";
|
|||
import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
|
||||
import store from "@/store";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { Form } from "vee-validate";
|
||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
|
|
@ -70,22 +71,48 @@ export default {
|
|||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContent = await fetchCmsContentForPage(to.query.fmgPage);
|
||||
const wipersPromise = baseMixin.methods.dispatchStoreAction(storeActions.GET_WIPERS);
|
||||
const rainDefensePromise = baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.GET_RAIN_DEFENSE
|
||||
);
|
||||
const supportingItemsPromise = baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.GET_SUPPORTING_ITEMS
|
||||
);
|
||||
|
||||
// TODOS - modify as needed, just a rough sketch to place initializations
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "wipers",
|
||||
promise: wipersPromise,
|
||||
},
|
||||
{
|
||||
resultKey: "rainDefense",
|
||||
promise: rainDefensePromise,
|
||||
},
|
||||
{
|
||||
resultKey: "supportingItems",
|
||||
promise: supportingItemsPromise,
|
||||
},
|
||||
];
|
||||
|
||||
// get supporting availableLineItems
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
const glassParts = store.getters.order.lineItems.glassParts ?? [];
|
||||
const availableLineItems = [
|
||||
resultMap.rainDefense,
|
||||
...resultMap.supportingItems,
|
||||
...resultMap.wipers,
|
||||
...glassParts,
|
||||
];
|
||||
|
||||
// get wiper and rain defense availableLineItems
|
||||
|
||||
// Settle promises and get results
|
||||
|
||||
// get price of supporting, rain defense & wipers, and parts
|
||||
|
||||
// Settle pricing promise and get results
|
||||
const pricingResults = await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.PRICE_ORDER_ITEMS,
|
||||
availableLineItems,
|
||||
false
|
||||
);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
vm.setCmsContent(cmsContent);
|
||||
|
||||
vm.availableLineItems = [
|
||||
{
|
||||
partNumber: "001",
|
||||
|
|
@ -135,15 +162,20 @@ export default {
|
|||
},
|
||||
];
|
||||
|
||||
|
||||
vm.supportingItems = resultMap.supportingItems;
|
||||
vm.availableLineItems = pricingResults;
|
||||
vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue();
|
||||
|
||||
vm.dispatchStoreAction(storeActions.SAVE_IS_INSURANCE, vm.isInsuranceSelected);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pricingRequestResult: null,
|
||||
isInsuranceSelected: null,
|
||||
selectedPackage: null,
|
||||
availableLineItems: null,
|
||||
supportingItems: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -162,14 +194,18 @@ export default {
|
|||
}
|
||||
},
|
||||
backButtonAction() {
|
||||
vehicleQuestionsMixin.methods.backButtonAction(this);
|
||||
vehicleQuestionsMixin.methods.navigateBack(this);
|
||||
},
|
||||
forwardButtonAction() {
|
||||
// TODO KO if VAPS package is not selected, return
|
||||
|
||||
// TODO KO is VAPS package is selected, add the items as needed
|
||||
|
||||
this.dispatchStoreAction(storeActions.SAVE_IS_INSURANCE, this.isInsuranceSelected);
|
||||
async forwardButtonAction() {
|
||||
await this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_QUOTE_PAGE_SELECTIONS,
|
||||
{
|
||||
isInsuranceSelected: this.isInsuranceSelected,
|
||||
vapsItemsToAdd: this.selectedPackage,
|
||||
supportingItemsToAdd: this.supportingItems,
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
navigateToHeritageFunnel({loadingModal: this.$refs.loadingModal});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,580 @@
|
|||
export const mockProcessedCmsContent = {
|
||||
"05_01_CSR_Quote_Standard_Repair": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_Recal": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass+NonWindshield": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass+Windshield": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlassNoFrontFit": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_Windshield+SideGlass": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_SideGlass": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_NoWiperFit": {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
badCustomValue: {
|
||||
EconomyServicePackage: {
|
||||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
},
|
||||
StandardServicePackage: {
|
||||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
PremiumServicePackage: {
|
||||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>{if:custom:badCustomValue}DO NOT SHOW{end}New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const inputQuestionWidgetAnswers = {
|
||||
CashServicePackageQuestionWidget: {
|
||||
Answers: [
|
||||
{
|
||||
Name: "TierOne",
|
||||
SubWidgetName: "EconomyServicePackage",
|
||||
},
|
||||
{
|
||||
Name: "TierTwo",
|
||||
SubWidgetName: "StandardServicePackage",
|
||||
},
|
||||
{
|
||||
Name: "TierThree",
|
||||
SubWidgetName: "PremiumServicePackage",
|
||||
},
|
||||
],
|
||||
},
|
||||
InsuranceServicePackageQuestionWidget: {
|
||||
Answers: [
|
||||
{
|
||||
Name: "TierOne",
|
||||
SubWidgetName: "EconomyServicePackage",
|
||||
},
|
||||
{
|
||||
Name: "TierTwo",
|
||||
SubWidgetName: "StandardServicePackage",
|
||||
},
|
||||
{
|
||||
Name: "TierThree",
|
||||
SubWidgetName: "PremiumServicePackage",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const expectedModifiedAnswers = {
|
||||
"05_01_CSR_Quote_Standard_Repair": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li></ul>",
|
||||
buttonAuxillaryCopy: "$500.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li></ul>",
|
||||
buttonAuxillaryCopy: "$585.90",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>Expert windshield repair</li><li>Exclusive resin sealant</li><li>Nationwide lifetime guarantee</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$621.40",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_Recal": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation and {textLink:EstimateRecalModal,recalibration}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$500.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation and {textLink:EstimateRecalModal,recalibration}</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li></ul>",
|
||||
buttonAuxillaryCopy: "$585.90",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation and {textLink:EstimateRecalModal,recalibration}</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$621.40",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li></ul>",
|
||||
buttonAuxillaryCopy: "$374.70",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,front wiper blades}</li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li><li></li></ul>",
|
||||
buttonAuxillaryCopy: "$460.38",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass+NonWindshield": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li></ul>",
|
||||
buttonAuxillaryCopy: "$374.70",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,front wiper blades}</li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li><li></li></ul>",
|
||||
buttonAuxillaryCopy: "$460.38",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlass+Windshield": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,front wiper blades}</li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li></ul>",
|
||||
buttonAuxillaryCopy: "$460.38",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,front wiper blades}</li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$495.88",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_RearGlassNoFrontFit": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li></ul>",
|
||||
buttonAuxillaryCopy: "$374.70",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li>New {textLink:EstimateRearWiperModal,rear wiper blade}</li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$410.20",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_Windshield+SideGlass": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy:
|
||||
"New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.",
|
||||
},
|
||||
tierTwo: {
|
||||
value: "TierTwo",
|
||||
buttonLabel: "Standard service",
|
||||
buttonLabelSubCopy: "MOST POPULAR",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li></ul>",
|
||||
buttonAuxillaryCopy: "$435.90",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$471.40",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_SideGlass": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li>New {textLink:EstimateFrontWiperModal,wiper blades}</li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$471.40",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
"05_01_CSR_Quote_NoWiperFit": {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$385.72",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
badCustomValue: {
|
||||
tierOne: {
|
||||
value: "TierOne",
|
||||
buttonLabel: "Economy service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
buttonAuxillaryCopy: "$350.22",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
tierThree: {
|
||||
value: "TierThree",
|
||||
buttonLabel: "Premium service",
|
||||
buttonLabelSubCopy: "",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation</li><li>Nationwide lifetime warranty</li><li></li><li></li><li>{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment</li></ul>",
|
||||
buttonAuxillaryCopy: "$385.72",
|
||||
buttonFooterCopy: "",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,602 @@
|
|||
import { shallowMount, mount } from "@vue/test-utils";
|
||||
import servicePackageQuestion from "./service-package-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import {
|
||||
expectedModifiedAnswers,
|
||||
mockProcessedCmsContent,
|
||||
inputQuestionWidgetAnswers,
|
||||
} from "./service-package-question-test-helper";
|
||||
|
||||
jest.mock("@/store", () => ({
|
||||
commit: jest.fn(),
|
||||
dispatch: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("service-package-question.vue", () => {
|
||||
beforeEach(async () => {
|
||||
processedCmsContent = inputQuestionWidgetAnswers;
|
||||
mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return processedCmsContent[widgetName][cmsFieldName];
|
||||
}),
|
||||
},
|
||||
};
|
||||
mockProps = {
|
||||
modelValue: "initialValue",
|
||||
isInsuranceSelected: false,
|
||||
insuranceCmsWidgetName: "InsuranceServicePackageQuestionWidget",
|
||||
cashCmsWidgetName: "CashServicePackageQuestionWidget",
|
||||
availableLineItems: [
|
||||
{
|
||||
partNumber: "001",
|
||||
Description: "Windshield with Recal",
|
||||
partType: "Windshield",
|
||||
Quantity: "1",
|
||||
BasePartNumber: "001",
|
||||
Color: "Green",
|
||||
CanSafeliteRecalibrate: true,
|
||||
price: 350.22,
|
||||
},
|
||||
{
|
||||
partNumber: "RAIN DEFENSE",
|
||||
description: null,
|
||||
partType: "RAIN DEFENSE",
|
||||
price: 35.5,
|
||||
},
|
||||
],
|
||||
};
|
||||
const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
});
|
||||
it("should emit relevant VAPS items in an array", () => {
|
||||
// Arrange
|
||||
const wrapper = setupMocks({});
|
||||
// Act
|
||||
wrapper.componentVM.selectedValues = "TierThree";
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([
|
||||
{
|
||||
description: null,
|
||||
partNumber: "RAIN DEFENSE",
|
||||
partType: "RAIN DEFENSE",
|
||||
price: 35.5,
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("should have the correct insurance pricing text when insurance is selected", () => {
|
||||
// Arrange
|
||||
mockProps.isInsuranceSelected = true;
|
||||
const wrapper = setupMocks({});
|
||||
// Act
|
||||
|
||||
// Assert
|
||||
expect(
|
||||
wrapper.vm.servicePackageAnswers[0].buttonAuxillaryCopy.includes("As little as")
|
||||
).toBe(true);
|
||||
});
|
||||
it("should return [] from nullSafeAvailableLineItems and not error out if availableLineItems is null", () => {
|
||||
// Arrange
|
||||
mockProps.availableLineItems = null;
|
||||
const wrapper = setupMocks({});
|
||||
// Act
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.nullSafeAvailableLineItems).toEqual([]);
|
||||
});
|
||||
it("should return a null servicePackageAnswers if the cmsContent is falsy", () => {
|
||||
// Arrange
|
||||
mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
};
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.servicePackageAnswers).toBe(null);
|
||||
});
|
||||
it("should treat an undefined 'getCustomValueFromString' as a false value and not error out", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "badCustomValue";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Windshield" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer should not be created
|
||||
expect(wrapper.vm.servicePackageAnswers.length).toBe(2);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("service-package-question.vue, matching business rules for package display", () => {
|
||||
// mock scenarios in figma:
|
||||
// https://www.figma.com/file/Spt9hBtGj8r8PFFGNIN3G5/New-Funnel?node-id=100%3A11383
|
||||
beforeEach(async () => {
|
||||
processedCmsContent = inputQuestionWidgetAnswers;
|
||||
mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return processedCmsContent[widgetName][cmsFieldName];
|
||||
}),
|
||||
},
|
||||
};
|
||||
mockProps = {
|
||||
modelValue: "initialValue",
|
||||
isInsuranceSelected: false,
|
||||
insuranceCmsWidgetName: "InsuranceServicePackageQuestionWidget",
|
||||
cashCmsWidgetName: "CashServicePackageQuestionWidget",
|
||||
availableLineItems: [
|
||||
{
|
||||
partNumber: "001",
|
||||
Description: "Windshield with Recal",
|
||||
partType: "Windshield",
|
||||
Quantity: "1",
|
||||
BasePartNumber: "001",
|
||||
Color: "Green",
|
||||
CanSafeliteRecalibrate: true,
|
||||
price: 350.22,
|
||||
},
|
||||
{
|
||||
partNumber: "RAIN DEFENSE",
|
||||
description: null,
|
||||
partType: "RAIN DEFENSE",
|
||||
price: 35.5,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_Standard_Repair mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: true,
|
||||
glassToReplace: [],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_Recal mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_Recal";
|
||||
mockProps.availableLineItems.push(recalLineItem);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Windshield" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_RearGlass mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_RearGlass";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Rear" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_RearGlass+NonWindshield mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_RearGlass+NonWindshield";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [
|
||||
{ glassLocation: "Rear" },
|
||||
{ glassLocation: "Driver" },
|
||||
],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
//console.log(wrapper.vm.servicePackageAnswers);
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_RearGlass+Windshield mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_RearGlass+Windshield";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [
|
||||
{ glassLocation: "Rear" },
|
||||
{ glassLocation: "Windshield" },
|
||||
],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_RearGlassNoFrontFit mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_RearGlassNoFrontFit";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Rear" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_Windshield+SideGlass mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_Windshield+SideGlass";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [
|
||||
{ glassLocation: "Driver" },
|
||||
{ glassLocation: "Windshield" },
|
||||
],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierTwo
|
||||
);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[2],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_SideGlass mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_SideGlass";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(rearWiperLineItem);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Driver" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer should not be created
|
||||
expect(wrapper.vm.servicePackageAnswers.length).toBe(2);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_NoWiperFit mock", () => {
|
||||
// Arrange
|
||||
const packageNameKey = "05_01_CSR_Quote_NoWiperFit";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Windshield" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
// economy answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[0],
|
||||
expectedModifiedAnswers[packageNameKey].tierOne
|
||||
);
|
||||
// standard answer should not be created
|
||||
expect(wrapper.vm.servicePackageAnswers.length).toBe(2);
|
||||
// premium answer
|
||||
runPackageAnswerExpectStatements(
|
||||
wrapper.vm.servicePackageAnswers[1],
|
||||
expectedModifiedAnswers[packageNameKey].tierThree
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function runPackageAnswerExpectStatements(servicePackageAnswer, expectedOutput) {
|
||||
expect(servicePackageAnswer.buttonLabel).toBe(expectedOutput.buttonLabel);
|
||||
expect(servicePackageAnswer.buttonLabelSubCopy).toBe(expectedOutput.buttonLabelSubCopy);
|
||||
expect(servicePackageAnswer.buttonBodyCopy).toBe(expectedOutput.buttonBodyCopy);
|
||||
expect(servicePackageAnswer.buttonFooterCopy).toBe(expectedOutput.buttonFooterCopy);
|
||||
}
|
||||
|
||||
function setupMocks({ mountOptionsMockData, props = mockProps }) {
|
||||
var mountOptionsMockDataDefault = {
|
||||
store: {
|
||||
getters: {
|
||||
order: {
|
||||
damage: {
|
||||
isRepair: false,
|
||||
glassToReplace: [{ glassLocation: "Windshield" }],
|
||||
},
|
||||
},
|
||||
hasAnyNonWindshieldGlassParts: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
mountOptionsMockData = Object.assign(mountOptionsMockDataDefault, mountOptionsMockData);
|
||||
const mountOptions = getMountOptions(mountOptionsMockData);
|
||||
|
||||
// Modify/augment default mount options
|
||||
mountOptions.global.mixins = [mockMixin];
|
||||
mountOptions.propsData = props;
|
||||
const wrapper = shallowMount(servicePackageQuestion, mountOptions);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
///////////////
|
||||
// Constants //
|
||||
///////////////
|
||||
|
||||
let processedCmsContent;
|
||||
|
||||
let mockMixin;
|
||||
|
||||
let mockProps;
|
||||
|
||||
let recalLineItem = {
|
||||
partNumber: "RECAL STATIC",
|
||||
Description: "Recalibration",
|
||||
partType: "recalibration",
|
||||
Quantity: "1",
|
||||
price: 150.0,
|
||||
};
|
||||
|
||||
let driverFrontWiperLineItem = {
|
||||
partNumber: "SBB16",
|
||||
description: "SAFELITE BEAM BLADE 16",
|
||||
partType: "FRONT WIPER",
|
||||
price: 32.64,
|
||||
};
|
||||
|
||||
let passengerFrontWiperLineItem = {
|
||||
partNumber: "SBB26",
|
||||
description: "SAFELITE BEAM BLADE 26",
|
||||
partType: "FRONT WIPER",
|
||||
price: 53.04,
|
||||
};
|
||||
|
||||
let rearWiperLineItem = {
|
||||
partNumber: "SBBR12A",
|
||||
description: "SAFELITE REAR BLADE 12A",
|
||||
partType: "REAR WIPER",
|
||||
price: 24.48,
|
||||
};
|
||||
|
|
@ -43,7 +43,9 @@ export default {
|
|||
return this.modelValue;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
const VapsProductsInSelectedPackage =
|
||||
this.getVapsLineItemsForSelectedPackage(newValue);
|
||||
this.$emit("update:modelValue", VapsProductsInSelectedPackage);
|
||||
},
|
||||
},
|
||||
nullSafeAvailableLineItems() {
|
||||
|
|
@ -206,6 +208,38 @@ export default {
|
|||
});
|
||||
return vapsPrice;
|
||||
},
|
||||
getVapsLineItemsForSelectedPackage(packageName) {
|
||||
const vapsLineItemsForSelectedPackage = [];
|
||||
if (packageName === packageNames.TIER_TWO) {
|
||||
if (this.frontWipersApplicableForTierTwo) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||
);
|
||||
}
|
||||
if (this.rearWiperApplicableForTierTwo) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||
);
|
||||
}
|
||||
} else if (packageName === packageNames.TIER_THREE) {
|
||||
if (this.frontWipersApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||
);
|
||||
}
|
||||
if (this.rearWiperApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||
);
|
||||
}
|
||||
if (this.rainDefenseApplicableForTierThree) {
|
||||
vapsLineItemsForSelectedPackage.push(
|
||||
...this.getLineItemsContainingPartType(partTypeStrings.RAIN_DEFENSE)
|
||||
);
|
||||
}
|
||||
}
|
||||
return vapsLineItemsForSelectedPackage;
|
||||
},
|
||||
getCustomValueFromString(str) {
|
||||
switch (str) {
|
||||
case "isRecalibrationOnOrder":
|
||||
|
|
@ -224,10 +258,14 @@ export default {
|
|||
return null;
|
||||
}
|
||||
},
|
||||
lineItemsContainsPartType(partType) {
|
||||
getLineItemsContainingPartType(partType) {
|
||||
const partTypeMatches = this.nullSafeAvailableLineItems.filter(
|
||||
(lineItem) => lineItem.partType.toUpperCase() === partType
|
||||
);
|
||||
return partTypeMatches;
|
||||
},
|
||||
lineItemsContainsPartType(partType) {
|
||||
const partTypeMatches = this.getLineItemsContainingPartType(partType);
|
||||
return !!partTypeMatches.length;
|
||||
},
|
||||
glassToReplaceContainsGlassLocation(glassLocation) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
import { mount } from "@vue/test-utils";
|
||||
import servicePackageRadio from "./service-package-radio";
|
||||
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||
|
||||
describe("service-package-radio.vue", () => {
|
||||
it("Should include buttonLabel in html", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabel"]));
|
||||
});
|
||||
|
||||
it("Should include buttonLabelAuxillaryCopy in html", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabelAuxillaryCopy"]));
|
||||
});
|
||||
|
||||
it("Should include buttonLabelSubCopy in html", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabelSubCopy"]));
|
||||
});
|
||||
it("Should include buttonFooterCopy in html", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const outputHtml = wrapper.html();
|
||||
|
||||
// Assert
|
||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonFooterCopy"]));
|
||||
});
|
||||
it("Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when provided with a <ul><li>...</li>(x5)</ul> buttonBodyCopy", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
it("Should get strings from getArrayOfListItemsFromRawCmsCopy without <ul> or <li> tags when provided with a <ul><li>...</li></ul> buttonBodyCopy", async () => {
|
||||
// Arrange
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: mockProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
const fileredResults = results.filter((result) => {
|
||||
return (
|
||||
result.includes("<ul>") ||
|
||||
result.includes("</ul>") ||
|
||||
result.includes("<li>") ||
|
||||
result.includes("</li>")
|
||||
);
|
||||
});
|
||||
expect(fileredResults.length).toBe(0);
|
||||
});
|
||||
it("Should get 5 strings from getArrayOfListItemsFromRawCmsCopy when buttonBodyCopy has 6 total <li>...</li>, but one is empty ", async () => {
|
||||
// Arrange
|
||||
const moddedProps = mockProps;
|
||||
moddedProps["buttonBodyCopy"] =
|
||||
"<ul><li>buttonBodyCopy test copy</li><li>2</li><li>3</li><li>4</li><li>5</li><li></li></ul>";
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: moddedProps,
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
const results = wrapper.vm.getArrayOfListItemsFromRawCmsCopy(wrapper.vm.buttonBodyCopy);
|
||||
|
||||
// Assert
|
||||
expect(results.length).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
const mockProps = {
|
||||
buttonLabel: "buttonLabel test copy",
|
||||
buttonLabelAuxillaryCopy: "buttonLabelAuxillaryCopy test copy",
|
||||
buttonLabelSubCopy: "buttonLabelSubCopy test copy",
|
||||
buttonBodyCopy:
|
||||
"<ul><li>buttonBodyCopy test copy</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>",
|
||||
buttonFooterCopy: "buttonFooterCopy test copy",
|
||||
};
|
||||
|
||||
function setupMocks({ mountOptionsMockData = {} }) {
|
||||
const wrapper = mount(servicePackageRadio, {
|
||||
...mountOptionsMockData,
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange">
|
||||
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||
<div class="package-label" for="testradio">
|
||||
<div class="package-specs">
|
||||
<p :class="[this.buttonLabelSubCopy ? 'mb-2' : 'm-0']">
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
</ul>
|
||||
<!-- End of body text parsing -->
|
||||
<div
|
||||
class="package-footer"
|
||||
class="package-footer fw-bold caption ms-n6"
|
||||
v-if="this.buttonFooterCopy"
|
||||
v-html="this.buttonFooterCopy"></div>
|
||||
</div>
|
||||
|
|
@ -179,10 +179,7 @@ export default {
|
|||
}
|
||||
|
||||
.package-footer {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #d4281c;
|
||||
margin-left: -32px;
|
||||
color: $red;
|
||||
}
|
||||
|
||||
.package-specs {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ describe("vehicle-parts.vue", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("User had part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||
test("User had part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
|
|
@ -248,7 +248,7 @@ describe("vehicle-parts.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -257,7 +257,7 @@ describe("vehicle-parts.vue", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("User did not have part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||
test("User did not have part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
|
|
@ -294,7 +294,7 @@ describe("vehicle-parts.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -497,7 +497,7 @@ describe("vehicle-parts.vue", () => {
|
|||
|
||||
// TODO KO UNCOMMENT FOR QUOTE PAGES RELEASE
|
||||
// expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
// navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
// navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
// { query: { fmgPage: "vehicle-parts" } }
|
||||
// );
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
ref="funnelFooter"
|
||||
:isForwardActionDisabled="isForwardActionDisabled"
|
||||
@tempButtonClicked="() => handleTempButtonClicked(this)"
|
||||
@back-clicked="backButtonAction"
|
||||
@back-click="navigateBack"
|
||||
@ForwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
<template>
|
||||
<div class="vin-information">
|
||||
<div
|
||||
class="vin-toggle d-inline-flex mt-2"
|
||||
:class="[isActive ? 'active' : '']"
|
||||
@click="toggleClass()">
|
||||
<div class="vin-toggle mt-2" :class="[isActive ? 'active' : '']" @click="toggleClass()">
|
||||
<textLink linkType="text" href="#!" :text="WhereCanIFindMyVINHeadline" />
|
||||
</div>
|
||||
<div class="vin-info">
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ describe("vin-lookup.vue", () => {
|
|||
//Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toBeCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
wrapper.vm.$route,
|
||||
expect.anything(),
|
||||
expect.anything()
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ export default {
|
|||
async navigateForward() {
|
||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ export default {
|
|||
partNumber: singlePart.partNumber,
|
||||
description: singlePart.description,
|
||||
color: singlePart.color,
|
||||
partType: singlePart.partType,
|
||||
canSafeliteRecalibrate: singlePart.canSafeliteRecalibrate,
|
||||
requiresRecalibration: singlePart.requiresRecalibration,
|
||||
requiresCapabilityQuestions: singlePart.requiresCapabilityQuestions,
|
||||
recalibrationType: singlePart.recalibrationType,
|
||||
|
|
@ -378,7 +380,7 @@ export default {
|
|||
this.currentPageComesBeforePage(currentPage, fmgPageValues.PART_QUESTIONS)
|
||||
) {
|
||||
self.$router.navigateWithSaving(
|
||||
self.navigationScenarios.HAS_PART_QUESTIONS,
|
||||
self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
self.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -391,7 +393,7 @@ export default {
|
|||
// if multiple parts on any glass
|
||||
// go to vehicle-parts page and pass the partsData
|
||||
self.$router.navigateWithSaving(
|
||||
self.navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
self.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -404,7 +406,7 @@ export default {
|
|||
// if any childpart questions
|
||||
// go to molding-questions page and pass the partsData
|
||||
self.$router.navigateWithSaving(
|
||||
self.navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
self.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -444,7 +446,7 @@ export default {
|
|||
}
|
||||
|
||||
self.$router.navigateWithSaving(
|
||||
self.navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
self.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -464,19 +466,19 @@ export default {
|
|||
shouldGoToHeritageQuote || (payment.isInsurance && payment.insuranceCoverage.isVerified)
|
||||
? navigateToHeritageFunnel({loadingModal: self.$refs.loadingModal})
|
||||
: self.$router.navigateWithSaving(
|
||||
self.navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
self.$route
|
||||
);
|
||||
}
|
||||
},
|
||||
// Can't use `this` because navigateForward is also called from quote
|
||||
backButtonAction(vm) {
|
||||
navigateBack(vm) {
|
||||
const self = vm ?? this;
|
||||
const partsOrQuestions = (
|
||||
self.$store.getters.pageData(fmgPageValues.PART_QUESTIONS) ??
|
||||
self.$store.getters.pageData(fmgPageValues.VEHICLE_PARTS) ??
|
||||
self.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS) ??
|
||||
self.$store.getters.pageData(fmgPageValues.MOLDING_QUESTIONS) ??
|
||||
self.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)
|
||||
self.$store.getters.pageData(fmgPageValues.VEHICLE_PARTS) ??
|
||||
self.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)
|
||||
)?.partsOrQuestions;
|
||||
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions);
|
||||
const hasGlassLocationWithMultipleParts =
|
||||
|
|
|
|||
|
|
@ -1261,7 +1261,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_PART_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1376,7 +1376,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_PART_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1483,7 +1483,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_PART_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1638,7 +1638,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_PART_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1686,7 +1686,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1798,7 +1798,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -1976,7 +1976,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -2035,7 +2035,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -2077,7 +2077,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
wrapper.vm.$route,
|
||||
{},
|
||||
{},
|
||||
|
|
@ -2124,7 +2124,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
{ query: { fmgPage: "vin-lookup" } }
|
||||
);
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).not.toHaveBeenCalled();
|
||||
|
|
@ -2235,7 +2235,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
|
||||
navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
{ query: { fmgPage: "vin-lookup" } }
|
||||
);
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).not.toHaveBeenCalled();
|
||||
|
|
@ -2243,7 +2243,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("backButtonAction", () => {
|
||||
describe("navigateBack", () => {
|
||||
// TODO KO
|
||||
test.todo(
|
||||
"current page is quote, there are no questions, and we don't have their vin => go to estimate"
|
||||
|
|
@ -2254,7 +2254,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE, hasVin: true });
|
||||
|
||||
// Act
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -2269,7 +2269,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true);
|
||||
|
||||
// Act
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -2285,7 +2285,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true);
|
||||
|
||||
// Act
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -2303,7 +2303,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true);
|
||||
|
||||
// Act
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
@ -2321,7 +2321,7 @@ describe("vehicle-questions-mixin", () => {
|
|||
wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true);
|
||||
|
||||
// Act
|
||||
wrapper.vm.backButtonAction();
|
||||
wrapper.vm.navigateBack();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
/**
|
||||
* We want to name these to describe the scenario rather than what page(s) they're used on.
|
||||
*
|
||||
* Naming convention: [PAST_TENSE_VERB]_[DESCRIPTOR_OF_STATE]
|
||||
* ex: Rather than "HAS_PART_QUESTIONS", we might name the
|
||||
* scenario "CLICKED_FORWARD_WITH_PART_QUESTIONS"
|
||||
*/
|
||||
|
||||
const navigationScenarios = {
|
||||
// General
|
||||
CLICKED_BACK: "CLICKED_BACK",
|
||||
|
|
@ -9,31 +17,29 @@ const navigationScenarios = {
|
|||
SELECTED_MAKE: "SELECTED_MAKE",
|
||||
SELECTED_STYLE: "SELECTED_STYLE",
|
||||
|
||||
// Vin pages
|
||||
// Vin selection
|
||||
CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN",
|
||||
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
|
||||
CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE: "CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE",
|
||||
CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE: "CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE",
|
||||
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
|
||||
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
|
||||
SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS",
|
||||
CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES: "CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES",
|
||||
SELECTED_VIN_WITH_MISMATCHED_GLASS: "SELECTED_VIN_WITH_MISMATCHED_GLASS",
|
||||
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
||||
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
||||
SELECTED_HOME_ADDRESS: "SELECTED_HOME_ADDRESS",
|
||||
HAS_NO_QUESTIONS: "HAS_NO_QUESTIONS",
|
||||
CLICKED_FORWARD_WITH_NO_QUESTIONS: "CLICKED_FORWARD_WITH_NO_QUESTIONS",
|
||||
|
||||
// Question pages
|
||||
HAS_PART_QUESTIONS: "HAS_PART_QUESTIONS",
|
||||
HAS_MULTIPLE_PARTS_TO_CHOOSE: "HAS_MULTIPLE_PARTS_TO_CHOOSE",
|
||||
HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS",
|
||||
HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS",
|
||||
HAS_NO_MORE_QUESTIONS: "HAS_NO_MORE_QUESTIONS",
|
||||
// Part selection
|
||||
CLICKED_FORWARD_WITH_PART_QUESTIONS: "CLICKED_FORWARD_WITH_PART_QUESTIONS",
|
||||
CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE",
|
||||
CLICKED_FORWARD_WITH_MOLDING_QUESTIONS: "CLICKED_FORWARD_WITH_MOLDING_QUESTIONS",
|
||||
CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS: "CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS",
|
||||
CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS: "CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS",
|
||||
CLICKED_BACK_WITH_PART_QUESTIONS: "CLICKED_BACK_WITH_PART_QUESTIONS",
|
||||
CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE",
|
||||
CLICKED_BACK_WITH_MOLDING_QUESTIONS: "CLICKED_BACK_WITH_MOLDING_QUESTIONS",
|
||||
CLICKED_BACK_WITH_CAPABILITY_QUESTIONS: "CLICKED_BACK_WITH_CAPABILITY_QUESTIONS",
|
||||
|
||||
// Quote
|
||||
CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS: "CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS",
|
||||
CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS: "CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||
},
|
||||
{
|
||||
|
|
@ -102,23 +102,23 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -135,23 +135,23 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -164,31 +164,31 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
|
||||
destinationFmgPageValue: fmgPageValues.ADDRESS_VEHICLES,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS,
|
||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -205,23 +205,23 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -246,7 +246,7 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.ADDRESS_LOOKUP,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -263,19 +263,19 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -300,15 +300,15 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.ESTIMATE,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -333,11 +333,11 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
@ -366,7 +366,7 @@ const routingTable = function (store) {
|
|||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ const getDefaultState = () => {
|
|||
},
|
||||
lineItems: {
|
||||
glassParts: null,
|
||||
supportingItems: null,
|
||||
vaps: null,
|
||||
serverData: null,
|
||||
},
|
||||
payment: {
|
||||
isInsurance: null,
|
||||
|
|
@ -145,8 +148,11 @@ export const mutations = {
|
|||
updateGlassParts(state, partsData) {
|
||||
state.order.lineItems.glassParts = partsData;
|
||||
},
|
||||
updateOtherParts(state, partsData) {
|
||||
state.order.lineItems.otherParts = partsData;
|
||||
updateVaps(state, partsData) {
|
||||
state.order.lineItems.vaps = partsData;
|
||||
},
|
||||
updateSupportingItems(state, partsData) {
|
||||
state.order.lineItems.supportingItems = partsData;
|
||||
},
|
||||
updatePageData(state, pageData) {
|
||||
state.applicationUser.pageData[pageData.page] = pageData.data;
|
||||
|
|
@ -298,6 +304,12 @@ export const mutations = {
|
|||
state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null;
|
||||
state.applicationUser.pageData[fmgPageValues.CAPABILITY_QUESTIONS] = null;
|
||||
},
|
||||
resetSupportingItemsState(state) {
|
||||
state.order.lineItems.supportingItems = null;
|
||||
},
|
||||
resetVapsState(state) {
|
||||
state.order.lineItems.vaps = null;
|
||||
},
|
||||
resetState(state) {
|
||||
Object.assign(state, getDefaultState());
|
||||
},
|
||||
|
|
@ -305,13 +317,13 @@ export const mutations = {
|
|||
state.applicationUser.saveSessionPromise = null;
|
||||
},
|
||||
// Misc Mutations
|
||||
updateStateWithOrderInformation(state, orderInformation) {
|
||||
state.order.referralNumber = orderInformation.referralNumber;
|
||||
state.order.referralDate = orderInformation.referralDate;
|
||||
state.order.referralCorrelationId = orderInformation.referralCorrelationId;
|
||||
state.order.eon = orderInformation.eon;
|
||||
updateStateWithOrderInformation(state, sessionInformation) {
|
||||
state.order.referralNumber = sessionInformation.order.referralNumber;
|
||||
state.order.referralDate = sessionInformation.order.referralDate;
|
||||
state.order.referralCorrelationId = sessionInformation.order.referralCorrelationId;
|
||||
state.order.eon = sessionInformation.order.eon;
|
||||
|
||||
if (state.order.vehicle.vin !== orderInformation.vehicle?.vin) {
|
||||
if (state.order.vehicle.vin !== sessionInformation.order.vehicle?.vin) {
|
||||
state.applicationUser.pageData[fmgPageValues.PART_QUESTIONS] = null;
|
||||
state.applicationUser.pageData[fmgPageValues.VEHICLE_PARTS] = null;
|
||||
state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null;
|
||||
|
|
@ -319,46 +331,56 @@ export const mutations = {
|
|||
}
|
||||
|
||||
state.order.vehicle = Object.assign(state.order.vehicle, {
|
||||
year: orderInformation.vehicle?.year,
|
||||
make: orderInformation.vehicle?.make,
|
||||
model: orderInformation.vehicle?.model,
|
||||
style: orderInformation.vehicle?.style,
|
||||
vin: orderInformation.vehicle?.vin,
|
||||
carId: orderInformation.vehicle?.carId,
|
||||
category: orderInformation.vehicle?.category,
|
||||
imageUrl: orderInformation.vehicle?.imageUrl,
|
||||
imageVifNumber: orderInformation.vehicle?.imageVifNumber,
|
||||
imageColor: orderInformation.vehicle?.imageVifColor,
|
||||
year: sessionInformation.order.vehicle?.year,
|
||||
make: sessionInformation.order.vehicle?.make,
|
||||
model: sessionInformation.order.vehicle?.model,
|
||||
style: sessionInformation.order.vehicle?.style,
|
||||
vin: sessionInformation.order.vehicle?.vin,
|
||||
carId: sessionInformation.order.vehicle?.carId,
|
||||
category: sessionInformation.order.vehicle?.category,
|
||||
imageUrl: sessionInformation.order.vehicle?.imageUrl,
|
||||
imageVifNumber: sessionInformation.order.vehicle?.imageVifNumber,
|
||||
imageColor: sessionInformation.order.vehicle?.imageVifColor,
|
||||
registration: {
|
||||
firstName: orderInformation.vehicle.registration.firstName,
|
||||
lastName: orderInformation.vehicle.registration.lastName,
|
||||
address: orderInformation.vehicle.registration.streetAddress,
|
||||
city: orderInformation.vehicle.registration.city,
|
||||
state: orderInformation.vehicle.registration.state,
|
||||
zipCode: orderInformation.vehicle.registration.zipCode,
|
||||
licensePlate: orderInformation.vehicle.registration.licensePlateNumber,
|
||||
firstName: sessionInformation.order.vehicle.registration.firstName,
|
||||
lastName: sessionInformation.order.vehicle.registration.lastName,
|
||||
address: sessionInformation.order.vehicle.registration.streetAddress,
|
||||
city: sessionInformation.order.vehicle.registration.city,
|
||||
state: sessionInformation.order.vehicle.registration.state,
|
||||
zipCode: sessionInformation.order.vehicle.registration.zipCode,
|
||||
licensePlate: sessionInformation.order.vehicle.registration.licensePlateNumber,
|
||||
},
|
||||
});
|
||||
|
||||
state.order.damage.glassToReplace = orderInformation.damage.glassToReplace;
|
||||
state.order.damage.isRepair = orderInformation.damage.isRepair;
|
||||
state.order.damage.numberOfChips = orderInformation.damage.numberOfChips;
|
||||
state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace;
|
||||
state.order.damage.isRepair = sessionInformation.order.damage.isRepair;
|
||||
state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips;
|
||||
|
||||
state.order.lineItems.glassParts = orderInformation.parts;
|
||||
state.order.accountNumber = orderInformation.accountNumber;
|
||||
(state.order.serviceLocation.address = orderInformation.serviceLocation.streetAddress),
|
||||
(state.order.serviceLocation.city = orderInformation.serviceLocation.city),
|
||||
(state.order.serviceLocation.state = orderInformation.serviceLocation.state),
|
||||
(state.order.serviceLocation.zipCode = orderInformation.serviceLocation.zipCode);
|
||||
state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts;
|
||||
state.order.lineItems.supportingItems = sessionInformation.order.lineItems.supportingItems;
|
||||
state.order.lineItems.vaps = sessionInformation.order.lineItems.vaps;
|
||||
state.order.lineItems.serverData = sessionInformation.order.lineItems.serverData;
|
||||
state.order.accountNumber = sessionInformation.order.accountNumber;
|
||||
state.order.providerNumber = sessionInformation.order.providerNumber;
|
||||
(state.order.serviceLocation.address =
|
||||
sessionInformation.order.serviceLocation.streetAddress),
|
||||
(state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city),
|
||||
(state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state),
|
||||
(state.order.serviceLocation.zipCode =
|
||||
sessionInformation.order.serviceLocation.zipCode);
|
||||
|
||||
state.order.payment.isInsurance = orderInformation.isInsuranceOrder;
|
||||
|
||||
state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance;
|
||||
state.order.payment.insuranceCoverage.isVerified =
|
||||
orderInformation?.insuranceInfo.coverageVerified;
|
||||
state.order.payment.insuranceCoverage.coverageStatus = orderInformation?.insuranceInfo.coverageStatus
|
||||
sessionInformation?.order.payment.insuranceCoverage.isVerified;
|
||||
// TODO KO CSR-747 double check this
|
||||
state.order.payment.insuranceCoverage.coverageStatus = sessionInformation?.insuranceInfo.coverageStatus
|
||||
|
||||
state.order.customer.emailAddress = orderInformation.customer.emailAddress;
|
||||
state.applicationUser.experiments = orderInformation.experiments;
|
||||
state.order.customer.emailAddress = sessionInformation.order.customer.emailAddress;
|
||||
state.order.existingPromoCode = sessionInformation.order.existingPromoCode;
|
||||
state.applicationUser.experiments = sessionInformation.applicationUser.experiments;
|
||||
state.applicationUser.crmCustomerId = sessionInformation.applicationUser.crmCustomerId;
|
||||
state.applicationUser.pageData = sessionInformation.applicationUser.pageData;
|
||||
state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage;
|
||||
},
|
||||
updateExperiments(state, experiments) {
|
||||
state.applicationUser.experiments = experiments;
|
||||
|
|
@ -433,7 +455,11 @@ export const getters = {
|
|||
"partNumber"
|
||||
),
|
||||
...getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.otherParts,
|
||||
state.order.lineItems.supportingItems,
|
||||
"partNumber"
|
||||
),
|
||||
...getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.vaps,
|
||||
"partNumber"
|
||||
),
|
||||
],
|
||||
|
|
@ -443,10 +469,6 @@ export const getters = {
|
|||
state.order.lineItems.glassParts,
|
||||
"recalibrationType"
|
||||
),
|
||||
...getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.otherParts,
|
||||
"recalibrationType"
|
||||
),
|
||||
],
|
||||
};
|
||||
},
|
||||
|
|
@ -569,21 +591,22 @@ export const actions = {
|
|||
},
|
||||
|
||||
// Dependency Actions
|
||||
resetVehicleAndDependencies(context) {
|
||||
context.commit(storeMutations.RESET_VEHICLE_STATE);
|
||||
context.commit(storeMutations.RESET_DAMAGE_STATE);
|
||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||
},
|
||||
resetDamageAndDependencies(context) {
|
||||
context.commit(storeMutations.RESET_DAMAGE_STATE);
|
||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.RESET_VAPS_STATE);
|
||||
},
|
||||
resetRegistrationAndDependencies(context) {
|
||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.RESET_VAPS_STATE);
|
||||
},
|
||||
resetPartsAndDependencies(context) {
|
||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.RESET_VAPS_STATE);
|
||||
},
|
||||
resetState(context) {
|
||||
context.commit(storeMutations.RESET_STATE);
|
||||
|
|
@ -868,6 +891,49 @@ export const actions = {
|
|||
return response;
|
||||
},
|
||||
|
||||
getWipers(context) {
|
||||
const carId = context.getters.vehicle.carId;
|
||||
const serviceZipCode = context.getters.order.serviceLocation.zipCode;
|
||||
return globalMethods
|
||||
.callHttpClient({
|
||||
method: endpoints.GetWipers.method,
|
||||
endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`,
|
||||
})
|
||||
.catch((error) => {
|
||||
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
|
||||
return [];
|
||||
});
|
||||
},
|
||||
|
||||
getRainDefense(context) {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetRainDefense.method,
|
||||
endpoint: endpoints.GetRainDefense.url,
|
||||
});
|
||||
},
|
||||
|
||||
getSupportingItems(context) {
|
||||
const glassPartsArray = context.getters.lineItems.glassParts;
|
||||
if (!glassPartsArray) {
|
||||
return [];
|
||||
}
|
||||
const carId = context.getters.vehicle.carId;
|
||||
const isRepair = context.getters.damage.isRepair;
|
||||
const numberOfChips = context.getters.damage.numberOfChips;
|
||||
const parentAccountNumber = context.getters.order.accountNumber.toString();
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetSupportingItems.method,
|
||||
endpoint: endpoints.GetSupportingItems.url,
|
||||
payload: {
|
||||
carId: carId,
|
||||
serviceType: isRepair ? "Repair" : "Replace",
|
||||
parentAccountNumber: parentAccountNumber,
|
||||
parts: glassPartsArray,
|
||||
numberOfRepairChips: isRepair ? numberOfChips : 0,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getCapabilityQuestions(context, { carId, partNumber }) {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetCapabilityQuestions.method,
|
||||
|
|
@ -948,6 +1014,9 @@ export const actions = {
|
|||
},
|
||||
lineItems: {
|
||||
glassParts: lineItems.glassParts,
|
||||
supportingItems: lineItems.supportingItems,
|
||||
vaps: lineItems.vaps,
|
||||
serverData: lineItems.serverData,
|
||||
},
|
||||
payment: {
|
||||
InsuranceCoverage: {
|
||||
|
|
@ -972,21 +1041,16 @@ export const actions = {
|
|||
},
|
||||
});
|
||||
},
|
||||
loadSession(context, { referralNumber, referralDate, referralCorrelationId, accountNumber }) {
|
||||
loadSession(context, { savedSessionId }) {
|
||||
return globalMethods
|
||||
.callHttpClient({
|
||||
method: endpoints.LoadSession.method,
|
||||
endpoint: endpoints.LoadSession.url,
|
||||
payload: {
|
||||
referralNumber: referralNumber?.toString(),
|
||||
referralDate: referralDate,
|
||||
referralCorrelationId: referralCorrelationId,
|
||||
accountNumber: accountNumber?.toString(),
|
||||
},
|
||||
endpoint:
|
||||
endpoints.LoadSession.url + "?savedSessionId=" + savedSessionId?.toString(),
|
||||
})
|
||||
.then((response) => {
|
||||
// Flatten location and name properties
|
||||
response.data.damage?.glassToReplace?.map((glass) => {
|
||||
response.data.order.damage?.glassToReplace?.map((glass) => {
|
||||
glass.glassLocation = glass.location;
|
||||
glass.glassName = glass.name;
|
||||
delete glass.location;
|
||||
|
|
@ -1204,6 +1268,7 @@ export const actions = {
|
|||
|
||||
if (havePartQuestionAnswersChanged) {
|
||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||
|
|
@ -1249,6 +1314,7 @@ export const actions = {
|
|||
|
||||
if (haveSelectedVehiclePartsChanged) {
|
||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||
|
|
@ -1278,6 +1344,7 @@ export const actions = {
|
|||
|
||||
if (haveMoldingQuestionAnswersChanged) {
|
||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||
|
|
@ -1305,6 +1372,7 @@ export const actions = {
|
|||
|
||||
if (haveCapabilityQuestionAnswersChanged) {
|
||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
}
|
||||
|
||||
//Save new values
|
||||
|
|
@ -1313,6 +1381,25 @@ export const actions = {
|
|||
capabilityQuestionAnswers
|
||||
);
|
||||
},
|
||||
// Quote Page
|
||||
saveQuotePageSelections(
|
||||
context,
|
||||
{ isInsuranceSelected, vapsItemsToAdd, supportingItemsToAdd }
|
||||
) {
|
||||
context.commit(storeMutations.RESET_SUPPORTING_ITEMS_STATE);
|
||||
context.commit(storeMutations.RESET_VAPS_STATE);
|
||||
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsuranceSelected);
|
||||
context.commit(storeMutations.UPDATE_VAPS, vapsItemsToAdd);
|
||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItemsToAdd);
|
||||
},
|
||||
// Price order actions
|
||||
// PLACEHOLDER, WILL CHANGE WHEN PRICING END POINT IS IMPLEMENTED
|
||||
priceOrderItems(context, availableLineItems) {
|
||||
availableLineItems.forEach((lineItem) => {
|
||||
lineItem["price"] = parseFloat((Math.random() * 100).toFixed(2));
|
||||
});
|
||||
return availableLineItems;
|
||||
},
|
||||
// Misc order actions
|
||||
saveServiceLocation(context, serviceLocationInfo) {
|
||||
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
|
||||
|
|
@ -1341,6 +1428,30 @@ export const actions = {
|
|||
saveIsInsurance(context, isInsurance) {
|
||||
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance);
|
||||
},
|
||||
isVinOptionalVehicle(context) {
|
||||
switch (context.state.order.vehicle.make.toLowerCase()) {
|
||||
case "mercedes benz":
|
||||
case "volkswagen":
|
||||
case "audi":
|
||||
case "porsche":
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
|
||||
if (
|
||||
context.state.order.vehicle.make.toLowerCase() === "ford" &&
|
||||
context.state.order.vehicle.year >= 2018
|
||||
)
|
||||
return true;
|
||||
|
||||
if (
|
||||
context.state.order.vehicle.make.toLowerCase() === "bmw" &&
|
||||
context.state.order.vehicle.year <= 2017
|
||||
)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
export default createStore({
|
||||
|
|
@ -1399,7 +1510,13 @@ function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
|||
}
|
||||
|
||||
function convertGlassPieceNamingForApi(glassArray) {
|
||||
if (!glassArray) return [];
|
||||
if (!glassArray || glassArray.length === 0) return [];
|
||||
|
||||
// check if array already converted. (likely when a session has been saved previously and then reloaded)
|
||||
if (glassArray[0].location !== undefined) {
|
||||
return glassArray;
|
||||
}
|
||||
|
||||
const converted = [];
|
||||
glassArray.forEach((glass) => {
|
||||
converted.push({
|
||||
|
|
|
|||
|
|
@ -203,34 +203,65 @@ describe("Mutations", () => {
|
|||
expect(storeState.applicationUser.pageData["vehicle-year"]).toEqual({});
|
||||
});
|
||||
|
||||
it("updateStateWithOrderInformation, should set order information in state", () => {
|
||||
it("updateStateWithSessonInformation, should set session information in state", () => {
|
||||
// Arrange
|
||||
const storeState = state;
|
||||
|
||||
// Act
|
||||
mutations.updateStateWithOrderInformation(storeState, {
|
||||
referralNumber: 123,
|
||||
referralDate: new Date().toUTCString(),
|
||||
referralCorrelationId: "xxx-xxx-xxx",
|
||||
vehicle: {
|
||||
year: "2019",
|
||||
make: "Acura",
|
||||
model: "ILX",
|
||||
style: "4 DOOR SEDAN",
|
||||
carId: "C0000001",
|
||||
category: "CAR",
|
||||
registration: {},
|
||||
order: {
|
||||
referralNumber: 123,
|
||||
referralDate: new Date().toUTCString(),
|
||||
referralCorrelationId: "xxx-xxx-xxx",
|
||||
vehicle: {
|
||||
year: "2019",
|
||||
make: "Acura",
|
||||
model: "ILX",
|
||||
style: "4 DOOR SEDAN",
|
||||
carId: "C0000001",
|
||||
category: "CAR",
|
||||
registration: {},
|
||||
},
|
||||
damage: {
|
||||
glassToReplace: ["Windshield"],
|
||||
isRepair: false,
|
||||
numberOfChips: 0,
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: null,
|
||||
},
|
||||
payment: {
|
||||
insuranceCoverage: {
|
||||
isVerified: false,
|
||||
},
|
||||
isInsurance: false,
|
||||
},
|
||||
parts: [],
|
||||
accountNumber: "123456789",
|
||||
insuranceInfo: {},
|
||||
serviceLocation: {},
|
||||
customer: {},
|
||||
},
|
||||
damage: {
|
||||
glassToReplace: ["Windshield"],
|
||||
isRepair: false,
|
||||
numberOfChips: 0,
|
||||
applicationUser: {
|
||||
experiments: [
|
||||
{
|
||||
universeName: "Concept Funnel Test With Rules",
|
||||
universeId: 463,
|
||||
testName: "Concept Dev Test",
|
||||
testId: 392,
|
||||
variationName: "Concept Test Variation",
|
||||
variationId: 1133,
|
||||
isActive: false,
|
||||
isExposed: true,
|
||||
userPartitionNumber: 84,
|
||||
assignmentId: 12211739,
|
||||
settings: {
|
||||
someKey: "false",
|
||||
sampleSetting: "Hi, my name is Vidya",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
parts: [],
|
||||
accountNumber: "123456789",
|
||||
insuranceInfo: {},
|
||||
serviceLocation: {},
|
||||
customer: {},
|
||||
});
|
||||
|
||||
// Assert
|
||||
|
|
@ -445,21 +476,6 @@ describe("Actions", () => {
|
|||
expect(response.data).toEqual("43201");
|
||||
});
|
||||
|
||||
it("resetVehicleAndDependencies action", async () => {
|
||||
// Arrange
|
||||
const context = state;
|
||||
const commit = jest.fn();
|
||||
|
||||
context.commit = commit;
|
||||
|
||||
// Act
|
||||
await actions.resetVehicleAndDependencies(context);
|
||||
|
||||
expect(commit).toBeCalledWith(storeMutations.RESET_VEHICLE_STATE);
|
||||
expect(commit).toBeCalledWith(storeMutations.RESET_DAMAGE_STATE);
|
||||
expect(commit).toBeCalledWith(storeMutations.RESET_REGISTRATION_STATE);
|
||||
});
|
||||
|
||||
it("resetDamageAndDependencies action", async () => {
|
||||
// Arrange
|
||||
const context = state;
|
||||
|
|
@ -631,7 +647,7 @@ describe("Actions", () => {
|
|||
const context = state;
|
||||
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ data: { referralNumber: 123 } });
|
||||
return Promise.resolve({ data: { referralNumber: 123, order: {} } });
|
||||
});
|
||||
|
||||
const commit = jest.fn();
|
||||
|
|
@ -640,15 +656,14 @@ describe("Actions", () => {
|
|||
|
||||
// Act
|
||||
const response = await actions.loadSession(context, {
|
||||
referralNumber: "123",
|
||||
referralDate: new Date().toUTCString(),
|
||||
referralCorrelationId: "xxx-xxx-xxx",
|
||||
savedSessionId: "",
|
||||
});
|
||||
|
||||
// Assert
|
||||
expect(response.data).toEqual({ referralNumber: 123 });
|
||||
expect(response.data).toEqual({ referralNumber: 123, order: {} });
|
||||
expect(commit).toBeCalledWith(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, {
|
||||
referralNumber: 123,
|
||||
order: {},
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -657,7 +672,7 @@ describe("Actions", () => {
|
|||
const context = state;
|
||||
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ data: { eon: "123" } });
|
||||
return Promise.resolve({ data: { eon: "123", order: {} } });
|
||||
});
|
||||
|
||||
context.commit = jest.fn();
|
||||
|
|
@ -667,9 +682,7 @@ describe("Actions", () => {
|
|||
|
||||
// Act
|
||||
const response = await actions.loadSession(context, {
|
||||
referralNumber: "123",
|
||||
referralDate: new Date().toUTCString(),
|
||||
referralCorrelationId: "xxx-xxx-xxx",
|
||||
savedSessionId: "",
|
||||
});
|
||||
|
||||
// Assert
|
||||
|
|
@ -682,7 +695,7 @@ describe("Actions", () => {
|
|||
const context = state;
|
||||
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ data: { eon: "123" } });
|
||||
return Promise.resolve({ data: { eon: "123", order: {} } });
|
||||
});
|
||||
|
||||
context.commit = jest.fn();
|
||||
|
|
@ -694,9 +707,7 @@ describe("Actions", () => {
|
|||
|
||||
// Act
|
||||
const response = await actions.loadSession(context, {
|
||||
referralNumber: "123",
|
||||
referralDate: new Date().toUTCString(),
|
||||
referralCorrelationId: "xxx-xxx-xxx",
|
||||
savedSessionId: "",
|
||||
});
|
||||
|
||||
// Assert
|
||||
|
|
@ -2383,7 +2394,8 @@ describe("Getters", () => {
|
|||
funnelParentAccountNumber: "999999",
|
||||
funnelIsCoverageVerified: true,
|
||||
funnelGlassParts: null,
|
||||
funnelOtherParts: null,
|
||||
funnelSupportingItems: null,
|
||||
funnelVaps: null,
|
||||
funnelGlassToReplace: null,
|
||||
};
|
||||
|
||||
|
|
@ -2406,7 +2418,8 @@ describe("Getters", () => {
|
|||
mockStateValues.funnelIsCoverageVerified
|
||||
);
|
||||
mutations.updateGlassParts(storeState, mockStateValues.funnelGlassParts);
|
||||
mutations.updateOtherParts(storeState, mockStateValues.funnelOtherParts);
|
||||
mutations.updateSupportingItems(storeState, mockStateValues.funnelSupportingItems);
|
||||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.funnelGlassToReplace);
|
||||
|
||||
//Assert
|
||||
|
|
@ -2474,7 +2487,8 @@ describe("Getters", () => {
|
|||
mockStateValues.funnelIsCoverageVerified
|
||||
);
|
||||
mutations.updateGlassParts(storeState, mockStateValues.funnelGlassParts);
|
||||
mutations.updateOtherParts(storeState, mockStateValues.funnelOtherParts);
|
||||
mutations.updateSupportingItems(storeState, mockStateValues.funnelSupportingItems);
|
||||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.funnelGlassToReplace);
|
||||
|
||||
//Assert
|
||||
|
|
@ -2552,7 +2566,8 @@ describe("Getters", () => {
|
|||
mutations.updateParentAcctNumber(storeState, mockStateValues.parentAccountNumber);
|
||||
mutations.updateInsuranceVerifiedStatus(storeState, mockStateValues.isCoverageVerified);
|
||||
mutations.updateGlassParts(storeState, mockStateValues.glassParts);
|
||||
mutations.updateOtherParts(storeState, mockStateValues.otherParts);
|
||||
mutations.updateSupportingItems(storeState, mockStateValues.funnelSupportingItems);
|
||||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace);
|
||||
|
||||
//Assert
|
||||
|
|
@ -2656,7 +2671,8 @@ describe("Getters", () => {
|
|||
mutations.updateParentAcctNumber(storeState, mockStateValues.parentAccountNumber);
|
||||
mutations.updateInsuranceVerifiedStatus(storeState, mockStateValues.isCoverageVerified);
|
||||
mutations.updateGlassParts(storeState, mockStateValues.glassParts);
|
||||
mutations.updateOtherParts(storeState, mockStateValues.otherParts);
|
||||
mutations.updateSupportingItems(storeState, mockStateValues.funnelSupportingItems);
|
||||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace);
|
||||
|
||||
//Assert
|
||||
|
|
@ -2685,3 +2701,33 @@ describe("Getters", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("isVinOptionalVehicle", () => {
|
||||
const testVehicles = [
|
||||
["2017", "acura", false],
|
||||
["2017", "ford", false],
|
||||
["2018", "ford", true],
|
||||
["2018", "bmw", false],
|
||||
["2017", "bmw", true],
|
||||
["2016", "bmw", true],
|
||||
["2016", "mercedes benz", true],
|
||||
["2016", "volkswagen", true],
|
||||
["2016", "audi", true],
|
||||
["2016", "porsche", true],
|
||||
];
|
||||
test.each(testVehicles)(
|
||||
"%s %s should skip vin lookup is %s",
|
||||
async (year, make, expectedVinSkip) => {
|
||||
const context = state;
|
||||
|
||||
context.state = {
|
||||
order: {
|
||||
vehicle: { year: year, make: make },
|
||||
},
|
||||
};
|
||||
|
||||
var vinOptionalResult = actions.isVinOptionalVehicle(context);
|
||||
expect(vinOptionalResult).toEqual(expectedVinSkip);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
html {
|
||||
.has-error {
|
||||
// START HOVER
|
||||
&.list-button-horizontal,
|
||||
&.list-button,
|
||||
&.list-button.list-group,
|
||||
&.list-card {
|
||||
border: 1px solid $red;
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
|
||||
.button-content {
|
||||
border: none;
|
||||
|
|
@ -16,6 +14,30 @@ html {
|
|||
@include box-shadow-hover($red-200);
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
input[type="radio"]:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
|
||||
.list-button-content,
|
||||
.list-button-horizontal-content {
|
||||
border: 1px solid $red;
|
||||
}
|
||||
|
||||
input[type="radio"]:focus + .list-button-horizontal-content {
|
||||
z-index: 5;
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
|
||||
input[type="radio"]:hover + .list-button-content,
|
||||
input[type="radio"]:hover + .list-button-horizontal-content {
|
||||
z-index: 5;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-card {
|
||||
border: 1px solid $red;
|
||||
}
|
||||
|
||||
&.ui-radio {
|
||||
|
|
@ -26,7 +48,11 @@ html {
|
|||
}
|
||||
}
|
||||
}
|
||||
// END HOVER
|
||||
.form-check-input {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-button,
|
||||
&.list-card {
|
||||
|
|
@ -159,13 +185,13 @@ html {
|
|||
pointer-events: all;
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
&.btn.btn-primary:hover {
|
||||
&.btn.btn-primary:hover,
|
||||
&.btn.btn-primary:focus {
|
||||
background: $gray-200;
|
||||
box-shadow: none;
|
||||
}
|
||||
&.btn.btn-primary:focus,
|
||||
&.btn.btn-primary:focus-visible {
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,9 @@ $spacers: (
|
|||
/* 48px */
|
||||
);
|
||||
|
||||
//Enable negative spacing (does NOT work on padding)
|
||||
$enable-negative-margins: true;
|
||||
|
||||
//Grid breakpoints
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<button
|
||||
:aria-disabled="isDisabled"
|
||||
class="btn d-flex align-items-center py-3 px-4 delay"
|
||||
class="btn d-flex align-items-center justify-content-center py-3 px-4 delay"
|
||||
:class="[
|
||||
isPrimary ? 'btn-primary' : 'btn-secondary',
|
||||
isFloat ? 'float-end' : '',
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<span class="m-0">{{ this.buttonText }}</span>
|
||||
<loader
|
||||
class="ms-2"
|
||||
v-if="isLoaderDisplayed"
|
||||
v-if="isLoaderDisplayed && !suppressLoader"
|
||||
v-bind:class="[this.loaderColor, this.loaderPosition]" />
|
||||
</button>
|
||||
</template>
|
||||
|
|
@ -28,6 +28,7 @@ export default {
|
|||
loaderColor: String,
|
||||
loaderPosition: String,
|
||||
isFloat: Boolean,
|
||||
suppressLoader: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -50,6 +51,12 @@ export default {
|
|||
this.$emit("click-event");
|
||||
}
|
||||
},
|
||||
resetButtonStyle() {
|
||||
this.isLoaderDisplayed = false;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.isLoaderDisplayed = false;
|
||||
},
|
||||
components: {
|
||||
loader,
|
||||
|
|
|
|||
|
|
@ -60,56 +60,54 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-group {
|
||||
.loader {
|
||||
position: absolute;
|
||||
}
|
||||
&.list-button {
|
||||
outline: none;
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
position: static; //override bootstrap
|
||||
.loader {
|
||||
position: absolute;
|
||||
}
|
||||
.list-button {
|
||||
outline: none;
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
position: static; //override bootstrap
|
||||
|
||||
&:focus-visible + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
background: $blue-100;
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
}
|
||||
&:checked:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content p,
|
||||
&:checked + .list-button-content span {
|
||||
font-weight: 500;
|
||||
}
|
||||
&:checked + .list-button-content span:nth-child(2) {
|
||||
font-weight: 400;
|
||||
color: $gray-600;
|
||||
}
|
||||
&:focus-visible + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
background: $blue-100;
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
}
|
||||
&:checked:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content p,
|
||||
&:checked + .list-button-content span {
|
||||
font-weight: 500;
|
||||
}
|
||||
&:checked + .list-button-content span:nth-child(2) {
|
||||
font-weight: 400;
|
||||
color: $gray-600;
|
||||
}
|
||||
}
|
||||
.list-button-content {
|
||||
color: $gray-600;
|
||||
position: relative;
|
||||
background: $white;
|
||||
transition: all 150ms linear;
|
||||
border-radius: $border-radius-lg;
|
||||
border: 1px solid $gray-500;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
}
|
||||
.list-button-content {
|
||||
color: $gray-600;
|
||||
position: relative;
|
||||
background: $white;
|
||||
transition: all 150ms linear;
|
||||
border-radius: $border-radius-lg;
|
||||
border: 1px solid $gray-500;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
|
||||
span {
|
||||
&.small {
|
||||
font-size: 0.75rem;
|
||||
color: $gray-550;
|
||||
}
|
||||
span {
|
||||
&.small {
|
||||
font-size: 0.75rem;
|
||||
color: $gray-550;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
<template>
|
||||
<a v-if="linkType === 'navigation'" @click="handleClick" class="navigation-link" :href="href">{{
|
||||
text
|
||||
}}</a>
|
||||
<a v-if="linkType === 'navigation'" @click="handleClick" class="navigation-link" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a
|
||||
v-else-if="linkType === 'footer'"
|
||||
@click="handleClick"
|
||||
class="footer-link"
|
||||
:href="href"
|
||||
target="_blank"
|
||||
>{{ text }}</a
|
||||
>
|
||||
<a v-else-if="linkType === 'textSmall'" @click="handleClick" class="small" :href="href">{{
|
||||
text
|
||||
}}</a>
|
||||
<a v-else-if="linkType === 'text'" @click="handleClick" :href="href">{{ text }}</a>
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a v-else-if="linkType === 'textSmall'" @click="handleClick" class="small" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a v-else-if="linkType === 'text'" @click="handleClick" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -48,6 +50,7 @@ a {
|
|||
line-height: 26px;
|
||||
padding: 0 0 4px 0;
|
||||
font-weight: 500;
|
||||
max-width: fit-content;
|
||||
&:hover {
|
||||
color: $blue-700;
|
||||
}
|
||||
|
|
@ -61,6 +64,7 @@ a {
|
|||
color: $black;
|
||||
line-height: 26px;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
&.footer-link {
|
||||
color: $gray-600;
|
||||
|
|
|
|||
Loading…
Reference in a new issue