CSR-762 Fix merge conflicts

This commit is contained in:
Katie 2022-09-19 16:20:26 -04:00
commit 9b3d67fd6e
28 changed files with 1250 additions and 255 deletions

View file

@ -86,7 +86,6 @@ stages:
indexDeployVariables: indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
cfDistributionId: $(cfDistributionId)
# QA Build/Deploy # QA Build/Deploy

View file

@ -28,8 +28,7 @@ module.exports = {
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: { coverageThreshold: {
global: { global: {
// TODO after release/2022.09.15, raise this back up!! statements: 85,
statements: 80,
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90 // Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
}, },
}, },

View file

@ -6,7 +6,7 @@
<div class="modal-body px-4 py-5"> <div class="modal-body px-4 py-5">
<img :src="this.ModalImage" class="w-100 mb-4" alt="" /> <img :src="this.ModalImage" class="w-100 mb-4" alt="" />
<h5 class="mb-4" v-html="this.ModalHeadline"></h5> <h5 class="mb-4" v-html="this.ModalHeadline"></h5>
<p class="fw-bold mb-2" v-html="this.ModalSubheadertext"></p> <p class="fw-bold mb-2 subheader-text" v-html="this.ModalSubheadertext"></p>
<p class="mb-0" v-html="this.ModalBodyText"></p> <p class="mb-0" v-html="this.ModalBodyText"></p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -45,6 +45,11 @@ export default {
<style lang="scss"> <style lang="scss">
.modal { .modal {
h5,
strong,
.subheader-text {
color: $black;
}
&.modal-component { &.modal-component {
.modal-dialog { .modal-dialog {
.modal-content { .modal-content {

View file

@ -7,7 +7,7 @@
:class="(q.questionSequence === currentQuestionNum) && 'current-question'" :class="(q.questionSequence === currentQuestionNum) && 'current-question'"
:questionText="q.questionText" :questionText="q.questionText"
:answers="q.answers" :answers="q.answers"
:groupName="`${keyString}-${q.questionSequence}`" :groupName="`question-${glassIndex}-${q.questionSequence}`"
v-model="q.answerSelected" v-model="q.answerSelected"
@isCheckedChanged="handleAnswer" @isCheckedChanged="handleAnswer"
isRequired isRequired
@ -34,19 +34,16 @@ export default {
validationRules: String, validationRules: String,
modelValue: Array, modelValue: Array,
glassIndex: Number, glassIndex: Number,
keyString: String,
}, },
async created() { async created() {
// validate form upon create to prevent out of sync / persistent valid states // do a test validation check upon create to prevent out of sync / incorrect valid states
await useValidateForm(); // do a test validation check, without triggering full validation await useValidateForm(); // NOTE: needs to have async/await here; tested and won't work without it
this.questionData.map((q, i) => { this.questionData.map((q, i) => {
let answerPair = [];
const question = { const question = {
questionText: q.questionText, questionText: q.questionText,
questionSequence: q.questionSequence, questionSequence: q.questionSequence,
answers: q.answers.map((a) => { answers: q.answers.map((a) => {
answerPair.push(a.nextQuestionSequence ? a.nextQuestionSequence : a.answerResult);
return { return {
Text: a.answerText, Text: a.answerText,
// Name will either be nextQuestionSequence or answerResult // Name will either be nextQuestionSequence or answerResult
@ -65,7 +62,6 @@ export default {
}), }),
answerSelected: q.answerSelected || "", answerSelected: q.answerSelected || "",
}; };
question.answerPair = answerPair;
if (!q.suppressQuestion) { if (!q.suppressQuestion) {
this.questions.push(question); this.questions.push(question);
} }

View file

@ -10,7 +10,7 @@
:manualHeadline="AlertFewMoreQuestionsHeader" :manualCopy="AlertFewMoreQuestionsCopy" :manualHeadline="AlertFewMoreQuestionsHeader" :manualCopy="AlertFewMoreQuestionsCopy"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<div v-for="(glass, i) in capabilityQuestionsData" :key="glass.key"> <div v-for="(glass, i) in capabilityQuestionsData" :key="glass.key">
<questionChain ref="questionChain" :keyString="glass.key" <questionChain ref="questionChain"
v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.capabilityQuestions" :glassIndex="i" :questionData="glass.capabilityQuestions" :glassIndex="i"
v-if="showThisQuestionChain(glass, i)" v-if="showThisQuestionChain(glass, i)"

View file

@ -36,48 +36,6 @@ describe("estimate.vue", () => {
//Assesrt //Assesrt
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: ["Provide my license plate # Most accurate VIN match"] }]); expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: ["Provide my license plate # Most accurate VIN match"] }]);
}); });
test("isRepair is set to true, arePagePrerequisitesValid should return true", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, true );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("isRepair is set to true, arePagePrerequisitesValid should return true", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, true );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test.todo("isRepair is false and there are no lineItems => should return false")
test.todo("isRepair is false and lineItems is null => should return false")
test.todo("isRepair is false are there are lineItems => should return true")
test("isRepair is set to null, arePagePrerequisitesValid should return false", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
store.commit( storeMutations.UPDATE_IS_REPAIR, null );
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(false);
});
test("After selecting provide my home address on ForwardButtonAction triggers a router.navigateWithSaving", async () => { test("After selecting provide my home address on ForwardButtonAction triggers a router.navigateWithSaving", async () => {
@ -132,20 +90,104 @@ describe("estimate.vue", () => {
test("Provide my license plate on ForwardButtonAction triggers a router.navigateWithSaving", async () => { test("Provide my license plate on ForwardButtonAction triggers a router.navigateWithSaving", async () => {
//Arrange //Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
await wrapper.setData({ await wrapper.setData({
selectedVinLookupMethod: vinLookupMethodSelections.LICENSEPLATE selectedVinLookupMethod: vinLookupMethodSelections.LICENSEPLATE
}) })
//Act //Act
wrapper.vm.forwardButtonAction(); wrapper.vm.forwardButtonAction();
//Assert //Assert
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
}); });
describe("arePagePrerequisitesValid", () => {
beforeEach(() => {
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, null);
})
test("isRepair is false and there are no glassToReplace => should return false", () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(false);
})
test("isRepair is false and glassToReplace is null => should return false", () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, null);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(false);
})
test("isRepair is false are there is one glassToReplace => should return true", () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, [{glassLocation: "TEST", glassName: "NAME"}]);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(true);
})
test("isRepair is false are there are multiple glassToReplace => should return true", () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, [{glassLocation: "TEST1", glassName: "NAME1"}, {glassLocation: "TEST2", glassName: "NAME2"}, {glassLocation: "TEST3", glassName: "NAME3"}]);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(true);
})
test("isRepair is set to null => arePagePrerequisitesValid should return false", async () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, null);
// Act
console.log(store.getters.damage)
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(false);
});
test("isRepair is set to true => arePagePrerequisitesValid should return true", async () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_IS_REPAIR, true);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(true);
});
})
test("Changing zip should reset alert", async () => { test("Changing zip should reset alert", async () => {
//Arrange //Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -166,6 +208,7 @@ function setupMocks({
groupName = "estimate", groupName = "estimate",
cmsQuestionText = "Let's get your VIN. Or we can look it up for you!", 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" }, { Name: "Provide my license plate # Most accurate VIN match" }, { Name: "Provide my home address Most convenient VIN match" }], cmsAnswers = [{ Name: "Provide my VIN manually Most specific to your vehicle" }, { Name: "Provide my license plate # Most accurate VIN match" }, { Name: "Provide my home address Most convenient VIN match" }],
funnelFooterWidget = { ForwardButtonText: "test txt" },
mountOptionsMockData = { mountOptionsMockData = {
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
@ -179,13 +222,15 @@ function setupMocks({
const cmsContent = { const cmsContent = {
groupName: groupName, groupName: groupName,
QuestionText: cmsQuestionText, QuestionText: cmsQuestionText,
Answers: cmsAnswers Answers: cmsAnswers,
FunnelFooterWidget: funnelFooterWidget
}; };
const apiPromise = Promise.resolve(cmsContent); const apiPromise = Promise.resolve({ cmsContent });
settleAllPromises.mockImplementation(() => apiPromise); settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [baseMixin] }); const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [baseMixin] });
mountOptions['attachTo'] = document.body; mountOptions['attachTo'] = document.body;

View file

@ -151,6 +151,18 @@ export default {
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => { next((vm) => {
if (resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.includes("|"))
{
const forwardTextOption = resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.split("|");
if (store.getters.damage.isRepair){
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText = forwardTextOption[1]
}
else
{
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText = forwardTextOption[0]
}
}
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
}); });
}, },
@ -181,13 +193,13 @@ export default {
state: zipCodeData.state, state: zipCodeData.state,
}, false); }, false);
if (!zipCodeData.isZipValid) { if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
if (!zipCodeData.isZipServiceable) { if (!zipCodeData.isServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
} }
@ -220,7 +232,6 @@ export default {
}, },
computed: { computed: {
AlertNonServiceableZipHeader(){ AlertNonServiceableZipHeader(){
console.log(this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText"));
return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.serviceZipCode); return this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.serviceZipCode);
}, },
AlertNonServiceableZipBody(){ AlertNonServiceableZipBody(){

View file

@ -23,7 +23,6 @@
<div v-for="(glass, i) in moldingQuestionsData" :key="glass.key"> <div v-for="(glass, i) in moldingQuestionsData" :key="glass.key">
<questionChain <questionChain
ref="questionChain" ref="questionChain"
:keyString="glass.key"
v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.questions" :questionData="glass.questions"
:glassIndex="i" :glassIndex="i"

View file

@ -23,7 +23,6 @@
<div v-for="(glass, i) in partsQuestionsData" :key="glass.key"> <div v-for="(glass, i) in partsQuestionsData" :key="glass.key">
<questionChain <questionChain
ref="questionChain" ref="questionChain"
:keyString="glass.key"
v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.questions" :questionData="glass.questions"
:glassIndex="i" :glassIndex="i"

View file

@ -30,6 +30,76 @@
typeStyle="caption" typeStyle="caption"
class="mt-4" class="mt-4"
/> />
<h3 style="m-0">h1</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h1"
class="mt-4"
/>
<h3 style="m-0">h2</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h2"
class="mt-4"
/>
<h3 style="m-0">h3</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h3"
class="mt-4"
/>
<h3 style="m-0">h4</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h4"
class="mt-4"
/>
<h3 style="m-0">h5</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h5"
class="mt-4"
/>
<h3 style="m-0">h6</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="h6"
class="mt-4"
/>
<h3 style="m-0">Body</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="body"
class="mt-4"
/>
<h3 style="m-0">Label</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="label"
class="mt-4"
/>
<h3 style="m-0">Small</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="small"
class="mt-4"
/>
<h3 style="m-0">Caption</h3>
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
typeStyle="caption"
class="mt-4"
/>
<funnel-footer <funnel-footer
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@ -75,10 +145,7 @@ export default {
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
if (store.getters.order.damage.isRepair || store.getters.order.lineItems.glassParts.length > 0) { return store.getters.order.damage.isRepair || (store.getters.order.lineItems?.glassParts != null && store.getters.order.lineItems.glassParts.length > 0);
return true;
}
return false;
} }
}, },
computed: { computed: {

View file

@ -236,7 +236,7 @@ describe("vehicle-parts.vue", () => {
wrapper.vm.backButtonAction(); wrapper.vm.backButtonAction();
//Assert //Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, wrapper.vm.$route); expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, wrapper.vm.$route);
}); });
@ -277,7 +277,7 @@ describe("vehicle-parts.vue", () => {
wrapper.vm.backButtonAction(); wrapper.vm.backButtonAction();
//Assert //Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, wrapper.vm.$route); expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, wrapper.vm.$route);
}); });

View file

@ -10,6 +10,9 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import router from "@/router"
import store from "@/store"
import { storeMutations } from "@/constants/store-mutations";
// Mock our module for promises. // Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({ jest.mock("@/helpers/layout-helper.js", () => ({
@ -21,25 +24,16 @@ jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(), fetchCmsContentForPage: jest.fn(),
})); }));
// Mock Store // Mock fetchCmsContentForPage
jest.mock("@/store", () => ({ jest.mock("@/router", () => ({
getters: { overrideNavigation: jest.fn(),
vehicle: {
model: "TL",
},
applicationUser:{
pageData: {
"part-questions": null,
"vehicle-make": {},
"vehicle-model": {},
"vehicle-style": {},
"vehicle-damage": {}
}
}
},
})); }));
describe("vehicle-style.vue", () => { describe("vehicle-style.vue", () => {
beforeEach(() => {
jest.clearAllMocks();
})
test("Style question component is initized with api data", async (done) => { test("Style question component is initized with api data", async (done) => {
//Arrange //Arrange
const styleQuestionInitialData = ["2 Door", "4 Door"]; const styleQuestionInitialData = ["2 Door", "4 Door"];
@ -63,9 +57,7 @@ describe("vehicle-style.vue", () => {
done(); done();
}); });
}); });
});
describe("vehicle-style.vue", () => {
test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => {
//Arrange //Arrange
const { wrapper, apiPromise } = setupMocks({ const { wrapper, apiPromise } = setupMocks({
@ -95,20 +87,12 @@ describe("vehicle-style.vue", () => {
done(); done();
}); });
}); });
});
describe("vehicle-style.vue", () => { test("setVehicle triggers a dispatchStoreAction commit", async (done) => {
test("selectVehicle triggers a dispatchStoreAction commit", async (done) => {
//Arrange //Arrange
const { wrapper, apiPromise } = setupMocks({ const { wrapper, apiPromise } = setupMocks({
pageHeaderWidgetHeaderText: "Select a style to get started", pageHeaderWidgetHeaderText: "Select a style to get started",
mountOptionsMockData: { mountOptionsMockData: {
store: {
commit: jest.fn(),
getters: {
vehicle: {},
},
},
actionList: [ actionList: [
{ {
actionName: storeActions.SET_VEHICLE, actionName: storeActions.SET_VEHICLE,
@ -134,9 +118,7 @@ describe("vehicle-style.vue", () => {
done(); done();
}); });
}); });
});
describe("vehicle-style.vue", () => {
test("Model set, arePagePrerequisitesValid should be true ", async () => { test("Model set, arePagePrerequisitesValid should be true ", async () => {
//Arrange //Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -155,7 +137,61 @@ describe("vehicle-style.vue", () => {
//Assert //Assert
expect(arePagePrerequisitesValid).toBe(true); expect(arePagePrerequisitesValid).toBe(true);
}); });
test("there is only one vehicle style => autoselect and move to vehicle damage", async () => {
//Arrange
const { wrapper } = setupMocks({
styleQuestionInitialData: ["2 door sedan"],
});
// Act
await vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
// Assert
expect(store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan");
expect(router.overrideNavigation).toHaveBeenCalled();
})
test("there is only one vehicle style and vehicle-damage was visited => don't autoselect or move to vehicle damage", async () => {
//Arrange
const { wrapper } = setupMocks({
styleQuestionInitialData: ["2 door sedan"],
mountOptionsMockData: {
store: {
getters: {
applicationUser: {
pageData: {
"part-questions": null,
"vehicle-make": {},
"vehicle-model": {},
"vehicle-style": {},
"vehicle-damage": {}
}
}
}
}
}
});
// Act
await vehicleStyle.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "vehicle-style" } },
undefined,
(c) => c(wrapper.vm)
);
// Assert
expect(store.commit).not.toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan");
expect(router.overrideNavigation).not.toHaveBeenCalled();
})
}); });
function setupMocks({ function setupMocks({
vehicleStyleQuestionCmsContent = {}, vehicleStyleQuestionCmsContent = {},
styleQuestionInitialData = {}, styleQuestionInitialData = {},
@ -190,7 +226,26 @@ function setupMocks({
initializeComponent: jest.fn(), initializeComponent: jest.fn(),
}; };
const mountOptions = getMountOptions(mountOptionsMockData); store.commit = jest.fn();
store.dispatch = jest.fn();
store.getters = mountOptionsMockData.store?.getters ?? {
vehicle: {
model: "TL",
},
applicationUser: {
pageData: {
"part-questions": null,
"vehicle-make": {},
"vehicle-model": {},
"vehicle-style": {},
}
}
}
const mountOptions = getMountOptions({
...mountOptionsMockData,
store
});
const wrapper = shallowMount(vehicleStyle, mountOptions); const wrapper = shallowMount(vehicleStyle, mountOptions);
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;

View file

@ -26,6 +26,7 @@
<script> <script>
// Components // Components
import baseMixin from "@/mixins/base-mixin.js";
import styleQuestion from "@/layouts/vehicle-style/style-question/style-question"; import styleQuestion from "@/layouts/vehicle-style/style-question/style-question";
import funnelHeader from "@/common-components/funnel-header/funnel-header"; import funnelHeader from "@/common-components/funnel-header/funnel-header";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
@ -72,13 +73,11 @@ export default {
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
const visitedVehicleDamage = JSON.stringify(store.getters.applicationUser.pageData).indexOf(fmgPageValues.VEHICLE_DAMAGE) < 0 ? false : true; const visitedVehicleDamage = JSON.stringify(store.getters.applicationUser.pageData).indexOf(fmgPageValues.VEHICLE_DAMAGE) < 0 ? false : true;
// Call the "next" function to complete the transition to this page.
// If we have exactly one style then navigate directly to vehicle-damage // If we have exactly one style then navigate directly to vehicle-damage
if(resultMap.styleQuestionInitialData.length === 1 && !visitedVehicleDamage) { if(resultMap.styleQuestionInitialData.length === 1 && !visitedVehicleDamage) {
store.commit(storeMutations.UPDATE_STYLE, resultMap.styleQuestionInitialData[0]); store.commit(storeMutations.UPDATE_STYLE, resultMap.styleQuestionInitialData[0]);
await store.dispatch(storeActions.SET_VEHICLE, await baseMixin.methods.dispatchStoreAction(storeActions.SET_VEHICLE,
{ {
year: store.getters.vehicle.year, year: store.getters.vehicle.year,
make: store.getters.vehicle.make, make: store.getters.vehicle.make,

View file

@ -65,7 +65,7 @@ describe("vin-lookup.vue", () => {
it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => { it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
mockOutPromises(); mockOutPromises({ carId: "C00000" });
wrapper.vm.navigateForward = jest.fn(); wrapper.vm.navigateForward = jest.fn();
// Act // Act
@ -78,7 +78,7 @@ describe("vin-lookup.vue", () => {
it("Should not call navigateForward() if the store carId does not match the vin response carId and forward button is clicked", async () => { it("Should not call navigateForward() if the store carId does not match the vin response carId and forward button is clicked", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
mockOutPromises('C11111'); mockOutPromises({ carId: 'C11111' });
wrapper.vm.vinTouched = true; wrapper.vm.vinTouched = true;
wrapper.vm.vin = ""; wrapper.vm.vin = "";
@ -95,7 +95,7 @@ describe("vin-lookup.vue", () => {
it("Should call navigateForward() if the store carId does not match the vin response carId but does match previously enterted carId and forward button is clicked", async () => { it("Should call navigateForward() if the store carId does not match the vin response carId but does match previously enterted carId and forward button is clicked", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
mockOutPromises('C11111'); mockOutPromises({ carId: 'C11111' });
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise); wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
wrapper.vm.navigateForward = jest.fn(); wrapper.vm.navigateForward = jest.fn();
@ -203,6 +203,22 @@ describe("vin-lookup.vue", () => {
expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1); expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1);
}) })
}) })
describe("alerts", () => {
test("Zip is invalid => show AlertInvalidZipWidget", async () => {
// Arrange
const { wrapper } = setupMocks({});
mockOutPromises({ isZipValid: false });
await wrapper.setData({serviceZipCode: "11111"})
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.displayInvalidZipAlert).toEqual(true);
expect(wrapper.findComponent({ref: "alertInvalidZip"}).exists()).toBe(true);
})
})
}); });
@ -217,15 +233,17 @@ function setupMocks({ customMountOptions }) {
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
const wrapper = shallowMount(vinLookup, mountOptions); const wrapper = shallowMount(vinLookup, mountOptions);
mockOutPromises(wrapper);
mockOutStubFunctions(wrapper); mockOutStubFunctions(wrapper);
return { wrapper }; return { wrapper };
} }
function mockOutPromises(carId = 'C00000') { function mockOutPromises({carId, isZipValid = true, isZipServiceable = true}) {
const apiResponses = { const apiResponses = {
vehicleLookupResponse: { vehicleLookupResponse: {
carId: carId carId: carId
},
zipCodeData: {
isValid: true, isServiceable: true, state: "OH"
} }
}; };

View file

@ -238,13 +238,16 @@ export default {
resultKey: "vehicleLookupResponse", resultKey: "vehicleLookupResponse",
promise: vehicleLookupResponse, promise: vehicleLookupResponse,
}, },
{
resultKey: "zipCodeData",
promise: this.getZipCodeData(this.serviceZipCode)
}
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
// If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert // If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
const isZipValid = zipCodeData.isValid; const isZipValid = resultMap.zipCodeData.isValid;
if (this.serviceZipCode && !isZipValid) { if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.funnelFooter.removeLoader();
@ -252,14 +255,14 @@ export default {
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
// If either lookup fails, remove the loader and stop processing the page. // If either lookup fails, remove the loader and stop processing the page.
if (!resultMap.vehicleLookupResponse || !zipCodeData.isServiceable) { if (!resultMap.vehicleLookupResponse || !resultMap.zipCodeData.isServiceable) {
// If the vehicle result is undefined, the vin entered was invalid. // If the vehicle result is undefined, the vin entered was invalid.
if(!resultMap.vehicleLookupResponse) { if(!resultMap.vehicleLookupResponse) {
this.displayVinNotFoundAlert = true; this.displayVinNotFoundAlert = true;
} }
// Check if Service Zip entered is serviceable, if not display an alert // Check if Service Zip entered is serviceable, if not display an alert
if (!zipCodeData.isServiceable) { if (!resultMap.zipCodeData.isServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
} }
@ -293,7 +296,7 @@ export default {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false); await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, { await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, {
zipCode: this.serviceZipCode, zipCode: this.serviceZipCode,
state: zipCodeData.state, state: resultMap.zipCodeData.state,
}, false); }, false);
return await this.navigateForward(); return await this.navigateForward();

View file

@ -49,21 +49,12 @@ export default {
return footerInfoBox ? footerInfoBox.offsetHeight : 0; return footerInfoBox ? footerInfoBox.offsetHeight : 0;
}, },
async getZipCodeData(zipCode) { async getZipCodeData(zipCode) {
const serviceZipValidationResponse = this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { zip: zipCode }); const serviceZipValidationResponse = await this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { zip: zipCode });
const promiseResultMap = [
{
resultKey: "serviceZipValidationResponse",
promise: serviceZipValidationResponse,
}
];
const resultMap = await settleAllPromises(promiseResultMap);
return { return {
isZipValid: resultMap.serviceZipValidationResponse.isValid, isValid: serviceZipValidationResponse.data.isValid,
isZipServiceable: resultMap.serviceZipValidationResponse.isServiceable, isServiceable: serviceZipValidationResponse.data.isServiceable,
state: resultMap.serviceZipValidationResponse.state state: serviceZipValidationResponse.data.state
}; };
} }
}, },

View file

@ -99,7 +99,7 @@ describe("baseMixin.js", () => {
test("getZipCodeData calls dispatch", () => { test("getZipCodeData calls dispatch", () => {
const mixIn = getMixInInstance({}); const mixIn = getMixInInstance({});
mixIn.methods.dispatchStoreAction = jest.fn(); mixIn.methods.dispatchStoreAction = jest.fn();
mixIn.methods.dispatchStoreAction.mockReturnValue({ isValid:true, isServiceable:true, state:"OH" }); mixIn.methods.dispatchStoreAction.mockReturnValue({data: { isValid:true, isServiceable:true, state:"OH" }});
const type = ""; const type = "";
const payload = { zip: 43015 }; const payload = { zip: 43015 };

View file

@ -115,6 +115,7 @@ export default {
// if single parts only // if single parts only
const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions);
// save to store lineItems.glassParts // save to store lineItems.glassParts
// TODO KO
self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts); self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
self.$refs.loadingModal.showModal(); self.$refs.loadingModal.showModal();
@ -127,20 +128,20 @@ export default {
const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions); const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
let backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP; let backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS;
const currentPage = this.$route.query.fmgPage; const currentPage = this.$route.query.fmgPage;
if (hasCapabilityQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)) { if (hasCapabilityQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_CAPABILITY_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS;
} }
else if (hasChildPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.MOLDING_QUESTIONS)) { else if (hasChildPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.MOLDING_QUESTIONS)) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS;
} }
else if (hasGlassLocationWithMultipleParts && this.currentPageComesAfterPage(currentPage, fmgPageValues.VEHICLE_PARTS)) { else if (hasGlassLocationWithMultipleParts && this.currentPageComesAfterPage(currentPage, fmgPageValues.VEHICLE_PARTS)) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE;
} }
else if (hasPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.PART_QUESTIONS)) { else if (hasPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.PART_QUESTIONS)) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS;
} }
this.$router.navigateWithoutSaving( this.$router.navigateWithoutSaving(

View file

@ -7,6 +7,7 @@ import { storeActions } from "@/constants/store-actions";
import loadingModal from '@/common-components/loading-modal/loading-modal.vue'; import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { navigationScenarios } from "../router/router-constants/navigation-scenarios"; import { navigationScenarios } from "../router/router-constants/navigation-scenarios";
import { getters } from "@/store"
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn() navigateToHeritageFunnel: jest.fn()
@ -154,6 +155,46 @@ describe("vehicle-questions-mixin", () => {
}); });
}); });
describe("currentPageComesBeforePage", () => {
const testCases = [[fmgPageValues.PART_QUESTIONS, fmgPageValues.VEHICLE_PARTS, true],
[fmgPageValues.VEHICLE_PARTS, fmgPageValues.VEHICLE_PARTS, false],
[fmgPageValues.QUOTE, fmgPageValues.VEHICLE_PARTS, false],
[fmgPageValues.QUOTE, fmgPageValues.QUOTE, false],
[fmgPageValues.VEHICLE_PARTS, fmgPageValues.PART_QUESTIONS, false],
[fmgPageValues.PART_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, true],
[fmgPageValues.MOLDING_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, true],];
test.each(testCases)("%s comes before %s is %s", (currentPage, nextPage, expectedResult) => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.currentPageComesBeforePage(currentPage, nextPage);
// Assert
expect(result).toEqual(expectedResult);
})
});
describe("currentPageComesAfterPage", () => {
const testCases = [[fmgPageValues.PART_QUESTIONS, fmgPageValues.VEHICLE_PARTS, false],
[fmgPageValues.VEHICLE_PARTS, fmgPageValues.VEHICLE_PARTS, false],
[fmgPageValues.QUOTE, fmgPageValues.VEHICLE_PARTS, true],
[fmgPageValues.QUOTE, fmgPageValues.QUOTE, false],
[fmgPageValues.VEHICLE_PARTS, fmgPageValues.PART_QUESTIONS, true],
[fmgPageValues.PART_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, false],
[fmgPageValues.MOLDING_QUESTIONS, fmgPageValues.CAPABILITY_QUESTIONS, false],];
test.each(testCases)("%s comes after %s is %s", (currentPage, nextPage, expectedResult) => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.currentPageComesAfterPage(currentPage, nextPage);
// Assert
expect(result).toEqual(expectedResult);
})
});
describe("navigateForward", () => { describe("navigateForward", () => {
describe("should go to parts-questions", () => { describe("should go to parts-questions", () => {
test("single glass location has part question => go to parts-questions", async () => { test("single glass location has part question => go to parts-questions", async () => {
@ -890,20 +931,20 @@ describe("vehicle-questions-mixin", () => {
"childParts": null, "childParts": null,
"childPartQuestions": [ "childPartQuestions": [
{ {
"questionSequence": 1, "questionSequence": 1,
"questionText": "Does the rubber seal around your windshield have a chrome strip running through it?", "questionText": "Does the rubber seal around your windshield have a chrome strip running through it?",
"answers": [ "answers": [
{ {
"answerResult": "WKT D1106 C", "answerResult": "WKT D1106 C",
"answerText": "Yes", "answerText": "Yes",
"nextQuestionSequence": null "nextQuestionSequence": null
}, },
{ {
"answerResult": "WKT D1106 B", "answerResult": "WKT D1106 B",
"answerText": "No", "answerText": "No",
"nextQuestionSequence": null "nextQuestionSequence": null
} }
] ]
} }
] ]
@ -1105,7 +1146,63 @@ describe("vehicle-questions-mixin", () => {
expect(navigateToHeritageFunnel).toHaveBeenCalledTimes(1); expect(navigateToHeritageFunnel).toHaveBeenCalledTimes(1);
}); });
}); });
}) });
describe("backButtonAction", () => {
test("current page is quote and there are no questions => go to vin-lookup", () => {
// Arrange
const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE });
// Act
wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}})
})
test("current page is quote and there are part questions and molding questions => go to molding questions", () => {
// Arrange
const { wrapper } = setupMocks({ fmgPage: fmgPageValues.QUOTE });
wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true);
wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true);
// Act
wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS, {"query": {"fmgPage": fmgPageValues.QUOTE}})
})
test("current page is molding questions and there are part questions, multiple parts to choose, and capability questions => go to vehicle-parts", () => {
// Arrange
const { wrapper } = setupMocks({ fmgPage: fmgPageValues.MOLDING_QUESTIONS });
wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true);
wrapper.vm.hasGlassLocationWithMultipleParts = jest.fn().mockReturnValue(true);
wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true);
wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true);
// Act
wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, {"query": {"fmgPage": fmgPageValues.MOLDING_QUESTIONS}})
})
test("current page is molding questions and there are part questions and capability questions => go to part-questions", () => {
// Arrange
const { wrapper } = setupMocks({ fmgPage: fmgPageValues.MOLDING_QUESTIONS });
wrapper.vm.hasPartQuestions = jest.fn().mockReturnValue(true);
wrapper.vm.hasGlassLocationWithMultipleParts = jest.fn().mockReturnValue(false);
wrapper.vm.hasChildPartQuestions = jest.fn().mockReturnValue(true);
wrapper.vm.hasCapabilityQuestions = jest.fn().mockReturnValue(true);
// Act
wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, {"query": {"fmgPage": fmgPageValues.MOLDING_QUESTIONS}})
})
});
}); });
function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) { function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) {
@ -1118,11 +1215,12 @@ function setupMocks({ fmgPage = fmgPageValues.VIN_LOOKUP }) {
const mocks = getMountOptions({ const mocks = getMountOptions({
router: { router: {
navigate: jest.fn(), navigateWithSaving: jest.fn(), navigateWithSaving: jest.fn() navigate: jest.fn(), navigateWithSaving: jest.fn(), navigateWithoutSaving: jest.fn()
}, },
store: { store: {
commit: jest.fn(), commit: jest.fn(),
dispatch: jest.fn() dispatch: jest.fn(),
getters: getters
}, },
route: { route: {
query: { query: {

View file

@ -25,10 +25,10 @@ const navigationScenarios = {
HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS", HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS",
HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS", HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS",
HAS_NO_MORE_QUESTIONS: "HAS_NO_MORE_QUESTIONS", HAS_NO_MORE_QUESTIONS: "HAS_NO_MORE_QUESTIONS",
CLICKED_BACK_TO_GO_TO_VIN_LOOKUP: "CLICKED_BACK_TO_GO_TO_VIN_LOOKUP", CLICKED_BACK_WITH_NO_QUESTIONS: "CLICKED_BACK_WITH_NO_QUESTIONS",
CLICKED_BACK_TO_GO_TO_PART_QUESTIONS: "CLICKED_BACK_TO_GO_TO_PART_QUESTIONS", CLICKED_BACK_WITH_PART_QUESTIONS: "CLICKED_BACK_WITH_PART_QUESTIONS",
CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS: "CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS", CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE: "CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE",
CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS: "CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS" CLICKED_BACK_WITH_MOLDING_QUESTIONS: "CLICKED_BACK_WITH_MOLDING_QUESTIONS"
}; };
export { navigationScenarios }; export { navigationScenarios };

View file

@ -227,7 +227,7 @@ const routingTable = function(store) {
fmgPageValue: fmgPageValues.PART_QUESTIONS, fmgPageValue: fmgPageValues.PART_QUESTIONS,
maps: [ maps: [
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
}, },
{ {
@ -256,11 +256,11 @@ const routingTable = function(store) {
destinationFmgPageValue: fmgPageValues.REVEAL, destinationFmgPageValue: fmgPageValues.REVEAL,
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS, destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP, destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
}, },
{ {
@ -281,15 +281,15 @@ const routingTable = function(store) {
fmgPageValue: fmgPageValues.MOLDING_QUESTIONS, fmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
maps: [ maps: [
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS, scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
}, },
{ {
@ -306,19 +306,19 @@ const routingTable = function(store) {
fmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS, fmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
maps: [ maps: [
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, scenario: navigationScenarios.CLICKED_BACK_WITH_NO_QUESTIONS,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS, scenario: navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE,
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
}, },
{ {
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS, scenario: navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS,
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
}, },
{ {

View file

@ -717,7 +717,7 @@ export const actions = {
endpoint: endpoints.GetPartsOrQuestions.url, endpoint: endpoints.GetPartsOrQuestions.url,
payload: { payload: {
carId: carId, carId: carId,
glass: glassArray, glass: glassArray ?? [],
zip: zipCode, zip: zipCode,
vin: vin vin: vin
}, },
@ -942,8 +942,14 @@ export const actions = {
.slice() .slice()
.sort() .sort()
.every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName); .every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName);
const isWindshieldRepairTheSame = isWindshieldRepair === context.state.order.damage.isRepair;
const isChipCountTheSame = Array.isArray(selectedWindshieldChipCount) //TODO: fix the underlying components so this is never an array
? selectedWindshieldChipCount[0] === context.state.order.damage.numberOfChips
: selectedWindshieldChipCount === context.state.order.damage.numberOfChips;
if (!isGlassToReplaceTheSame) { const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame || (isWindshieldRepair && !isChipCountTheSame);
if (isDamageChanging) {
//Reset dependent state when changing //Reset dependent state when changing
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
@ -1004,9 +1010,10 @@ export const actions = {
}, },
savePartQuestionAnswers(context, partQuestionAnswersArray) { savePartQuestionAnswers(context, partQuestionAnswersArray) {
// if part question answers have changed, reset subsequent question answers // if part question answers have changed, reset subsequent question answers
const previousResultsArray = context.getters.damage.partQuestionAnswers; const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.partQuestionAnswers, "result");
const havePartQuestionAnswersChanged = previousResultsArray?.length !== partQuestionAnswersArray.length || const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(partQuestionAnswersArray, "result")
!previousResultsArray.every((x, i) => x.result === partQuestionAnswersArray[i].result); const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result);
if (havePartQuestionAnswersChanged) { if (havePartQuestionAnswersChanged) {
context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
@ -1021,7 +1028,6 @@ export const actions = {
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray); context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
}, },
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) { resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
const previousResultsArray = [{ parts: context.getters.lineItems.glassParts }];
const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? []; const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? [];
function getAllPartNumbers(partsOrQuestions) { function getAllPartNumbers(partsOrQuestions) {
@ -1044,9 +1050,10 @@ export const actions = {
} }
}, },
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) { saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
const previousResultsArray = context.getters.damage.moldingQuestionAnswers; const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.moldingQuestionAnswers, "partNum");
const haveMoldingQuestionAnswersChanged = previousResultsArray?.length !== moldingQuestionAnswers.length || const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswers, "partNum");
!previousResultsArray.every((x, i) => x.partNum === moldingQuestionAnswers[i].partNum); const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every((x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum);
if (haveMoldingQuestionAnswersChanged) { if (haveMoldingQuestionAnswersChanged) {
context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
@ -1058,9 +1065,10 @@ export const actions = {
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers); context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
}, },
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) { saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
const previousResultsArray = context.getters.damage.capabilityQuestionAnswers; const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.capabilityQuestionAnswers, "result");
const haveCapabilityQuestionAnswersChanged = previousResultsArray?.length !== capabilityQuestionAnswers.length || const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result");
!previousResultsArray.every((x, i) => x.result === capabilityQuestionAnswers[i].result); const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result);
if (haveCapabilityQuestionAnswersChanged) { if (haveCapabilityQuestionAnswersChanged) {
context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
@ -1127,3 +1135,16 @@ function getHasRecalibrationPart(state) {
} }
} }
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
if (!arrayOfObjects) return null;
return arrayOfObjects.sort((a, b) => {
if (a[propertyName] < b[propertyName])
return -1;
else if (a[propertyName] > b[propertyName])
return 1;
else
return 0;
})
}

View file

@ -3,6 +3,7 @@ import { mutations, state, actions, getters } from "@/store";
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { experimentTriggers } from "@/constants/experiments"; import { experimentTriggers } from "@/constants/experiments";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values"
// Mock global method // Mock global method
globalMethods.callHttpClient = jest.fn(); globalMethods.callHttpClient = jest.fn();
@ -258,9 +259,9 @@ describe("Mutations", () => {
{ {
universeName: "XYZ", universeName: "XYZ",
settings: { settings: {
ExperimentSetting: "ExperimentValue" ExperimentSetting: "ExperimentValue"
} }
} }
] ]
// Act // Act
@ -649,6 +650,51 @@ describe("Actions", () => {
expect(commit).toBeCalledWith(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, { "referralNumber": 123 }); expect(commit).toBeCalledWith(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, { "referralNumber": 123 });
}); });
it("loadOrder: state doesn't have EON => do not reset state", async () => {
// Arrange
const context = state;
globalMethods.callHttpClient.mockImplementation(() => {
return Promise.resolve({ data: { eon: "123" } });
});
context.commit = jest.fn();
context.state = {
order: {
}
}
// Act
const response = await actions.loadOrder(context, { referralNumber: "123", referralDate: new Date().toUTCString(), referralCorrelationId: "xxx-xxx-xxx" });
// Assert
expect(response.data.eon).toEqual("123");
expect(context.commit).not.toBeCalledWith(storeMutations.RESET_STATE);
});
it("loadOrder eon doesn't match eon in state => reset state", async () => {
// Arrange
const context = state;
globalMethods.callHttpClient.mockImplementation(() => {
return Promise.resolve({ data: { eon: "123" } });
});
context.commit = jest.fn();
context.state = {
order: {
eon: "456"
}
}
// Act
const response = await actions.loadOrder(context, { referralNumber: "123", referralDate: new Date().toUTCString(), referralCorrelationId: "xxx-xxx-xxx" });
// Assert
expect(response.data.eon).toEqual("123");
expect(context.commit).toBeCalledWith(storeMutations.RESET_STATE);
});
it("updateStoreWithSaveOrderResponse, should call commit six times", () => { it("updateStoreWithSaveOrderResponse, should call commit six times", () => {
// Arrange // Arrange
const context = state; const context = state;
@ -1065,7 +1111,7 @@ describe("Actions", () => {
context.state = { context.state = {
order: { order: {
damage: { damage: {
glassToReplace: [{glassName: 'Single', glassLocation: 'Windshield'}] glassToReplace: [{ glassName: 'Single', glassLocation: 'Windshield' }]
} }
} }
}; };
@ -1077,7 +1123,7 @@ describe("Actions", () => {
context.dispatch = dispatch; context.dispatch = dispatch;
// Act // Act
const payload = { isWindshieldRepair: false, selectedGlassToReplace: [{glassName: 'Rear', glassLocation: 'quarter'}], selectedWindshieldChipCount: 0}; const payload = { isWindshieldRepair: false, selectedGlassToReplace: [{ glassName: 'Rear', glassLocation: 'quarter' }], selectedWindshieldChipCount: 0 };
actions.saveVehicleDamage(context, payload); actions.saveVehicleDamage(context, payload);
// Assert // Assert
@ -1156,50 +1202,677 @@ describe("Actions", () => {
}) })
describe("savePartQuestionAnswers", () => { describe("savePartQuestionAnswers", () => {
test.todo("saves partQuestionAnswers") let context;
beforeEach(() => {
jest.clearAllMocks();
mutations.resetState(state);
context = state;
context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value));
context.getters = {
...getters,
damage: getters.damage(context)
};
})
test.todo("there are no previous answers => resets necessary fields") function testPartQuestionAnswerDependenciesHaveBeenReset(context, shouldPartQuestionAnswersBeReset) {
if (shouldPartQuestionAnswersBeReset) {
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null });
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
else {
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null });
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
// mix up the order to make sure sort is working expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PART_QUESTION_ANSWERS, expect.anything());
test.todo("previous answers match current answers => does not reset fields") }
test.todo("previous answers does not match current answers => resets necessary fields") test("there are no previous answers => resets necessary fields", async () => {
// Arrange
const previousPartQuestionAnswers = [];
const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }];
actions.savePartQuestionAnswers(context, previousPartQuestionAnswers);
jest.clearAllMocks();
// Act
actions.savePartQuestionAnswers(context, currentPartQuestionAnswers);
// Assert
testPartQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers does not match current answers => resets necessary fields", () => {
// Arrange
const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART4!" }, { result: "I'M A PART3!" }];
const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }];
actions.savePartQuestionAnswers(context, previousPartQuestionAnswers);
jest.clearAllMocks();
// Act
actions.savePartQuestionAnswers(context, currentPartQuestionAnswers);
// Assert
testPartQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers match current answers => does not reset fields", () => {
// Arrange
const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART!" }, { result: "I'M A PART3!" }];
const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }];
actions.savePartQuestionAnswers(context, previousPartQuestionAnswers);
jest.clearAllMocks();
// Act
actions.savePartQuestionAnswers(context, currentPartQuestionAnswers);
// Assert
testPartQuestionAnswerDependenciesHaveBeenReset(context, false);
})
test("previous answers have more questions/answers than current => resets fields", () => {
// Arrange
const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART!" }, { result: "I'M A PART3!" }];
const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }];
actions.savePartQuestionAnswers(context, previousPartQuestionAnswers);
jest.clearAllMocks();
// Act
actions.savePartQuestionAnswers(context, currentPartQuestionAnswers);
// Assert
testPartQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("current answers have more questions/answers than previous => resets fields", () => {
// Arrange
const previousPartQuestionAnswers = [{ result: "I'M A PART2!" }, { result: "I'M A PART3!" }];
const currentPartQuestionAnswers = [{ result: "I'M A PART!" }, { result: "I'M A PART3!" }, { result: "I'M A PART2!" }];
actions.savePartQuestionAnswers(context, previousPartQuestionAnswers);
jest.clearAllMocks();
// Act
actions.savePartQuestionAnswers(context, currentPartQuestionAnswers);
// Assert
testPartQuestionAnswerDependenciesHaveBeenReset(context, true);
})
}) })
describe("resetMoldingAndCapabilityQuestionAnswersIfNeeded", () => { describe("resetMoldingAndCapabilityQuestionAnswersIfNeeded", () => {
test.todo("there are no saved parts => resets necessary fields") let context;
beforeEach(() => {
mutations.resetState(state);
context = state;
context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value));
context.getters = {
...getters,
pageData: getters.pageData(context)
};
})
// make sure you check the different variations where molding-questions and capability-questions do or don't have pageData function testVehiclePartDependenciesHaveBeenReset(context, shouldAnswersBeReset) {
// mix up the order to make sure sort is working if (shouldAnswersBeReset) {
test.todo("previously saved parts match selected parts => does not reset fields") expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
else {
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
}
test.todo("previously saved parts do not match selected parts => resets necessary fields") test("there are no saved parts from molding or capability question pages => resets necessary fields", () => {
// Arrange
const previouslySelectedParts = {};
const currentlySelectedParts = [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
mutations.updatePageData(context, {
page: fmgPageValues.CAPABILITY_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, true);
})
describe("previously saved parts from molding-questions match selected parts => does not reset fields", () => {
test("single glass location", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, false);
})
test("multiple glass locations", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }]
},
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }]
},
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, false);
})
})
describe("previously saved parts from capability-questions match selected parts and there are none from molding-questions => does not reset fields", () => {
test("Single glass location", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.CAPABILITY_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, false);
})
test("multiple glass locations", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART2" }, { partNumber: "PART3" }]
},
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }]
},
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.CAPABILITY_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, false);
})
})
describe("previously saved parts from molding-questions do not match selected parts => resets necessary fields", () => {
test("single glass location", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, true);
})
test("multiple glass locations", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }]
},
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }]
},
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, true);
})
})
describe("previously saved parts from capability-questions do not match selected parts => resets necessary fields", () => {
test("single glass location", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.MOLDING_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, true);
})
test("multiple glass locations", () => {
// Arrange
const previouslySelectedParts = {
partsOrQuestions: [
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART1" }, { partNumber: "PART6" }, { partNumber: "PART3" }]
},
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART5" }, { partNumber: "PART4" }]
}
]
};
const currentlySelectedParts = [
{
glassLocation: "Driver",
glassName: "Front",
parts: [{ partNumber: "PART4" }, { partNumber: "PART5" }]
},
{
glassLocation: "Windshield",
glassName: "Single",
parts: [{ partNumber: "PART3" }, { partNumber: "PART1" }, { partNumber: "PART2" }]
}
];
mutations.updatePageData(context, {
page: fmgPageValues.CAPABILITY_QUESTIONS,
data: previouslySelectedParts
});
// Act
actions.resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, currentlySelectedParts);
// Assert
testVehiclePartDependenciesHaveBeenReset(context, true);
})
})
}) })
describe("saveMoldingQuestionAnswers", () => { describe("saveMoldingQuestionAnswers", () => {
test.todo("saves moldingQuestionAnswers") let context;
beforeEach(() => {
jest.clearAllMocks();
mutations.resetState(state);
context = state;
context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value));
context.getters = {
...getters,
damage: getters.damage(context)
};
})
test.todo("there are no previous answers => resets necessary fields") function testMoldingQuestionAnswerDependenciesHaveBeenReset(context, shouldAnswersBeReset) {
if (shouldAnswersBeReset) {
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
else {
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
}
}
// mix up the order to make sure sort is working test("there are no previous answers => resets necessary fields", () => {
test.todo("previous answers match current answers => does not reset fields") // Arrange
const previousMoldingQuestionAnswers = [];
const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }];
test.todo("previous answers does not match current answers => resets necessary fields") actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers);
// Assert
testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers match current answers => does not reset fields", () => {
// Arrange
const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART!" }];;
const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }];
actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers);
// Assert
testMoldingQuestionAnswerDependenciesHaveBeenReset(context, false);
})
test("previous answers do not match current answers => resets necessary fields", () => {
// Arrange
const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART4!" }, { partNum: "I'M A PART!" }];;
const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }];
actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers);
// Assert
testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers have more questions/answers than current => resets fields", () => {
// Arrange
const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART4!" }, { partNum: "I'M A PART!" }];;
const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }];
actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers);
// Assert
testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("current answers have more questions/answers than previous => resets fields", () => {
// Arrange
const previousMoldingQuestionAnswers = [{ partNum: "I'M A PART2!" }, { partNum: "I'M A PART!" }];;
const currentMoldingQuestionAnswers = [{ partNum: "I'M A PART!" }, { partNum: "I'M A PART3!" }, { partNum: "I'M A PART2!" }];
actions.saveMoldingQuestionAnswers(context, previousMoldingQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveMoldingQuestionAnswers(context, currentMoldingQuestionAnswers);
// Assert
testMoldingQuestionAnswerDependenciesHaveBeenReset(context, true);
})
}) })
describe("saveCapabilityQuestionAnswers", () => { describe("saveCapabilityQuestionAnswers", () => {
test.todo("saves capabilityQuestionAnswers") let context;
beforeEach(() => {
jest.clearAllMocks();
mutations.resetState(state);
context = state;
context.commit = jest.fn().mockImplementation((storeMutation, value) => mutations[storeMutation](context, value));
context.getters = {
...getters,
damage: getters.damage(context)
};
})
test.todo("there are no previous answers => resets necessary fields") function testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, shouldAnswersBeReset) {
if (shouldAnswersBeReset) {
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
}
else {
expect(context.commit).not.toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, null);
}
}
// mix up the order to make sure sort is working test("there are no previous answers => resets necessary fields", () => {
test.todo("previous answers match current answers => does not reset fields") // Arrange
const previousCapabilityQuestionAnswers = [];
const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }];
test.todo("previous answers does not match current answers => resets necessary fields") actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers);
// Assert
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers match current answers => does not reset fields", () => {
// Arrange
const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "DYNAMIC" }, { result: "UNKNOWN" }];
const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }];
actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers);
// Assert
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, false);
})
test("previous answers do not match current answers => resets necessary fields", () => {
// Arrange
const previousCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "DYNAMIC" }, { result: "STATIC" }];
const currentCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "STATIC" }, { result: "DYNAMIC" }];
actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers);
// Assert
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("previous answers have more questions/answers than current => resets fields", () => {
// Arrange
const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "DYNAMIC" }, { result: "UNKNOWN" }];
const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }];
actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers);
// Assert
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
})
test("current answers have more questions/answers than previous => resets fields", () => {
// Arrange
const previousCapabilityQuestionAnswers = [{ result: "STATIC" }, { result: "UNKNOWN" }];
const currentCapabilityQuestionAnswers = [{ result: "DYNAMIC" }, { result: "STATIC" }, { result: "UNKNOWN" }];
actions.saveCapabilityQuestionAnswers(context, previousCapabilityQuestionAnswers);
jest.clearAllMocks();
// Act
actions.saveCapabilityQuestionAnswers(context, currentCapabilityQuestionAnswers);
// Assert
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
})
}) })
}); });
describe("Getters", () => { describe("Getters", () => {
it("Vehicle getter, should return vehicle data", () => { it("Vehicle getter, should return vehicle data", () => {
// Arrange // Arrange

View file

@ -211,11 +211,12 @@ describe("list-button-horizontal.vue", () => {
isWide: false, isWide: false,
modelValue: ["List Card Checkbox"], modelValue: ["List Card Checkbox"],
isMultiSelect: false, isMultiSelect: false,
value: "Car-Front",
selectedValues: ["Car-Front"] selectedValues: ["Car-Front"]
}, },
}); });
// Assert // Assert
expect(wrapper.componentVM.checkValue).toEqual(["Car-Front"]); expect(wrapper.vm.checkValue).toEqual(true);
}); });
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => { it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {

View file

@ -70,14 +70,11 @@ export default {
checkValue: Boolean, checkValue: Boolean,
}; };
}, },
mounted() { created() {
if (Array.isArray(this.validateValue)) { if (Array.isArray(this.selectedValues)) {
this.checkValue = this.isValueSelectedByArray(this.selectedValues); this.checkValue = this.isMultiSelect
const isSelectedByValidator = this.isValueSelectedByArray(this.validateValue); ? this.selectedValues.includes(this.value)
: this.selectedValues[0] == this.value;
if (this.checkValue != isSelectedByValidator) {
this.handleChange(this.value);
}
} }
else { else {
this.checkValue = this.selectedValues; this.checkValue = this.selectedValues;
@ -117,7 +114,7 @@ export default {
handleCheckChange() { handleCheckChange() {
const emitEvent = { const emitEvent = {
checkValue: this.checkValue, // only read on checkboxes, on handleCheckedChanged on button-question checkValue: this.checkValue, // only read on checkboxes, on handleCheckedChanged on button-question
value: this.value.toString(), value: this.value,
buttonId: this.buttonID && this.buttonID.toString(), buttonId: this.buttonID && this.buttonID.toString(),
}; };
@ -278,6 +275,12 @@ export default {
} }
} }
} }
&.list-button-horizontal {
height: 100%;
label {
height: 100%;
}
}
} }
.col { .col {

View file

@ -21,7 +21,10 @@
<p class="sub-label m-0">most popular</p> <p class="sub-label m-0">most popular</p>
<ul> <ul>
<li>New replacement windshield</li> <li>New replacement windshield</li>
<li>Expert installation and <textLink linkType="dashedUnderline" text="recalibration" href="#!" data-bs-toggle="modal" data-bs-target="#EstimateRainDefenseModal" aria-label="Modal window" /></li> <li><textLink linkType="dashedUnderline" text="Rain Defense" href="#!" data-bs-toggle="modal" data-bs-target="#EstimateRainDefenseModal" aria-label="Modal window" /> treatment</li>
<li>New <textLink linkType="dashedUnderline" text="front wiper blades" href="#!" data-bs-toggle="modal" data-bs-target="#EstimateFrontWiperModal" aria-label="Modal window" /></li>
<li>New <textLink linkType="dashedUnderline" text="rear wiper blade" href="#!" data-bs-toggle="modal" data-bs-target="#EstimateRearWiperModal" aria-label="Modal window" /></li>
<li>Expert <textLink linkType="dashedUnderline" text="recalibration" href="#!" data-bs-toggle="modal" data-bs-target="#EstimateRecalModal" aria-label="Modal window" /></li>
<li>Nationwide lifetime warranty</li> <li>Nationwide lifetime warranty</li>
<li>New wiper blades</li> <li>New wiper blades</li>
</ul> </ul>
@ -46,6 +49,15 @@
<modal <modal
cmsWidgetName="EstimateRainDefenseModal" cmsWidgetName="EstimateRainDefenseModal"
/> />
<modal
cmsWidgetName="EstimateFrontWiperModal"
/>
<modal
cmsWidgetName="EstimateRearWiperModal"
/>
<modal
cmsWidgetName="EstimateRecalModal"
/>
</div> </div>
</template> </template>